refactor(document): Made status changes to be "global"

This commit is contained in:
Fanilo-Nantenaina 2025-12-30 11:56:18 +03:00
parent bad6f3b44b
commit c89db29963
3 changed files with 85 additions and 44 deletions

89
api.py
View file

@ -817,39 +817,76 @@ async def envoyer_devis_email(
logger.error(f"Erreur envoi email: {e}") logger.error(f"Erreur envoi email: {e}")
raise HTTPException(500, str(e)) raise HTTPException(500, str(e))
@app.put("/document/{type_doc}/{numero}/statut", tags=["Documents"])
@app.put("/devis/{id}/statut", tags=["Devis"]) async def changer_statut_document(
async def changer_statut_devis( type_doc: int = Path(
id: str, ...,
description="Type de document (0=Devis, 10=Commande, 30=Livraison, 60=Facture, 50=Avoir)",
),
numero: str = Path(..., description="Numéro du document"),
nouveau_statut: int = Query( nouveau_statut: int = Query(
..., ge=0, le=6, description="0=Brouillon, 2=Accepté, 5=Transformé, 6=Annulé" ..., ge=0, le=6, description="0=Saisi, 1=Confirmé, 2=Accepté"
), ),
): ):
document_type = 0
try: try:
devis_existant = sage_client.lire_devis(id) match type_doc:
if not devis_existant: case 0:
raise HTTPException(404, f"Devis {id} introuvable") document_type = TypeDocumentSQL.DEVIS
case 10 | 1:
document_type = TypeDocumentSQL.BON_COMMANDE
case 20 | 2:
document_type = TypeDocumentSQL.PREPARATION
case 30 | 3:
document_type = TypeDocumentSQL.BON_LIVRAISON
case 40 | 4:
document_type = TypeDocumentSQL.BON_RETOUR
case 50 | 5:
document_type = TypeDocumentSQL.BON_AVOIR
case 60 | 6:
document_type = TypeDocumentSQL.FACTURE
case _:
raise HTTPException(
400,
f"Type de document invalide: {type_doc}. "
f"Types valides: {list(settings.__dict__.values())}",
)
statut_actuel = devis_existant.get("statut", 0) document_existant = sage_client.lire_document(numero, document_type)
if not document_existant:
raise HTTPException(404, f"Document {numero} introuvable")
if statut_actuel == 5: statut_actuel = document_existant.get("statut", 0)
raise HTTPException(
400,
f"Le devis {id} a déjà été transformé et ne peut plus changer de statut",
)
if statut_actuel == 6: match type_doc:
raise HTTPException( case 0:
400, f"Le devis {id} est annulé et ne peut plus changer de statut" if statut_actuel >= 2:
) statuts_devis = {2: "accepté", 3: "perdu", 4: "archivé"}
raise HTTPException(
400,
f"Le devis {numero} est {statuts_devis.get(statut_actuel, 'verrouillé')} "
f"et ne peut plus changer de statut",
)
resultat = sage_client.changer_statut_devis(id, nouveau_statut) case 10 | 1 | 30 | 3 | 60 | 6 | 50 | 5:
if statut_actuel >= 2:
type_names = {10: "commande", 1: "commande", 30: "livraison",
3: "livraison", 60: "facture", 6: "facture",
50: "avoir", 5: "avoir"}
raise HTTPException(
400,
f"Le document {numero} ({type_names.get(type_doc, 'document')}) "
f"ne peut plus changer de statut (statut actuel: {statut_actuel})",
)
logger.info(f"Statut devis {id} changé: {statut_actuel}{nouveau_statut}") resultat = sage_client.changer_statut_document(numero, nouveau_statut)
logger.info(f"Statut document {numero} changé: {statut_actuel}{nouveau_statut}")
return { return {
"success": True, "success": True,
"devis_id": id, "document_id": numero,
"type_document": type_doc,
"statut_ancien": resultat.get("statut_ancien", statut_actuel), "statut_ancien": resultat.get("statut_ancien", statut_actuel),
"statut_nouveau": resultat.get("statut_nouveau", nouveau_statut), "statut_nouveau": resultat.get("statut_nouveau", nouveau_statut),
"message": f"Statut mis à jour: {statut_actuel}{nouveau_statut}", "message": f"Statut mis à jour: {statut_actuel}{nouveau_statut}",
@ -858,10 +895,9 @@ async def changer_statut_devis(
except HTTPException: except HTTPException:
raise raise
except Exception as e: except Exception as e:
logger.error(f"Erreur changement statut devis {id}: {e}") logger.error(f"Erreur changement statut document {numero}: {e}")
raise HTTPException(500, str(e)) raise HTTPException(500, str(e))
@app.get("/commandes/{id}", tags=["Commandes"]) @app.get("/commandes/{id}", tags=["Commandes"])
async def lire_commande(id: str): async def lire_commande(id: str):
try: try:
@ -3053,7 +3089,12 @@ async def modifier_contact(numero: str, contact_numero: int, contact: ContactUpd
raise HTTPException(400, "Aucune modification fournie") raise HTTPException(400, "Aucune modification fournie")
resultat = sage_client.modifier_contact(numero, contact_numero, updates) resultat = sage_client.modifier_contact(numero, contact_numero, updates)
return Contact(**resultat) if isinstance(resultat, dict) and "data" in resultat:
contact_data = resultat["data"]
else:
contact_data = resultat
return Contact(**contact_data)
except HTTPException: except HTTPException:
raise raise

View file

@ -24,12 +24,12 @@ def debug_log(message: str, level: str = "INFO"):
if ULTRA_DEBUG: if ULTRA_DEBUG:
timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3] timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3]
prefix = { prefix = {
"INFO": "🔍", "INFO": "[INFO]",
"SUCCESS": "", "SUCCESS": "[SUCCESS]",
"ERROR": "", "ERROR": "[ERROR]",
"WARN": "⚠️", "WARN": "[WARN]",
"STEP": "📍", "STEP": "[STEP]",
"DATA": "📦" "DATA": "[DATA]"
}.get(level, "") }.get(level, "")
logger.info(f"{prefix} [{timestamp}] {message}") logger.info(f"{prefix} [{timestamp}] {message}")
@ -56,15 +56,15 @@ class EmailQueue:
worker.start() worker.start()
self.workers.append(worker) self.workers.append(worker)
logger.info(f" Queue email démarrée avec {num_workers} worker(s)") logger.info(f" Queue email démarrée avec {num_workers} worker(s)")
def stop(self): def stop(self):
logger.info("🛑 Arrêt de la queue email...") logger.info("Arrêt de la queue email...")
self.running = False self.running = False
try: try:
self.queue.join() self.queue.join()
logger.info(" Queue email arrêtée proprement") logger.info(" Queue email arrêtée proprement")
except: except:
logger.warning("⚠️ Timeout lors de l'arrêt de la queue") logger.warning("⚠️ Timeout lors de l'arrêt de la queue")
@ -93,7 +93,7 @@ class EmailQueue:
except queue.Empty: except queue.Empty:
continue continue
except Exception as e: except Exception as e:
logger.error(f" Erreur worker {worker_name}: {e}", exc_info=True) logger.error(f" Erreur worker {worker_name}: {e}", exc_info=True)
try: try:
self.queue.task_done() self.queue.task_done()
except: except:
@ -109,7 +109,7 @@ class EmailQueue:
debug_log(f"═══ DÉBUT TRAITEMENT EMAIL {email_log_id} ═══", "STEP") debug_log(f"═══ DÉBUT TRAITEMENT EMAIL {email_log_id} ═══", "STEP")
if not self.session_factory: if not self.session_factory:
logger.error(" session_factory non configuré") logger.error(" session_factory non configuré")
return return
async with self.session_factory() as session: async with self.session_factory() as session:
@ -119,7 +119,7 @@ class EmailQueue:
email_log = result.scalar_one_or_none() email_log = result.scalar_one_or_none()
if not email_log: if not email_log:
logger.error(f" Email log {email_log_id} introuvable en DB") logger.error(f" Email log {email_log_id} introuvable en DB")
return return
debug_log(f"Email trouvé en DB:", "DATA") debug_log(f"Email trouvé en DB:", "DATA")
@ -401,13 +401,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:
@ -468,7 +468,7 @@ class EmailQueue:
y = height - 3 * cm y = height - 3 * cm
pdf.setFont("Helvetica", 9) pdf.setFont("Helvetica", 9)
# FIX: Gérer les valeurs None correctement # FIX: Gérer les valeurs None correctement
designation = ( designation = (
ligne.get("designation") ligne.get("designation")
or ligne.get("designation_article") or ligne.get("designation_article")
@ -512,7 +512,7 @@ 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()

View file

@ -94,10 +94,10 @@ class SageGatewayClient:
payload["statut"] = statut payload["statut"] = statut
return self._post("/sage/devis/list", payload).get("data", []) return self._post("/sage/devis/list", payload).get("data", [])
def changer_statut_devis(self, numero: str, nouveau_statut: int) -> Dict: def changer_statut_document(self, numero: str, nouveau_statut: int) -> Dict:
try: try:
r = requests.post( r = requests.post(
f"{self.url}/sage/devis/statut", f"{self.url}/sage/document/statut",
params={ params={
"numero": numero, "numero": numero,
"nouveau_statut": nouveau_statut, "nouveau_statut": nouveau_statut,