diff --git a/api.py b/api.py index 3bc05b5..00fbb68 100644 --- a/api.py +++ b/api.py @@ -817,39 +817,76 @@ async def envoyer_devis_email( logger.error(f"Erreur envoi email: {e}") raise HTTPException(500, str(e)) - -@app.put("/devis/{id}/statut", tags=["Devis"]) -async def changer_statut_devis( - id: str, +@app.put("/document/{type_doc}/{numero}/statut", tags=["Documents"]) +async def changer_statut_document( + type_doc: int = Path( + ..., + description="Type de document (0=Devis, 10=Commande, 30=Livraison, 60=Facture, 50=Avoir)", + ), + numero: str = Path(..., description="Numéro du document"), nouveau_statut: int = Query( - ..., ge=0, le=6, description="0=Brouillon, 2=Accepté, 5=Transformé, 6=Annulé" + ..., ge=0, le=6, description="0=Saisi, 1=Confirmé, 2=Accepté" ), ): + document_type = 0 try: - devis_existant = sage_client.lire_devis(id) - if not devis_existant: - raise HTTPException(404, f"Devis {id} introuvable") + match type_doc: + case 0: + document_type = TypeDocumentSQL.DEVIS + case 10 | 1: + document_type = TypeDocumentSQL.BON_COMMANDE + case 20 | 2: + document_type = TypeDocumentSQL.PREPARATION + case 30 | 3: + document_type = TypeDocumentSQL.BON_LIVRAISON + case 40 | 4: + document_type = TypeDocumentSQL.BON_RETOUR + case 50 | 5: + document_type = TypeDocumentSQL.BON_AVOIR + case 60 | 6: + document_type = TypeDocumentSQL.FACTURE + case _: + raise HTTPException( + 400, + f"Type de document invalide: {type_doc}. " + f"Types valides: {list(settings.__dict__.values())}", + ) + + document_existant = sage_client.lire_document(numero, document_type) + if not document_existant: + raise HTTPException(404, f"Document {numero} introuvable") - statut_actuel = devis_existant.get("statut", 0) + statut_actuel = document_existant.get("statut", 0) - if statut_actuel == 5: - raise HTTPException( - 400, - f"Le devis {id} a déjà été transformé et ne peut plus changer de statut", - ) + match type_doc: + case 0: + if statut_actuel >= 2: + statuts_devis = {2: "accepté", 3: "perdu", 4: "archivé"} + raise HTTPException( + 400, + f"Le devis {numero} est {statuts_devis.get(statut_actuel, 'verrouillé')} " + f"et ne peut plus changer de statut", + ) + + case 10 | 1 | 30 | 3 | 60 | 6 | 50 | 5: + if statut_actuel >= 2: + type_names = {10: "commande", 1: "commande", 30: "livraison", + 3: "livraison", 60: "facture", 6: "facture", + 50: "avoir", 5: "avoir"} + raise HTTPException( + 400, + f"Le document {numero} ({type_names.get(type_doc, 'document')}) " + f"ne peut plus changer de statut (statut actuel: {statut_actuel})", + ) + + resultat = sage_client.changer_statut_document(numero, nouveau_statut) - if statut_actuel == 6: - raise HTTPException( - 400, f"Le devis {id} est annulé et ne peut plus changer de statut" - ) - - resultat = sage_client.changer_statut_devis(id, nouveau_statut) - - logger.info(f"Statut devis {id} changé: {statut_actuel} → {nouveau_statut}") + logger.info(f"Statut document {numero} changé: {statut_actuel} → {nouveau_statut}") return { "success": True, - "devis_id": id, + "document_id": numero, + "type_document": type_doc, "statut_ancien": resultat.get("statut_ancien", statut_actuel), "statut_nouveau": resultat.get("statut_nouveau", nouveau_statut), "message": f"Statut mis à jour: {statut_actuel} → {nouveau_statut}", @@ -858,10 +895,9 @@ async def changer_statut_devis( except HTTPException: raise except Exception as e: - logger.error(f"Erreur changement statut devis {id}: {e}") + logger.error(f"Erreur changement statut document {numero}: {e}") raise HTTPException(500, str(e)) - @app.get("/commandes/{id}", tags=["Commandes"]) async def lire_commande(id: str): try: @@ -3053,7 +3089,12 @@ async def modifier_contact(numero: str, contact_numero: int, contact: ContactUpd raise HTTPException(400, "Aucune modification fournie") resultat = sage_client.modifier_contact(numero, contact_numero, updates) - return Contact(**resultat) + if isinstance(resultat, dict) and "data" in resultat: + contact_data = resultat["data"] + else: + contact_data = resultat + + return Contact(**contact_data) except HTTPException: raise diff --git a/email_queue.py b/email_queue.py index 5faea6a..44bbb77 100644 --- a/email_queue.py +++ b/email_queue.py @@ -24,12 +24,12 @@ def debug_log(message: str, level: str = "INFO"): if ULTRA_DEBUG: timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3] prefix = { - "INFO": "🔍", - "SUCCESS": "✅", - "ERROR": "❌", - "WARN": "⚠️", - "STEP": "📍", - "DATA": "📦" + "INFO": "[INFO]", + "SUCCESS": "[SUCCESS]", + "ERROR": "[ERROR]", + "WARN": "[WARN]", + "STEP": "[STEP]", + "DATA": "[DATA]" }.get(level, "•") logger.info(f"{prefix} [{timestamp}] {message}") @@ -56,15 +56,15 @@ class EmailQueue: worker.start() self.workers.append(worker) - logger.info(f"✅ Queue email démarrée avec {num_workers} worker(s)") + logger.info(f" Queue email démarrée avec {num_workers} worker(s)") def stop(self): - logger.info("🛑 Arrêt de la queue email...") + logger.info("Arrêt de la queue email...") self.running = False try: self.queue.join() - logger.info("✅ Queue email arrêtée proprement") + logger.info(" Queue email arrêtée proprement") except: logger.warning("⚠️ Timeout lors de l'arrêt de la queue") @@ -93,7 +93,7 @@ class EmailQueue: except queue.Empty: continue except Exception as e: - logger.error(f"❌ Erreur worker {worker_name}: {e}", exc_info=True) + logger.error(f" Erreur worker {worker_name}: {e}", exc_info=True) try: self.queue.task_done() except: @@ -109,7 +109,7 @@ class EmailQueue: debug_log(f"═══ DÉBUT TRAITEMENT EMAIL {email_log_id} ═══", "STEP") if not self.session_factory: - logger.error("❌ session_factory non configuré") + logger.error(" session_factory non configuré") return async with self.session_factory() as session: @@ -119,7 +119,7 @@ class EmailQueue: email_log = result.scalar_one_or_none() if not email_log: - logger.error(f"❌ Email log {email_log_id} introuvable en DB") + logger.error(f" Email log {email_log_id} introuvable en DB") return debug_log(f"Email trouvé en DB:", "DATA") @@ -401,13 +401,13 @@ class EmailQueue: def _generate_pdf(self, doc_id: str, type_doc: int) -> bytes: if not self.sage_client: - logger.error("❌ sage_client non configuré") + logger.error(" sage_client non configuré") raise Exception("sage_client non disponible") try: doc = self.sage_client.lire_document(doc_id, type_doc) except Exception as e: - logger.error(f"❌ Erreur récupération document {doc_id}: {e}") + logger.error(f" Erreur récupération document {doc_id}: {e}") raise Exception(f"Document {doc_id} inaccessible") if not doc: @@ -468,7 +468,7 @@ class EmailQueue: y = height - 3 * cm pdf.setFont("Helvetica", 9) - # ✅ FIX: Gérer les valeurs None correctement + # FIX: Gérer les valeurs None correctement designation = ( ligne.get("designation") or ligne.get("designation_article") @@ -512,7 +512,7 @@ class EmailQueue: pdf.save() buffer.seek(0) - logger.info(f"✅ PDF généré: {doc_id}.pdf") + logger.info(f" PDF généré: {doc_id}.pdf") return buffer.read() diff --git a/sage_client.py b/sage_client.py index 0384be1..5bdba56 100644 --- a/sage_client.py +++ b/sage_client.py @@ -94,10 +94,10 @@ class SageGatewayClient: payload["statut"] = statut return self._post("/sage/devis/list", payload).get("data", []) - def changer_statut_devis(self, numero: str, nouveau_statut: int) -> Dict: + def changer_statut_document(self, numero: str, nouveau_statut: int) -> Dict: try: r = requests.post( - f"{self.url}/sage/devis/statut", + f"{self.url}/sage/document/statut", params={ "numero": numero, "nouveau_statut": nouveau_statut,