from __future__ import annotations import json from datetime import datetime from typing import Any, Optional from pydantic import BaseModel, ConfigDict, HttpUrl, field_validator class ProductBase(BaseModel): boutique: str url: HttpUrl asin: str titre: Optional[str] url_image: Optional[HttpUrl] categorie: Optional[str] type: Optional[str] actif: Optional[bool] = True class ProductCreate(ProductBase): pass class ProductUpdate(BaseModel): titre: Optional[str] = None url_image: Optional[HttpUrl] = None categorie: Optional[str] = None type: Optional[str] = None actif: Optional[bool] = None class ProductRead(ProductBase): model_config = ConfigDict(from_attributes=True) id: int cree_le: datetime modifie_le: datetime class ProductSnapshotBase(BaseModel): prix_actuel: Optional[float] prix_conseille: Optional[float] prix_min_30j: Optional[float] etat_stock: Optional[str] en_stock: Optional[bool] note: Optional[float] nombre_avis: Optional[int] prime: Optional[bool] choix_amazon: Optional[bool] offre_limitee: Optional[bool] exclusivite_amazon: Optional[bool] # Données étendues a_propos: Optional[list[str]] = None description: Optional[str] = None carateristique: Optional[dict[str, Any]] = None details: Optional[dict[str, Any]] = None categorie_amazon: Optional[str] = None statut_scrap: Optional[str] message_erreur: Optional[str] class ProductSnapshotRead(ProductSnapshotBase): model_config = ConfigDict(from_attributes=True) id: int produit_id: int scrape_le: datetime @field_validator("a_propos", mode="before") @classmethod def parse_a_propos(cls, v: Any) -> list[str] | None: if v is None: return None if isinstance(v, str): try: return json.loads(v) except json.JSONDecodeError: return None return v @field_validator("carateristique", "details", mode="before") @classmethod def parse_json_dict(cls, v: Any) -> dict[str, Any] | None: if v is None: return None if isinstance(v, str): try: return json.loads(v) except json.JSONDecodeError: return None return v class ProductWithSnapshot(ProductBase): """Produit enrichi avec les données du dernier snapshot.""" model_config = ConfigDict(from_attributes=True) id: int cree_le: datetime modifie_le: datetime # Données du dernier snapshot prix_actuel: Optional[float] = None prix_conseille: Optional[float] = None prix_min_30j: Optional[float] = None reduction_pourcent: Optional[int] = None etat_stock: Optional[str] = None en_stock: Optional[bool] = None note: Optional[float] = None nombre_avis: Optional[int] = None prime: Optional[bool] = None choix_amazon: Optional[bool] = None offre_limitee: Optional[bool] = None exclusivite_amazon: Optional[bool] = None # Données étendues a_propos: Optional[list[str]] = None description: Optional[str] = None carateristique: Optional[dict[str, Any]] = None details: Optional[dict[str, Any]] = None categorie_amazon: Optional[str] = None dernier_scrape: Optional[datetime] = None statut_scrap: Optional[str] = None class ProductCreateWithSnapshot(ProductBase): """Création d'un produit avec données de snapshot initiales (depuis preview).""" # Données du snapshot initial prix_actuel: Optional[float] = None prix_conseille: Optional[float] = None prix_min_30j: Optional[float] = None etat_stock: Optional[str] = None en_stock: Optional[bool] = None note: Optional[float] = None nombre_avis: Optional[int] = None prime: Optional[bool] = None choix_amazon: Optional[bool] = None offre_limitee: Optional[bool] = None exclusivite_amazon: Optional[bool] = None # Données étendues a_propos: Optional[list[str]] = None description: Optional[str] = None carateristique: Optional[dict[str, Any]] = None details: Optional[dict[str, Any]] = None categorie_amazon: Optional[str] = None