diff --git a/backend/src/jobs.ts b/backend/src/jobs.ts index b9aea48..2df20b4 100644 --- a/backend/src/jobs.ts +++ b/backend/src/jobs.ts @@ -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 { try { @@ -16,8 +16,12 @@ async function runAutoJobs(): Promise { async function runAutoCancelNoShows(): Promise { // 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 { `) 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 { 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 { async function runAutoCheckouts(): Promise { // 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 { `) 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 { 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