better debbuging for universign

This commit is contained in:
Fanilo-Nantenaina 2025-12-30 08:42:16 +03:00
parent 8b2c49b65c
commit 971d35b078
2 changed files with 101 additions and 25 deletions

56
api.py
View file

@ -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(

View file

@ -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