"""Schémas d'entrée/sortie de l'import. Le rapport ne contient que des **codes** de traduction + des paramètres structurés, jamais de phrase (voir `locales/fr.json`). """ import datetime as dt import uuid from typing import Literal from pydantic import BaseModel, Field Severity = Literal["ERROR", "WARNING"] RowAction = Literal["CREATED", "UPDATED", "SKIPPED"] class ColumnMapping(BaseModel): first_name: str last_name: str email: str | None = None phone: str | None = None tshirt_size: str | None = None diet: str | None = None comment: str | None = None skills: str | None = None class AvailabilityColumnMapping(BaseModel): header: str date: dt.date day_part_code: str class ImportMapping(BaseModel): dry_run: bool = True columns: ColumnMapping availability_columns: list[AvailabilityColumnMapping] = Field( default_factory=list ) class Issue(BaseModel): code: str severity: Severity field: str | None = None params: dict[str, str | int | None] = Field(default_factory=dict) class RowReport(BaseModel): line: int action: RowAction volunteer_id: uuid.UUID | None = None issues: list[Issue] = Field(default_factory=list) class ImportReport(BaseModel): dry_run: bool total_rows: int created: int = 0 updated: int = 0 skipped: int = 0 availabilities_written: int = 0 skills_created: list[str] = Field(default_factory=list) rows: list[RowReport] = Field(default_factory=list) class PreviewRow(BaseModel): line: int values: dict[str, str] class DayPartInfo(BaseModel): code: str label: str start_time: dt.time end_time: dt.time order: int class AnalyzeResponse(BaseModel): filename: str format: Literal["csv", "xlsx"] headers: list[str] row_count: int preview: list[PreviewRow] suggested_mapping: dict[str, str] edition_dates: list[dt.date] day_parts: list[DayPartInfo]