From dbb2a6f16e6cacd0e64607bc27b50de03e92688f Mon Sep 17 00:00:00 2001 From: Fanilo-Nantenaina Date: Sat, 20 Dec 2025 16:19:23 +0300 Subject: [PATCH] feat(api): add date fields to document models --- api.py | 39 +++++++++++++++++++++++++++++++-- sage_client.py | 58 +++++++++++--------------------------------------- 2 files changed, 49 insertions(+), 48 deletions(-) diff --git a/api.py b/api.py index c95d95e..d8a6fb4 100644 --- a/api.py +++ b/api.py @@ -357,6 +357,8 @@ class LigneDevis(BaseModel): class DevisRequest(BaseModel): client_id: str date_devis: Optional[date] = None + date_livraison: Optional[date] = None + date_expedition: Optional[date] = None reference: Optional[str] = None lignes: List[LigneDevis] @@ -564,6 +566,8 @@ class DevisUpdateRequest(BaseModel): """Modèle pour modification d'un devis existant""" date_devis: Optional[date] = None + date_livraison: Optional[date] = None + date_expedition: Optional[date] = None reference: Optional[str] = None lignes: Optional[List[LigneDevis]] = None statut: Optional[int] = Field(None, ge=0, le=6) @@ -572,6 +576,8 @@ class DevisUpdateRequest(BaseModel): json_schema_extra = { "example": { "date_devis": "2024-01-15", + "date_livraison": "2024-01-15", + "date_expedition": "2024-01-15", "reference": "DEV-001", "lignes": [ { @@ -604,8 +610,10 @@ class CommandeCreateRequest(BaseModel): client_id: str date_commande: Optional[date] = None + date_livraison: Optional[date] = None + date_expedition: Optional[date] = None lignes: List[LigneCommande] - reference: Optional[str] = None # Référence externe + reference: Optional[str] = None class Config: json_schema_extra = { @@ -629,6 +637,8 @@ class CommandeUpdateRequest(BaseModel): """Modification d'une commande existante""" date_commande: Optional[date] = None + date_livraison: Optional[date] = None + date_expedition: Optional[date] = None lignes: Optional[List[LigneCommande]] = None statut: Optional[int] = Field(None, ge=0, le=6) reference: Optional[str] = None @@ -637,6 +647,8 @@ class CommandeUpdateRequest(BaseModel): json_schema_extra = { "example": { "date_commande": "2024-01-15", + "date_livraison": "2024-01-15", + "date_expedition": "2024-01-15", "reference": "CMD-EXT-001", "lignes": [ { @@ -668,6 +680,8 @@ class LivraisonCreateRequest(BaseModel): client_id: str date_livraison: Optional[date] = None + date_livraison_prevue: Optional[date] = None + date_expedition: Optional[date] = None lignes: List[LigneLivraison] reference: Optional[str] = None @@ -693,6 +707,8 @@ class LivraisonUpdateRequest(BaseModel): """Modification d'une livraison existante""" date_livraison: Optional[date] = None + date_livraison_prevue: Optional[date] = None + date_expedition: Optional[date] = None lignes: Optional[List[LigneLivraison]] = None statut: Optional[int] = Field(None, ge=0, le=6) reference: Optional[str] = None @@ -700,6 +716,10 @@ class LivraisonUpdateRequest(BaseModel): class Config: json_schema_extra = { "example": { + "date_livraison": "2024-01-15", + "date_livraison_prevue": "2024-01-15", + "date_expedition": "2024-01-15", + "reference": "BL-EXT-001", "lignes": [ { "article_code": "ART001", @@ -730,6 +750,8 @@ class AvoirCreateRequest(BaseModel): client_id: str date_avoir: Optional[date] = None + date_livraison: Optional[date] = None + date_expedition: Optional[date] = None lignes: List[LigneAvoir] reference: Optional[str] = None @@ -755,6 +777,8 @@ class AvoirUpdateRequest(BaseModel): """Modification d'un avoir existant""" date_avoir: Optional[date] = None + date_livraison: Optional[date] = None + date_expedition: Optional[date] = None lignes: Optional[List[LigneAvoir]] = None statut: Optional[int] = Field(None, ge=0, le=6) reference: Optional[str] = None @@ -762,6 +786,10 @@ class AvoirUpdateRequest(BaseModel): class Config: json_schema_extra = { "example": { + "date_avoir": "2024-01-15", + "date_livraison": "2024-01-15", + "date_expedition": "2024-01-15", + "reference": "AV-EXT-001", "lignes": [ { "article_code": "ART001", @@ -792,6 +820,8 @@ class FactureCreateRequest(BaseModel): client_id: str date_facture: Optional[date] = None + date_livraison: Optional[date] = None + date_expedition: Optional[date] = None lignes: List[LigneFacture] reference: Optional[str] = None @@ -817,6 +847,8 @@ class FactureUpdateRequest(BaseModel): """Modification d'une facture existante""" date_facture: Optional[date] = None + date_livraison: Optional[date] = None + date_expedition: Optional[date] = None lignes: Optional[List[LigneFacture]] = None statut: Optional[int] = Field(None, ge=0, le=6) reference: Optional[str] = None @@ -824,6 +856,9 @@ class FactureUpdateRequest(BaseModel): class Config: json_schema_extra = { "example": { + "date_facture": "2024-01-15", + "date_livraison": "2024-01-15", + "date_expedition": "2024-01-15", "lignes": [ { "article_code": "ART001", @@ -1907,7 +1942,7 @@ async def modifier_devis( if devis_update.statut is not None: update_data["statut"] = devis_update.statut - + if devis_update.reference is not None: update_data["reference"] = devis_update.reference diff --git a/sage_client.py b/sage_client.py index 64208ae..631669d 100644 --- a/sage_client.py +++ b/sage_client.py @@ -7,10 +7,6 @@ logger = logging.getLogger(__name__) class SageGatewayClient: - """ - Client HTTP pour communiquer avec la gateway Sage Windows - """ - def __init__(self): self.url = settings.sage_gateway_url.rstrip("/") self.headers = { @@ -264,9 +260,6 @@ class SageGatewayClient: """Lecture d'une livraison avec ses lignes""" return self._post("/sage/livraisons/get", {"code": numero}).get("data") - # ===================================================== - # CACHE (ADMIN) - # ===================================================== def refresh_cache(self) -> Dict: """Force le rafraîchissement du cache Windows""" return self._post("/sage/cache/refresh") @@ -275,9 +268,6 @@ class SageGatewayClient: """Récupère les infos du cache Windows""" return self._get("/sage/cache/info").get("data", {}) - # ===================================================== - # HEALTH - # ===================================================== def health(self) -> dict: """Health check de la gateway Windows""" try: @@ -336,12 +326,11 @@ class SageGatewayClient: try: logger.info(f"📄 Demande génération PDF: doc_id={doc_id}, type={type_doc}") - # Appel HTTP vers la gateway Windows r = requests.post( f"{self.url}/sage/documents/generate-pdf", json={"doc_id": doc_id, "type_doc": type_doc}, headers=self.headers, - timeout=60, # Timeout élevé pour génération PDF + timeout=60, ) r.raise_for_status() @@ -350,7 +339,6 @@ class SageGatewayClient: response_data = r.json() - # Vérifier que la réponse contient bien le PDF if not response_data.get("success"): error_msg = response_data.get("error", "Erreur inconnue") raise RuntimeError(f"Gateway a retourné une erreur: {error_msg}") @@ -362,7 +350,6 @@ class SageGatewayClient: f"PDF vide retourné par la gateway pour {doc_id} (type {type_doc})" ) - # Décoder le base64 pdf_bytes = base64.b64decode(pdf_base64) logger.info(f"✅ PDF décodé: {len(pdf_bytes)} octets") @@ -409,16 +396,13 @@ class SageGatewayClient: def get_stats_familles(self) -> Dict: return self._get("/sage/familles/stats").get("data", {}) - - + def creer_entree_stock(self, entree_data: Dict) -> Dict: return self._post("/sage/stock/entree", entree_data).get("data", {}) - def creer_sortie_stock(self, sortie_data: Dict) -> Dict: return self._post("/sage/stock/sortie", sortie_data).get("data", {}) - def lire_mouvement_stock(self, numero: str) -> Optional[Dict]: try: response = self._get(f"/sage/stock/mouvement/{numero}") @@ -427,14 +411,11 @@ class SageGatewayClient: logger.error(f"Erreur lecture mouvement {numero}: {e}") return None - def lister_modeles_disponibles(self) -> Dict: """Liste les modèles Crystal Reports disponibles""" try: r = requests.get( - f"{self.url}/sage/modeles/list", - headers=self.headers, - timeout=30 + f"{self.url}/sage/modeles/list", headers=self.headers, timeout=30 ) r.raise_for_status() return r.json().get("data", {}) @@ -442,46 +423,31 @@ class SageGatewayClient: logger.error(f"❌ Erreur listage modèles: {e}") raise - def generer_pdf_document( - self, - numero: str, - type_doc: int, - modele: str = None, - base64_encode: bool = True + self, numero: str, type_doc: int, modele: str = None, base64_encode: bool = True ) -> Union[bytes, str, Dict]: - """ - Génère un PDF d'un document Sage - - Returns: - Dict: Avec pdf_base64 si base64_encode=True - bytes: Contenu PDF brut si base64_encode=False - """ try: - params = { - "type_doc": type_doc, - "base64_encode": base64_encode - } - + params = {"type_doc": type_doc, "base64_encode": base64_encode} + if modele: params["modele"] = modele - + r = requests.get( f"{self.url}/sage/documents/{numero}/pdf", params=params, headers=self.headers, - timeout=60 # PDF peut prendre du temps + timeout=60, ) r.raise_for_status() - + if base64_encode: return r.json().get("data", {}) else: return r.content - + except requests.exceptions.RequestException as e: logger.error(f"❌ Erreur génération PDF: {e}") raise - - + + sage_client = SageGatewayClient()