"""Import duty schedule: delete range, insert duties/unavailable/vacation. Accepts session.""" from datetime import date, timedelta from sqlalchemy.orm import Session from duty_teller.db.repository import ( get_or_create_user_by_full_name, delete_duties_in_range, insert_duty, ) from duty_teller.importers.duty_schedule import DutyScheduleResult from duty_teller.utils.dates import day_start_iso, day_end_iso, duty_to_iso def _consecutive_date_ranges(dates: list[date]) -> list[tuple[date, date]]: """Sort dates and merge consecutive ones into (first, last) ranges. Empty list -> [].""" if not dates: return [] sorted_dates = sorted(set(dates)) ranges: list[tuple[date, date]] = [] start_d = end_d = sorted_dates[0] for d in sorted_dates[1:]: if (d - end_d).days == 1: end_d = d else: ranges.append((start_d, end_d)) start_d = end_d = d ranges.append((start_d, end_d)) return ranges def run_import( session: Session, result: DutyScheduleResult, hour_utc: int, minute_utc: int, ) -> tuple[int, int, int, int]: """Run import: delete range per user, insert duty/unavailable/vacation. Returns (num_users, num_duty, num_unavailable, num_vacation).""" from_date_str = result.start_date.isoformat() to_date_str = result.end_date.isoformat() num_duty = num_unavailable = num_vacation = 0 for entry in result.entries: user = get_or_create_user_by_full_name(session, entry.full_name) delete_duties_in_range(session, user.id, from_date_str, to_date_str) for d in entry.duty_dates: start_at = duty_to_iso(d, hour_utc, minute_utc) d_next = d + timedelta(days=1) end_at = duty_to_iso(d_next, hour_utc, minute_utc) insert_duty(session, user.id, start_at, end_at, event_type="duty") num_duty += 1 for d in entry.unavailable_dates: insert_duty( session, user.id, day_start_iso(d), day_end_iso(d), event_type="unavailable", ) num_unavailable += 1 for start_d, end_d in _consecutive_date_ranges(entry.vacation_dates): insert_duty( session, user.id, day_start_iso(start_d), day_end_iso(end_d), event_type="vacation", ) num_vacation += 1 return (len(result.entries), num_duty, num_unavailable, num_vacation)