65 lines
2.8 KiB
Python
65 lines
2.8 KiB
Python
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)
|