From d0db0e40777f5d9125601341550cb57862e97c8a Mon Sep 17 00:00:00 2001 From: Fanilo-Nantenaina Date: Mon, 29 Dec 2025 20:43:27 +0300 Subject: [PATCH] Reverted delocalized function --- api.py | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 150 insertions(+), 1 deletion(-) diff --git a/api.py b/api.py index ccc8c8d..9dc0bc2 100644 --- a/api.py +++ b/api.py @@ -75,7 +75,6 @@ from schemas import ( ContactCreate, ContactUpdate, ) -from utils.generic_functions import universign_envoyer, universign_statut from utils.normalization import normaliser_type_tiers logging.basicConfig( @@ -126,6 +125,156 @@ app.add_middleware( app.include_router(auth_router) + +async def universign_envoyer( + doc_id: str, + pdf_bytes: bytes, + email: str, + nom: str, + doc_data: dict, + session: AsyncSession, +) -> dict: + import requests + + try: + api_key = settings.universign_api_key + api_url = settings.universign_api_url + auth = (api_key, "") + + logger.info(f"Démarrage processus Universign pour {email}") + + if not pdf_bytes or len(pdf_bytes) == 0: + raise Exception("Le PDF généré est vide") + + # ÉTAPE 1: Création transaction + response = requests.post( + f"{api_url}/transactions", + auth=auth, + json={"name": f"{doc_data.get('type_label', 'Document')} {doc_id}", "language": "fr"}, + timeout=30, + ) + if response.status_code != 200: + raise Exception(f"Erreur création transaction: {response.status_code}") + transaction_id = response.json().get("id") + + # ÉTAPE 2: Upload PDF + files = {"file": (f"{doc_data.get('type_label', 'Document')}_{doc_id}.pdf", pdf_bytes, "application/pdf")} + response = requests.post(f"{api_url}/files", auth=auth, files=files, timeout=60) + if response.status_code not in [200, 201]: + raise Exception(f"Erreur upload fichier: {response.status_code}") + file_id = response.json().get("id") + + # ÉTAPE 3: Ajout document + response = requests.post( + f"{api_url}/transactions/{transaction_id}/documents", + auth=auth, data={"document": file_id}, timeout=30 + ) + if response.status_code not in [200, 201]: + raise Exception(f"Erreur ajout document: {response.status_code}") + document_id = response.json().get("id") + + # ÉTAPE 4: Création champ signature + response = requests.post( + f"{api_url}/transactions/{transaction_id}/documents/{document_id}/fields", + auth=auth, data={"type": "signature"}, timeout=30 + ) + if response.status_code not in [200, 201]: + raise Exception(f"Erreur création champ: {response.status_code}") + field_id = response.json().get("id") + + # ÉTAPE 5: Liaison signataire + response = requests.post( + f"{api_url}/transactions/{transaction_id}/signatures", + auth=auth, data={"signer": email, "field": field_id}, timeout=30 + ) + if response.status_code not in [200, 201]: + raise Exception(f"Erreur liaison signataire: {response.status_code}") + + # ÉTAPE 6: Démarrage + response = requests.post(f"{api_url}/transactions/{transaction_id}/start", auth=auth, timeout=30) + if response.status_code not in [200, 201]: + raise Exception(f"Erreur démarrage: {response.status_code}") + final_data = response.json() + + # Récupération URL + signer_url = "" + if final_data.get("actions"): + for action in final_data["actions"]: + if action.get("url"): + signer_url = action["url"] + break + if not signer_url and final_data.get("signers"): + for signer in final_data["signers"]: + if signer.get("email") == email: + signer_url = signer.get("url", "") + break + if not signer_url: + raise ValueError("URL de signature non retournée par Universign") + + # Préparation email + template = templates_signature_email["demande_signature"] + type_labels = {0: "Devis", 10: "Commande", 30: "Bon de Livraison", 60: "Facture", 50: "Avoir"} + variables = { + "NOM_SIGNATAIRE": nom, + "TYPE_DOC": type_labels.get(doc_data.get("type_doc", 0), "Document"), + "NUMERO": doc_id, + "DATE": doc_data.get("date", datetime.now().strftime("%d/%m/%Y")), + "MONTANT_TTC": f"{doc_data.get('montant_ttc', 0):.2f}", + "SIGNER_URL": signer_url, + "CONTACT_EMAIL": settings.smtp_from, + } + sujet = template["sujet"] + corps = template["corps_html"] + for var, valeur in variables.items(): + sujet = sujet.replace(f"{{{{{var}}}}}", str(valeur)) + corps = corps.replace(f"{{{{{var}}}}}", str(valeur)) + + email_log = EmailLog( + id=str(uuid.uuid4()), + destinataire=email, + sujet=sujet, + corps_html=corps, + document_ids=doc_id, + type_document=doc_data.get("type_doc"), + statut=StatutEmailEnum.EN_ATTENTE, + date_creation=datetime.now(), + nb_tentatives=0, + ) + session.add(email_log) + await session.flush() + email_queue.enqueue(email_log.id) + + return { + "transaction_id": transaction_id, + "signer_url": signer_url, + "statut": "ENVOYE", + "email_log_id": email_log.id, + "email_sent": True, + } + + except Exception as e: + logger.error(f"Erreur Universign: {e}", exc_info=True) + return {"error": str(e), "statut": "ERREUR", "email_sent": False} + + +async def universign_statut(transaction_id: str) -> dict: + import requests + try: + response = requests.get( + f"{settings.universign_api_url}/transactions/{transaction_id}", + auth=(settings.universign_api_key, ""), + timeout=10, + ) + if response.status_code == 200: + data = response.json() + statut_map = {"draft": "EN_ATTENTE", "started": "EN_ATTENTE", "completed": "SIGNE", "refused": "REFUSE", "expired": "EXPIRE", "canceled": "REFUSE"} + return {"statut": statut_map.get(data.get("state"), "EN_ATTENTE"), "date_signature": data.get("completed_at")} + return {"statut": "ERREUR"} + except Exception as e: + logger.error(f"Erreur statut Universign: {e}") + return {"statut": "ERREUR", "error": str(e)} + + @app.get("/clients", response_model=List[ClientDetails], tags=["Clients"]) async def obtenir_clients(query: Optional[str] = Query(None)): try: