feat: Zahlungen finden ihren Vertrag von selbst – Preisaenderungen werden gemeldet

Ein Abo stand bisher unverbunden neben seinen Zahlungen. Wer wissen wollte,
ob Netflix diesen Monat abgebucht wurde, musste es in der Buchungsliste
suchen. Jetzt verknuepft Certain Buchung und Vertrag beim Import selbst.

Drei Stufen, bewusst unterschiedlich mutig:

- sicher (Betrag und Text passen, Datum im Fenster): wird zugeordnet.
- Vorschlag: Betrag passt, Text nicht – oder der Text passt und der Betrag
  weicht ab. Der zweite Fall ist die Preiserhoehung.
- nichts: im Zweifel lieber schweigen.

Eine Preiserhoehung wird nie stillschweigend uebernommen. Sie ist eine
Nachricht an den Nutzer, kein Wartungsvorgang – er entscheidet, ob der
neue Preis der richtige ist.

Die Zuordnung ist ein Etikett, keine Umbuchung: die Buchung selbst bleibt
unangetastet, und ein geloeschter Vertrag nimmt sie nicht mit.

Beim Backup wandern Vertraege nun vor die Buchungen, sonst haenge eine
Rueckspielung Zahlungen an die falschen Vertraege.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-30 20:16:13 +02:00
co-authored by Claude Opus 5
parent 41db67f53e
commit 152483707e
10 changed files with 822 additions and 16 deletions
+14 -12
View File
@@ -104,12 +104,26 @@ USER_TABLES: list[TableSpec] = [
TableSpec("import_batches", ImportBatch, "owner",
{"account_id": "accounts", "template_id": "import_templates"},
label="Import-Läufe"),
# Abos & Vertraege VOR den Buchungen: Eine Buchung traegt das Etikett ihres
# Vertrags, und ein Verweis darf nur auf eine schon eingefuegte Tabelle
# zeigen. Umgekehrt verweist kein Vertrag auf eine Buchung.
TableSpec("subscriptions", Subscription, "owner", {
"account_id": "accounts",
"savings_account_id": "accounts",
"category_id": "categories",
}, label="Abos & Vertraege"),
# Das Logo gehoert zum Vertrag. Klein gerechnet ist es ein paar Kilobyte –
# muehsam nachzutragen waere es trotzdem.
TableSpec("subscription_logos", SubscriptionLogo, "subscription",
{"subscription_id": "subscriptions"}, has_id=False,
label="Vertrags-Logos"),
TableSpec("transactions", Transaction, "owner", {
"account_id": "accounts",
"to_account_id": "accounts",
"category_id": "categories",
"budget_category_id": "categories",
"import_batch_id": "import_batches",
"subscription_id": "subscriptions",
}, label="Buchungen"),
TableSpec("budget_template_lines", BudgetTemplateLine, "owner",
{"category_id": "categories"}, label="Budget-Vorlage"),
@@ -134,18 +148,6 @@ USER_TABLES: list[TableSpec] = [
"category_id": "categories",
"transaction_id": "transactions",
}, label="Eingang"),
# Abos & Vertraege: reine Stammdaten, aber muehsam nachzutragen – und sie
# verweisen auf Konten und Kategorien, stehen deshalb nach beiden.
TableSpec("subscriptions", Subscription, "owner", {
"account_id": "accounts",
"savings_account_id": "accounts",
"category_id": "categories",
}, label="Abos & Vertraege"),
# Das Logo gehoert zum Vertrag. Klein gerechnet ist es ein paar Kilobyte –
# muehsam nachzutragen waere es trotzdem.
TableSpec("subscription_logos", SubscriptionLogo, "subscription",
{"subscription_id": "subscriptions"}, has_id=False,
label="Vertrags-Logos"),
TableSpec("transfer_links", TransferLink, "owner",
{"from_txn_id": "transactions", "to_txn_id": "transactions"},
label="Übertrags-Verknüpfungen"),