""" Budget Alert System Monitors spending and sends email alerts when budget limits are exceeded """ from flask import render_template_string from flask_mail import Mail, Message from app.models.category import Category from app.models.user import User from app import db from datetime import datetime import os mail = None def init_mail(app): """Initialize Flask-Mail with app configuration""" global mail # Email configuration from environment variables app.config['MAIL_SERVER'] = os.environ.get('MAIL_SERVER', 'smtp.gmail.com') app.config['MAIL_PORT'] = int(os.environ.get('MAIL_PORT', 587)) app.config['MAIL_USE_TLS'] = os.environ.get('MAIL_USE_TLS', 'true').lower() == 'true' app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME') app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD') app.config['MAIL_DEFAULT_SENDER'] = os.environ.get('MAIL_DEFAULT_SENDER', 'noreply@fina.app') mail = Mail(app) return mail def check_budget_alerts(): """Check all categories for budget overruns and send alerts""" if not mail: print("[Budget Alerts] Mail not configured") return 0 alerts_sent = 0 # Get all categories with budgets that need checking categories = Category.query.filter( Category.monthly_budget.isnot(None), Category.monthly_budget > 0 ).all() for category in categories: if category.should_send_budget_alert(): user = User.query.get(category.user_id) if user and user.budget_alerts_enabled: if send_budget_alert(user, category): category.budget_alert_sent = True category.last_budget_check = datetime.now() alerts_sent += 1 db.session.commit() return alerts_sent def send_budget_alert(user, category): """Send budget alert email to user""" if not mail: print(f"[Budget Alert] Mail not configured, skipping alert for {user.email}") return False try: status = category.get_budget_status() alert_email = user.alert_email or user.email # Get user's language lang = user.language or 'en' # Email templates in multiple languages subjects = { 'en': f'⚠️ Budget Alert: {category.name}', 'ro': f'⚠️ Alertă Buget: {category.name}', 'es': f'⚠️ Alerta de Presupuesto: {category.name}' } # Email body template html_template = """

🔔 {title}

⚠️ {alert_message}

{alert_description}

{details_title}

{spent_label}
{currency}{spent:.2f}
{budget_label}
{currency}{budget:.2f}
{remaining_label}
{currency}{remaining:.2f}
{percentage:.1f}%

{category_label}: {category_name}
{threshold_label}: {threshold}%

{button_text}
""" # Translations translations = { 'en': { 'title': 'Budget Alert', 'alert_message': 'Budget Limit Exceeded!', 'alert_description': f'Your spending in the "{category.name}" category has exceeded {int(category.budget_alert_threshold * 100)}% of your monthly budget.', 'details_title': 'Budget Overview', 'spent_label': 'Spent This Month', 'budget_label': 'Monthly Budget', 'remaining_label': 'Over Budget', 'category_label': 'Category', 'threshold_label': 'Alert Threshold', 'button_text': 'View Dashboard', 'footer_text': 'This is an automated budget alert from FINA Finance Tracker.', 'disable_text': 'To disable budget alerts, go to Settings > Profile.' }, 'ro': { 'title': 'Alertă Buget', 'alert_message': 'Limită buget depășită!', 'alert_description': f'Cheltuielile în categoria "{category.name}" au depășit {int(category.budget_alert_threshold * 100)}% din bugetul lunar.', 'details_title': 'Rezumat Buget', 'spent_label': 'Cheltuit Luna Aceasta', 'budget_label': 'Buget Lunar', 'remaining_label': 'Peste Buget', 'category_label': 'Categorie', 'threshold_label': 'Prag Alertă', 'button_text': 'Vezi Tabloul de Bord', 'footer_text': 'Aceasta este o alertă automată de buget de la FINA Finance Tracker.', 'disable_text': 'Pentru a dezactiva alertele de buget, mergi la Setări > Profil.' }, 'es': { 'title': 'Alerta de Presupuesto', 'alert_message': '¡Límite de presupuesto excedido!', 'alert_description': f'Tus gastos en la categoría "{category.name}" han superado el {int(category.budget_alert_threshold * 100)}% de tu presupuesto mensual.', 'details_title': 'Resumen de Presupuesto', 'spent_label': 'Gastado Este Mes', 'budget_label': 'Presupuesto Mensual', 'remaining_label': 'Sobre Presupuesto', 'category_label': 'Categoría', 'threshold_label': 'Umbral de Alerta', 'button_text': 'Ver Panel', 'footer_text': 'Esta es una alerta automática de presupuesto de FINA Finance Tracker.', 'disable_text': 'Para desactivar las alertas de presupuesto, ve a Configuración > Perfil.' } } t = translations.get(lang, translations['en']) # Determine progress bar color if status['percentage'] >= 100: progress_color = '#ef4444' # Red elif status['percentage'] >= 90: progress_color = '#f59e0b' # Orange else: progress_color = '#10b981' # Green # Dashboard URL (adjust based on your deployment) dashboard_url = os.environ.get('APP_URL', 'http://localhost:5001') + '/dashboard' html_body = html_template.format( title=t['title'], alert_message=t['alert_message'], alert_description=t['alert_description'], details_title=t['details_title'], spent_label=t['spent_label'], budget_label=t['budget_label'], remaining_label=t['remaining_label'], category_label=t['category_label'], threshold_label=t['threshold_label'], button_text=t['button_text'], footer_text=t['footer_text'], disable_text=t['disable_text'], currency=user.currency, spent=status['spent'], budget=status['budget'], remaining=abs(status['remaining']), percentage=min(status['percentage'], 100), progress_color=progress_color, category_name=category.name, threshold=int(category.budget_alert_threshold * 100), dashboard_url=dashboard_url ) msg = Message( subject=subjects.get(lang, subjects['en']), recipients=[alert_email], html=html_body ) mail.send(msg) print(f"[Budget Alert] Sent to {alert_email} for category {category.name}") return True except Exception as e: print(f"[Budget Alert] Error sending email: {e}") return False def send_test_budget_alert(user_email): """Send a test budget alert email""" if not mail: return False, "Mail not configured" try: msg = Message( subject='Test Budget Alert - FINA', recipients=[user_email], body='This is a test email from FINA budget alert system. If you received this, email alerts are working correctly!', html='''

✅ Test Email Successful

This is a test email from the FINA budget alert system.

If you received this message, your email configuration is working correctly!


FINA Finance Tracker

''' ) mail.send(msg) return True, "Test email sent successfully" except Exception as e: return False, str(e)