Spaces:
Running
Running
| """Weekly report scheduling — Sunday cron + startup catch-up.""" | |
| import logging | |
| from datetime import date, datetime, time, timedelta | |
| from db import queries | |
| from llm.weekly_report import generate_weekly_report | |
| logger = logging.getLogger(__name__) | |
| _DEFAULT_REPORT_DAY = "Sunday" | |
| _DEFAULT_REPORT_TIME = "20:00" | |
| _WEEKDAY_BY_NAME = { | |
| "monday": 0, | |
| "tuesday": 1, | |
| "wednesday": 2, | |
| "thursday": 3, | |
| "friday": 4, | |
| "saturday": 5, | |
| "sunday": 6, | |
| } | |
| def _parse_report_time(raw_time: str) -> time: | |
| """Parse HH:MM report time from weekly_check_structure.""" | |
| try: | |
| hours_text, minutes_text = raw_time.strip().split(":", 1) | |
| return time(hour=int(hours_text), minute=int(minutes_text)) | |
| except (AttributeError, TypeError, ValueError): | |
| return time(hour=20, minute=0) | |
| def _report_date_in_week(week_start: date, report_day: str) -> date: | |
| """Return the calendar date of report_day within the Monday-based week.""" | |
| target_weekday = _WEEKDAY_BY_NAME.get(report_day.strip().lower(), 6) | |
| for offset in range(7): | |
| candidate = week_start + timedelta(days=offset) | |
| if candidate.weekday() == target_weekday: | |
| return candidate | |
| return week_start + timedelta(days=6) | |
| def _report_deadline_for_week(week_start: date) -> datetime: | |
| """Return the local datetime when a week's report becomes due.""" | |
| structure = queries.get_weekly_check_structure() or {} | |
| report_day = str(structure.get("report_day", _DEFAULT_REPORT_DAY)) | |
| report_time = str(structure.get("report_time", _DEFAULT_REPORT_TIME)) | |
| report_date = _report_date_in_week(week_start, report_day) | |
| parsed_time = _parse_report_time(report_time) | |
| return datetime.combine(report_date, parsed_time) | |
| def is_weekly_report_due(week_start: date, now: datetime | None = None) -> bool: | |
| """Return true when the report deadline for week_start has passed.""" | |
| current = now or datetime.now() | |
| return current >= _report_deadline_for_week(week_start) | |
| def pending_weekly_report_start(now: datetime | None = None) -> date | None: | |
| """Return the Monday week_start that needs a report, or None.""" | |
| if not queries.check_onboarding_status(): | |
| return None | |
| current = now or datetime.now() | |
| today = current.date() | |
| this_week = queries.monday_of_week(today) | |
| last_week = this_week - timedelta(days=7) | |
| for week_start in (last_week, this_week): | |
| if not is_weekly_report_due(week_start, current): | |
| continue | |
| if queries.get_weekly_report(week_start) is not None: | |
| continue | |
| return week_start | |
| return None | |
| def ensure_weekly_report(force: bool = False, now: datetime | None = None) -> bool: | |
| """Generate the pending weekly report when due; return True if one exists.""" | |
| current = now or datetime.now() | |
| week_start = queries.monday_of_week(current.date()) if force else pending_weekly_report_start(current) | |
| if week_start is None and not force: | |
| return queries.get_weekly_report(queries.monday_of_week(current.date())) is not None | |
| if week_start is None: | |
| week_start = queries.monday_of_week(current.date()) | |
| report = generate_weekly_report(week_start, force=force) | |
| if report is None: | |
| return False | |
| logger.info( | |
| "[weekly_report] Ready for week %s (%s chars).", | |
| week_start.isoformat(), | |
| len(report.report_text), | |
| ) | |
| return True | |
| def run_weekly_startup(force: bool = False) -> None: | |
| """Run idempotent weekly startup tasks for onboarded users.""" | |
| if not queries.check_onboarding_status(): | |
| return | |
| ensure_weekly_report(force=force) | |