"""Dynamic slot generation. Slots are generated from runtime settings (working hours, slot duration, default capacity) and per-day `FacilitySchedule` overrides (capacity for the day, days off). Generation is idempotent — re-running updates existing slots instead of duplicating them. """ from datetime import datetime, timedelta from apps.core.settings_service import SettingsService from apps.reservations.models import FacilitySchedule, Slot class SlotService: def generate_slots(self, facility, day, line=None) -> int: schedule = FacilitySchedule.objects.filter(facility=facility, date=day).first() if schedule is not None and not schedule.is_open: return 0 # day off service = SettingsService() if schedule is not None and schedule.start_time: start_str = schedule.start_time.strftime("%H:%M") else: start_str = service.get("reservation.working_hours_start", "08:00") if schedule is not None and schedule.end_time: end_str = schedule.end_time.strftime("%H:%M") else: end_str = service.get("reservation.working_hours_end", "17:00") duration = int(service.get("reservation.slot_duration_minutes", 30)) if schedule is not None: capacity = schedule.capacity else: capacity = int(service.get("reservation.default_capacity", 2)) if duration <= 0: raise ValueError("Slot duration must be positive.") start_t = datetime.strptime(start_str, "%H:%M").time() end_t = datetime.strptime(end_str, "%H:%M").time() current = datetime.combine(day, start_t) end_dt = datetime.combine(day, end_t) created = 0 while current + timedelta(minutes=duration) <= end_dt: slot_end = (current + timedelta(minutes=duration)).time() _, was_created = Slot.objects.update_or_create( facility=facility, line=line, date=day, start_time=current.time(), defaults={"end_time": slot_end, "capacity": capacity}, ) if was_created: created += 1 current += timedelta(minutes=duration) return created