feat(workflow): add direct quote-to-invoice and order-to-delivery endpoints

This commit is contained in:
Fanilo-Nantenaina 2025-12-08 09:54:39 +03:00
parent 57d1f313f4
commit 5a6a721f16

180
api.py
View file

@ -3170,6 +3170,186 @@ async def livraison_vers_facture(id: str, session: AsyncSession = Depends(get_se
raise HTTPException(500, str(e))
@app.post("/workflow/devis/{id}/to-facture", tags=["US-A2"])
async def devis_vers_facture_direct(id: str, session: AsyncSession = Depends(get_session)):
"""
🔧 Transformation Devis Facture (DIRECT, sans commande)
Utilise les VRAIS types Sage (0 60)
Met à jour le statut du devis source à 5 (Transformé)
**Workflow raccourci** : Permet de facturer directement depuis un devis
sans passer par la création d'une commande.
**Cas d'usage** :
- Prestations de services facturées directement
- Petites commandes sans besoin de suivi intermédiaire
- Ventes au comptoir
Args:
id: Numéro du devis source
Returns:
Informations de la facture créée
"""
try:
# Étape 1: Vérifier que le devis n'a pas déjà été transformé
devis_existant = sage_client.lire_devis(id)
if not devis_existant:
raise HTTPException(404, f"Devis {id} introuvable")
statut_devis = devis_existant.get("statut", 0)
if statut_devis == 5:
raise HTTPException(
400,
f"Le devis {id} a déjà été transformé (statut=5). "
f"Vérifiez les documents déjà créés depuis ce devis."
)
# Étape 2: Transformation
resultat = sage_client.transformer_document(
numero_source=id,
type_source=settings.SAGE_TYPE_DEVIS, # = 0
type_cible=settings.SAGE_TYPE_FACTURE, # = 60
)
# Étape 3: Mettre à jour le statut du devis à 5 (Transformé)
try:
sage_client.changer_statut_devis(id, nouveau_statut=5)
logger.info(f"✅ Statut devis {id} mis à jour: 5 (Transformé)")
except Exception as e:
logger.warning(f"⚠️ Impossible de mettre à jour le statut du devis {id}: {e}")
# On continue même si la MAJ statut échoue
# Étape 4: Logger la transformation
workflow_log = WorkflowLog(
id=str(uuid.uuid4()),
document_source=id,
type_source=TypeDocument.DEVIS,
document_cible=resultat.get("document_cible", ""),
type_cible=TypeDocument.FACTURE,
nb_lignes=resultat.get("nb_lignes", 0),
date_transformation=datetime.now(),
succes=True,
)
session.add(workflow_log)
await session.commit()
logger.info(
f"✅ Transformation DIRECTE: Devis {id} → Facture {resultat['document_cible']}"
)
return {
"success": True,
"workflow": "devis_to_facture_direct",
"document_source": id,
"document_cible": resultat["document_cible"],
"nb_lignes": resultat["nb_lignes"],
"statut_devis_mis_a_jour": True,
"message": f"Facture {resultat['document_cible']} créée directement depuis le devis {id}",
}
except HTTPException:
raise
except Exception as e:
logger.error(f"❌ Erreur transformation devis→facture: {e}", exc_info=True)
raise HTTPException(500, str(e))
@app.post("/workflow/commande/{id}/to-livraison", tags=["US-A2"])
async def commande_vers_livraison(id: str, session: AsyncSession = Depends(get_session)):
"""
🔧 Transformation Commande Bon de livraison
Utilise les VRAIS types Sage (10 30)
**Workflow typique** : Après validation d'une commande, génère
le bon de livraison pour préparer l'expédition.
**Cas d'usage** :
- Préparation d'une expédition
- Génération du bordereau de livraison
- Suivi logistique
**Workflow complet** :
1. Devis Commande (via `/workflow/devis/{id}/to-commande`)
2. **Commande Livraison** (cette route)
3. Livraison Facture (via `/workflow/livraison/{id}/to-facture`)
Args:
id: Numéro de la commande source
Returns:
Informations du bon de livraison créé
"""
try:
# Étape 1: Vérifier que la commande existe
commande_existante = sage_client.lire_document(
id,
settings.SAGE_TYPE_BON_COMMANDE
)
if not commande_existante:
raise HTTPException(404, f"Commande {id} introuvable")
statut_commande = commande_existante.get("statut", 0)
if statut_commande == 5:
raise HTTPException(
400,
f"La commande {id} a déjà été transformée (statut=5). "
f"Un bon de livraison existe probablement déjà."
)
if statut_commande == 6:
raise HTTPException(
400,
f"La commande {id} est annulée (statut=6) et ne peut pas être transformée."
)
# Étape 2: Transformation
resultat = sage_client.transformer_document(
numero_source=id,
type_source=settings.SAGE_TYPE_BON_COMMANDE, # = 10
type_cible=settings.SAGE_TYPE_BON_LIVRAISON, # = 30
)
# Étape 3: Logger la transformation
workflow_log = WorkflowLog(
id=str(uuid.uuid4()),
document_source=id,
type_source=TypeDocument.BON_COMMANDE,
document_cible=resultat.get("document_cible", ""),
type_cible=TypeDocument.BON_LIVRAISON,
nb_lignes=resultat.get("nb_lignes", 0),
date_transformation=datetime.now(),
succes=True,
)
session.add(workflow_log)
await session.commit()
logger.info(
f"✅ Transformation: Commande {id} → Livraison {resultat['document_cible']}"
)
return {
"success": True,
"workflow": "commande_to_livraison",
"document_source": id,
"document_cible": resultat["document_cible"],
"nb_lignes": resultat["nb_lignes"],
"message": f"Bon de livraison {resultat['document_cible']} créé depuis la commande {id}",
"next_step": f"Utilisez /workflow/livraison/{resultat['document_cible']}/to-facture pour créer la facture",
}
except HTTPException:
raise
except Exception as e:
logger.error(f"❌ Erreur transformation commande→livraison: {e}", exc_info=True)
raise HTTPException(500, str(e))
@app.get("/debug/users", response_model=List[UserResponse], tags=["Debug"])
async def lister_utilisateurs_debug(
session: AsyncSession = Depends(get_session),