From 971d35b07804c50ccd9a91decb2765d3dff184e1 Mon Sep 17 00:00:00 2001 From: Fanilo-Nantenaina Date: Tue, 30 Dec 2025 08:42:16 +0300 Subject: [PATCH] better debbuging for universign --- api.py | 56 ++++++++++++++++++++++++++++++---------- sage_client.py | 70 ++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 101 insertions(+), 25 deletions(-) diff --git a/api.py b/api.py index 9dc0bc2..1d9e4a5 100644 --- a/api.py +++ b/api.py @@ -979,21 +979,46 @@ def normaliser_type_doc(type_doc: int) -> int: return type_doc if type_doc == 0 else type_doc // 10 + @app.post("/signature/universign/send", tags=["Signatures"]) async def envoyer_signature_optimise( demande: SignatureRequest, session: AsyncSession = Depends(get_session) ): try: - doc = sage_client.lire_document( - demande.doc_id, normaliser_type_doc(demande.type_doc) - ) + # === DEBUG 1: Normalisation du type === + type_doc_normalise = normaliser_type_doc(demande.type_doc) + logger.info(f"🔍 DEBUG: type_doc original={demande.type_doc}, normalisé={type_doc_normalise}") + + # === DEBUG 2: Lecture document === + logger.info(f"🔍 DEBUG: Lecture document {demande.doc_id} (type={type_doc_normalise})") + + # Pour les devis, utiliser lire_devis qui est plus fiable + if demande.type_doc == 0: + doc = sage_client.lire_devis(demande.doc_id) + logger.info(f"🔍 DEBUG: lire_devis retourne: {type(doc)} - {doc}") + else: + doc = sage_client.lire_document(demande.doc_id, type_doc_normalise) + logger.info(f"🔍 DEBUG: lire_document retourne: {type(doc)} - {doc}") + if not doc: + logger.error(f"❌ Document {demande.doc_id} introuvable ou vide") raise HTTPException(404, f"Document {demande.doc_id} introuvable") - pdf_bytes = email_queue._generate_pdf( - demande.doc_id, normaliser_type_doc(demande.type_doc) - ) + # === DEBUG 3: Vérification structure du document === + logger.info(f"🔍 DEBUG: Clés du document: {doc.keys() if isinstance(doc, dict) else 'PAS UN DICT!'}") + + # === DEBUG 4: Génération PDF === + logger.info(f"🔍 DEBUG: Génération PDF pour {demande.doc_id}") + + try: + # Utiliser le type original pour _generate_pdf + pdf_bytes = email_queue._generate_pdf(demande.doc_id, type_doc_normalise) + logger.info(f"✅ PDF généré: {len(pdf_bytes)} octets") + except Exception as pdf_error: + logger.error(f"❌ Erreur génération PDF: {pdf_error}", exc_info=True) + raise HTTPException(500, f"Erreur génération PDF: {str(pdf_error)}") + # === Construction doc_data avec protection contre None === doc_data = { "type_doc": demande.type_doc, "type_label": { @@ -1003,10 +1028,13 @@ async def envoyer_signature_optimise( 60: "Facture", 50: "Avoir", }.get(demande.type_doc, "Document"), - "montant_ttc": doc.get("total_ttc", 0), - "date": doc.get("date", datetime.now().strftime("%d/%m/%Y")), + "montant_ttc": doc.get("total_ttc", 0) if doc else 0, + "date": doc.get("date", datetime.now().strftime("%d/%m/%Y")) if doc else datetime.now().strftime("%d/%m/%Y"), } + + logger.info(f"🔍 DEBUG: doc_data={doc_data}") + # === Appel Universign === resultat = await universign_envoyer( doc_id=demande.doc_id, pdf_bytes=pdf_bytes, @@ -1017,8 +1045,10 @@ async def envoyer_signature_optimise( ) if "error" in resultat: + logger.error(f"❌ Erreur Universign: {resultat['error']}") raise HTTPException(500, resultat["error"]) + # === Enregistrement en base === signature_log = SignatureLog( id=str(uuid.uuid4()), document_id=demande.doc_id, @@ -1038,9 +1068,7 @@ async def envoyer_signature_optimise( demande.doc_id, demande.type_doc, "UniversignID", resultat["transaction_id"] ) - logger.info( - f"Signature envoyée: {demande.doc_id} (Email: {resultat['email_sent']})" - ) + logger.info(f"✅ Signature envoyée: {demande.doc_id} → {demande.email_signataire}") return { "success": True, @@ -1054,9 +1082,9 @@ async def envoyer_signature_optimise( except HTTPException: raise except Exception as e: - logger.error(f"Erreur signature: {e}") - raise HTTPException(500, str(e)) - + logger.error(f"❌ Erreur inattendue signature: {e}", exc_info=True) + raise HTTPException(500, f"Erreur: {str(e)}") + @app.post("/webhooks/universign", tags=["Signatures"]) async def webhook_universign( diff --git a/sage_client.py b/sage_client.py index 0384be1..c0f89cd 100644 --- a/sage_client.py +++ b/sage_client.py @@ -16,7 +16,7 @@ class SageGatewayClient: self.timeout = 30 def _post(self, endpoint: str, data: dict = None, retries: int = 3) -> dict: - """POST avec retry automatique""" + """POST avec retry automatique et meilleur logging""" import time for attempt in range(retries): @@ -28,12 +28,22 @@ class SageGatewayClient: timeout=self.timeout, ) r.raise_for_status() - return r.json() + + response_json = r.json() + + # DEBUG: Logger la réponse brute + logger.debug(f"🔍 Response {endpoint}: {response_json}") + + # Vérifier que c'est bien un dict + if not isinstance(response_json, dict): + logger.error(f"❌ Réponse inattendue (pas un dict): {type(response_json)}") + return {"success": False, "data": None, "error": "Réponse invalide"} + + return response_json + except requests.exceptions.RequestException as e: if attempt == retries - 1: - logger.error( - f" Échec après {retries} tentatives sur {endpoint}: {e}" - ) + logger.error(f"❌ Échec après {retries} tentatives sur {endpoint}: {e}") raise time.sleep(2**attempt) @@ -80,8 +90,26 @@ class SageGatewayClient: return self._post("/sage/devis/create", devis_data).get("data", {}) def lire_devis(self, numero: str) -> Optional[Dict]: - """Lecture d'un devis""" - return self._post("/sage/devis/get", {"code": numero}).get("data") + """Lecture d'un devis avec meilleure gestion d'erreur""" + try: + response = self._post("/sage/devis/get", {"code": numero}) + + logger.info(f"🔍 lire_devis({numero}) response keys: {response.keys() if response else 'None'}") + + if not response: + return None + + data = response.get("data") + + # Si data est None mais success=True, c'est suspect + if data is None and response.get("success"): + logger.warning(f"⚠️ success=True mais data=None pour devis {numero}") + + return data + + except Exception as e: + logger.error(f"❌ Erreur lire_devis {numero}: {e}") + return None def lister_devis( self, @@ -112,10 +140,30 @@ class SageGatewayClient: raise def lire_document(self, numero: str, type_doc: int) -> Optional[Dict]: - """Lecture d'un document générique""" - return self._post( - "/sage/documents/get", {"numero": numero, "type_doc": type_doc} - ).get("data") + """Lecture d'un document générique avec meilleure gestion d'erreur""" + try: + response = self._post( + "/sage/documents/get", + {"numero": numero, "type_doc": type_doc} + ) + + # Debug + logger.info(f"🔍 lire_document({numero}, {type_doc}) response: {response}") + + if not response: + logger.warning(f"⚠️ Réponse vide pour document {numero}") + return None + + data = response.get("data") + + if data is None: + logger.warning(f"⚠️ data=None pour document {numero}, response={response}") + + return data + + except Exception as e: + logger.error(f"❌ Erreur lire_document {numero}: {e}") + return None def transformer_document( self, numero_source: str, type_source: int, type_cible: int