klydekushy commited on
Commit
eae5bee
·
verified ·
1 Parent(s): 0c7aef1

Update src/modules/notifications.py

Browse files
Files changed (1) hide show
  1. src/modules/notifications.py +138 -43
src/modules/notifications.py CHANGED
@@ -1,73 +1,168 @@
 
 
1
  import smtplib
2
  from email.mime.text import MIMEText
3
  from email.mime.multipart import MIMEMultipart
4
  from datetime import datetime, timedelta
5
- import pandas as pd
6
- import streamlit as st
7
 
8
- # Configuration SMTP (A mettre dans st.secrets idéalement)
9
- # SMTP_SERVER = "smtp.gmail.com"
10
- # SMTP_PORT = 587
11
- # SENDER_EMAIL = "votre_email@gmail.com"
12
- # SENDER_PASSWORD = "votre_mot_de_passe_application"
 
 
 
 
13
 
14
- def envoyer_email(destinataire, sujet, corps):
 
 
 
15
  try:
16
- # Récupération des secrets (si configurés)
17
  smtp_server = st.secrets["smtp"]["server"]
18
  smtp_port = st.secrets["smtp"]["port"]
19
  sender_email = st.secrets["smtp"]["email"]
20
  sender_password = st.secrets["smtp"]["password"]
 
 
 
21
 
22
- msg = MIMEMultipart()
23
- msg['From'] = sender_email
24
- msg['To'] = destinataire
25
- msg['Subject'] = sujet
26
- msg.attach(MIMEText(corps, 'plain'))
 
 
 
 
 
 
 
 
 
 
 
27
 
 
 
 
 
 
 
 
 
28
  server = smtplib.SMTP(smtp_server, smtp_port)
29
  server.starttls()
30
  server.login(sender_email, sender_password)
31
- text = msg.as_string()
32
- server.sendmail(sender_email, destinataire, text)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  server.quit()
34
  return True
35
  except Exception as e:
36
- st.error(f"Erreur d'envoi mail : {e}")
37
  return False
38
 
39
  def verifier_et_notifier_echeances(client, sheet_name):
40
- st.subheader("📧 Gestion des Alertes & Notifications")
 
 
 
 
 
 
41
 
42
- if st.button("🔄 Vérifier les échéances à venir (J+3)"):
 
 
 
 
43
  try:
44
  sh = client.open(sheet_name)
45
- # On suppose que tu as une feuille 'Echeancier_Global' ou qu'on le calcule
46
- # Pour l'exemple, on imagine qu'on scanne les prêts actifs
47
  ws_prets = sh.worksheet("Prets_Master")
48
  df_prets = pd.DataFrame(ws_prets.get_all_records())
 
 
 
 
49
 
