Modified generate_pdf function that caused error
This commit is contained in:
parent
971d35b078
commit
ab062747cb
3 changed files with 49 additions and 115 deletions
56
api.py
56
api.py
|
|
@ -979,46 +979,21 @@ def normaliser_type_doc(type_doc: int) -> int:
|
||||||
return type_doc if type_doc == 0 else type_doc // 10
|
return type_doc if type_doc == 0 else type_doc // 10
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/signature/universign/send", tags=["Signatures"])
|
@app.post("/signature/universign/send", tags=["Signatures"])
|
||||||
async def envoyer_signature_optimise(
|
async def envoyer_signature_optimise(
|
||||||
demande: SignatureRequest, session: AsyncSession = Depends(get_session)
|
demande: SignatureRequest, session: AsyncSession = Depends(get_session)
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
# === DEBUG 1: Normalisation du type ===
|
doc = sage_client.lire_document(
|
||||||
type_doc_normalise = normaliser_type_doc(demande.type_doc)
|
demande.doc_id, 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:
|
if not doc:
|
||||||
logger.error(f"❌ Document {demande.doc_id} introuvable ou vide")
|
|
||||||
raise HTTPException(404, f"Document {demande.doc_id} introuvable")
|
raise HTTPException(404, f"Document {demande.doc_id} introuvable")
|
||||||
|
|
||||||
# === DEBUG 3: Vérification structure du document ===
|
pdf_bytes = email_queue._generate_pdf(
|
||||||
logger.info(f"🔍 DEBUG: Clés du document: {doc.keys() if isinstance(doc, dict) else 'PAS UN DICT!'}")
|
demande.doc_id, normaliser_type_doc(demande.type_doc)
|
||||||
|
)
|
||||||
# === 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 = {
|
doc_data = {
|
||||||
"type_doc": demande.type_doc,
|
"type_doc": demande.type_doc,
|
||||||
"type_label": {
|
"type_label": {
|
||||||
|
|
@ -1028,13 +1003,10 @@ async def envoyer_signature_optimise(
|
||||||
60: "Facture",
|
60: "Facture",
|
||||||
50: "Avoir",
|
50: "Avoir",
|
||||||
}.get(demande.type_doc, "Document"),
|
}.get(demande.type_doc, "Document"),
|
||||||
"montant_ttc": doc.get("total_ttc", 0) if doc else 0,
|
"montant_ttc": doc.get("total_ttc", 0),
|
||||||
"date": doc.get("date", datetime.now().strftime("%d/%m/%Y")) if doc else datetime.now().strftime("%d/%m/%Y"),
|
"date": doc.get("date", datetime.now().strftime("%d/%m/%Y")),
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(f"🔍 DEBUG: doc_data={doc_data}")
|
|
||||||
|
|
||||||
# === Appel Universign ===
|
|
||||||
resultat = await universign_envoyer(
|
resultat = await universign_envoyer(
|
||||||
doc_id=demande.doc_id,
|
doc_id=demande.doc_id,
|
||||||
pdf_bytes=pdf_bytes,
|
pdf_bytes=pdf_bytes,
|
||||||
|
|
@ -1045,10 +1017,8 @@ async def envoyer_signature_optimise(
|
||||||
)
|
)
|
||||||
|
|
||||||
if "error" in resultat:
|
if "error" in resultat:
|
||||||
logger.error(f"❌ Erreur Universign: {resultat['error']}")
|
|
||||||
raise HTTPException(500, resultat["error"])
|
raise HTTPException(500, resultat["error"])
|
||||||
|
|
||||||
# === Enregistrement en base ===
|
|
||||||
signature_log = SignatureLog(
|
signature_log = SignatureLog(
|
||||||
id=str(uuid.uuid4()),
|
id=str(uuid.uuid4()),
|
||||||
document_id=demande.doc_id,
|
document_id=demande.doc_id,
|
||||||
|
|
@ -1068,7 +1038,9 @@ async def envoyer_signature_optimise(
|
||||||
demande.doc_id, demande.type_doc, "UniversignID", resultat["transaction_id"]
|
demande.doc_id, demande.type_doc, "UniversignID", resultat["transaction_id"]
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(f"✅ Signature envoyée: {demande.doc_id} → {demande.email_signataire}")
|
logger.info(
|
||||||
|
f"Signature envoyée: {demande.doc_id} (Email: {resultat['email_sent']})"
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
|
|
@ -1082,9 +1054,9 @@ async def envoyer_signature_optimise(
|
||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"❌ Erreur inattendue signature: {e}", exc_info=True)
|
logger.error(f"Erreur signature: {e}")
|
||||||
raise HTTPException(500, f"Erreur: {str(e)}")
|
raise HTTPException(500, str(e))
|
||||||
|
|
||||||
|
|
||||||
@app.post("/webhooks/universign", tags=["Signatures"])
|
@app.post("/webhooks/universign", tags=["Signatures"])
|
||||||
async def webhook_universign(
|
async def webhook_universign(
|
||||||
|
|
|
||||||
|
|
@ -180,13 +180,13 @@ class EmailQueue:
|
||||||
def _generate_pdf(self, doc_id: str, type_doc: int) -> bytes:
|
def _generate_pdf(self, doc_id: str, type_doc: int) -> bytes:
|
||||||
|
|
||||||
if not self.sage_client:
|
if not self.sage_client:
|
||||||
logger.error(" sage_client non configuré")
|
logger.error("❌ sage_client non configuré")
|
||||||
raise Exception("sage_client non disponible")
|
raise Exception("sage_client non disponible")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
doc = self.sage_client.lire_document(doc_id, type_doc)
|
doc = self.sage_client.lire_document(doc_id, type_doc)
|
||||||
except Exception as e:
|
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")
|
raise Exception(f"Document {doc_id} inaccessible")
|
||||||
|
|
||||||
if not doc:
|
if not doc:
|
||||||
|
|
@ -218,11 +218,11 @@ class EmailQueue:
|
||||||
|
|
||||||
y -= 0.8 * cm
|
y -= 0.8 * cm
|
||||||
pdf.setFont("Helvetica", 11)
|
pdf.setFont("Helvetica", 11)
|
||||||
pdf.drawString(2 * cm, y, f"Code: {doc.get('client_code', '')}")
|
pdf.drawString(2 * cm, y, f"Code: {doc.get('client_code') or ''}")
|
||||||
y -= 0.6 * cm
|
y -= 0.6 * cm
|
||||||
pdf.drawString(2 * cm, y, f"Nom: {doc.get('client_intitule', '')}")
|
pdf.drawString(2 * cm, y, f"Nom: {doc.get('client_intitule') or ''}")
|
||||||
y -= 0.6 * cm
|
y -= 0.6 * cm
|
||||||
pdf.drawString(2 * cm, y, f"Date: {doc.get('date', '')}")
|
pdf.drawString(2 * cm, y, f"Date: {doc.get('date') or ''}")
|
||||||
|
|
||||||
y -= 1.5 * cm
|
y -= 1.5 * cm
|
||||||
pdf.setFont("Helvetica-Bold", 14)
|
pdf.setFont("Helvetica-Bold", 14)
|
||||||
|
|
@ -247,11 +247,20 @@ class EmailQueue:
|
||||||
y = height - 3 * cm
|
y = height - 3 * cm
|
||||||
pdf.setFont("Helvetica", 9)
|
pdf.setFont("Helvetica", 9)
|
||||||
|
|
||||||
designation = ligne.get("designation", "")[:50]
|
designation = (
|
||||||
|
ligne.get("designation")
|
||||||
|
or ligne.get("designation_article")
|
||||||
|
or ""
|
||||||
|
)
|
||||||
|
if designation:
|
||||||
|
designation = str(designation)[:50]
|
||||||
|
else:
|
||||||
|
designation = ""
|
||||||
|
|
||||||
pdf.drawString(2 * cm, y, designation)
|
pdf.drawString(2 * cm, y, designation)
|
||||||
pdf.drawString(10 * cm, y, str(ligne.get("quantite", 0)))
|
pdf.drawString(10 * cm, y, str(ligne.get("quantite") or 0))
|
||||||
pdf.drawString(12 * cm, y, f"{ligne.get('prix_unitaire', 0):.2f}€")
|
pdf.drawString(12 * cm, y, f"{ligne.get('prix_unitaire_ht') or ligne.get('prix_unitaire', 0):.2f}€")
|
||||||
pdf.drawString(15 * cm, y, f"{ligne.get('montant_ht', 0):.2f}€")
|
pdf.drawString(15 * cm, y, f"{ligne.get('montant_ligne_ht') or ligne.get('montant_ht', 0):.2f}€")
|
||||||
y -= 0.6 * cm
|
y -= 0.6 * cm
|
||||||
|
|
||||||
y -= 1 * cm
|
y -= 1 * cm
|
||||||
|
|
@ -260,17 +269,17 @@ class EmailQueue:
|
||||||
y -= 0.8 * cm
|
y -= 0.8 * cm
|
||||||
pdf.setFont("Helvetica-Bold", 11)
|
pdf.setFont("Helvetica-Bold", 11)
|
||||||
pdf.drawString(12 * cm, y, "Total HT:")
|
pdf.drawString(12 * cm, y, "Total HT:")
|
||||||
pdf.drawString(15 * cm, y, f"{doc.get('total_ht', 0):.2f}€")
|
pdf.drawString(15 * cm, y, f"{doc.get('total_ht') or 0:.2f}€")
|
||||||
|
|
||||||
y -= 0.6 * cm
|
y -= 0.6 * cm
|
||||||
pdf.drawString(12 * cm, y, "TVA (20%):")
|
pdf.drawString(12 * cm, y, "TVA (20%):")
|
||||||
tva = doc.get("total_ttc", 0) - doc.get("total_ht", 0)
|
tva = (doc.get("total_ttc") or 0) - (doc.get("total_ht") or 0)
|
||||||
pdf.drawString(15 * cm, y, f"{tva:.2f}€")
|
pdf.drawString(15 * cm, y, f"{tva:.2f}€")
|
||||||
|
|
||||||
y -= 0.6 * cm
|
y -= 0.6 * cm
|
||||||
pdf.setFont("Helvetica-Bold", 14)
|
pdf.setFont("Helvetica-Bold", 14)
|
||||||
pdf.drawString(12 * cm, y, "Total TTC:")
|
pdf.drawString(12 * cm, y, "Total TTC:")
|
||||||
pdf.drawString(15 * cm, y, f"{doc.get('total_ttc', 0):.2f}€")
|
pdf.drawString(15 * cm, y, f"{doc.get('total_ttc') or 0:.2f}€")
|
||||||
|
|
||||||
pdf.setFont("Helvetica", 8)
|
pdf.setFont("Helvetica", 8)
|
||||||
pdf.drawString(
|
pdf.drawString(
|
||||||
|
|
@ -281,9 +290,10 @@ class EmailQueue:
|
||||||
pdf.save()
|
pdf.save()
|
||||||
buffer.seek(0)
|
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()
|
return buffer.read()
|
||||||
|
|
||||||
|
|
||||||
def _send_smtp(self, msg):
|
def _send_smtp(self, msg):
|
||||||
try:
|
try:
|
||||||
with smtplib.SMTP(
|
with smtplib.SMTP(
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ class SageGatewayClient:
|
||||||
self.timeout = 30
|
self.timeout = 30
|
||||||
|
|
||||||
def _post(self, endpoint: str, data: dict = None, retries: int = 3) -> dict:
|
def _post(self, endpoint: str, data: dict = None, retries: int = 3) -> dict:
|
||||||
"""POST avec retry automatique et meilleur logging"""
|
"""POST avec retry automatique"""
|
||||||
import time
|
import time
|
||||||
|
|
||||||
for attempt in range(retries):
|
for attempt in range(retries):
|
||||||
|
|
@ -28,22 +28,12 @@ class SageGatewayClient:
|
||||||
timeout=self.timeout,
|
timeout=self.timeout,
|
||||||
)
|
)
|
||||||
r.raise_for_status()
|
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:
|
except requests.exceptions.RequestException as e:
|
||||||
if attempt == retries - 1:
|
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
|
raise
|
||||||
time.sleep(2**attempt)
|
time.sleep(2**attempt)
|
||||||
|
|
||||||
|
|
@ -90,26 +80,8 @@ class SageGatewayClient:
|
||||||
return self._post("/sage/devis/create", devis_data).get("data", {})
|
return self._post("/sage/devis/create", devis_data).get("data", {})
|
||||||
|
|
||||||
def lire_devis(self, numero: str) -> Optional[Dict]:
|
def lire_devis(self, numero: str) -> Optional[Dict]:
|
||||||
"""Lecture d'un devis avec meilleure gestion d'erreur"""
|
"""Lecture d'un devis"""
|
||||||
try:
|
return self._post("/sage/devis/get", {"code": numero}).get("data")
|
||||||
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(
|
def lister_devis(
|
||||||
self,
|
self,
|
||||||
|
|
@ -140,30 +112,10 @@ class SageGatewayClient:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def lire_document(self, numero: str, type_doc: int) -> Optional[Dict]:
|
def lire_document(self, numero: str, type_doc: int) -> Optional[Dict]:
|
||||||
"""Lecture d'un document générique avec meilleure gestion d'erreur"""
|
"""Lecture d'un document générique"""
|
||||||
try:
|
return self._post(
|
||||||
response = self._post(
|
"/sage/documents/get", {"numero": numero, "type_doc": type_doc}
|
||||||
"/sage/documents/get",
|
).get("data")
|
||||||
{"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(
|
def transformer_document(
|
||||||
self, numero_source: str, type_source: int, type_cible: int
|
self, numero_source: str, type_source: int, type_cible: int
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue