from pydantic import BaseModel, Field, validator from typing import List, Optional, Dict, Any from datetime import datetime, date from enum import Enum class TipoPasto(str, Enum): pranzo = "pranzo" cena = "cena" class PastoBase(BaseModel): data_pasto: date tipo_pasto: TipoPasto = TipoPasto.pranzo portate: Optional[Dict[str, Dict[int, int]]] = Field( default_factory=dict, description="Portate structure: {'primo': {pietanza_id: max_prenotazioni}}" ) turni: Optional[Dict[str, int]] = Field( default_factory=dict, description="Turni structure: {'12:45': max_posti}" ) disponibile: bool = True @validator('portate') def validate_portate(cls, v): if v is None: return {} # Validate structure: each portata should have pietanza_id -> max_count mapping valid_portate = ['primo', 'secondo', 'contorno', 'dolce', 'frutta'] for portata, pietanze in v.items(): if portata not in valid_portate: raise ValueError(f"Portata non valida: {portata}") if not isinstance(pietanze, dict): raise ValueError(f"Pietanze per {portata} deve essere un dizionario") for pietanza_id, max_count in pietanze.items(): if not isinstance(int(pietanza_id), int) or int(pietanza_id) <= 0: raise ValueError(f"ID pietanza non valido: {pietanza_id}") if not isinstance(max_count, int) or max_count < 0: raise ValueError(f"Numero massimo prenotazioni non valido per pietanza {pietanza_id}") return v @validator('turni') def validate_turni(cls, v): if v is None: return {} # Validate time format and capacity import re time_pattern = re.compile(r'^([01]\d|2[0-3]):([0-5]\d)$') for turno, capacity in v.items(): if not time_pattern.match(turno): raise ValueError(f"Formato orario non valido: {turno}. Usare HH:MM") if not isinstance(capacity, int) or capacity < 0: raise ValueError(f"Capacità non valida per turno {turno}: {capacity}") return v class PastoCreate(PastoBase): pass class PastoUpdate(BaseModel): tipo_pasto: Optional[TipoPasto] = None portate: Optional[Dict[str, Dict[int, int]]] = None turni: Optional[Dict[str, int]] = None disponibile: Optional[bool] = None # Same validators as PastoBase for optional fields @validator('portate') def validate_portate(cls, v): if v is None: return v valid_portate = ['primo', 'secondo', 'contorno', 'dolce', 'frutta'] for portata, pietanze in v.items(): if portata not in valid_portate: raise ValueError(f"Portata non valida: {portata}") if not isinstance(pietanze, dict): raise ValueError(f"Pietanze per {portata} deve essere un dizionario") for pietanza_id, max_count in pietanze.items(): if not isinstance(int(pietanza_id), int) or int(pietanza_id) <= 0: raise ValueError(f"ID pietanza non valido: {pietanza_id}") if not isinstance(max_count, int) or max_count < 0: raise ValueError(f"Numero massimo prenotazioni non valido per pietanza {pietanza_id}") return v @validator('turni') def validate_turni(cls, v): if v is None: return v import re time_pattern = re.compile(r'^([01]\d|2[0-3]):([0-5]\d)$') for turno, capacity in v.items(): if not time_pattern.match(turno): raise ValueError(f"Formato orario non valido: {turno}. Usare HH:MM") if not isinstance(capacity, int) or capacity < 0: raise ValueError(f"Capacità non valida per turno {turno}: {capacity}") return v class PastoResponse(PastoBase): id: int created_at: datetime updated_at: datetime class Config: from_attributes = True