"""Working-hours helpers. Working hours are stored per tenant as: {"mon": [["09:00", "13:00"], ["14:00", "18:00"]], ..., "sun": []} Multiple intervals per day model lunch breaks. Missing/empty day = closed. All computations happen in the tenant's timezone. """ from __future__ import annotations from datetime import date, datetime, time, timedelta from zoneinfo import ZoneInfo WEEKDAY_KEYS = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"] # Bosnian day names (Latin) for UI / agent context DAY_NAMES_BS = { "mon": "ponedjeljak", "tue": "utorak", "wed": "srijeda", "thu": "četvrtak", "fri": "petak", "sat": "subota", "sun": "nedjelja", } DEFAULT_WORKING_HOURS: dict[str, list[list[str]]] = { "mon": [["09:00", "18:00"]], "tue": [["09:00", "18:00"]], "wed": [["09:00", "18:00"]], "thu": [["09:00", "18:00"]], "fri": [["09:00", "18:00"]], "sat": [["09:00", "14:00"]], "sun": [], } def _parse_hhmm(s: str) -> time: h, m = s.split(":") return time(int(h), int(m)) def day_intervals( working_hours: dict, day: date, tz: ZoneInfo ) -> list[tuple[datetime, datetime]]: """Open intervals for a calendar day as tz-aware datetimes.""" key = WEEKDAY_KEYS[day.weekday()] out = [] for start_s, end_s in working_hours.get(key, []): start = datetime.combine(day, _parse_hhmm(start_s), tzinfo=tz) end = datetime.combine(day, _parse_hhmm(end_s), tzinfo=tz) if end > start: out.append((start, end)) return out def is_open_at(working_hours: dict, at: datetime, tz: ZoneInfo) -> bool: at = at.astimezone(tz) return any(s <= at < e for s, e in day_intervals(working_hours, at.date(), tz)) def hours_summary_bs(working_hours: dict) -> str: """Human-readable Bosnian working-hours summary for prompts/emails.""" parts = [] for key in WEEKDAY_KEYS: intervals = working_hours.get(key, []) if not intervals: parts.append(f"{DAY_NAMES_BS[key]}: zatvoreno") else: spans = ", ".join(f"{a}–{b}" for a, b in intervals) parts.append(f"{DAY_NAMES_BS[key]}: {spans}") return "; ".join(parts) def iter_days(start: date, end: date): d = start while d <= end: yield d d += timedelta(days=1)