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:
@@ -3,7 +3,7 @@ import { broadcast } from './routes/ws'
|
|||||||
import { createNotification } from './routes/notifications'
|
import { createNotification } from './routes/notifications'
|
||||||
import { getHkSettings } from './routes/housekeeping-settings'
|
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> {
|
async function runAutoJobs(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
@@ -16,8 +16,12 @@ async function runAutoJobs(): Promise<void> {
|
|||||||
|
|
||||||
async function runAutoCancelNoShows(): Promise<void> {
|
async function runAutoCancelNoShows(): Promise<void> {
|
||||||
// Find hotels where auto_cancel_noshow_enabled = true
|
// 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,
|
SELECT h.id, h.slug,
|
||||||
|
COALESCE(h.check_in_time, '14:00') AS "checkInTime",
|
||||||
COALESCE(
|
COALESCE(
|
||||||
(SELECT (value::text)::int FROM hotel_settings
|
(SELECT (value::text)::int FROM hotel_settings
|
||||||
WHERE hotel_id = h.id AND key = 'auto_cancel_noshow_hours'),
|
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) {
|
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<{
|
const { rows: bookings } = await db.query<{
|
||||||
id: string; guest_name: string | null; room_id: string
|
id: string; guest_name: string | null; room_id: string
|
||||||
}>(`
|
}>(`
|
||||||
@@ -40,8 +46,12 @@ async function runAutoCancelNoShows(): Promise<void> {
|
|||||||
FROM bookings b
|
FROM bookings b
|
||||||
WHERE b.hotel_id = $1
|
WHERE b.hotel_id = $1
|
||||||
AND b.status = 'confirmed'
|
AND b.status = 'confirmed'
|
||||||
AND (b.check_in::timestamp + ($2 || ' hours')::interval) < NOW()
|
AND (
|
||||||
`, [hotel.id, hotel.hours])
|
b.check_in::date
|
||||||
|
+ $2::time
|
||||||
|
+ ($3 || ' hours')::interval
|
||||||
|
) < NOW()
|
||||||
|
`, [hotel.id, hotel.checkInTime, hotel.hours])
|
||||||
|
|
||||||
for (const b of bookings) {
|
for (const b of bookings) {
|
||||||
const { rows } = await db.query(
|
const { rows } = await db.query(
|
||||||
@@ -65,8 +75,12 @@ async function runAutoCancelNoShows(): Promise<void> {
|
|||||||
|
|
||||||
async function runAutoCheckouts(): Promise<void> {
|
async function runAutoCheckouts(): Promise<void> {
|
||||||
// Find hotels where auto_checkout_enabled = true
|
// 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,
|
SELECT h.id, h.slug,
|
||||||
|
COALESCE(h.check_out_time, '12:00') AS "checkOutTime",
|
||||||
COALESCE(
|
COALESCE(
|
||||||
(SELECT (value::text)::int FROM hotel_settings
|
(SELECT (value::text)::int FROM hotel_settings
|
||||||
WHERE hotel_id = h.id AND key = 'auto_checkout_hours'),
|
WHERE hotel_id = h.id AND key = 'auto_checkout_hours'),
|
||||||
@@ -82,6 +96,8 @@ async function runAutoCheckouts(): Promise<void> {
|
|||||||
`)
|
`)
|
||||||
|
|
||||||
for (const hotel of hotels) {
|
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<{
|
const { rows: bookings } = await db.query<{
|
||||||
id: string; guest_name: string | null; room_id: string
|
id: string; guest_name: string | null; room_id: string
|
||||||
}>(`
|
}>(`
|
||||||
@@ -89,8 +105,12 @@ async function runAutoCheckouts(): Promise<void> {
|
|||||||
FROM bookings b
|
FROM bookings b
|
||||||
WHERE b.hotel_id = $1
|
WHERE b.hotel_id = $1
|
||||||
AND b.status = 'checked_in'
|
AND b.status = 'checked_in'
|
||||||
AND (b.check_out::timestamp + ($2 || ' hours')::interval) < NOW()
|
AND (
|
||||||
`, [hotel.id, hotel.hours])
|
b.check_out::date
|
||||||
|
+ $2::time
|
||||||
|
+ ($3 || ' hours')::interval
|
||||||
|
) < NOW()
|
||||||
|
`, [hotel.id, hotel.checkOutTime, hotel.hours])
|
||||||
|
|
||||||
for (const b of bookings) {
|
for (const b of bookings) {
|
||||||
// Update booking to checked_out
|
// Update booking to checked_out
|
||||||
|
|||||||
Reference in New Issue
Block a user