"""Génération des créneaux d'un poste à partir des créneaux types (DayPart).""" import datetime as dt from sqlmodel import Session, select from app.models import DayPart, Edition, Position, Shift def _dates(edition: Edition) -> list[dt.date]: span = (edition.end_date - edition.start_date).days return [edition.start_date + dt.timedelta(days=i) for i in range(span + 1)] def _day_boundary(day_parts: list[DayPart]) -> dt.time: """Début du premier créneau type du jour (le plus petit `order`) — même frontière que `validation.engine._day_boundary`. Un créneau type dont l'heure de début tombe avant cette frontière est la suite de la nuit du jour précédent (ex. `Nuit3` 00 h–01 h après `Soirée` 19 h–00 h) : il doit être généré sur le jour *suivant*, pas sur `day` lui-même.""" if not day_parts: return dt.time(0, 0) return min(day_parts, key=lambda part: part.order).start_time def _window(day: dt.date, part: DayPart, boundary: dt.time) -> tuple[dt.datetime, dt.datetime]: actual_day = day + dt.timedelta(days=1) if part.start_time < boundary else day start = dt.datetime.combine(actual_day, part.start_time) end_day = ( actual_day if part.end_time > part.start_time else actual_day + dt.timedelta(days=1) ) return start, dt.datetime.combine(end_day, part.end_time) def generate_missing_shifts( session: Session, edition: Edition, position: Position ) -> int: """Crée, pour chaque jour de l'édition et chaque créneau type, un créneau à besoin 0/0 s'il n'existe pas déjà. Retourne le nombre créé.""" day_parts = list( session.exec(select(DayPart).where(DayPart.edition_id == edition.id)) ) boundary = _day_boundary(day_parts) existing = { (s.day_part_id, s.starts_at.date()) for s in session.exec( select(Shift).where(Shift.position_id == position.id) ) } created = 0 for day in _dates(edition): for part in day_parts: start, end = _window(day, part, boundary) if (part.id, start.date()) in existing: continue session.add( Shift( edition_id=edition.id, position_id=position.id, day_part_id=part.id, starts_at=start, ends_at=end, min_staff=0, ideal_staff=0, ) ) created += 1 return created