feat(documents): add generic PDF download endpoint for documents
This commit is contained in:
parent
14b2758b68
commit
a1794ac90f
2 changed files with 163 additions and 0 deletions
82
api.py
82
api.py
|
|
@ -1252,6 +1252,88 @@ async def telecharger_devis_pdf(id: str):
|
|||
logger.error(f"Erreur génération PDF: {e}")
|
||||
raise HTTPException(500, str(e))
|
||||
|
||||
@app.get("/documents/{type_doc}/{numero}/pdf", tags=["Documents"])
|
||||
async def telecharger_document_pdf(
|
||||
type_doc: int = Query(..., description="Type de document (0=Devis, 10=Commande, 30=Livraison, 60=Facture, 50=Avoir)"),
|
||||
numero: str = Query(..., description="Numéro du document")
|
||||
):
|
||||
"""
|
||||
📄 Téléchargement PDF d'un document (route généralisée)
|
||||
|
||||
**Types de documents supportés:**
|
||||
- `0`: Devis
|
||||
- `10`: Bon de commande
|
||||
- `30`: Bon de livraison
|
||||
- `60`: Facture
|
||||
- `50`: Bon d'avoir
|
||||
|
||||
**Exemple d'utilisation:**
|
||||
- `GET /documents/0/DE00001/pdf` → PDF du devis DE00001
|
||||
- `GET /documents/60/FA00001/pdf` → PDF de la facture FA00001
|
||||
|
||||
**Retour:**
|
||||
- Fichier PDF prêt à télécharger
|
||||
- Nom de fichier formaté selon le type de document
|
||||
|
||||
Args:
|
||||
type_doc: Type de document Sage (0-60)
|
||||
numero: Numéro du document
|
||||
|
||||
Returns:
|
||||
StreamingResponse avec le PDF
|
||||
"""
|
||||
try:
|
||||
# Mapping des types vers les libellés
|
||||
types_labels = {
|
||||
0: "Devis",
|
||||
10: "Commande",
|
||||
20: "Preparation",
|
||||
30: "BonLivraison",
|
||||
40: "BonRetour",
|
||||
50: "Avoir",
|
||||
60: "Facture"
|
||||
}
|
||||
|
||||
# Vérifier que le type est valide
|
||||
if type_doc not in types_labels:
|
||||
raise HTTPException(
|
||||
400,
|
||||
f"Type de document invalide: {type_doc}. "
|
||||
f"Types valides: {list(types_labels.keys())}"
|
||||
)
|
||||
|
||||
label = types_labels[type_doc]
|
||||
|
||||
logger.info(f"📄 Génération PDF: {label} {numero} (type={type_doc})")
|
||||
|
||||
# Appel à sage_client pour générer le PDF
|
||||
pdf_bytes = sage_client.generer_pdf_document(numero, type_doc)
|
||||
|
||||
if not pdf_bytes:
|
||||
raise HTTPException(
|
||||
500,
|
||||
f"Le PDF du document {numero} est vide"
|
||||
)
|
||||
|
||||
logger.info(f"✅ PDF généré: {len(pdf_bytes)} octets")
|
||||
|
||||
# Nom de fichier formaté
|
||||
filename = f"{label}_{numero}.pdf"
|
||||
|
||||
return StreamingResponse(
|
||||
iter([pdf_bytes]),
|
||||
media_type="application/pdf",
|
||||
headers={
|
||||
"Content-Disposition": f"attachment; filename={filename}",
|
||||
"Content-Length": str(len(pdf_bytes))
|
||||
}
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Erreur génération PDF {numero} (type {type_doc}): {e}", exc_info=True)
|
||||
raise HTTPException(500, f"Erreur génération PDF: {str(e)}")
|
||||
|
||||
@app.post("/devis/{id}/envoyer", tags=["Devis"])
|
||||
async def envoyer_devis_email(
|
||||
|
|
|
|||
|
|
@ -544,6 +544,87 @@ class SageGatewayClient:
|
|||
"facture_data": facture_data
|
||||
}).get("data", {})
|
||||
|
||||
def generer_pdf_document(self, doc_id: str, type_doc: int) -> bytes:
|
||||
"""
|
||||
🆕 Génère le PDF d'un document via la gateway Windows (route généralisée)
|
||||
|
||||
**Cette méthode remplace les appels spécifiques par type de document**
|
||||
|
||||
Args:
|
||||
doc_id: Numéro du document (ex: "DE00001", "FA00001")
|
||||
type_doc: Type de document Sage:
|
||||
- 0: Devis
|
||||
- 10: Bon de commande
|
||||
- 30: Bon de livraison
|
||||
- 60: Facture
|
||||
- 50: Bon d'avoir
|
||||
|
||||
Returns:
|
||||
bytes: Contenu du PDF (binaire)
|
||||
|
||||
Raises:
|
||||
ValueError: Si le PDF retourné est vide
|
||||
RuntimeError: Si erreur de communication avec la gateway
|
||||
|
||||
Example:
|
||||
>>> pdf_bytes = sage_client.generer_pdf_document("DE00001", 0)
|
||||
>>> with open("devis.pdf", "wb") as f:
|
||||
... f.write(pdf_bytes)
|
||||
"""
|
||||
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
|
||||
)
|
||||
|
||||
r.raise_for_status()
|
||||
|
||||
import base64
|
||||
|
||||
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}")
|
||||
|
||||
pdf_base64 = response_data.get("data", {}).get("pdf_base64", "")
|
||||
|
||||
if not pdf_base64:
|
||||
raise ValueError(
|
||||
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")
|
||||
|
||||
return pdf_bytes
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
logger.error(f"⏱️ Timeout génération PDF pour {doc_id}")
|
||||
raise RuntimeError(
|
||||
f"Timeout lors de la génération du PDF (>60s). "
|
||||
f"Le document {doc_id} est peut-être trop volumineux."
|
||||
)
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"❌ Erreur HTTP génération PDF: {e}")
|
||||
raise RuntimeError(f"Erreur de communication avec la gateway: {str(e)}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Erreur génération PDF: {e}", exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
|
||||
# Instance globale
|
||||
|
|
|
|||
Loading…
Reference in a new issue