Spaces:
Running
Running
Update src/modules/Check_Up_Loans.py
Browse files- src/modules/Check_Up_Loans.py +55 -54
src/modules/Check_Up_Loans.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
|
|
|
|
| 2 |
import streamlit as st
|
| 3 |
import pandas as pd
|
| 4 |
from datetime import datetime, date, timedelta
|
|
@@ -9,8 +10,9 @@ from Analytics.AnalyseFinance import (
|
|
| 9 |
analyser_capacite,
|
| 10 |
generer_tableau_amortissement,
|
| 11 |
calculer_taux_endettement,
|
| 12 |
-
clean_taux_value,
|
| 13 |
-
clean_currency_value
|
|
|
|
| 14 |
)
|
| 15 |
from DocumentGen.AutoPDFGeneration import generer_contrat_pret, generer_reconnaissance_dette, generer_contrat_caution
|
| 16 |
|
|
@@ -268,7 +270,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 268 |
apply_checkup_loans_styles()
|
| 269 |
st.markdown('<div id="checkup-loans-module">', unsafe_allow_html=True)
|
| 270 |
|
| 271 |
-
st.header("MISE À JOUR DE PRÊT")
|
| 272 |
st.markdown("*Modification des conditions d'un prêt avant tout remboursement*")
|
| 273 |
|
| 274 |
st.markdown('<div class="checkup-section-divider"></div>', unsafe_allow_html=True)
|
|
@@ -315,7 +317,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 315 |
# ÉTAPE 2 : SÉLECTION DU CLIENT
|
| 316 |
# ============================================================================
|
| 317 |
|
| 318 |
-
st.subheader("Étape 1 : Sélectionner le client")
|
| 319 |
|
| 320 |
# Préparation de la liste de sélection
|
| 321 |
df_clients['search_label'] = df_clients['ID_Client'].astype(str) + " - " + df_clients['Nom_Complet'].astype(str)
|
|
@@ -327,7 +329,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 327 |
)
|
| 328 |
|
| 329 |
if not selected_client_label:
|
| 330 |
-
st.info("Sélectionnez un client pour commencer")
|
| 331 |
st.markdown('</div>', unsafe_allow_html=True)
|
| 332 |
return
|
| 333 |
|
|
@@ -343,7 +345,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 343 |
# ÉTAPE 3 : IDENTIFICATION DES PRÊTS ACTIFS DU CLIENT
|
| 344 |
# ============================================================================
|
| 345 |
|
| 346 |
-
st.subheader("Étape 2 : Identifier le prêt à modifier")
|
| 347 |
|
| 348 |
# Filtrage des prêts ACTIF du client sélectionné
|
| 349 |
df_prets_client = df_prets[
|
|
@@ -446,7 +448,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 446 |
# ÉTAPE 5 : AFFICHAGE DES INFORMATIONS ACTUELLES
|
| 447 |
# ============================================================================
|
| 448 |
|
| 449 |
-
st.subheader("Étape 3 : Informations actuelles du prêt")
|
| 450 |
|
| 451 |
st.markdown('<div class="checkup-loan-card">', unsafe_allow_html=True)
|
| 452 |
st.markdown(f"### Prêt {loan_id}")
|
|
@@ -454,7 +456,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 454 |
# Récupération des valeurs actuelles (avec nettoyage)
|
| 455 |
montant_capital_actuel = clean_currency_value(selected_loan['Montant_Capital'])
|
| 456 |
taux_hebdo_actuel = clean_taux_value(selected_loan['Taux_Hebdo'])
|
| 457 |
-
taux_endettement_actuel =
|
| 458 |
duree_semaines_actuel = clean_currency_value(selected_loan['Duree_Semaines'])
|
| 459 |
montant_total_actuel = clean_currency_value(selected_loan['Montant_Total'])
|
| 460 |
cout_credit_actuel = clean_currency_value(selected_loan['Cout_Credit'])
|
|
@@ -469,7 +471,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 469 |
|
| 470 |
with col2:
|
| 471 |
st.metric("Taux hebdomadaire", f"{taux_hebdo_actuel}%")
|
| 472 |
-
st.metric("Taux d'endettement", f"{taux_endettement_actuel}%") # ✅
|
| 473 |
st.metric("Durée", f"{int(duree_semaines_actuel)} semaines")
|
| 474 |
st.metric("Moyen de transfert", selected_loan.get('Moyen_Transfert', 'N/A'))
|
| 475 |
|
|
@@ -641,7 +643,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 641 |
nouveau_nb_versements = 1
|
| 642 |
|
| 643 |
# Affichage résultat simulation
|
| 644 |
-
st.markdown("### Simulation des nouveaux montants")
|
| 645 |
res1, res2, res3 = st.columns(3)
|
| 646 |
res1.metric("Versement unique", f"{int(nouveau_montant_versement):,} XOF".replace(",", " "))
|
| 647 |
res2.metric("Coût du crédit", f"{int(nouveau_cout_credit):,} XOF".replace(",", " "))
|
|
@@ -741,7 +743,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 741 |
nouveau_nb_versements = int(nouvelle_duree_semaines)
|
| 742 |
|
| 743 |
# Affichage résultat simulation
|
| 744 |
-
st.markdown("### Simulation des nouveaux montants")
|
| 745 |
res1, res2, res3 = st.columns(3)
|
| 746 |
res1.metric("Versement Hebdo", f"{int(hebdomadalite):,} XOF".replace(",", " "))
|
| 747 |
res2.metric("Coût du crédit", f"{int(nouveau_cout_credit):,} XOF".replace(",", " "))
|
|
@@ -752,7 +754,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 752 |
# 5. LOGIQUE PERSONNALISÉE (Dates manuelles)
|
| 753 |
# -----------------------------------------------------------
|
| 754 |
else: # PERSONNALISE
|
| 755 |
-
st.info("Configurez les dates de versement ci-dessous")
|
| 756 |
|
| 757 |
# Interface d'ajout de dates
|
| 758 |
st.markdown("**Dates de versement :**")
|
|
@@ -819,11 +821,11 @@ def show_check_up_loans(client, sheet_name):
|
|
| 819 |
client_info['Revenus_Mensuels']
|
| 820 |
)
|
| 821 |
|
| 822 |
-
|
| 823 |
-
|
| 824 |
-
|
| 825 |
-
|
| 826 |
-
|
| 827 |
|
| 828 |
# Affichage pour information
|
| 829 |
if nouveau_taux_endettement > 0:
|
|
@@ -865,7 +867,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 865 |
selected_loan['Type_Pret'],
|
| 866 |
f"{int(montant_capital_actuel):,} XOF".replace(",", " "),
|
| 867 |
f"{taux_hebdo_actuel}%",
|
| 868 |
-
f"{taux_endettement_actuel}%" if taux_endettement_actuel > 0 else "N/A", # ✅
|
| 869 |
f"{int(duree_semaines_actuel)} semaines",
|
| 870 |
f"{int(montant_total_actuel):,} XOF".replace(",", " "),
|
| 871 |
f"{int(cout_credit_actuel):,} XOF".replace(",", " "),
|
|
@@ -885,7 +887,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 885 |
"Modifié" if nouveau_type_code != selected_loan['Type_Pret'] else "=",
|
| 886 |
f"{int(nouveau_montant - montant_capital_actuel):+,} XOF".replace(",", " ") if nouveau_montant != montant_capital_actuel else "=",
|
| 887 |
f"{nouveau_taux - taux_hebdo_actuel:+.1f}%" if nouveau_taux != taux_hebdo_actuel else "=",
|
| 888 |
-
f"{nouveau_taux_endettement - taux_endettement_actuel:+.1f}%" if taux_endettement_actuel > 0 else f"{nouveau_taux_endettement:.1f}%", # ✅
|
| 889 |
f"{int(diff_duree):+} sem" if diff_duree != 0 else "=",
|
| 890 |
f"{int(diff_montant_total):+,} XOF".replace(",", " ") if diff_montant_total != 0 else "=",
|
| 891 |
f"{int(diff_cout_credit):+,} XOF".replace(",", " ") if diff_cout_credit != 0 else "=",
|
|
@@ -922,7 +924,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 922 |
|
| 923 |
if warnings:
|
| 924 |
st.markdown('<div class="checkup-warning-box">', unsafe_allow_html=True)
|
| 925 |
-
st.markdown("### Points d'attention")
|
| 926 |
for warning in warnings:
|
| 927 |
st.markdown(f"- {warning}")
|
| 928 |
st.markdown('</div>', unsafe_allow_html=True)
|
|
@@ -932,7 +934,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 932 |
# ============================================================================
|
| 933 |
|
| 934 |
st.markdown('<div class="checkup-section-divider"></div>', unsafe_allow_html=True)
|
| 935 |
-
st.subheader("Nouvelle analyse de solvabilité")
|
| 936 |
|
| 937 |
# Appel du cerveau analytique
|
| 938 |
analyse = analyser_capacite(
|
|
@@ -946,7 +948,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 946 |
unsafe_allow_html=True)
|
| 947 |
st.info(analyse['message'])
|
| 948 |
|
| 949 |
-
with st.expander("Détails financiers"):
|
| 950 |
st.markdown(analyse['details'])
|
| 951 |
|
| 952 |
# ============================================================================
|
|
@@ -954,7 +956,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 954 |
# ============================================================================
|
| 955 |
|
| 956 |
st.markdown('<div class="checkup-section-divider"></div>', unsafe_allow_html=True)
|
| 957 |
-
st.subheader("Nouveau tableau d'échéances")
|
| 958 |
|
| 959 |
# Génération du tableau
|
| 960 |
if nouveau_type_code == "PERSONNALISE":
|
|
@@ -980,7 +982,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 980 |
# ============================================================================
|
| 981 |
|
| 982 |
st.markdown('<div class="checkup-section-divider"></div>', unsafe_allow_html=True)
|
| 983 |
-
st.subheader("Validation de la mise à jour")
|
| 984 |
|
| 985 |
st.info("🔒 **Attention** : Cette action va créer un nouveau prêt et archiver l'ancien avec le statut UPDATED.")
|
| 986 |
|
|
@@ -1007,23 +1009,23 @@ def show_check_up_loans(client, sheet_name):
|
|
| 1007 |
help="Ce commentaire sera enregistré dans la feuille Prets_Update pour traçabilité"
|
| 1008 |
)
|
| 1009 |
|
| 1010 |
-
submit_update = st.form_submit_button("VALIDER LA MISE À JOUR", use_container_width=True)
|
| 1011 |
|
| 1012 |
-
|
| 1013 |
-
|
| 1014 |
-
|
| 1015 |
-
|
| 1016 |
-
|
| 1017 |
-
|
| 1018 |
-
|
| 1019 |
-
|
| 1020 |
-
|
| 1021 |
-
|
| 1022 |
-
|
| 1023 |
-
|
| 1024 |
-
|
| 1025 |
-
|
| 1026 |
-
|
| 1027 |
|
| 1028 |
|
| 1029 |
if submit_update:
|
|
@@ -1032,7 +1034,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 1032 |
# ÉTAPE A : MISE À JOUR DU STATUT DANS Prets_Master
|
| 1033 |
# ========================================================================
|
| 1034 |
|
| 1035 |
-
with st.spinner("Mise à jour du prêt en cours..."):
|
| 1036 |
ws_prets_master = sh.worksheet("Prets_Master")
|
| 1037 |
|
| 1038 |
# Recherche de la ligne du prêt à modifier
|
|
@@ -1078,7 +1080,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 1078 |
# ÉTAPE B : CRÉATION DU NOUVEAU PRÊT DANS Prets_Update
|
| 1079 |
# ========================================================================
|
| 1080 |
|
| 1081 |
-
with st.spinner("Création du nouveau prêt dans Prets_Update..."):
|
| 1082 |
# Vérification/Création de la feuille Prets_Update
|
| 1083 |
try:
|
| 1084 |
ws_prets_update = sh.worksheet("Prets_Update")
|
|
@@ -1092,11 +1094,11 @@ def show_check_up_loans(client, sheet_name):
|
|
| 1092 |
cols=25
|
| 1093 |
)
|
| 1094 |
|
| 1095 |
-
# En-têtes
|
| 1096 |
headers = [
|
| 1097 |
"ID_Pret", "ID_Pret_Source", "Version", "Date_Modification",
|
| 1098 |
"ID_Client", "Nom_Complet", "Type_Pret", "Motif",
|
| 1099 |
-
"Montant_Capital", "Taux_Hebdo", "Duree_Semaines",
|
| 1100 |
"Montant_Versement", "Montant_Total", "Cout_Credit",
|
| 1101 |
"Nb_Versements", "Dates_Versements", "Date_Deblocage",
|
| 1102 |
"Date_Fin", "Moyen_Transfert", "Statut", "ID_Garant",
|
|
@@ -1118,7 +1120,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 1118 |
d.strftime("%d/%m/%Y") for d in nouvelles_dates_versements
|
| 1119 |
]) if nouvelles_dates_versements else ""
|
| 1120 |
|
| 1121 |
-
# Construction de la ligne de données
|
| 1122 |
row_data_update = [
|
| 1123 |
nouveau_id, # ID_Pret
|
| 1124 |
loan_id, # ID_Pret_Source
|
|
@@ -1130,7 +1132,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 1130 |
nouveau_motif, # Motif
|
| 1131 |
nouveau_montant, # Montant_Capital
|
| 1132 |
nouveau_taux, # Taux_Hebdo
|
| 1133 |
-
round(nouveau_taux_endettement, 2),
|
| 1134 |
nouvelle_duree_semaines, # Duree_Semaines
|
| 1135 |
round(nouveau_montant_versement), # Montant_Versement
|
| 1136 |
round(nouveau_montant_total), # Montant_Total
|
|
@@ -1188,8 +1190,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 1188 |
# Nettoyage du cache pour forcer le rechargement
|
| 1189 |
st.cache_data.clear()
|
| 1190 |
|
| 1191 |
-
st.success("
|
| 1192 |
-
st.rerun()
|
| 1193 |
|
| 1194 |
except Exception as e:
|
| 1195 |
st.error(f"❌ Erreur lors de la mise à jour : {e}")
|
|
@@ -1201,7 +1202,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 1201 |
|
| 1202 |
if st.session_state.get('loan_updated', False):
|
| 1203 |
st.markdown('<div class="checkup-section-divider"></div>', unsafe_allow_html=True)
|
| 1204 |
-
st.markdown(f"###
|
| 1205 |
|
| 1206 |
st.success(f"✅ Prêt mis à jour : **{st.session_state.get('new_loan_data', {}).get('ID_Pret_Source')}** → **{st.session_state.new_loan_id}**")
|
| 1207 |
|
|
@@ -1221,7 +1222,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 1221 |
with col_pdf1:
|
| 1222 |
pdf_contrat = generer_contrat_pret(loan_data_pdf, client_data_pdf, df_amort_pdf)
|
| 1223 |
st.download_button(
|
| 1224 |
-
"Contrat de Prêt",
|
| 1225 |
pdf_contrat,
|
| 1226 |
f"Contrat_{st.session_state.new_loan_id}.pdf",
|
| 1227 |
"application/pdf",
|
|
@@ -1232,7 +1233,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 1232 |
with col_pdf2:
|
| 1233 |
pdf_dette = generer_reconnaissance_dette(loan_data_pdf, client_data_pdf)
|
| 1234 |
st.download_button(
|
| 1235 |
-
"Reconnaissance Dette",
|
| 1236 |
pdf_dette,
|
| 1237 |
f"Dette_{st.session_state.new_loan_id}.pdf",
|
| 1238 |
"application/pdf",
|
|
@@ -1244,7 +1245,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 1244 |
if garant_data_pdf is not None:
|
| 1245 |
pdf_caution = generer_contrat_caution(loan_data_pdf, garant_data_pdf)
|
| 1246 |
st.download_button(
|
| 1247 |
-
"Contrat Caution",
|
| 1248 |
pdf_caution,
|
| 1249 |
f"Caution_{st.session_state.new_loan_id}.pdf",
|
| 1250 |
"application/pdf",
|
|
@@ -1255,7 +1256,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 1255 |
|
| 1256 |
# BOUTON RESET : Nouvelle mise à jour
|
| 1257 |
with col_reset:
|
| 1258 |
-
if st.button("Nouvelle Mise à Jour", use_container_width=True, type="primary"):
|
| 1259 |
# Nettoyage du session state
|
| 1260 |
st.session_state.loan_updated = False
|
| 1261 |
st.session_state.pop('new_loan_id', None)
|
|
@@ -1269,7 +1270,7 @@ def show_check_up_loans(client, sheet_name):
|
|
| 1269 |
|
| 1270 |
# Affichage d'un récapitulatif
|
| 1271 |
st.markdown("---")
|
| 1272 |
-
with st.expander("Récapitulatif de la mise à jour"):
|
| 1273 |
col_recap1, col_recap2 = st.columns(2)
|
| 1274 |
|
| 1275 |
with col_recap1:
|
|
|
|
| 1 |
|
| 2 |
+
#code claude AI
|
| 3 |
import streamlit as st
|
| 4 |
import pandas as pd
|
| 5 |
from datetime import datetime, date, timedelta
|
|
|
|
| 10 |
analyser_capacite,
|
| 11 |
generer_tableau_amortissement,
|
| 12 |
calculer_taux_endettement,
|
| 13 |
+
clean_taux_value,
|
| 14 |
+
clean_currency_value,
|
| 15 |
+
clean_percentage_value # ✅ AJOUT de la nouvelle fonction
|
| 16 |
)
|
| 17 |
from DocumentGen.AutoPDFGeneration import generer_contrat_pret, generer_reconnaissance_dette, generer_contrat_caution
|
| 18 |
|
|
|
|
| 270 |
apply_checkup_loans_styles()
|
| 271 |
st.markdown('<div id="checkup-loans-module">', unsafe_allow_html=True)
|
| 272 |
|
| 273 |
+
st.header("🔄 MISE À JOUR DE PRÊT")
|
| 274 |
st.markdown("*Modification des conditions d'un prêt avant tout remboursement*")
|
| 275 |
|
| 276 |
st.markdown('<div class="checkup-section-divider"></div>', unsafe_allow_html=True)
|
|
|
|
| 317 |
# ÉTAPE 2 : SÉLECTION DU CLIENT
|
| 318 |
# ============================================================================
|
| 319 |
|
| 320 |
+
st.subheader("📋 Étape 1 : Sélectionner le client")
|
| 321 |
|
| 322 |
# Préparation de la liste de sélection
|
| 323 |
df_clients['search_label'] = df_clients['ID_Client'].astype(str) + " - " + df_clients['Nom_Complet'].astype(str)
|
|
|
|
| 329 |
)
|
| 330 |
|
| 331 |
if not selected_client_label:
|
| 332 |
+
st.info("👆 Sélectionnez un client pour commencer")
|
| 333 |
st.markdown('</div>', unsafe_allow_html=True)
|
| 334 |
return
|
| 335 |
|
|
|
|
| 345 |
# ÉTAPE 3 : IDENTIFICATION DES PRÊTS ACTIFS DU CLIENT
|
| 346 |
# ============================================================================
|
| 347 |
|
| 348 |
+
st.subheader("🔍 Étape 2 : Identifier le prêt à modifier")
|
| 349 |
|
| 350 |
# Filtrage des prêts ACTIF du client sélectionné
|
| 351 |
df_prets_client = df_prets[
|
|
|
|
| 448 |
# ÉTAPE 5 : AFFICHAGE DES INFORMATIONS ACTUELLES
|
| 449 |
# ============================================================================
|
| 450 |
|
| 451 |
+
st.subheader("📊 Étape 3 : Informations actuelles du prêt")
|
| 452 |
|
| 453 |
st.markdown('<div class="checkup-loan-card">', unsafe_allow_html=True)
|
| 454 |
st.markdown(f"### Prêt {loan_id}")
|
|
|
|
| 456 |
# Récupération des valeurs actuelles (avec nettoyage)
|
| 457 |
montant_capital_actuel = clean_currency_value(selected_loan['Montant_Capital'])
|
| 458 |
taux_hebdo_actuel = clean_taux_value(selected_loan['Taux_Hebdo'])
|
| 459 |
+
taux_endettement_actuel = clean_percentage_value(selected_loan.get('Taux_Endettement', 0)) # ✅ CORRECTION - utiliser clean_percentage_value
|
| 460 |
duree_semaines_actuel = clean_currency_value(selected_loan['Duree_Semaines'])
|
| 461 |
montant_total_actuel = clean_currency_value(selected_loan['Montant_Total'])
|
| 462 |
cout_credit_actuel = clean_currency_value(selected_loan['Cout_Credit'])
|
|
|
|
| 471 |
|
| 472 |
with col2:
|
| 473 |
st.metric("Taux hebdomadaire", f"{taux_hebdo_actuel}%")
|
| 474 |
+
st.metric("Taux d'endettement", f"{taux_endettement_actuel}%") # ✅ Maintenant correct
|
| 475 |
st.metric("Durée", f"{int(duree_semaines_actuel)} semaines")
|
| 476 |
st.metric("Moyen de transfert", selected_loan.get('Moyen_Transfert', 'N/A'))
|
| 477 |
|
|
|
|
| 643 |
nouveau_nb_versements = 1
|
| 644 |
|
| 645 |
# Affichage résultat simulation
|
| 646 |
+
st.markdown("### 💰 Simulation des nouveaux montants")
|
| 647 |
res1, res2, res3 = st.columns(3)
|
| 648 |
res1.metric("Versement unique", f"{int(nouveau_montant_versement):,} XOF".replace(",", " "))
|
| 649 |
res2.metric("Coût du crédit", f"{int(nouveau_cout_credit):,} XOF".replace(",", " "))
|
|
|
|
| 743 |
nouveau_nb_versements = int(nouvelle_duree_semaines)
|
| 744 |
|
| 745 |
# Affichage résultat simulation
|
| 746 |
+
st.markdown("### 💰 Simulation des nouveaux montants")
|
| 747 |
res1, res2, res3 = st.columns(3)
|
| 748 |
res1.metric("Versement Hebdo", f"{int(hebdomadalite):,} XOF".replace(",", " "))
|
| 749 |
res2.metric("Coût du crédit", f"{int(nouveau_cout_credit):,} XOF".replace(",", " "))
|
|
|
|
| 754 |
# 5. LOGIQUE PERSONNALISÉE (Dates manuelles)
|
| 755 |
# -----------------------------------------------------------
|
| 756 |
else: # PERSONNALISE
|
| 757 |
+
st.info("📅 Configurez les dates de versement ci-dessous")
|
| 758 |
|
| 759 |
# Interface d'ajout de dates
|
| 760 |
st.markdown("**Dates de versement :**")
|
|
|
|
| 821 |
client_info['Revenus_Mensuels']
|
| 822 |
)
|
| 823 |
|
| 824 |
+
|
| 825 |
+
|
| 826 |
+
|
| 827 |
+
|
| 828 |
+
|
| 829 |
|
| 830 |
# Affichage pour information
|
| 831 |
if nouveau_taux_endettement > 0:
|
|
|
|
| 867 |
selected_loan['Type_Pret'],
|
| 868 |
f"{int(montant_capital_actuel):,} XOF".replace(",", " "),
|
| 869 |
f"{taux_hebdo_actuel}%",
|
| 870 |
+
f"{taux_endettement_actuel}%" if taux_endettement_actuel > 0 else "N/A", # ✅ Maintenant correct
|
| 871 |
f"{int(duree_semaines_actuel)} semaines",
|
| 872 |
f"{int(montant_total_actuel):,} XOF".replace(",", " "),
|
| 873 |
f"{int(cout_credit_actuel):,} XOF".replace(",", " "),
|
|
|
|
| 887 |
"Modifié" if nouveau_type_code != selected_loan['Type_Pret'] else "=",
|
| 888 |
f"{int(nouveau_montant - montant_capital_actuel):+,} XOF".replace(",", " ") if nouveau_montant != montant_capital_actuel else "=",
|
| 889 |
f"{nouveau_taux - taux_hebdo_actuel:+.1f}%" if nouveau_taux != taux_hebdo_actuel else "=",
|
| 890 |
+
f"{nouveau_taux_endettement - taux_endettement_actuel:+.1f}%" if taux_endettement_actuel > 0 else f"{nouveau_taux_endettement:.1f}%", # ✅ Maintenant correct
|
| 891 |
f"{int(diff_duree):+} sem" if diff_duree != 0 else "=",
|
| 892 |
f"{int(diff_montant_total):+,} XOF".replace(",", " ") if diff_montant_total != 0 else "=",
|
| 893 |
f"{int(diff_cout_credit):+,} XOF".replace(",", " ") if diff_cout_credit != 0 else "=",
|
|
|
|
| 924 |
|
| 925 |
if warnings:
|
| 926 |
st.markdown('<div class="checkup-warning-box">', unsafe_allow_html=True)
|
| 927 |
+
st.markdown("### ⚠️ Points d'attention")
|
| 928 |
for warning in warnings:
|
| 929 |
st.markdown(f"- {warning}")
|
| 930 |
st.markdown('</div>', unsafe_allow_html=True)
|
|
|
|
| 934 |
# ============================================================================
|
| 935 |
|
| 936 |
st.markdown('<div class="checkup-section-divider"></div>', unsafe_allow_html=True)
|
| 937 |
+
st.subheader(" Nouvelle analyse de solvabilité")
|
| 938 |
|
| 939 |
# Appel du cerveau analytique
|
| 940 |
analyse = analyser_capacite(
|
|
|
|
| 948 |
unsafe_allow_html=True)
|
| 949 |
st.info(analyse['message'])
|
| 950 |
|
| 951 |
+
with st.expander(" Détails financiers"):
|
| 952 |
st.markdown(analyse['details'])
|
| 953 |
|
| 954 |
# ============================================================================
|
|
|
|
| 956 |
# ============================================================================
|
| 957 |
|
| 958 |
st.markdown('<div class="checkup-section-divider"></div>', unsafe_allow_html=True)
|
| 959 |
+
st.subheader(" Nouveau tableau d'échéances")
|
| 960 |
|
| 961 |
# Génération du tableau
|
| 962 |
if nouveau_type_code == "PERSONNALISE":
|
|
|
|
| 982 |
# ============================================================================
|
| 983 |
|
| 984 |
st.markdown('<div class="checkup-section-divider"></div>', unsafe_allow_html=True)
|
| 985 |
+
st.subheader(" Validation de la mise à jour")
|
| 986 |
|
| 987 |
st.info("🔒 **Attention** : Cette action va créer un nouveau prêt et archiver l'ancien avec le statut UPDATED.")
|
| 988 |
|
|
|
|
| 1009 |
help="Ce commentaire sera enregistré dans la feuille Prets_Update pour traçabilité"
|
| 1010 |
)
|
| 1011 |
|
| 1012 |
+
submit_update = st.form_submit_button(" VALIDER LA MISE À JOUR", use_container_width=True)
|
| 1013 |
|
| 1014 |
+
|
| 1015 |
+
|
| 1016 |
+
|
| 1017 |
+
|
| 1018 |
+
|
| 1019 |
+
|
| 1020 |
+
|
| 1021 |
+
|
| 1022 |
+
|
| 1023 |
+
|
| 1024 |
+
|
| 1025 |
+
|
| 1026 |
+
|
| 1027 |
+
|
| 1028 |
+
|
| 1029 |
|
| 1030 |
|
| 1031 |
if submit_update:
|
|
|
|
| 1034 |
# ÉTAPE A : MISE À JOUR DU STATUT DANS Prets_Master
|
| 1035 |
# ========================================================================
|
| 1036 |
|
| 1037 |
+
with st.spinner(" Mise à jour du prêt en cours..."):
|
| 1038 |
ws_prets_master = sh.worksheet("Prets_Master")
|
| 1039 |
|
| 1040 |
# Recherche de la ligne du prêt à modifier
|
|
|
|
| 1080 |
# ÉTAPE B : CRÉATION DU NOUVEAU PRÊT DANS Prets_Update
|
| 1081 |
# ========================================================================
|
| 1082 |
|
| 1083 |
+
with st.spinner(" Création du nouveau prêt dans Prets_Update..."):
|
| 1084 |
# Vérification/Création de la feuille Prets_Update
|
| 1085 |
try:
|
| 1086 |
ws_prets_update = sh.worksheet("Prets_Update")
|
|
|
|
| 1094 |
cols=25
|
| 1095 |
)
|
| 1096 |
|
| 1097 |
+
# ✅ CORRECTION - En-têtes avec Taux_Endettement
|
| 1098 |
headers = [
|
| 1099 |
"ID_Pret", "ID_Pret_Source", "Version", "Date_Modification",
|
| 1100 |
"ID_Client", "Nom_Complet", "Type_Pret", "Motif",
|
| 1101 |
+
"Montant_Capital", "Taux_Hebdo", "Taux_Endettement", "Duree_Semaines", # ✅ Taux_Endettement ajouté
|
| 1102 |
"Montant_Versement", "Montant_Total", "Cout_Credit",
|
| 1103 |
"Nb_Versements", "Dates_Versements", "Date_Deblocage",
|
| 1104 |
"Date_Fin", "Moyen_Transfert", "Statut", "ID_Garant",
|
|
|
|
| 1120 |
d.strftime("%d/%m/%Y") for d in nouvelles_dates_versements
|
| 1121 |
]) if nouvelles_dates_versements else ""
|
| 1122 |
|
| 1123 |
+
# ✅ CORRECTION - Construction de la ligne de données (avec Taux_Endettement)
|
| 1124 |
row_data_update = [
|
| 1125 |
nouveau_id, # ID_Pret
|
| 1126 |
loan_id, # ID_Pret_Source
|
|
|
|
| 1132 |
nouveau_motif, # Motif
|
| 1133 |
nouveau_montant, # Montant_Capital
|
| 1134 |
nouveau_taux, # Taux_Hebdo
|
| 1135 |
+
round(nouveau_taux_endettement, 2), # ✅ Taux_Endettement (maintenant aligné avec headers)
|
| 1136 |
nouvelle_duree_semaines, # Duree_Semaines
|
| 1137 |
round(nouveau_montant_versement), # Montant_Versement
|
| 1138 |
round(nouveau_montant_total), # Montant_Total
|
|
|
|
| 1190 |
# Nettoyage du cache pour forcer le rechargement
|
| 1191 |
st.cache_data.clear()
|
| 1192 |
|
| 1193 |
+
st.success("🎉
|
|
|
|
| 1194 |
|
| 1195 |
except Exception as e:
|
| 1196 |
st.error(f"❌ Erreur lors de la mise à jour : {e}")
|
|
|
|
| 1202 |
|
| 1203 |
if st.session_state.get('loan_updated', False):
|
| 1204 |
st.markdown('<div class="checkup-section-divider"></div>', unsafe_allow_html=True)
|
| 1205 |
+
st.markdown(f"### Documents du prêt **{st.session_state.new_loan_id}**")
|
| 1206 |
|
| 1207 |
st.success(f"✅ Prêt mis à jour : **{st.session_state.get('new_loan_data', {}).get('ID_Pret_Source')}** → **{st.session_state.new_loan_id}**")
|
| 1208 |
|
|
|
|
| 1222 |
with col_pdf1:
|
| 1223 |
pdf_contrat = generer_contrat_pret(loan_data_pdf, client_data_pdf, df_amort_pdf)
|
| 1224 |
st.download_button(
|
| 1225 |
+
" Contrat de Prêt",
|
| 1226 |
pdf_contrat,
|
| 1227 |
f"Contrat_{st.session_state.new_loan_id}.pdf",
|
| 1228 |
"application/pdf",
|
|
|
|
| 1233 |
with col_pdf2:
|
| 1234 |
pdf_dette = generer_reconnaissance_dette(loan_data_pdf, client_data_pdf)
|
| 1235 |
st.download_button(
|
| 1236 |
+
" Reconnaissance Dette",
|
| 1237 |
pdf_dette,
|
| 1238 |
f"Dette_{st.session_state.new_loan_id}.pdf",
|
| 1239 |
"application/pdf",
|
|
|
|
| 1245 |
if garant_data_pdf is not None:
|
| 1246 |
pdf_caution = generer_contrat_caution(loan_data_pdf, garant_data_pdf)
|
| 1247 |
st.download_button(
|
| 1248 |
+
" Contrat Caution",
|
| 1249 |
pdf_caution,
|
| 1250 |
f"Caution_{st.session_state.new_loan_id}.pdf",
|
| 1251 |
"application/pdf",
|
|
|
|
| 1256 |
|
| 1257 |
# BOUTON RESET : Nouvelle mise à jour
|
| 1258 |
with col_reset:
|
| 1259 |
+
if st.button(" Nouvelle Mise à Jour", use_container_width=True, type="primary"):
|
| 1260 |
# Nettoyage du session state
|
| 1261 |
st.session_state.loan_updated = False
|
| 1262 |
st.session_state.pop('new_loan_id', None)
|
|
|
|
| 1270 |
|
| 1271 |
# Affichage d'un récapitulatif
|
| 1272 |
st.markdown("---")
|
| 1273 |
+
with st.expander(" Récapitulatif de la mise à jour"):
|
| 1274 |
col_recap1, col_recap2 = st.columns(2)
|
| 1275 |
|
| 1276 |
with col_recap1:
|