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}")