feat: long-stay deposit charge + refunds + auto-confirm widget + white page fix

- Widget white page fix: fallback photo when real rooms have no photos array
- Long-stay deposits: if booking > threshold days and toggle on → full charge instead of hold (bypasses YooKassa 7-day limit)
- DepositSettingsPage: toggle + day threshold input for long-stay full payment
- Refund endpoint: POST /deposit/refund supports full and partial refunds via YooKassa refunds API
- DepositWidget: refund UI for yookassa_charge deposits (full/partial, shows remaining amount)
- partially_refunded status support with badge and "Вернуть ещё" button
- Auto-confirm: webhook now auto-confirms booking status on payment.succeeded for widget bookings
- PaymentSettingsPage: auto-confirm toggle per gateway (shown when booking-widget module active)
- Migration 067: long_stay columns on hotel_deposit_settings, auto_confirm_on_payment on gateways, refunded_amount on deposits

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-07 20:30:26 +03:00
parent bddfa355f2
commit 57531f2022
9 changed files with 368 additions and 53 deletions

View File

@@ -805,6 +805,9 @@ export const api = {
cancel: (slug: string, bookingId: string) =>
req<void>('DELETE', `/api/hotels/${slug}/bookings/${bookingId}/deposit`),
refund: (slug: string, bookingId: string, amount?: number, reason?: string) =>
req<BookingDeposit>('POST', `/api/hotels/${slug}/bookings/${bookingId}/deposit/refund`, { amount, reason }),
getMinibarForBooking: (slug: string, bookingId: string) =>
req<{ items: Array<{ itemName: string; quantity: number; recordedPrice: number; currentPrice: number; lineTotal: number }>; total: number }>(
'GET', `/api/hotels/${slug}/bookings/${bookingId}/deposit/minibar`,
@@ -1555,6 +1558,8 @@ export interface DepositSettings {
yookassaShopId: string | null
yookassaSecretKey: string | null
releaseRequiresCheckout: boolean
longStayFullPayment: boolean
longStayThresholdDays: number
updatedAt?: string
}
@@ -1564,6 +1569,8 @@ export interface DepositSettingsPayload {
yookassa_shop_id?: string
yookassa_secret_key?: string
release_requires_checkout?: boolean
long_stay_full_payment?: boolean
long_stay_threshold_days?: number
}
export interface BookingDeposit {
@@ -1576,6 +1583,7 @@ export interface BookingDeposit {
yookassaPaymentId: string | null
yookassaConfirmationUrl: string | null
capturedAmount: number | null
refundedAmount: number | null
retentionReason: string | null
guestEmailSent: boolean
cardLast4: string | null
@@ -1600,6 +1608,7 @@ export interface PaymentGateway {
currency: string
isActive: boolean
modules: string[]
autoConfirmOnPayment: boolean
createdAt: string
}
@@ -1611,6 +1620,7 @@ export interface PaymentGatewayPayload {
currency?: string
isActive?: boolean
modules?: string[]
autoConfirmOnPayment?: boolean
}
export interface WidgetRoom {