50
- # Simulation de détection (Logique à adapter selon ta structure de données exacte)
51
- # Ici on simule une alerte pour l'exemple
52
- alertes_envoyees = 0
53
-
54
- # Exemple de logique : Si une date de versement est proche
55
- today = datetime.now().date()
56
- deadline = today + timedelta(days=3) # Alerte à 3 jours
57
-
58
- # ... (Ici tu bouclerais sur ton tableau d'amortissement réel) ...
59
-
60
- # Exemple d'envoi
61
- # email_client = "client@exemple.com" # À récupérer dans df_clients via ID
62
- # corps_message = f"Bonjour, votre échéance de prêt arrive le {deadline}."
63
- # succes = envoyer_email(email_client, "Rappel Echéance - Vortex", corps_message)
64
-
65
- # Si pas de config SMTP, on affiche juste à l'écran pour le moment
66
- st.info("Simulation : 3 clients détectés avec échéance proche.")
67
- st.write("1. Moussa Diop (15/05/2024) - 50 000 XOF")
68
- st.write("2. Fatou Ndiaye (16/05/2024) - 25 000 XOF")
69
-
70
- st.warning("⚠️ Pour activer l'envoi réel, configurez les secrets SMTP dans Streamlit.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
  except Exception as e:
73
- st.error(f"Erreur : {e}")
 
1
+ import streamlit as st
2
+ import pandas as pd
3
  import smtplib
4
  from email.mime.text import MIMEText
5
  from email.mime.multipart import MIMEMultipart
6
  from datetime import datetime, timedelta
 
 
7
 
8
+ # ==============================================================================
9
+ # CONFIGURATION SMTP (À sécuriser via st.secrets sur Hugging Face)
10
+ # ==============================================================================
11
+ # Dans st.secrets, ajoutez une section [smtp] avec :
12
+ # server = "smtp.gmail.com"
13
+ # port = 587
14
+ # email = "votre_email@gmail.com"
15
+ # password = "votre_mot_de_passe_application"
16
+ # ==============================================================================
17
 
18
+ def envoyer_email_rappel(destinataire_client, destinataire_admin, details_pret):
19
+ """
20
+ Envoie un email au Client (Rappel) et à l'Admin (Notification).
21
+ """
22
  try:
 
23
  smtp_server = st.secrets["smtp"]["server"]
24
  smtp_port = st.secrets["smtp"]["port"]
25
  sender_email = st.secrets["smtp"]["email"]
26
  sender_password = st.secrets["smtp"]["password"]
27
+ except Exception:
28
+ st.error("⚠️ Secrets SMTP non configurés. Impossible d'envoyer l'email.")
29
+ return False
30
 
31
+ sujet = f"🔔 Rappel Échéance - Prêt {details_pret['ID_Pret']}"
32
+
33
+ # Corps du message
34
+ corps = f"""
35
+ Bonjour {details_pret['Nom_Complet']},
36
+
37
+ Ceci est un rappel automatique concernant votre prêt chez Vortex-Flux.
38
+
39
+ Une échéance de paiement est prévue pour demain.
40
+
41
+ 📋 Détails de l'échéance :
42
+ --------------------------------
43
+ ID Prêt : {details_pret['ID_Pret']}
44
+ Date prévue : {details_pret['Date_Echeance']}
45
+ Montant : {details_pret['Montant_Versement']} XOF
46
+ --------------------------------
47
 
48
+ Merci de prévoir les fonds nécessaires.
49
+
50
+ Cordialement,
51
+ L'équipe Vortex-Flux.
52
+ """
53
+
54
+ try:
55
+ # Connexion SMTP
56
  server = smtplib.SMTP(smtp_server, smtp_port)
57
  server.starttls()
58
  server.login(sender_email, sender_password)
59
+
60
+ # 1. Envoi au CLIENT
61
+ if destinataire_client and "@" in destinataire_client:
62
+ msg_client = MIMEMultipart()
63
+ msg_client['From'] = sender_email
64
+ msg_client['To'] = destinataire_client
65
+ msg_client['Subject'] = sujet
66
+ msg_client.attach(MIMEText(corps, 'plain'))
67
+ server.sendmail(sender_email, destinataire_client, msg_client.as_string())
68
+
69
+ # 2. Envoi à l'ADMIN (Copie)
70
+ msg_admin = MIMEMultipart()
71
+ msg_admin['From'] = sender_email
72
+ msg_admin['To'] = destinataire_admin
73
+ msg_admin['Subject'] = f"[ADMIN] Copie Rappel - {details_pret['Nom_Complet']}"
74
+ msg_admin.attach(MIMEText(f"Notification envoyée au client.\n\n{corps}", 'plain'))
75
+ server.sendmail(sender_email, destinataire_admin, msg_admin.as_string())
76
+
77
  server.quit()
78
  return True
79
  except Exception as e:
80
+ st.error(f"Erreur technique SMTP : {e}")
81
  return False
82
 
83
  def verifier_et_notifier_echeances(client, sheet_name):
84
+ st.markdown("### 📧 Centre de Notifications")
85
+
86
+ # Utilisation de session_state pour éviter de spammer à chaque rechargement de page
87
+ if 'check_done' not in st.session_state:
88
+ st.session_state.check_done = False
89
+
90
+ col_btn, col_info = st.columns([1, 3])
91
 
92
+ with col_btn:
93
+ lancer_verif = st.button("🔄 Vérifier Échéances (1.5j)")
94
+
95
+ if lancer_verif:
96
+ st.session_state.check_done = True
97
  try:
98
  sh = client.open(sheet_name)
99
+
100
+ # 1. Récupération des Prêts
101
  ws_prets = sh.worksheet("Prets_Master")
102
  df_prets = pd.DataFrame(ws_prets.get_all_records())
103
+
104
+ # 2. Récupération des Clients (pour avoir les emails)
105
+ ws_clients = sh.worksheet("Clients_KYC")
106
+ df_clients = pd.DataFrame(ws_clients.get_all_records())
107
 
108
+ # Création d'un dictionnaire ID -> Email pour recherche rapide
109
+ map_emails = dict(zip(df_clients['ID_Client'], df_clients['Email']))
110
+
111
+ now = datetime.now()
112
+ delta_limit = timedelta(days=1.5) # 36 heures
113
+ alertes_count = 0
114
+
115
+ st.write("Analyse des échéanciers en cours...")
116
+
117
+ for index, row in df_prets.iterrows():
118
+ # On ne traite que les prêts ACTIFS
119
+ if str(row.get('Statut', '')).upper() != "ACTIF":
120
+ continue
121
+
122
+ # Récupération de la chaîne de dates (ex: "10/05/2025;17/05/2025")
123
+ dates_str = str(row.get('Dates_Versements', ''))
124
+ if not dates_str:
125
+ continue
126
+
127
+ dates_list = dates_str.split(';')
128
+
129
+ for d_str in dates_list:
130
+ try:
131
+ d_obj = datetime.strptime(d_str.strip(), "%d/%m/%Y")
132
+
133
+ # LOGIQUE 1.5 JOURS
134
+ # L'échéance est dans le futur ET la différence est < 1.5 jours
135
+ diff = d_obj - now
136
+
137
+ if timedelta(seconds=0) < diff <= delta_limit:
138
+ client_id = row['ID_Client']
139
+ email_client = map_emails.get(client_id, "")
140
+ # Email Admin (Vous) - À changer ou mettre dans secrets
141
+ email_admin = st.secrets["smtp"]["email"] if "smtp" in st.secrets else "admin@vortex.com"
142
+
143
+ details = {
144
+ 'ID_Pret': row['ID_Pret'],
145
+ 'Nom_Complet': row['Nom_Complet'],
146
+ 'Date_Echeance': d_str,
147
+ 'Montant_Versement': row['Montant_Versement']
148
+ }
149
+
150
+ # Envoi
151
+ succes = envoyer_email_rappel(email_client, email_admin, details)
152
+
153
+ if succes:
154
+ st.toast(f"📧 Rappel envoyé pour {row['Nom_Complet']} (Echéance : {d_str})", icon="✅")
155
+ alertes_count += 1
156
+ else:
157
+ st.toast(f"❌ Échec envoi pour {row['Nom_Complet']}", icon="⚠️")
158
+
159
+ except ValueError:
160
+ continue # Format date invalide, on ignore
161
+
162
+ if alertes_count == 0:
163
+ st.info("Aucune échéance proche (< 1.5 jours) détectée.")
164
+ else:
165
+ st.success(f"✅ Terminé : {alertes_count} notifications envoyées.")
166
 
167
  except Exception as e:
168
+ st.error(f"Erreur lors de la vérification : {e}")