from __future__ import annotations from datetime import date, timedelta from app.extensions import db from app.models import InAppNotification, Month, NotificationPreference, User class NotificationService: def __init__(self, month_service, push_service, threshold: float): self.month_service = month_service self.push_service = push_service self.threshold = threshold def run_monthly_checks(self, today: date | None = None) -> int: today = today or date.today() current_month = self.month_service.ensure_month(today) next_month_date = (today.replace(day=28) + timedelta(days=4)).replace(day=1) next_month = Month.query.filter_by( label=f"{next_month_date.year:04d}-{next_month_date.month:02d}" ).first() summary = self.month_service.compute_summary(current_month) count = 0 for user in User.query.filter_by(is_active=True).all(): pref = user.notification_preference or NotificationPreference(user_id=user.id) if pref.id is None: db.session.add(pref) db.session.flush() if pref.notify_month_end and next_month is None and today.day >= 25: self._notify( user, "month_end", "Folgemonat fehlt", "Der nächste Monat ist noch nicht vorbereitet. Öffne Saldo und prüfe die Planung.", "/months/", ) count += 1 if pref.notify_missing_distribution and summary.remainder != summary.allocation_total: self._notify( user, "missing_distribution", "Restverteilung unvollständig", "Die geplante Verteilung deckt den aktuellen Restbetrag noch nicht vollständig ab.", f"/planning/{current_month.label}", ) count += 1 if pref.notify_missing_values and abs(float(summary.deltas["income_delta"])) >= self.threshold: self._notify( user, "income_change", "Einkommen hat sich deutlich verändert", "Durch eine Einkommensänderung sollten die Vorschläge und Verteilungen geprüft werden.", f"/planning/{current_month.label}", ) count += 1 db.session.commit() return count def _notify(self, user, kind: str, title: str, body: str, action_url: str) -> None: notification = InAppNotification( user_id=user.id, type=kind, title=title, body=body, action_url=action_url ) db.session.add(notification) self.push_service.send_to_user(user, title=title, body=body, url=action_url)