feat: early check-in / late checkout fees with room-level configuration
- 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>
This commit is contained in:
@@ -75,14 +75,18 @@ export function SettingsPage() {
|
||||
// Booking / assignment settings
|
||||
const [assignmentStrategy, setAssignmentStrategy] = useState<'spread' | 'together' | 'sequential' | 'manual'>('spread')
|
||||
const [showBookingSource, setShowBookingSource] = useState(false)
|
||||
const [requireGuestDocs, setRequireGuestDocs] = useState(false)
|
||||
const [hotelSettingsLoaded, setHotelSettingsLoaded] = useState(false)
|
||||
const [requireGuestDocs, setRequireGuestDocs] = useState(false)
|
||||
const [earlyCheckinEnabled, setEarlyCheckinEnabled] = useState(false)
|
||||
const [lateCheckoutEnabled, setLateCheckoutEnabled] = useState(false)
|
||||
const [hotelSettingsLoaded, setHotelSettingsLoaded] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (!slug || hotelSettingsLoaded) return
|
||||
api.hotelSettings.get(slug)
|
||||
.then(s => {
|
||||
setRequireGuestDocs(Boolean(s.require_guest_docs))
|
||||
setEarlyCheckinEnabled(Boolean(s.early_checkin_enabled))
|
||||
setLateCheckoutEnabled(Boolean(s.late_checkout_enabled))
|
||||
setHotelSettingsLoaded(true)
|
||||
})
|
||||
.catch(console.error)
|
||||
@@ -98,6 +102,26 @@ export function SettingsPage() {
|
||||
}
|
||||
}
|
||||
|
||||
const toggleEarlyCheckin = async () => {
|
||||
const next = !earlyCheckinEnabled
|
||||
setEarlyCheckinEnabled(next)
|
||||
try {
|
||||
await api.hotelSettings.update(slug, { early_checkin_enabled: next })
|
||||
} catch {
|
||||
setEarlyCheckinEnabled(!next)
|
||||
}
|
||||
}
|
||||
|
||||
const toggleLateCheckout = async () => {
|
||||
const next = !lateCheckoutEnabled
|
||||
setLateCheckoutEnabled(next)
|
||||
try {
|
||||
await api.hotelSettings.update(slug, { late_checkout_enabled: next })
|
||||
} catch {
|
||||
setLateCheckoutEnabled(!next)
|
||||
}
|
||||
}
|
||||
|
||||
// Guest settings
|
||||
const [guestTags, setGuestTags] = useState([
|
||||
{ id: 'vip', label: 'VIP', color: '#F59E0B' },
|
||||
@@ -299,6 +323,28 @@ export function SettingsPage() {
|
||||
<Toggle on={requireGuestDocs} onChange={toggleRequireGuestDocs} />
|
||||
</div>
|
||||
|
||||
{/* Early check-in fee */}
|
||||
<div className="flex items-center justify-between p-3 rounded-lg bg-slate-50 dark:bg-slate-700/40">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-slate-900 dark:text-slate-100">Платный ранний заезд</p>
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400">
|
||||
Предлагать доп. оплату при заселении до официального времени заезда. Сумма задаётся в настройках каждого номера.
|
||||
</p>
|
||||
</div>
|
||||
<Toggle on={earlyCheckinEnabled} onChange={toggleEarlyCheckin} />
|
||||
</div>
|
||||
|
||||
{/* Late checkout fee */}
|
||||
<div className="flex items-center justify-between p-3 rounded-lg bg-slate-50 dark:bg-slate-700/40">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-slate-900 dark:text-slate-100">Платный поздний выезд</p>
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400">
|
||||
Предлагать доп. оплату при выезде после официального времени выезда. Сумма задаётся в настройках каждого номера.
|
||||
</p>
|
||||
</div>
|
||||
<Toggle on={lateCheckoutEnabled} onChange={toggleLateCheckout} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
|
||||
Стратегия автоматического расселения
|
||||
|
||||
Reference in New Issue
Block a user