From 88e782c2054d552496e21a3307450dedecf022b6 Mon Sep 17 00:00:00 2001 From: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Wed, 17 Jun 2026 11:14:29 -0400 Subject: [PATCH] Add holiday shifts with 3CX routing and late-pickup approval (#121) Holiday day-shifts (08:00-17:00 ET) with N slots and 1.5x pay. A new afterhours-holiday-router Lambda, fired by per-holiday EventBridge Scheduler one-offs, repoints IVR 800 (key-0 + no-input/timeout) to holiday queue 802 and sets 802's membership to the day's assignees (ext 100 fallback when unfilled), reverting at 17:00. Pickups after a shift starts go through an admin Approve/Deny flow for both regular and holiday shifts. Pay (weekly post + /oncall pay) shows holiday rates distinctly. Adds HOLIDAY and PICKUP_REQUEST DynamoDB record types, scheduler IAM scoped to holiday-* schedules with conditioned PassRole, and the holiday-router function with a 60-day log group and error alarm. --- CHANGELOG.md | 25 + README.md | 76 +- scripts/seed_schedule.py | 29 +- src/holiday-router/app.py | 192 ++++ src/holiday-router/requirements.txt | 2 + src/shared/shared/blocks.py | 202 +++- src/shared/shared/schedule.py | 360 +++++- src/shared/shared/three_cx_client.py | 69 +- src/slack-bot/CHANGELOG.md | 25 + src/slack-bot/app.py | 1005 ++++++++++++++++- src/weekly-post/app.py | 167 ++- template.yaml | 125 ++ tests/conftest.py | 19 + tests/holiday_router/conftest.py | 22 + tests/holiday_router/test_handler.py | 273 +++++ tests/shared/test_blocks.py | 191 ++++ tests/shared/test_schedule.py | 272 ++++- tests/shared/test_three_cx_client.py | 88 ++ tests/slack_bot/test_handle_holiday.py | 311 +++++ .../slack_bot/test_handle_holiday_actions.py | 229 ++++ tests/slack_bot/test_late_pickup.py | 374 ++++++ tests/weekly_post/test_pay_math.py | 187 +++ 22 files changed, 4132 insertions(+), 111 deletions(-) create mode 100644 src/holiday-router/app.py create mode 100644 src/holiday-router/requirements.txt create mode 100644 tests/holiday_router/conftest.py create mode 100644 tests/holiday_router/test_handler.py create mode 100644 tests/slack_bot/test_handle_holiday.py create mode 100644 tests/slack_bot/test_handle_holiday_actions.py create mode 100644 tests/slack_bot/test_late_pickup.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 6418eb7..b676ce6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,31 @@ fine and still supported. --- +## v1.11.0 — June 15, 2026 + +**Holiday coverage and last-minute pickups.** Two related additions: + +- **Holidays now have their own day shift.** An admin can schedule a holiday for + any date with `/oncall admin holiday add` — a single daytime shift (8am-5pm ET) + that can have more than one person on it. The bot shows the holiday in the + schedule with a button to grab an open slot, and holiday slots can be set to + pay a higher rate (1.5x by default). On the holiday itself the after-hours + phones automatically route to whoever claimed a slot, from 8am to 5pm, and + switch back to normal at 5pm — no one has to touch the phone system. If a + holiday goes by with nobody signed up, calls fall back to the default + extension. Admins can also list upcoming holidays and remove one they no longer + need. Holidays take priority over both regular overrides and the standing + weekly schedule for that date. +- **Picking up a shift after it has already started now needs an admin to say + yes.** Before, you could only pick up a shift that hadn't started. Now, if a + shift is already underway (8am for a day/holiday shift, 5pm for a night shift) + but hasn't ended yet, asking to pick it up sends every admin an Approve/Deny + message — the same way swaps are confirmed. The first admin to approve wins, + and once approved the shift is handed over and the phones are repointed right + away. Picking up a shift that hasn't started yet still happens instantly, and + a shift that has already ended can't be picked up at all. This applies to both + regular and holiday shifts. + ## v1.10.1 — June 15, 2026 **Payroll summary emails are sending again.** The automated weekly pay summary diff --git a/README.md b/README.md index 5bbf386..e789c92 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ The bot also has an **About** page: open the bot in Slack and click its **Home** |---|---| | `/oncall` | Show this week's schedule | | `/oncall next` | Show next week's schedule | -| `/oncall pick ` | Pick up an available shift | +| `/oncall pick ` | Pick up an available shift — instant if the shift hasn't started; if it's already underway (but not ended) it needs admin approval (see [Late-pickup approval](#late-pickup-approval)) | | `/oncall drop ` | Drop your shift (marks it available) — blocked within 24h of shift start; swap or ask an admin instead | | `/oncall swap @person` | Request a swap — the other person gets an Accept/Decline DM and the shift only moves once they accept | | `/oncall register ` | Link your Slack account to your phone extension | @@ -44,9 +44,16 @@ Available to users listed in `admin_users` in the CONFIG record: | `/oncall admin roster add ` | Add an employee to the roster | | `/oncall admin roster remove ` | Remove an employee | | `/oncall admin roster rename ` | Rename an employee | +| `/oncall admin holiday add [x]