""" Modèle de données commun pour les tickets de courses. Toutes les enseignes (Picnic, Leclerc, etc.) produisent une instance de Receipt après parsing. C'est le format JSON normalisé en sortie. """ import json from dataclasses import dataclass, field, asdict from datetime import date from typing import Optional @dataclass class Item: """Un article sur le ticket de courses.""" name: str """Nom du produit tel qu'il apparaît sur le ticket.""" quantity: float """Quantité achetée (ex: 2.0, 0.5).""" unit: str """Unité de mesure : 'pièce', 'kg', 'L', 'g', etc.""" unit_price: float """Prix unitaire en euros.""" total_price: float """Prix total pour cet article (quantity × unit_price).""" category: Optional[str] = None """Catégorie du produit, si disponible (ex: 'Fruits & Légumes').""" @dataclass class Receipt: """Ticket de courses normalisé, toutes enseignes confondues.""" store: str """Nom de l'enseigne : 'picnic' ou 'leclerc'.""" date: date """Date de la commande ou de l'achat.""" total: float """Montant total payé en euros.""" items: list[Item] = field(default_factory=list) """Liste des articles achetés.""" currency: str = "EUR" """Devise (EUR par défaut).""" order_id: Optional[str] = None """Identifiant de commande, si disponible.""" delivery_fee: Optional[float] = None """Frais de livraison en euros, si applicable (None pour Leclerc).""" def to_dict(self) -> dict: """Convertit le ticket en dictionnaire JSON-sérialisable.""" d = asdict(self) # La date n'est pas JSON-sérialisable nativement, on la convertit en string ISO d["date"] = self.date.isoformat() return d def to_json(self) -> str: """Sérialise le ticket en JSON formaté.""" return json.dumps(self.to_dict(), ensure_ascii=False, indent=2)