""" Daily cron safety-net: check all budgets for the current month and send any unsent 80% / 100% alert emails. Run daily (e.g. 9 AM) so alerts fire even if the triggering transaction was imported via a provider sync rather than entered manually through the UI. python scripts/check_budget_alerts.py """ import sys import os sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from datetime import date from app import create_app from app.extensions import db app = create_app() with app.app_context(): from app.models.user import User from app.models.budget import Budget from app.services.alert_service import ( _smtp_configured, _send_single_alert_email ) from app.services.budget_service import get_month_spending user = User.query.first() if not user or not user.budget_alerts_enabled: print("Budget alerts disabled — nothing to do.") sys.exit(0) if not _smtp_configured(): print("SMTP not configured — nothing to do.") sys.exit(0) month_str = date.today().strftime('%Y-%m') symbol = user.currency_symbol or '$' budgets = Budget.query.filter_by(month=month_str).all() sent = 0 for b in budgets: limit = float(b.limit_amount) + float(b.rollover_amount or 0) if limit <= 0: continue spent = get_month_spending(b.category_id, month_str) pct = spent / limit * 100 cat = b.category name = cat.name if cat else 'Unknown' if pct >= 100 and not b.alert_sent_100: _send_single_alert_email(name, spent, limit, pct, symbol, threshold=100) b.alert_sent_100 = True sent += 1 elif pct >= 80 and not b.alert_sent_80: _send_single_alert_email(name, spent, limit, pct, symbol, threshold=80) b.alert_sent_80 = True sent += 1 if sent: db.session.commit() print(f"Budget alert check complete — {sent} email(s) sent.")