diff --git a/src/shared/python/shared/schedule.py b/src/shared/python/shared/schedule.py index 45dc81e..5a29d31 100644 --- a/src/shared/python/shared/schedule.py +++ b/src/shared/python/shared/schedule.py @@ -142,6 +142,26 @@ class ShiftSchedule: return (FALLBACK_EXTENSION, "Available", "available") + # ── Schedule post tracking ─────────────────────────────────────────── + + def get_schedule_post(self, channel_id: str) -> dict | None: + resp = self.table.get_item( + Key={"PK": "SCHEDULE_POST", "SK": channel_id} + ) + return resp.get("Item") + + def save_schedule_post( + self, channel_id: str, message_ts: str, week_start: str + ) -> None: + self.table.put_item( + Item={ + "PK": "SCHEDULE_POST", + "SK": channel_id, + "message_ts": message_ts, + "week_start": week_start, + } + ) + # ── Pay records ───────────────────────────────────────────────────── def get_pay_record(self, week_key: str) -> dict | None: diff --git a/src/slack-bot/app.py b/src/slack-bot/app.py index 497e043..7a7bd25 100644 --- a/src/slack-bot/app.py +++ b/src/slack-bot/app.py @@ -185,6 +185,29 @@ def create_app( blocks=blocks, text=f"Shift picked up for {date_str}", ) + _refresh_schedule_post(client) + + def _refresh_schedule_post(client): + """Update the pinned schedule message in-place after a shift change.""" + channel = schedule_channel + if not channel: + return + post = schedule.get_schedule_post(channel) + if not post or not post.get("message_ts"): + return + try: + blocks = build_week_schedule(schedule) + now = datetime.now(EASTERN) + this_monday = now - timedelta(days=now.weekday()) + end_date = this_monday + timedelta(days=13) + client.chat_update( + channel=channel, + ts=post["message_ts"], + blocks=blocks, + text=f"After-Hours Schedule — {now.strftime('%b %-d')} to {end_date.strftime('%b %-d')}", + ) + except Exception: + logger.warning("Could not update schedule post", exc_info=True) # ── Subcommand handlers ───────────────────────────────────────────── @@ -350,6 +373,7 @@ def create_app( ) except Exception: logger.exception("Failed to post pickup notification to channel") + _refresh_schedule_post(client) def _handle_drop(respond, schedule, user_id, text, channel_id, client): parts = text.split(maxsplit=1) @@ -395,6 +419,7 @@ def create_app( ) except Exception: logger.exception("Failed to post drop notification to channel") + _refresh_schedule_post(client) def _handle_swap(respond, schedule, user_id, text, channel_id, client): # Expected format: swap @user OR swap @@ -466,5 +491,6 @@ def create_app( ) except Exception: logger.exception("Failed to post swap notification to channel") + _refresh_schedule_post(client) return app diff --git a/src/weekly-post/app.py b/src/weekly-post/app.py index a630210..f15b7cb 100644 --- a/src/weekly-post/app.py +++ b/src/weekly-post/app.py @@ -189,20 +189,33 @@ def handler(event, context): # Email pay summary to payroll _send_pay_email(week_label, pay_record) + # --- Delete previous week's schedule post --- + old_post = schedule.get_schedule_post(channel_id) + if old_post and old_post.get("message_ts"): + try: + slack.chat_delete(channel=channel_id, ts=old_post["message_ts"]) + logger.info("Deleted previous schedule post %s", old_post["message_ts"]) + except Exception: + logger.warning("Could not delete old schedule post", exc_info=True) + # --- Two-week schedule (always starts on Monday of this week) --- this_monday = now - timedelta(days=now.weekday()) blocks = build_week_schedule(schedule, start_date=this_monday) end_date = this_monday + timedelta(days=13) - slack.chat_postMessage( + result = slack.chat_postMessage( channel=channel_id, blocks=blocks, text=f"After-Hours Schedule — {now.strftime('%b %-d')} to {end_date.strftime('%b %-d')}", ) - logger.info("Posted weekly schedule to channel %s", channel_id) + schedule.save_schedule_post( + channel_id, result["ts"], this_monday.strftime("%Y-%m-%d") + ) + logger.info("Posted weekly schedule to channel %s (ts=%s)", channel_id, result["ts"]) return { "posted": True, "channel": channel_id, + "message_ts": result["ts"], "pay_calculated": bool(pay_record["breakdown"]), }