fix: jobs run every 1h, auto-checkout from hotel check_out_time

- Interval reduced from 10m to 1h (min period is 2h — hourly is enough)
- Auto-checkout threshold: check_out date + hotel.check_out_time + N hours
  (e.g. checkout Mar 23 + 12:00 + 2h = auto-checkout at 14:00)
- Auto-cancel threshold: check_in date + hotel.check_in_time + N hours

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-23 23:13:55 +03:00
parent b9116c427a
commit 9be51e5d07

View File

@@ -3,7 +3,7 @@ import { broadcast } from './routes/ws'
import { createNotification } from './routes/notifications'
import { getHkSettings } from './routes/housekeeping-settings'
const JOB_INTERVAL_MS = 10 * 60 * 1000 // every 10 minutes
const JOB_INTERVAL_MS = 60 * 60 * 1000 // every 1 hour
async function runAutoJobs(): Promise<void> {
try {
@@ -16,8 +16,12 @@ async function runAutoJobs(): Promise<void> {
async function runAutoCancelNoShows(): Promise<void> {
// Find hotels where auto_cancel_noshow_enabled = true
const { rows: hotels } = await db.query<{ id: string; slug: string; hours: number }>(`
// Also fetch check_in_time to calculate from the correct arrival time
const { rows: hotels } = await db.query<{
id: string; slug: string; hours: number; checkInTime: string
}>(`
SELECT h.id, h.slug,
COALESCE(h.check_in_time, '14:00') AS "checkInTime",
COALESCE(
(SELECT (value::text)::int FROM hotel_settings
WHERE hotel_id = h.id AND key = 'auto_cancel_noshow_hours'),
@@ -33,6 +37,8 @@ async function runAutoCancelNoShows(): Promise<void> {
`)
for (const hotel of hotels) {
// Threshold = check_in date + hotel check-in time + N hours
// e.g. check-in date 2025-03-23, check_in_time=14:00, hours=24 → cancel after 14:00 next day
const { rows: bookings } = await db.query<{
id: string; guest_name: string | null; room_id: string
}>(`
@@ -40,8 +46,12 @@ async function runAutoCancelNoShows(): Promise<void> {
FROM bookings b
WHERE b.hotel_id = $1
AND b.status = 'confirmed'
AND (b.check_in::timestamp + ($2 || ' hours')::interval) < NOW()
`, [hotel.id, hotel.hours])
AND (
b.check_in::date
+ $2::time
+ ($3 || ' hours')::interval
) < NOW()
`, [hotel.id, hotel.checkInTime, hotel.hours])
for (const b of bookings) {
const { rows } = await db.query(
@@ -65,8 +75,12 @@ async function runAutoCancelNoShows(): Promise<void> {
async function runAutoCheckouts(): Promise<void> {
// Find hotels where auto_checkout_enabled = true
const { rows: hotels } = await db.query<{ id: string; slug: string; hours: number }>(`
// Also fetch check_out_time so we calculate from the correct departure time
const { rows: hotels } = await db.query<{
id: string; slug: string; hours: number; checkOutTime: string
}>(`
SELECT h.id, h.slug,
COALESCE(h.check_out_time, '12:00') AS "checkOutTime",
COALESCE(
(SELECT (value::text)::int FROM hotel_settings
WHERE hotel_id = h.id AND key = 'auto_checkout_hours'),
@@ -82,6 +96,8 @@ async function runAutoCheckouts(): Promise<void> {
`)
for (const hotel of hotels) {
// Threshold = check_out date + hotel checkout time + N hours
// e.g. checkout date 2025-03-23, check_out_time=12:00, hours=2 → auto-checkout after 14:00
const { rows: bookings } = await db.query<{
id: string; guest_name: string | null; room_id: string
}>(`
@@ -89,8 +105,12 @@ async function runAutoCheckouts(): Promise<void> {
FROM bookings b
WHERE b.hotel_id = $1
AND b.status = 'checked_in'
AND (b.check_out::timestamp + ($2 || ' hours')::interval) < NOW()
`, [hotel.id, hotel.hours])
AND (
b.check_out::date
+ $2::time
+ ($3 || ' hours')::interval
) < NOW()
`, [hotel.id, hotel.checkOutTime, hotel.hours])
for (const b of bookings) {
// Update booking to checked_out