feat(reglements): add endpoint to get payment details by invoice number
This commit is contained in:
parent
06a5fc8df4
commit
437ac743c8
3 changed files with 388 additions and 348 deletions
13
main.py
13
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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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_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",
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in a new issue