Vortex-Flux / src /modules /notifications.py
klydekushy's picture
Update src/modules/notifications.py
eae5bee verified
import streamlit as st
import pandas as pd
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from datetime import datetime, timedelta
# ==============================================================================
# CONFIGURATION SMTP (À sécuriser via st.secrets sur Hugging Face)
# ==============================================================================
# Dans st.secrets, ajoutez une section [smtp] avec :
# server = "smtp.gmail.com"
# port = 587
# email = "votre_email@gmail.com"
# password = "votre_mot_de_passe_application"
# ==============================================================================
def envoyer_email_rappel(destinataire_client, destinataire_admin, details_pret):
"""
Envoie un email au Client (Rappel) et à l'Admin (Notification).
"""
try:
smtp_server = st.secrets["smtp"]["server"]
smtp_port = st.secrets["smtp"]["port"]
sender_email = st.secrets["smtp"]["email"]
sender_password = st.secrets["smtp"]["password"]
except Exception:
st.error("⚠️ Secrets SMTP non configurés. Impossible d'envoyer l'email.")
return False
sujet = f"🔔 Rappel Échéance - Prêt {details_pret['ID_Pret']}"
# Corps du message
corps = f"""
Bonjour {details_pret['Nom_Complet']},
Ceci est un rappel automatique concernant votre prêt chez Vortex-Flux.
Une échéance de paiement est prévue pour demain.
📋 Détails de l'échéance :
--------------------------------
ID Prêt : {details_pret['ID_Pret']}
Date prévue : {details_pret['Date_Echeance']}
Montant : {details_pret['Montant_Versement']} XOF
--------------------------------
Merci de prévoir les fonds nécessaires.
Cordialement,
L'équipe Vortex-Flux.
"""
try:
# Connexion SMTP
server = smtplib.SMTP(smtp_server, smtp_port)
server.starttls()
server.login(sender_email, sender_password)
# 1. Envoi au CLIENT
if destinataire_client and "@" in destinataire_client:
msg_client = MIMEMultipart()
msg_client['From'] = sender_email
msg_client['To'] = destinataire_client
msg_client['Subject'] = sujet
msg_client.attach(MIMEText(corps, 'plain'))
server.sendmail(sender_email, destinataire_client, msg_client.as_string())
# 2. Envoi à l'ADMIN (Copie)
msg_admin = MIMEMultipart()
msg_admin['From'] = sender_email
msg_admin['To'] = destinataire_admin
msg_admin['Subject'] = f"[ADMIN] Copie Rappel - {details_pret['Nom_Complet']}"
msg_admin.attach(MIMEText(f"Notification envoyée au client.\n\n{corps}", 'plain'))
server.sendmail(sender_email, destinataire_admin, msg_admin.as_string())
server.quit()
return True
except Exception as e:
st.error(f"Erreur technique SMTP : {e}")
return False
def verifier_et_notifier_echeances(client, sheet_name):
st.markdown("### 📧 Centre de Notifications")
# Utilisation de session_state pour éviter de spammer à chaque rechargement de page
if 'check_done' not in st.session_state:
st.session_state.check_done = False
col_btn, col_info = st.columns([1, 3])
with col_btn:
lancer_verif = st.button("🔄 Vérifier Échéances (1.5j)")
if lancer_verif:
st.session_state.check_done = True
try:
sh = client.open(sheet_name)
# 1. Récupération des Prêts
ws_prets = sh.worksheet("Prets_Master")
df_prets = pd.DataFrame(ws_prets.get_all_records())
# 2. Récupération des Clients (pour avoir les emails)
ws_clients = sh.worksheet("Clients_KYC")
df_clients = pd.DataFrame(ws_clients.get_all_records())
# Création d'un dictionnaire ID -> Email pour recherche rapide
map_emails = dict(zip(df_clients['ID_Client'], df_clients['Email']))
now = datetime.now()
delta_limit = timedelta(days=1.5) # 36 heures
alertes_count = 0
st.write("Analyse des échéanciers en cours...")
for index, row in df_prets.iterrows():
# On ne traite que les prêts ACTIFS
if str(row.get('Statut', '')).upper() != "ACTIF":
continue
# Récupération de la chaîne de dates (ex: "10/05/2025;17/05/2025")
dates_str = str(row.get('Dates_Versements', ''))
if not dates_str:
continue
dates_list = dates_str.split(';')
for d_str in dates_list:
try:
d_obj = datetime.strptime(d_str.strip(), "%d/%m/%Y")
# LOGIQUE 1.5 JOURS
# L'échéance est dans le futur ET la différence est < 1.5 jours
diff = d_obj - now
if timedelta(seconds=0) < diff <= delta_limit:
client_id = row['ID_Client']
email_client = map_emails.get(client_id, "")
# Email Admin (Vous) - À changer ou mettre dans secrets
email_admin = st.secrets["smtp"]["email"] if "smtp" in st.secrets else "admin@vortex.com"
details = {
'ID_Pret': row['ID_Pret'],
'Nom_Complet': row['Nom_Complet'],
'Date_Echeance': d_str,
'Montant_Versement': row['Montant_Versement']
}
# Envoi
succes = envoyer_email_rappel(email_client, email_admin, details)
if succes:
st.toast(f"📧 Rappel envoyé pour {row['Nom_Complet']} (Echéance : {d_str})", icon="✅")
alertes_count += 1
else:
st.toast(f"❌ Échec envoi pour {row['Nom_Complet']}", icon="⚠️")
except ValueError:
continue # Format date invalide, on ignore
if alertes_count == 0:
st.info("Aucune échéance proche (< 1.5 jours) détectée.")
else:
st.success(f"✅ Terminé : {alertes_count} notifications envoyées.")
except Exception as e:
st.error(f"Erreur lors de la vérification : {e}")