Ранее в форме удержания депозита показывалась цена на момент уборки (price_per_unit).
Теперь используется текущая цена позиции (mi.price) — чтобы изменения цен сразу
отражались в счёте. Если цена менялась — показываем индикатор ↑ с tooltip.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Форма удержания: позиции мини-бара расписаны по отдельности (товар × кол-во, цена/шт.)
с кнопками «+ Добавить» для каждой и «+ Добавить всё»
- Email гостю: HTML-шаблон с таблицей-чеком (позиция / сумма), итоговые строки,
остаток возврата, брендинг отеля; текстовый fallback сохранён
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wrong column names in SQL query: price_at_time→price_per_unit,
created_at→recorded_at. Also fixed type mismatch priceAtTime→pricePerUnit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Migration 060: card_last4, card_brand columns in booking_deposits
- Backend: webhook saves card brand/last4 from YooKassa notification
- Backend: GET /api/hotels/:slug/deposits — payment history with guest/room info
- Backend: DELETE /api/hotels/:slug/bookings/:bookingId/deposit — cancel hold_created or paid_cash deposit
- Backend: auto-create YooKassa hold + send deposit email for source='online' bookings
- Frontend: DepositHistoryPage with filters, card display, retention reasons
- Frontend: deposit cancel button for hold_created and paid_cash states
- Frontend: show card last4/brand in hold_confirmed status
- Frontend: release form presets (full return / hold all) + improved UX
- Frontend: webhook setup instructions in DepositSettingsPage
- Frontend: "История платежей" link in deposit settings header
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Backend: GET /api/pay/:slug (public) — returns active hold confirmation URL
- PayDepositPage: public page /:slug/pay for guests (no login required)
- DepositSettingsPage: QR code section with print button
- BookingDetailPanel: DepositWidget in payment tab
- Наличными / ЮКасса (QR) buttons
- hold_created: copy link + refresh
- hold_confirmed: release form (вернуть / списать)
- Final status badges
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Check localhost:9000 on panel open via getIdentity()
- If local agent is running → use its workstation_id directly, no picker
- If agent is offline → show subtle badge 'Агент не запущен · ключи недоступны' under tabs
- If agent offline but multiple server-side encoders online → still show picker
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Migration 051: add ttlock_com_port to workstations, drop com_port/workstation_id from hotel_ttlock_config
- Backend workstations PATCH: accepts ttlock_com_port alongside name
- Backend ttlock: test/issue-card use per-workstation com_port; auto-select online encoder if workstationId not specified
- TTLockPage Step 2: per-workstation table with COM port input, Save, Test buttons per row
- BookingDetailPanel: auto-issue if 1 encoder online, picker modal if multiple
- api.ts: TTLockConfig/Update cleaned up, Workstation gets ttlockComPort, issueCard/testEncoder updated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add TTLock electronic lock module: settings page, room-lock mapping,
card issuance via agent command (ttlock:write_card)
- Fix agent offline: EquipmentPage now polls every 30s + reacts to
workstation:online/offline WebSocket events instantly
- Backend broadcasts workstation online/offline events to hotel clients
via existing WebSocket (agent-ws.ts)
- New DB migration 048_ttlock.sql: hotel_ttlock_config, room_lock_mappings,
card_issuances tables
- New backend routes: GET/PATCH ttlock/config, POST ttlock/token,
GET ttlock/locks, POST/DELETE ttlock/room-locks, POST issue-card
- "Выдать ключ (TTLock)" button in BookingDetailPanel for confirmed/checked_in
- TTLock page added to sidebar under Настройки
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- BookingModal (room tab): replace Фамилия/Имя/Отчество grid with single 'ФИО *' input; parseFullName() splits by spaces into last/first/middle; DB search via api.guests.list (debounced 300ms); dropdown shows current bookings + DB guests with phone/email autofill
- BookingDetailPanel: merge Фамилия (with autocomplete) + Имя + Отчество into single ФИО * input; existing acQuery/acResults infrastructure reused; parseFio() updates all 3 bgForm fields on every keystroke; openEditForm initializes ФИО from full name
- RentalBookingModal + BookingModal rental tab: include middleName when displaying DB guest results and when setting guestName on selection; update type to include middleName field
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously earlyOutDate defaulted to today, which caused bookings checked
out on their first day (checkIn == today) to become 0-night invisible blocks
in the calendar. Now defaults to the planned checkOut date so the bar stays
visible; manager explicitly sets an earlier date for early departure.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PostgreSQL DATE columns serialize as ISO strings with time component
(2026-03-21T00:00:00.000Z), causing string comparison with yyyy-MM-dd
to incorrectly show the early check-in banner for same-day bookings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- DB migration 016: add early_checkin_fee, late_checkout_fee to rooms table
- Backend rooms: support new fee columns in POST/PATCH
- Backend hotel-settings GET: also returns check_in_time, check_out_time
- Room type + RoomPayload: add earlyCheckinFee, lateCheckoutFee fields
- RoomModal: add fee amount inputs in pricing section
- SettingsPage: add toggles for early_checkin_enabled / late_checkout_enabled
- BookingDetailPanel: on check-in shows fee warning + adds payment record if
current time is before checkInTime and fee is set on the room; same logic
for check-out after checkOutTime
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces simple 'Выселить' button with a checkout form:
- Date picker (min=checkIn, max=original checkOut)
- If leaving early: shows refund nights, refund amount, and payment method selector
- Adds negative payment record to local payment history
- On confirm: sets status=checked_out and updates checkOut date
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Show amber banner on confirmed bookings where check-in is in the future.
Opens an inline form to check in today: checks if current room is free,
otherwise shows available rooms with price difference. Allows overriding
checkout date. On confirm, sets status=checked_in and check-in=today.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Migration 014: add passport_issued_by, passport_issue_date to guests table
- guests.ts: include new fields in SELECT, INSERT, PATCH + encrypt/decrypt
- booking-guests.ts: sync issued_by/issue_date back to guests on update
- GuestApiType: add passportIssuedBy, passportIssueDate fields
- selectAcGuest: fill passport_issued_by and passport_issue_date from guest profile
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add lastName/firstName/middleName/phone fields to booking form
- Remove 'Документы гостя' tab entirely from BookingModal
- Auto-parse existing guestName into FIO parts when editing
- Add guestPhone to Booking type and propagate through CalendarPage/BookingsPage API calls
- Add middle_name to guests table (migration 011)
- Update guests backend route to include middle_name in all queries
- Add middleName to GuestApiType in api.ts
- Fix selectAcGuest in BookingDetailPanel to also fill middle_name
- Auto-open guest form pre-filled with booking FIO when no guests exist
- Add passport series+number lookup in BookingDetailPanel guest form
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Filter cancelled bookings from calendar grid (they no longer appear as red blocks)
- Remove cancelled from legend
- Drag-to-move: left-click drag a booking block to a different room row; click without dragging still opens the detail panel
- checked_out bookings are now semi-transparent and pointer-events-none so clicking through them creates a new booking
- Conflict detection in BookingDetailPanel now excludes checked_out bookings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- BookingsPage: hide Номер/Выезд/Источник columns on small screens, show nights inline on mobile
- GuestsPage: stats grid 2→4 cols (grid-cols-2 lg:grid-cols-4), table columns hidden on mobile (md/lg breakpoints), GuestModal stats 2→4 cols on sm+
- BookingDetailPanel: full-width on mobile (w-full sm:w-[400px])
- Topbar: notifications panel full-width on mobile (w-[calc(100vw-1rem)] sm:w-96)
- LoyaltyPage, MaintenancePage, DiscountsPage, TariffsPage: stats grids grid-cols-2 lg:grid-cols-4
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>