feat: deposit release lock + billing fixes + centralized payment gateway
- Add releaseRequiresCheckout toggle in DepositSettingsPage (UI + payload) - Migration 066: release_requires_checkout column on hotel_deposit_settings - Migration 065: hotel_payment_gateways table for centralized YooKassa config - Block deposit release buttons when releaseRequiresCheckout && not checked_out - Fix billing calculation: use Number() to prevent PostgreSQL NUMERIC string concat - Fix minibar billing: show current price (JOIN minibar_items.price) not recorded price - Auto-poll deposit status every 5s while hold_created; clear QR message on confirmation - Add billing/folio tab in BookingDetailPanel (room charges + minibar + payments + balance) - PaymentSettingsPage: new "Онлайн-оплата (ЮКасса)" section with gateway CRUD - DepositSettingsPage: replace YooKassa fields with link to centralized payment settings - BookingWidgetPage: connect to real API, gateway status banner, async booking submission - New backend routes: paymentGateways, publicWidget - YooKassa service: add createCharge() for immediate payment (online bookings) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,7 @@ export function DepositSettingsPage() {
|
||||
|
||||
const [isEnabled, setIsEnabled] = useState(false)
|
||||
const [amount, setAmount] = useState('5000')
|
||||
const [releaseRequiresCheckout, setReleaseRequiresCheckout] = useState(false)
|
||||
const [shopId, setShopId] = useState('')
|
||||
const [secretKey, setSecretKey] = useState('')
|
||||
const [showSecret, setShowSecret] = useState(false)
|
||||
@@ -51,6 +52,7 @@ export function DepositSettingsPage() {
|
||||
setSettings(s)
|
||||
setIsEnabled(s.isEnabled)
|
||||
setAmount(String(s.amount))
|
||||
setReleaseRequiresCheckout(s.releaseRequiresCheckout ?? false)
|
||||
setShopId(s.yookassaShopId ?? '')
|
||||
setSecretKey(s.yookassaSecretKey ?? '')
|
||||
setPresets(p)
|
||||
@@ -69,6 +71,7 @@ export function DepositSettingsPage() {
|
||||
const payload: Record<string, unknown> = {
|
||||
is_enabled: isEnabled,
|
||||
amount: parseFloat(amount) || 5000,
|
||||
release_requires_checkout: releaseRequiresCheckout,
|
||||
}
|
||||
if (shopId) payload.yookassa_shop_id = shopId
|
||||
if (secretKey && secretKey !== '••••••••') payload.yookassa_secret_key = secretKey
|
||||
@@ -182,6 +185,16 @@ export function DepositSettingsPage() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-slate-800 dark:text-slate-200">Запретить возврат депозита до выезда</p>
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400 mt-0.5">
|
||||
Кнопки «Вернуть» и «Списать» будут заблокированы, пока гость не выехал
|
||||
</p>
|
||||
</div>
|
||||
<Toggle on={releaseRequiresCheckout} onChange={() => setReleaseRequiresCheckout(v => !v)} />
|
||||
</div>
|
||||
|
||||
<div className="rounded-lg bg-violet-50 dark:bg-violet-900/10 border border-violet-200 dark:border-violet-700 p-3 space-y-1.5">
|
||||
<p className="text-xs font-semibold text-violet-800 dark:text-violet-300">ЮКасса настраивается в одном месте</p>
|
||||
<p className="text-xs text-violet-700 dark:text-violet-400">
|
||||
|
||||
Reference in New Issue
Block a user