feat: deposit deductions, booking payments persistence, minibar in release form

- Migrations 061 (booking_payments) + 062 (deposit_deduction_presets)
- Backend: booking payments CRUD (GET/POST/DELETE), auto-updates paid_amount on booking
- Backend: deposit deduction presets CRUD (GET/POST/PATCH/DELETE)
- Backend: GET /deposit/minibar endpoint returns minibar consumptions for booking
- Backend: release endpoint accepts items[] for itemized email to guest
- Frontend: payments loaded from API — persist across page reloads
- Frontend: deposit release form redesigned — preset buttons, minibar auto-fill, itemized list
- Frontend: onFocus select on all amount inputs (no more manual "0" removal)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-06 12:55:42 +03:00
parent 633625e7be
commit 1ab24dfe27
7 changed files with 478 additions and 87 deletions

View File

@@ -759,10 +759,11 @@ export const api = {
createYookassaHold: (slug: string, bookingId: string) =>
req<BookingDeposit & { confirmationUrl: string | null }>('POST', `/api/hotels/${slug}/bookings/${bookingId}/deposit/yookassa`),
release: (slug: string, bookingId: string, capturedAmount: number, reason?: string) =>
release: (slug: string, bookingId: string, capturedAmount: number, reason?: string, items?: Array<{ name: string; amount: number }>) =>
req<BookingDeposit>('POST', `/api/hotels/${slug}/bookings/${bookingId}/deposit/release`, {
captured_amount: capturedAmount,
reason,
items,
}),
history: (slug: string) =>
@@ -770,6 +771,29 @@ export const api = {
cancel: (slug: string, bookingId: string) =>
req<void>('DELETE', `/api/hotels/${slug}/bookings/${bookingId}/deposit`),
getMinibarForBooking: (slug: string, bookingId: string) =>
req<{ items: Array<{ itemName: string; quantity: number; priceAtTime: number; lineTotal: number }>; total: number }>(
'GET', `/api/hotels/${slug}/bookings/${bookingId}/deposit/minibar`,
),
getPresets: (slug: string) =>
req<DepositPreset[]>('GET', `/api/hotels/${slug}/deposit/presets`),
createPreset: (slug: string, name: string, amount: number) =>
req<DepositPreset>('POST', `/api/hotels/${slug}/deposit/presets`, { name, amount }),
updatePreset: (slug: string, presetId: string, data: { name?: string; amount?: number }) =>
req<DepositPreset>('PATCH', `/api/hotels/${slug}/deposit/presets/${presetId}`, data),
deletePreset: (slug: string, presetId: string) =>
req<void>('DELETE', `/api/hotels/${slug}/deposit/presets/${presetId}`),
},
payments: {
list: (slug: string, bookingId: string) =>
req<BookingPayment[]>('GET', `/api/hotels/${slug}/bookings/${bookingId}/payments`),
add: (slug: string, bookingId: string, amount: number, method: string, note?: string) =>
req<BookingPayment>('POST', `/api/hotels/${slug}/bookings/${bookingId}/payments`, { amount, method, note }),
remove: (slug: string, bookingId: string, paymentId: string) =>
req<void>('DELETE', `/api/hotels/${slug}/bookings/${bookingId}/payments/${paymentId}`),
},
}
@@ -1358,6 +1382,26 @@ export interface MinibarBookingCharge {
// ── Deposit types ─────────────────────────────────────────────────────────────
export interface DepositPreset {
id: string
hotelId: string
name: string
amount: number
sortOrder: number
createdAt: string
}
export interface BookingPayment {
id: string
hotelId: string
bookingId: string
amount: number
method: string
note: string | null
createdAt: string
createdByName: string | null
}
export interface DepositSettings {
hotelId: string
isEnabled: boolean