feat: Abos & Vertraege – was regelmaessig abgeht, an einer Stelle

Netflix, Handyvertrag, Krankenkasse, Halbtax. Bisher sah man sie nur als
einzelne Buchungen im Auszug; die Frage "welche Abos habe ich eigentlich, und
was kosten die zusammen im Monat" liess sich nicht beantworten. Genau die
steht jetzt oben auf der Seite.

Der Bereich heisst "Abos & Vertraege", nicht "Abos": Ein Handyvertrag ist kein
Abo und die Versicherung erst recht nicht – niemand soll ueberlegen muessen,
wo sie hingehoert.

Der Monatswert wird gerechnet, nicht gespeichert (Betrag durch Intervall).
Gespeichert veraltete er beim naechsten Preisaufschlag stillschweigend.

Bei laengerem Intervall klappt "Ich lege monatlich zurueck auf" auf, mit dem
gerechneten Monatsbetrag daneben. Bei monatlicher Abrechnung gibt es nichts
anzusparen, also steht es da auch nicht.

DAZU: Waehrungen sind offen.

Die Rechen-Maschinerie konnte immer schon beliebige Waehrungen – sie rechnet
ueber den Euro als Drehpunkt. Beschraenkt haben es zwei Konstanten: eine
Erlaubnisliste mit EUR und CHF, und ein Filter, der aus dem EZB-Feed alles
ausser CHF wegwarf, obwohl er dreissig Waehrungen liefert.

Massgeblich ist jetzt die Liste der EZB. Frei erfundene Waehrungen bleiben
draussen, und das ist kein Geiz: Ohne Kurs liesse sich der Betrag nie
umrechnen – er stuende in keiner Summe und in keinem Budget, und das faellt
erst spaet auf. Ein Vertrag in einer Waehrung ohne Kurs wird deshalb genannt,
statt die Summe stillschweigend zu klein anzuzeigen.

Erkannt und gebucht wird noch nichts; der Erkennungstext wird nur erfasst.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-07 15:45:59 +02:00
co-authored by Claude Opus 5
parent ff621984dc
commit f99be47587
18 changed files with 1297 additions and 10 deletions
+47 -1
View File
@@ -23,7 +23,8 @@
"system": "System",
"users": "Benutzer",
"settings": "Einstellungen",
"todo": "Zu erledigen"
"todo": "Zu erledigen",
"abos": "Abos"
},
"login": {
"subtitle": "Bitte anmelden",
@@ -320,6 +321,51 @@
"incomeCategory": "Kategorie",
"targetAccount": "Zielkonto"
},
"abos": {
"title": "Abos & Verträge",
"new": "Neuer Vertrag",
"edit": "Vertrag bearbeiten",
"delete": "Löschen",
"deleteConfirm": "„{{name}}“ wirklich löschen? Der Vertrag verschwindet samt seiner Angaben. Wenn er nur ausgelaufen ist, setz ihn lieber auf gekündigt – dann bleibt er zum Nachsehen stehen.",
"monthlyTotal": "Im Monat",
"yearlyTotal": "Im Jahr",
"activeCount": "Laufende Verträge",
"dueSoon": "Demnächst fällig",
"all": "Alle Verträge",
"cancelled": "Gekündigt",
"cancelledHint": "Zählen nicht mehr in der Summe. Sie bleiben stehen, damit du später nachsehen kannst, was du hattest.",
"empty": "Noch keine Verträge. Trag ein, was regelmässig abgeht – Streaming, Handy, Versicherung, Halbtax.",
"noRate": "Für {{waehrungen}} liegt kein Kurs vor. Diese Verträge fehlen in der Summe.",
"name": "Name",
"amount": "Betrag je Abrechnung",
"currency": "Währung",
"interval": "Abgerechnet",
"every": {
"1": "monatlich",
"2": "alle 2 Monate",
"3": "vierteljährlich",
"6": "halbjährlich",
"12": "jährlich"
},
"perMonth": "{{betrag}} im Monat",
"paidFrom": "Bezahlt über",
"accountNone": "Kein Konto gewählt",
"category": "Kategorie",
"categoryNone": "Keine Kategorie",
"nextDue": "Nächste Fälligkeit",
"dueIn": "in {{tage}} Tagen",
"dueToday": "heute fällig",
"overdue": "seit {{tage}} Tagen überfällig",
"savingsAccount": "Ich lege monatlich zurück auf",
"savingsNone": "Nicht ansparen",
"savingsHint": "Bei diesem Intervall wären das {{betrag}} im Monat. Wähl das Konto, auf das du zurücklegst – dann sprengt die Rechnung nicht einen einzelnen Monat.",
"savingInto": "spart auf {{name}}",
"pattern": "Erkennungstext",
"patternHint": "Woran die Abbuchung im Auszug zu erkennen ist. Auf dem Auszug steht selten der Name, unter dem du den Vertrag kennst. Wird noch nicht ausgewertet – kommt mit der automatischen Zuordnung.",
"cancelledFlag": "Gekündigt",
"cancelledFlagHint": "Zählt dann nicht mehr in der Monatssumme, bleibt aber in der Liste stehen.",
"notes": "Notiz"
},
"import": {
"title": "Import",
"modeCsv": "CSV",