From fd60bd3bc7deb88877298da1795a6a0ce5c58e3d Mon Sep 17 00:00:00 2001 From: fanilo Date: Sat, 17 Jan 2026 09:25:31 +0100 Subject: [PATCH] Updated methods on gathering "reglements" --- main.py | 6 +- utils/documents/settle.py | 343 +++++++++++++++++++++----------------- 2 files changed, 190 insertions(+), 159 deletions(-) diff --git a/main.py b/main.py index 8635d48..cd370af 100644 --- a/main.py +++ b/main.py @@ -1844,9 +1844,9 @@ def get_tous_reglements( # Route: Détail d'un règlement @app.get("/sage/reglements/facture/{facture_no}", dependencies=[Depends(verify_token)]) -def get_reglement_facture_detail(facture_no: int): +def get_reglement_facture_detail(facture_no): try: - result = sage.lire_reglement_detail(facture_no) + result = sage.lire_facture_reglement_detail(facture_no) return {"success": True, "data": result} except ValueError as e: raise HTTPException(404, str(e)) @@ -1856,7 +1856,7 @@ def get_reglement_facture_detail(facture_no: int): @app.get("/sage/reglements/{rg_no}", dependencies=[Depends(verify_token)]) -def get_reglement_detail(rg_no: int): +def get_reglement_detail(rg_no): try: result = sage.lire_reglement_detail(rg_no) return {"success": True, "data": result} diff --git a/utils/documents/settle.py b/utils/documents/settle.py index 26639b5..748afda 100644 --- a/utils/documents/settle.py +++ b/utils/documents/settle.py @@ -167,6 +167,85 @@ def lire_tous_journaux(self) -> List[Dict]: ] +def _format_facture(row, echeances: list) -> dict: + """Formatte une facture selon la structure unifiée.""" + types_doc = {6: "Facture", 7: "Avoir"} + + montant_ttc = float(row[6] or 0) + montant_regle = sum(e["montant_regle"] for e in echeances) + reste_a_regler = montant_ttc - montant_regle + + if montant_regle == 0: + statut = "Non réglé" + elif abs(reste_a_regler) < 0.01: + statut = "Soldé" + else: + statut = "Partiellement réglé" + + return { + "domaine": row[0], + "type_code": row[1], + "type_libelle": types_doc.get(row[1], f"Type {row[1]}"), + "numero": (row[2] or "").strip(), + "date": row[3].strftime("%Y-%m-%d") if row[3] else None, + "date_livraison": row[7].strftime("%Y-%m-%d") if row[7] else None, + "reference": (row[4] or "").strip(), + "souche": row[8], + "date_creation": row[9].strftime("%Y-%m-%d %H:%M:%S") if row[9] else None, + "client": { + "code": (row[5] or "").strip(), + "intitule": (row[10] or "").strip(), + "email": (row[11] or "").strip(), + "telephone": (row[12] or "").strip(), + "adresse": None, # Pas dans cette requête + "code_postal": None, + "ville": None, + }, + "montants": { + "total_ttc": montant_ttc, + "montant_regle": montant_regle, + "reste_a_regler": reste_a_regler, + }, + "statut_reglement": statut, + "nb_echeances": len(echeances), + "nb_reglements": sum(len(e["reglements"]) for e in echeances), + "echeances": echeances, + } + + +def _format_reglement(rg_row, rc_montant=None) -> dict: + """Formatte un règlement selon la structure unifiée.""" + return { + "rg_no": rg_row[0], + "numero_piece": (rg_row[4] or "").strip(), + "date": rg_row[2].strftime("%Y-%m-%d") if rg_row[2] else None, + "heure": rg_row[8].strftime("%H:%M:%S") + if rg_row[8] and hasattr(rg_row[8], "strftime") + else str(rg_row[8]) + if rg_row[8] + else None, + "reference": (rg_row[3] or "").strip(), + "libelle": (rg_row[7] or "").strip(), + "montant": float(rc_montant or rg_row[1] or 0), + "mode_reglement": { + "code": rg_row[5], + "libelle": (rg_row[6] or ModeReglement.get_libelle(rg_row[5] or 0)).strip() + if rg_row[6] + else ModeReglement.get_libelle(rg_row[5] or 0), + }, + "journal": { + "code": (rg_row[12] or "").strip(), + "intitule": (rg_row[13] or "").strip(), + }, + "banque": (rg_row[9] or "").strip(), + "est_impaye": rg_row[10] == 1, + "est_valide": rg_row[11] == 1, + "date_creation": rg_row[14].strftime("%Y-%m-%d %H:%M:%S") + if rg_row[14] + else None, + } + + def lire_tous_reglements( self, date_debut: datetime = None, @@ -174,6 +253,7 @@ def lire_tous_reglements( client_code: str = None, statut_reglement: str = None, ) -> Dict: + """Liste toutes les factures avec leurs règlements - VERSION UNIFIÉE.""" if not self.cial: raise RuntimeError("Connexion Sage non établie") @@ -198,13 +278,7 @@ def lire_tous_reglements( d.cbCreation, c.CT_Intitule, c.CT_EMail, - c.CT_Telephone, - (SELECT ISNULL(SUM(rc.RC_Montant), 0) - FROM F_REGLECH rc - INNER JOIN F_DOCREGL dr ON rc.DR_No = dr.DR_No - WHERE dr.DO_Domaine = d.DO_Domaine - AND dr.DO_Type = d.DO_Type - AND dr.DO_Piece = d.DO_Piece) as MontantRegleTotal + c.CT_Telephone FROM F_DOCENTETE d LEFT JOIN F_COMPTET c ON d.DO_Tiers = c.CT_Num WHERE d.DO_Type IN (6, 7) @@ -228,7 +302,6 @@ def lire_tous_reglements( cursor.execute(query, params) rows = cursor.fetchall() - types_doc = {6: "Facture", 7: "Avoir"} factures = [] total_factures = 0.0 total_regle = 0.0 @@ -239,59 +312,31 @@ def lire_tous_reglements( do_type = row[1] do_piece = (row[2] or "").strip() montant_ttc = float(row[6] or 0) - montant_regle_total = float(row[13] or 0) - reste_a_regler = montant_ttc - montant_regle_total - - if statut_reglement: - if statut_reglement == "solde" and abs(reste_a_regler) >= 0.01: - continue - if statut_reglement == "partiel" and ( - montant_regle_total == 0 or abs(reste_a_regler) < 0.01 - ): - continue - if statut_reglement == "non_regle" and montant_regle_total > 0: - continue - - if montant_regle_total == 0: - statut = "Non réglé" - elif abs(reste_a_regler) < 0.01: - statut = "Soldé" - else: - statut = "Partiellement réglé" echeances = _get_echeances_avec_reglements( cursor, do_domaine, do_type, do_piece, montant_ttc ) - facture = { - "domaine": do_domaine, - "type_code": do_type, - "type_libelle": types_doc.get(do_type, f"Type {do_type}"), - "numero": do_piece, - "date": row[3].strftime("%Y-%m-%d") if row[3] else None, - "reference": (row[4] or "").strip(), - "client_code": (row[5] or "").strip(), - "client_intitule": (row[10] or "").strip(), - "client_email": (row[11] or "").strip(), - "client_telephone": (row[12] or "").strip(), - "montant_ttc": montant_ttc, - "montant_regle": montant_regle_total, - "reste_a_regler": reste_a_regler, - "statut_reglement": statut, - "date_livraison": row[7].strftime("%Y-%m-%d") if row[7] else None, - "souche": row[8], - "date_creation": row[9].strftime("%Y-%m-%d %H:%M:%S") - if row[9] - else None, - "nb_echeances": len(echeances), - "nb_reglements": sum(len(e["reglements"]) for e in echeances), - "echeances": echeances, - } + facture = _format_facture(row, echeances) + + # Filtrer par statut si demandé + if statut_reglement: + reste = facture["montants"]["reste_a_regler"] + montant_regle = facture["montants"]["montant_regle"] + + if statut_reglement == "solde" and abs(reste) >= 0.01: + continue + if statut_reglement == "partiel" and ( + montant_regle == 0 or abs(reste) < 0.01 + ): + continue + if statut_reglement == "non_regle" and montant_regle > 0: + continue factures.append(facture) - total_factures += montant_ttc - total_regle += montant_regle_total - total_reste += reste_a_regler + total_factures += facture["montants"]["total_ttc"] + total_regle += facture["montants"]["montant_regle"] + total_reste += facture["montants"]["reste_a_regler"] nb_total = len(factures) nb_soldees = sum(1 for f in factures if f["statut_reglement"] == "Soldé") @@ -303,13 +348,15 @@ def lire_tous_reglements( ) return { - "nb_factures": nb_total, - "nb_soldees": nb_soldees, - "nb_partiellement_reglees": nb_partielles, - "nb_non_reglees": nb_non_reglees, - "total_factures": total_factures, - "total_regle": total_regle, - "total_reste": total_reste, + "statistiques": { + "nb_factures": nb_total, + "nb_soldees": nb_soldees, + "nb_partiellement_reglees": nb_partielles, + "nb_non_reglees": nb_non_reglees, + "total_factures": total_factures, + "total_regle": total_regle, + "total_reste": total_reste, + }, "filtres": { "date_debut": date_debut.strftime("%Y-%m-%d") if date_debut else None, "date_fin": date_fin.strftime("%Y-%m-%d") if date_fin else None, @@ -327,7 +374,7 @@ def _get_echeances_avec_reglements( do_piece: str, montant_ttc_facture: float, ) -> list: - """Récupère les échéances d'un document avec leurs règlements détaillés.""" + """Récupère les échéances d'un document avec leurs règlements - VERSION UNIFIÉE.""" cursor.execute( """ SELECT @@ -350,7 +397,7 @@ def _get_echeances_avec_reglements( echeances = [] nb_echeances = len(echeances_rows) - for idx, ech in enumerate(echeances_rows): + for ech in echeances_rows: reglements = _get_reglements_echeance(cursor, ech[0]) montant_regle = sum(r["montant"] for r in reglements) @@ -363,17 +410,20 @@ def _get_echeances_avec_reglements( "dr_no": ech[0], "date_echeance": ech[1].strftime("%Y-%m-%d") if ech[1] else None, "montant": montant_echeance, - "est_regle": ech[3] == 1, - "mode_reglement_code": ech[4], - "mode_reglement_libelle": ( - ech[6] or ModeReglement.get_libelle(ech[4] or 0) - ).strip() - if ech[6] - else ModeReglement.get_libelle(ech[4] or 0), - "reference_paiement": (ech[5] or "").strip(), - "reglements": reglements, "montant_regle": montant_regle, "reste_a_regler": montant_echeance - montant_regle, + "est_regle": ech[3] == 1, + "mode_reglement": { + "code": ech[4], + "libelle": ( + ech[6] or ModeReglement.get_libelle(ech[4] or 0) + ).strip() + if ech[6] + else ModeReglement.get_libelle(ech[4] or 0), + }, + "reference_paiement": (ech[5] or "").strip(), + "nb_reglements": len(reglements), + "reglements": reglements, } ) @@ -381,7 +431,7 @@ def _get_echeances_avec_reglements( def _get_reglements_echeance(cursor, dr_no: int) -> list: - """Récupère les règlements liés à une échéance avec détails complets.""" + """Récupère les règlements liés à une échéance - VERSION UNIFIÉE.""" cursor.execute( """ SELECT @@ -409,52 +459,12 @@ def _get_reglements_echeance(cursor, dr_no: int) -> list: """, (dr_no,), ) - reglements_rows = cursor.fetchall() - reglements = [] - for rg in reglements_rows: - heure_str = None - if rg[8]: - try: - heure_str = ( - rg[8].strftime("%H:%M:%S") - if hasattr(rg[8], "strftime") - else str(rg[8]) - ) - except Exception: - heure_str = str(rg[8]) - - reglements.append( - { - "rg_no": rg[0], - "montant": float(rg[1] or 0), - "date": rg[2].strftime("%Y-%m-%d") if rg[2] else None, - "heure": heure_str, - "reference": (rg[3] or "").strip(), - "numero_piece": (rg[4] or "").strip(), - "mode_reglement_code": rg[5], - "mode_reglement_libelle": ( - rg[6] or ModeReglement.get_libelle(rg[5] or 0) - ).strip() - if rg[6] - else ModeReglement.get_libelle(rg[5] or 0), - "libelle": (rg[7] or "").strip(), - "banque": (rg[9] or "").strip(), - "est_impaye": rg[10] == 1, - "est_valide": rg[11] == 1, - "journal_code": (rg[12] or "").strip(), - "journal_intitule": (rg[13] or "").strip(), - "date_creation": rg[14].strftime("%Y-%m-%d %H:%M:%S") - if rg[14] - else None, - } - ) - - return reglements + return [_format_reglement(row) for row in cursor.fetchall()] def lire_facture_reglement_detail(self, do_piece: str) -> Dict: - """Récupère le détail complet d'une facture avec tous ses règlements.""" + """Récupère le détail complet d'une facture - VERSION UNIFIÉE.""" if not self.cial: raise RuntimeError("Connexion Sage non établie") @@ -496,28 +506,32 @@ def lire_facture_reglement_detail(self, do_piece: str) -> Dict: montant_ttc = float(row[6] or 0) echeances = _get_echeances_avec_reglements( - cursor, do_domaine, do_type, do_piece + cursor, do_domaine, do_type, do_piece, montant_ttc ) - total_regle = sum(e["montant_regle"] for e in echeances) - reste_a_regler = montant_ttc - total_regle + # Utiliser la même structure que lire_tous_reglements + # mais avec les infos complètes du client + types_doc = {6: "Facture", 7: "Avoir"} + montant_regle = sum(e["montant_regle"] for e in echeances) + reste_a_regler = montant_ttc - montant_regle - if total_regle == 0: + if montant_regle == 0: statut = "Non réglé" elif abs(reste_a_regler) < 0.01: statut = "Soldé" else: statut = "Partiellement réglé" - types_doc = {6: "Facture", 7: "Avoir"} - return { "domaine": do_domaine, "type_code": do_type, "type_libelle": types_doc.get(do_type, f"Type {do_type}"), "numero": do_piece, "date": row[3].strftime("%Y-%m-%d") if row[3] else None, + "date_livraison": row[7].strftime("%Y-%m-%d") if row[7] else None, "reference": (row[4] or "").strip(), + "souche": row[8], + "date_creation": row[9].strftime("%Y-%m-%d %H:%M:%S") if row[9] else None, "client": { "code": (row[5] or "").strip(), "intitule": (row[10] or "").strip(), @@ -527,13 +541,12 @@ def lire_facture_reglement_detail(self, do_piece: str) -> Dict: "code_postal": (row[14] or "").strip(), "ville": (row[15] or "").strip(), }, - "montant_ttc": montant_ttc, - "montant_regle": total_regle, - "reste_a_regler": reste_a_regler, + "montants": { + "total_ttc": montant_ttc, + "montant_regle": montant_regle, + "reste_a_regler": reste_a_regler, + }, "statut_reglement": statut, - "date_livraison": row[7].strftime("%Y-%m-%d") if row[7] else None, - "souche": row[8], - "date_creation": row[9].strftime("%Y-%m-%d %H:%M:%S") if row[9] else None, "nb_echeances": len(echeances), "nb_reglements": sum(len(e["reglements"]) for e in echeances), "echeances": echeances, @@ -541,7 +554,7 @@ def lire_facture_reglement_detail(self, do_piece: str) -> Dict: def lire_reglement_detail(self, rg_no: int) -> Dict: - """Récupère le détail d'un règlement spécifique avec ses imputations.""" + """Récupère le détail d'un règlement spécifique - VERSION UNIFIÉE.""" if not self.cial: raise RuntimeError("Connexion Sage non établie") @@ -578,7 +591,8 @@ def lire_reglement_detail(self, rg_no: int) -> Dict: c.CT_Intitule, j.JO_Intitule, mr.R_Intitule, - dev.D_Intitule + dev.D_Intitule, + dev.D_Sigle FROM F_CREGLEMENT r LEFT JOIN F_COMPTET c ON r.CT_NumPayeur = c.CT_Num LEFT JOIN F_JOURNAUX j ON r.JO_Num = j.JO_Num @@ -593,6 +607,7 @@ def lire_reglement_detail(self, rg_no: int) -> Dict: if not row: raise ValueError(f"Règlement {rg_no} introuvable") + # Récupérer les imputations cursor.execute( """ SELECT @@ -636,15 +651,20 @@ def lire_reglement_detail(self, rg_no: int) -> Dict: "domaine": domaines.get(imp[2], f"Domaine {imp[2]}") if imp[2] is not None else None, - "type": types_doc.get(imp[3], f"Type {imp[3]}") + "type_code": imp[3], + "type_libelle": types_doc.get(imp[3], f"Type {imp[3]}") if imp[3] is not None else None, "numero": (imp[4] or "").strip() if imp[4] else None, "date": imp[5].strftime("%Y-%m-%d") if imp[5] else None, - "total_ttc": float(imp[6] or 0) if imp[6] else None, "reference": (imp[7] or "").strip() if imp[7] else None, - "tiers_code": (imp[8] or "").strip() if imp[8] else None, - "tiers_intitule": (imp[9] or "").strip() if imp[9] else None, + "montants": { + "total_ttc": float(imp[6] or 0) if imp[6] else None + }, + "client": { + "code": (imp[8] or "").strip() if imp[8] else None, + "intitule": (imp[9] or "").strip() if imp[9] else None, + }, }, } ) @@ -679,37 +699,48 @@ def lire_reglement_detail(self, rg_no: int) -> Dict: "libelle": (row[4] or "").strip(), "montant": rg_montant, "montant_devise": float(row[6] or 0), - "montant_impute": total_impute, - "reste_a_imputer": reste, + "cours": float(row[11] or 1), "montant_commission": float(row[20] or 0), "montant_net": float(row[21] or 0), - "cours": float(row[11] or 1), - "statut_imputation": statut_imputation, - "est_impute": row[8] == 1, - "est_comptabilise": row[9] == 1, + "devise": { + "code": row[12], + "intitule": (row[27] or "").strip() if row[27] else "", + "sigle": (row[28] or "").strip() if row[28] else "", + }, + "mode_reglement": { + "code": row[7], + "libelle": (row[26] or ModeReglement.get_libelle(row[7] or 0)).strip() + if row[26] + else ModeReglement.get_libelle(row[7] or 0), + }, + "journal": { + "code": (row[13] or "").strip(), + "intitule": (row[25] or "").strip(), + }, + "compte_general": (row[14] or "").strip(), + "banque": (row[18] or "").strip(), "est_impaye": row[15] == 1, "est_valide": row[19] == 1, - "type_code": row[10], - "type_libelle": types_reglement.get(row[10], f"Type {row[10]}"), - "client_code": (row[1] or "").strip(), - "client_intitule": (row[24] or "").strip(), - "journal_code": (row[13] or "").strip(), - "journal_intitule": (row[25] or "").strip(), - "compte_general": (row[14] or "").strip(), - "mode_reglement_code": row[7], - "mode_reglement_libelle": ( - row[26] or ModeReglement.get_libelle(row[7] or 0) - ).strip() - if row[26] - else ModeReglement.get_libelle(row[7] or 0), - "devise_code": row[12], - "devise_intitule": (row[27] or "").strip() if row[27] else "", - "banque": (row[18] or "").strip(), + "est_comptabilise": row[9] == 1, "date_creation": row[22].strftime("%Y-%m-%d %H:%M:%S") if row[22] else None, "date_modification": row[23].strftime("%Y-%m-%d %H:%M:%S") if row[23] else None, - "nb_imputations": len(imputations), + "client": { + "code": (row[1] or "").strip(), + "intitule": (row[24] or "").strip(), + }, + "type": { + "code": row[10], + "libelle": types_reglement.get(row[10], f"Type {row[10]}"), + }, + "imputation": { + "montant_impute": total_impute, + "reste_a_imputer": reste, + "statut": statut_imputation, + "est_impute": row[8] == 1, + "nb_imputations": len(imputations), + }, "imputations": imputations, }