"""Was die Verträge je Kategorie im Monat kosten. Die eine Stelle, an der aus Verträgen eine Budget-Zahl wird. Budget-Seite und Dashboard fragen beide hier – sonst könnten sie unterschiedliche Antworten geben, und man müsste raten, welche stimmt. Gerechnet wird in der Hauptwährung: Ein Vertrag in Euro und einer in Franken lassen sich sonst nicht addieren. Was sich mangels Kurs nicht umrechnen lässt, wird GEMELDET und nicht stillschweigend als Null verbucht – eine zu kleine Summe im Budget ist schlimmer als gar keine. """ from __future__ import annotations from collections import defaultdict from datetime import date from sqlalchemy.orm import Session from ..models import Subscription, User from . import currency def _monatlich_in(db: Session, s: Subscription, base: str, heute: date) -> int | None: """Monatswert eines Vertrags in der Hauptwährung, oder None ohne Kurs.""" monatlich = s.monatlich_cents if s.currency == base: return monatlich return currency.convert(db, monatlich, s.currency, base, heute) def uebersicht(db: Session, user: User, base: str) -> dict: """Alles, was die Budget-Seite über die Verträge wissen muss. ``je_kategorie`` Monatswert je Kategorie, in Hauptwährung ``anzahl`` wie viele Verträge je Kategorie – „aus 2 Verträgen" ``ohne_kategorie`` Summe und Anzahl der Verträge, die keiner Kategorie zugeordnet sind. Ohne diese Angabe fehlt ihr Geld im Budget, ohne dass irgendwo steht, dass es fehlt. ``ohne_kurs`` Währungen, die sich nicht umrechnen liessen. """ heute = date.today() je_kategorie: dict[int, int] = defaultdict(int) anzahl: dict[int, int] = defaultdict(int) ohne_kategorie_cents = 0 ohne_kategorie_anzahl = 0 ohne_kurs: set[str] = set() for s in db.query(Subscription).filter( Subscription.owner_id == user.id, Subscription.is_active.is_(True), ): cents = _monatlich_in(db, s, base, heute) if cents is None: ohne_kurs.add(s.currency) continue if s.category_id is None: ohne_kategorie_cents += cents ohne_kategorie_anzahl += 1 continue je_kategorie[s.category_id] += cents anzahl[s.category_id] += 1 return { "je_kategorie": dict(je_kategorie), "anzahl": dict(anzahl), "ohne_kategorie_cents": ohne_kategorie_cents, "ohne_kategorie_anzahl": ohne_kategorie_anzahl, "ohne_kurs": sorted(ohne_kurs), } def monatlich_je_kategorie(db: Session, user: User, base: str) -> dict[int, int]: """Nur die Beträge – für die Soll-Berechnung.""" return uebersicht(db, user, base)["je_kategorie"]