Bill arrival/departure-day emails (M9)
Three per-booking workflow phases keep Bill informed of daily activity:
| Phase | Fires at | What |
|---|---|---|
runArrivalDayBillEmail | A +0 14:00Z (8am MT) | “{guest} checking into {Property} today” |
runDepartureDayBillEmail | D +0 14:00Z (8am MT) | “{guest} checking out of {Property} today” |
runStillDirtyCheck | A +0 21:00Z (3pm MT) | Alert if cleaning still incomplete |
All in src/workflows/booking-flag.ts. Replaces BA AAs
287583 / 287600 / 287770 (+ functionally 291536 / 369597 — Bill SMS
day-before, which were no-ops in BA but the morning-of emails cover
the same awareness need).
Why per-booking instead of cron
Originally built as a daily-digest cron. Bill pushed back: workflow steps are the right pattern because each booking owns its own lifecycle. Cron is reserved for true account-wide aggregation (delivery summary, watchdog).
Arrival-day email
Subject: {guest} checking into {Property} today
Body:
{guest} is checking into {Property} today.
Booking: #{id}Guest: {full name}Phone: {phone}Email: {email}Channel: {apiSource}Stay: {arrival} → {departure}
https://stayonthesnow-pms.minnetonka.workers.dev/admin/booking/{id}Tagged purpose=bill_arrival_day in Mailgun variables.
Departure-day email
Subject: {guest} checking out of {Property} today
Body includes turnover info (computeTurnoverDays):
- “No next booking on calendar.” (turnover=-1)
- “BACK-TO-BACK — same-day turnover.” (turnover=0)
- “Next arrival in N days.” (turnover>0)
Tagged purpose=bill_departure_day.
Still-dirty check (3pm)
Reads cleanings.complete_at for this booking’s row. If null, alerts
Bill:
Subject: ⚠️ Still-dirty at 3pm — {Property}
Body: “is arriving today and the cleaning has not been marked complete yet.”
Tagged purpose=bill_dirty_at_3pm.
If complete_at IS set, no email — silent success.
Source
src/workflows/booking-flag.ts— threerun*BillEmailmethods +runStillDirtyCheck- Mailgun tagging makes these surface in
/admin/delivery-status?booking={id}
BA AA mapping
| BA AA | Status |
|---|---|
| 287583 (check in today internal) | Covered |
| 287600 (check-out today internal) | Covered |
| 287770 (3pm still dirty) | Covered |
| 291536 (9am tomorrow checkin SMS) | Functionally — morning-of email lands ~24h after BA’s SMS would have, but covers same awareness |
| 369597 (9am tomorrow checkout SMS) | Same |