diff --git a/main.py b/main.py index 811c4f9..8635d48 100644 --- a/main.py +++ b/main.py @@ -1835,7 +1835,6 @@ def get_tous_reglements( date_fin=date_fin_dt, client_code=client_code, type_reglement=type_reglement, - limit=limit, ) return {"success": True, "data": result} except Exception as e: @@ -1844,6 +1843,18 @@ 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): + try: + result = sage.lire_reglement_detail(facture_no) + return {"success": True, "data": result} + except ValueError as e: + raise HTTPException(404, str(e)) + except Exception as e: + logger.error(f"Erreur détail règlement {facture_no}: {e}") + raise HTTPException(500, str(e)) + + @app.get("/sage/reglements/{rg_no}", dependencies=[Depends(verify_token)]) def get_reglement_detail(rg_no: int): try: diff --git a/sage_connector.py b/sage_connector.py index ecbc526..99195d8 100644 --- a/sage_connector.py +++ b/sage_connector.py @@ -101,6 +101,7 @@ from utils.documents.settle import ( lire_tva_taux, lire_parametres_encaissement, lire_tous_reglements, + lire_facture_reglement_detail, lire_reglement_detail, regler_facture as _regler_facture, regler_factures_client as _regler_factures_client, @@ -8152,7 +8153,6 @@ class SageConnector: date_fin, client_code, type_reglement, - limit, ) -> dict: return lire_tous_reglements( self, @@ -8160,8 +8160,10 @@ class SageConnector: date_fin, client_code, type_reglement, - limit, ) + def lire_facture_reglement_detail(self, facture_no) -> dict: + return lire_facture_reglement_detail(self, facture_no) + def lire_reglement_detail(self, rg_no) -> dict: return lire_reglement_detail(self, rg_no) diff --git a/utils/documents/settle.py b/utils/documents/settle.py index a88d653..26639b5 100644 --- a/utils/documents/settle.py +++ b/utils/documents/settle.py @@ -172,15 +172,13 @@ def lire_tous_reglements( date_debut: datetime = None, date_fin: datetime = None, client_code: str = None, - type_reglement: str = None, - limit: int = 500, + statut_reglement: str = None, ) -> Dict: - """Liste tous les règlements avec TOUTES les colonnes F_CREGLEMENT""" if not self.cial: raise RuntimeError("Connexion Sage non établie") logger.info( - f"Lecture règlements (date_debut={date_debut}, date_fin={date_fin}, client={client_code})" + f"Lecture factures avec règlements (date_debut={date_debut}, date_fin={date_fin}, client={client_code})" ) with self._get_sql_connection() as conn: @@ -188,279 +186,362 @@ def lire_tous_reglements( query = """ SELECT - r.RG_No, - r.CT_NumPayeur, - r.RG_Date, - r.RG_Reference, - r.RG_Libelle, - r.RG_Montant, - r.RG_MontantDev, - r.N_Reglement, - r.RG_Impute, - r.RG_Compta, - r.EC_No, - r.RG_Type, - r.RG_Cours, - r.N_Devise, - r.JO_Num, - r.CG_NumCont, - r.RG_Impaye, - r.CG_Num, - r.RG_TypeReg, - r.RG_Heure, - r.RG_Piece, - r.CA_No, - r.CO_NoCaissier, - r.RG_Banque, - r.RG_Transfere, - r.RG_Cloture, - r.RG_Ticket, - r.RG_Souche, - r.CT_NumPayeurOrig, - r.RG_DateEchCont, - r.CG_NumEcart, - r.JO_NumEcart, - r.RG_MontantEcart, - r.RG_NoBonAchat, - r.RG_Valide, - r.RG_Anterieur, - r.RG_MontantCommission, - r.RG_MontantNet, - r.cbCreation, - r.cbModification, - r.cbCreateur, + d.DO_Domaine, + d.DO_Type, + d.DO_Piece, + d.DO_Date, + d.DO_Ref, + d.DO_Tiers, + d.DO_TotalTTC, + d.DO_DateLivr, + d.DO_Souche, + d.cbCreation, c.CT_Intitule, - j.JO_Intitule, - mr.R_Intitule as ModeReglementIntitule, - dev.D_Intitule as DeviseIntitule, - (SELECT ISNULL(SUM(RC_Montant), 0) FROM F_REGLECH WHERE RG_No = r.RG_No) as MontantImpute - 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 - LEFT JOIN P_REGLEMENT mr ON r.N_Reglement = mr.cbIndice - LEFT JOIN P_DEVISE dev ON r.N_Devise = dev.cbIndice - WHERE 1=1 + 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 + FROM F_DOCENTETE d + LEFT JOIN F_COMPTET c ON d.DO_Tiers = c.CT_Num + WHERE d.DO_Type IN (6, 7) """ params = [] - if type_reglement: - if type_reglement.lower() == "client": - query += " AND r.RG_Type = 0" - elif type_reglement.lower() == "fournisseur": - query += " AND r.RG_Type = 1" - if date_debut: - query += " AND r.RG_Date >= ?" + query += " AND d.DO_Date >= ?" params.append(date_debut) if date_fin: - query += " AND r.RG_Date <= ?" + query += " AND d.DO_Date <= ?" params.append(date_fin) if client_code: - query += " AND r.CT_NumPayeur = ?" + query += " AND d.DO_Tiers = ?" params.append(client_code) - query += " ORDER BY r.RG_Date DESC, r.RG_No DESC" - - if limit: - query = query.replace("SELECT", f"SELECT TOP {limit}") + query += " ORDER BY d.DO_Date DESC, d.DO_Piece DESC" cursor.execute(query, params) rows = cursor.fetchall() - types_reglement = {0: "Client", 1: "Fournisseur", 2: "Salarié"} - types_reg = { - 0: "Aucun", - 1: "Règlement", - 2: "Escompte accordé", - 3: "Effet encaissé", - 4: "Effet impayé", - } - - reglements = [] - total_montant = 0.0 - total_impute = 0.0 + types_doc = {6: "Facture", 7: "Avoir"} + factures = [] + total_factures = 0.0 + total_regle = 0.0 + total_reste = 0.0 for row in rows: - rg_montant = float(row[5] or 0) - montant_impute = float(row[45] or 0) - reste_a_imputer = rg_montant - montant_impute + do_domaine = row[0] + 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 montant_impute == 0: - statut_imputation = "Non imputé" - elif abs(reste_a_imputer) < 0.01: - statut_imputation = "Totalement imputé" + 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_imputation = "Partiellement imputé" + statut = "Partiellement réglé" - heure_str = None - if row[19]: - try: - heure_str = ( - row[19].strftime("%H:%M:%S") - if hasattr(row[19], "strftime") - else str(row[19]) - ) - except: - heure_str = str(row[19]) - - reglement = { - "rg_no": row[0], - "numero_piece": (row[20] or "").strip(), - "date": row[2].strftime("%Y-%m-%d") if row[2] else None, - "heure": heure_str, - "date_echeance_contrepartie": row[29].strftime("%Y-%m-%d") - if row[29] - else None, - "reference": (row[3] or "").strip(), - "libelle": (row[4] or "").strip(), - "montant": rg_montant, - "montant_devise": float(row[6] or 0), - "montant_impute": montant_impute, - "reste_a_imputer": reste_a_imputer, - "montant_ecart": float(row[32] or 0), - "montant_commission": float(row[36] or 0), - "montant_net": float(row[37] or 0), - "cours": float(row[12] or 1), - "statut_imputation": statut_imputation, - "est_impute": row[8] == 1, - "est_comptabilise": row[9] == 1, - "est_impaye": row[16] == 1, - "est_transfere": row[24] == 1, - "est_cloture": row[25] == 1, - "est_valide": row[34] == 1, - "est_anterieur": row[35] == 1, - "type_code": row[11], - "type_libelle": types_reglement.get(row[11], f"Type {row[11]}"), - "type_reg_code": row[18], - "type_reg_libelle": types_reg.get(row[18], f"TypeReg {row[18]}"), - "client_code": (row[1] or "").strip(), - "client_intitule": (row[41] or "").strip(), - "client_origine": (row[28] or "").strip(), - "journal_code": (row[14] or "").strip(), - "journal_intitule": (row[42] or "").strip(), - "compte_general": (row[17] or "").strip(), - "compte_contrepartie": (row[15] or "").strip(), - "compte_ecart": (row[30] or "").strip(), - "journal_ecart": (row[31] or "").strip(), - "mode_reglement_code": row[7], - "mode_reglement_libelle": ( - row[43] or ModeReglement.get_libelle(row[7] or 0) - ).strip() - if row[43] - else ModeReglement.get_libelle(row[7] or 0), - "devise_code": row[13], - "devise_intitule": (row[44] or "").strip(), - "banque": (row[23] or "").strip(), - "caisse_no": row[21], - "caissier_no": row[22], - "echeancier_no": row[10], - "ticket": (row[26] or "").strip(), - "souche": row[27], - "bon_achat_no": row[33], - "date_creation": row[38].strftime("%Y-%m-%d %H:%M:%S") - if row[38] - else None, - "date_modification": row[39].strftime("%Y-%m-%d %H:%M:%S") - if row[39] - else None, - "createur": (row[40] or "").strip() if row[40] else None, - } - - reglements.append(reglement) - total_montant += rg_montant - total_impute += montant_impute - - for reg in reglements: - cursor.execute( - """ - SELECT - re.RG_No, - re.RC_Montant, - re.DR_No, - dr.DO_Domaine, - dr.DO_Type, - dr.DO_Piece, - d.DO_Date, - d.DO_TotalTTC, - d.DO_Ref - FROM F_REGLECH re - LEFT JOIN F_DOCREGL dr ON re.DR_No = dr.DR_No - AND re.DO_Domaine = dr.DO_Domaine - AND re.DO_Type = dr.DO_Type - AND re.DO_Piece = dr.DO_Piece - LEFT JOIN F_DOCENTETE d ON dr.DO_Domaine = d.DO_Domaine - AND dr.DO_Type = d.DO_Type - AND dr.DO_Piece = d.DO_Piece - WHERE re.RG_No = ? - """, - (reg["rg_no"],), + echeances = _get_echeances_avec_reglements( + cursor, do_domaine, do_type, do_piece, montant_ttc ) - imputations = cursor.fetchall() - types_doc = { - 0: "Devis", - 1: "Bon de commande", - 2: "Préparation", - 3: "Bon de livraison", - 6: "Facture", - 7: "Avoir", + 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, } - domaines = {0: "Vente", 1: "Achat", 2: "Stock"} - reg["imputations"] = [ - { - "rg_no": imp[0], - "montant": float(imp[1] or 0), - "dr_no": imp[2], - "document_domaine": domaines.get(imp[3], f"Domaine {imp[3]}") - if imp[3] is not None - else None, - "document_type": types_doc.get(imp[4], f"Type {imp[4]}") - if imp[4] is not None - else None, - "document_piece": (imp[5] or "").strip() if imp[5] else None, - "document_date": imp[6].strftime("%Y-%m-%d") if imp[6] else None, - "document_total": float(imp[7] or 0) if imp[7] else None, - "document_reference": (imp[8] or "").strip() if imp[8] else None, - } - for imp in imputations - ] - reg["nb_imputations"] = len(imputations) + factures.append(facture) + total_factures += montant_ttc + total_regle += montant_regle_total + total_reste += reste_a_regler - nb_total = len(reglements) - nb_imputes = sum( - 1 for r in reglements if r["statut_imputation"] == "Totalement imputé" + nb_total = len(factures) + nb_soldees = sum(1 for f in factures if f["statut_reglement"] == "Soldé") + nb_partielles = sum( + 1 for f in factures if f["statut_reglement"] == "Partiellement réglé" ) - nb_partiels = sum( - 1 for r in reglements if r["statut_imputation"] == "Partiellement imputé" - ) - nb_non_imputes = sum( - 1 for r in reglements if r["statut_imputation"] == "Non imputé" + nb_non_reglees = sum( + 1 for f in factures if f["statut_reglement"] == "Non réglé" ) return { - "nb_reglements": nb_total, - "nb_totalement_imputes": nb_imputes, - "nb_partiellement_imputes": nb_partiels, - "nb_non_imputes": nb_non_imputes, - "total_montant": total_montant, - "total_impute": total_impute, - "total_reste": total_montant - total_impute, + "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, "client_code": client_code, - "type_reglement": type_reglement, - "limit": limit, + "statut_reglement": statut_reglement, }, - "reglements": reglements, + "factures": factures, + } + + +def _get_echeances_avec_reglements( + cursor, + do_domaine: int, + do_type: int, + do_piece: str, + montant_ttc_facture: float, +) -> list: + """Récupère les échéances d'un document avec leurs règlements détaillés.""" + cursor.execute( + """ + SELECT + dr.DR_No, + dr.DR_Date, + dr.DR_Montant, + dr.DR_Regle, + dr.N_Reglement, + dr.DR_RefPaiement, + mr.R_Intitule + FROM F_DOCREGL dr + LEFT JOIN P_REGLEMENT mr ON dr.N_Reglement = mr.cbIndice + WHERE dr.DO_Domaine = ? AND dr.DO_Type = ? AND dr.DO_Piece = ? + ORDER BY dr.DR_Date ASC + """, + (do_domaine, do_type, do_piece), + ) + echeances_rows = cursor.fetchall() + + echeances = [] + nb_echeances = len(echeances_rows) + + for idx, ech in enumerate(echeances_rows): + reglements = _get_reglements_echeance(cursor, ech[0]) + montant_regle = sum(r["montant"] for r in reglements) + + montant_echeance = float(ech[2] or 0) + if montant_echeance == 0 and nb_echeances == 1: + montant_echeance = montant_ttc_facture + + echeances.append( + { + "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, + } + ) + + return echeances + + +def _get_reglements_echeance(cursor, dr_no: int) -> list: + """Récupère les règlements liés à une échéance avec détails complets.""" + cursor.execute( + """ + SELECT + r.RG_No, + rc.RC_Montant, + r.RG_Date, + r.RG_Reference, + r.RG_Piece, + r.N_Reglement, + mr.R_Intitule, + r.RG_Libelle, + r.RG_Heure, + r.RG_Banque, + r.RG_Impaye, + r.RG_Valide, + r.JO_Num, + j.JO_Intitule, + r.cbCreation + FROM F_REGLECH rc + INNER JOIN F_CREGLEMENT r ON rc.RG_No = r.RG_No + LEFT JOIN P_REGLEMENT mr ON r.N_Reglement = mr.cbIndice + LEFT JOIN F_JOURNAUX j ON r.JO_Num = j.JO_Num + WHERE rc.DR_No = ? + ORDER BY r.RG_Date DESC + """, + (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 + + +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.""" + if not self.cial: + raise RuntimeError("Connexion Sage non établie") + + with self._get_sql_connection() as conn: + cursor = conn.cursor() + + cursor.execute( + """ + SELECT + d.DO_Domaine, + d.DO_Type, + d.DO_Piece, + d.DO_Date, + d.DO_Ref, + d.DO_Tiers, + d.DO_TotalTTC, + d.DO_DateLivr, + d.DO_Souche, + d.cbCreation, + c.CT_Intitule, + c.CT_EMail, + c.CT_Telephone, + c.CT_Adresse, + c.CT_CodePostal, + c.CT_Ville + FROM F_DOCENTETE d + LEFT JOIN F_COMPTET c ON d.DO_Tiers = c.CT_Num + WHERE d.DO_Piece = ? AND d.DO_Type IN (6, 7) + """, + (do_piece,), + ) + + row = cursor.fetchone() + if not row: + raise ValueError(f"Facture {do_piece} introuvable") + + do_domaine = row[0] + do_type = row[1] + montant_ttc = float(row[6] or 0) + + echeances = _get_echeances_avec_reglements( + cursor, do_domaine, do_type, do_piece + ) + + total_regle = sum(e["montant_regle"] for e in echeances) + reste_a_regler = montant_ttc - total_regle + + if total_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, + "reference": (row[4] or "").strip(), + "client": { + "code": (row[5] or "").strip(), + "intitule": (row[10] or "").strip(), + "email": (row[11] or "").strip(), + "telephone": (row[12] or "").strip(), + "adresse": (row[13] or "").strip(), + "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, + "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, } def lire_reglement_detail(self, rg_no: int) -> Dict: - """Récupère le détail complet d'un règlement par son numéro interne""" + """Récupère le détail d'un règlement spécifique avec ses imputations.""" if not self.cial: raise RuntimeError("Connexion Sage non établie") @@ -480,37 +561,20 @@ def lire_reglement_detail(self, rg_no: int) -> Dict: r.N_Reglement, r.RG_Impute, r.RG_Compta, - r.EC_No, r.RG_Type, r.RG_Cours, r.N_Devise, r.JO_Num, - r.CG_NumCont, - r.RG_Impaye, r.CG_Num, - r.RG_TypeReg, + r.RG_Impaye, r.RG_Heure, r.RG_Piece, - r.CA_No, - r.CO_NoCaissier, r.RG_Banque, - r.RG_Transfere, - r.RG_Cloture, - r.RG_Ticket, - r.RG_Souche, - r.CT_NumPayeurOrig, - r.RG_DateEchCont, - r.CG_NumEcart, - r.JO_NumEcart, - r.RG_MontantEcart, - r.RG_NoBonAchat, r.RG_Valide, - r.RG_Anterieur, r.RG_MontantCommission, r.RG_MontantNet, r.cbCreation, r.cbModification, - r.cbCreateur, c.CT_Intitule, j.JO_Intitule, mr.R_Intitule, @@ -521,7 +585,7 @@ def lire_reglement_detail(self, rg_no: int) -> Dict: LEFT JOIN P_REGLEMENT mr ON r.N_Reglement = mr.cbIndice LEFT JOIN P_DEVISE dev ON r.N_Devise = dev.cbIndice WHERE r.RG_No = ? - """, + """, (rg_no,), ) @@ -532,7 +596,6 @@ def lire_reglement_detail(self, rg_no: int) -> Dict: cursor.execute( """ SELECT - re.RG_No, re.RC_Montant, re.DR_No, dr.DO_Domaine, @@ -540,65 +603,48 @@ def lire_reglement_detail(self, rg_no: int) -> Dict: dr.DO_Piece, d.DO_Date, d.DO_TotalTTC, - d.DO_MontantRegle, d.DO_Ref, - d.DO_Tiers + d.DO_Tiers, + c.CT_Intitule FROM F_REGLECH re - LEFT JOIN F_DOCREGL dr ON re.DR_No = dr.DR_No - AND re.DO_Domaine = dr.DO_Domaine - AND re.DO_Type = dr.DO_Type - AND re.DO_Piece = dr.DO_Piece + LEFT JOIN F_DOCREGL dr ON re.DR_No = dr.DR_No LEFT JOIN F_DOCENTETE d ON dr.DO_Domaine = d.DO_Domaine AND dr.DO_Type = d.DO_Type AND dr.DO_Piece = d.DO_Piece + LEFT JOIN F_COMPTET c ON d.DO_Tiers = c.CT_Num WHERE re.RG_No = ? - """, + """, (rg_no,), ) imputations_rows = cursor.fetchall() - types_doc = { - 0: "Devis", - 1: "Bon de commande", - 2: "Préparation", - 3: "Bon de livraison", - 6: "Facture", - 7: "Avoir", - } - domaines = {0: "Vente", 1: "Achat", 2: "Stock"} - types_reglement = {0: "Client", 1: "Fournisseur", 2: "Salarié"} - types_reg = { - 0: "Aucun", - 1: "Règlement", - 2: "Escompte accordé", - 3: "Effet encaissé", - 4: "Effet impayé", - } + types_doc = {6: "Facture", 7: "Avoir"} + domaines = {0: "Vente", 1: "Achat"} + types_reglement = {0: "Client", 1: "Fournisseur"} imputations = [] total_impute = 0.0 for imp in imputations_rows: - montant_imp = float(imp[1] or 0) + montant_imp = float(imp[0] or 0) total_impute += montant_imp imputations.append( { - "rg_no": imp[0], "montant": montant_imp, - "dr_no": imp[2], + "dr_no": imp[1], "document": { - "domaine": domaines.get(imp[3], f"Domaine {imp[3]}") + "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]}") if imp[3] is not None else None, - "type": types_doc.get(imp[4], f"Type {imp[4]}") - if imp[4] is not None - else None, - "numero": (imp[5] or "").strip() if imp[5] else None, - "date": imp[6].strftime("%Y-%m-%d") if imp[6] else None, - "total_ttc": float(imp[7] or 0) if imp[7] else None, - "montant_regle": float(imp[8] or 0) if imp[8] else None, - "reference": (imp[9] or "").strip() if imp[9] else None, - "tiers": (imp[10] or "").strip() if imp[10] 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, }, } ) @@ -606,17 +652,6 @@ def lire_reglement_detail(self, rg_no: int) -> Dict: rg_montant = float(row[5] or 0) reste = rg_montant - total_impute - heure_str = None - if row[19]: - try: - heure_str = ( - row[19].strftime("%H:%M:%S") - if hasattr(row[19], "strftime") - else str(row[19]) - ) - except: - heure_str = str(row[19]) - if total_impute == 0: statut_imputation = "Non imputé" elif abs(reste) < 0.01: @@ -624,65 +659,56 @@ def lire_reglement_detail(self, rg_no: int) -> Dict: else: statut_imputation = "Partiellement imputé" + heure_str = None + if row[16]: + try: + heure_str = ( + row[16].strftime("%H:%M:%S") + if hasattr(row[16], "strftime") + else str(row[16]) + ) + except Exception: + heure_str = str(row[16]) + return { "rg_no": row[0], - "numero_piece": (row[20] or "").strip(), + "numero_piece": (row[17] or "").strip(), "date": row[2].strftime("%Y-%m-%d") if row[2] else None, "heure": heure_str, - "date_echeance_contrepartie": row[29].strftime("%Y-%m-%d") - if row[29] - else None, "reference": (row[3] or "").strip(), "libelle": (row[4] or "").strip(), "montant": rg_montant, "montant_devise": float(row[6] or 0), "montant_impute": total_impute, "reste_a_imputer": reste, - "montant_ecart": float(row[32] or 0), - "montant_commission": float(row[36] or 0), - "montant_net": float(row[37] or 0), - "cours": float(row[12] 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, - "est_impaye": row[16] == 1, - "est_transfere": row[24] == 1, - "est_cloture": row[25] == 1, - "est_valide": row[34] == 1, - "est_anterieur": row[35] == 1, - "type_code": row[11], - "type_libelle": types_reglement.get(row[11], f"Type {row[11]}"), - "type_reg_code": row[18], - "type_reg_libelle": types_reg.get(row[18], f"TypeReg {row[18]}"), + "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[41] or "").strip(), - "client_origine": (row[28] or "").strip(), - "journal_code": (row[14] or "").strip(), - "journal_intitule": (row[42] or "").strip(), - "compte_general": (row[17] or "").strip(), - "compte_contrepartie": (row[15] or "").strip(), - "compte_ecart": (row[30] or "").strip(), - "journal_ecart": (row[31] 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[43] or ModeReglement.get_libelle(row[7] or 0) + row[26] or ModeReglement.get_libelle(row[7] or 0) ).strip() - if row[43] + if row[26] else ModeReglement.get_libelle(row[7] or 0), - "devise_code": row[13], - "devise_intitule": (row[44] or "").strip() if row[44] else "", - "banque": (row[23] or "").strip(), - "caisse_no": row[21], - "caissier_no": row[22], - "echeancier_no": row[10], - "ticket": (row[26] or "").strip(), - "souche": row[27], - "bon_achat_no": row[33], - "date_creation": row[38].strftime("%Y-%m-%d %H:%M:%S") if row[38] else None, - "date_modification": row[39].strftime("%Y-%m-%d %H:%M:%S") - if row[39] + "devise_code": row[12], + "devise_intitule": (row[27] or "").strip() if row[27] else "", + "banque": (row[18] or "").strip(), + "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, - "createur": (row[40] or "").strip() if row[40] else None, "nb_imputations": len(imputations), "imputations": imputations, } @@ -1794,5 +1820,6 @@ __all__ = [ "lire_parametres_encaissement", "_get_modes_reglement_standards", "lire_tous_reglements", + "lire_facture_reglement_detail", "lire_reglement_detail", ]