from __future__ import annotations from datetime import time from sqlalchemy.ext.asyncio import AsyncSession from models.calendars import CalendarSlot class SlotError(ValueError): pass def _b(v): if isinstance(v, bool): return v s = str(v).lower() return s in {"1","true","t","yes","y","on"} async def update_slot( sess: AsyncSession, slot_id: int, *, name: str | None = None, description: str | None = None, days: dict | None = None, time_start: time | None = None, time_end: time | None = None, cost: float | None = None, flexible: bool | None = None, # NEW ): slot = await sess.get(CalendarSlot, slot_id) if not slot or slot.deleted_at is not None: raise SlotError("slot not found") if name is not None: slot.name = name if description is not None: slot.description = description or None if days is not None: slot.mon = _b(days.get("mon", slot.mon)) slot.tue = _b(days.get("tue", slot.tue)) slot.wed = _b(days.get("wed", slot.wed)) slot.thu = _b(days.get("thu", slot.thu)) slot.fri = _b(days.get("fri", slot.fri)) slot.sat = _b(days.get("sat", slot.sat)) slot.sun = _b(days.get("sun", slot.sun)) if time_start is not None: slot.time_start = time_start if time_end is not None: slot.time_end = time_end if (time_start or time_end) and slot.time_end <= slot.time_start: raise SlotError("time range invalid") if cost is not None: slot.cost = cost # NEW: update flexible flag only if explicitly provided if flexible is not None: slot.flexible = flexible await sess.flush() return slot async def soft_delete_slot(sess: AsyncSession, slot_id: int): slot = await sess.get(CalendarSlot, slot_id) if not slot or slot.deleted_at is not None: return from datetime import datetime, timezone slot.deleted_at = datetime.now(timezone.utc) await sess.flush() async def get_slot(sess: AsyncSession, slot_id: int) -> CalendarSlot | None: return await sess.get(CalendarSlot, slot_id) async def update_slot_description( sess: AsyncSession, slot_id: int, description: str | None, ) -> CalendarSlot: slot = await sess.get(CalendarSlot, slot_id) if not slot: raise SlotError("slot not found") slot.description = description or None await sess.flush() return slot