Finanzmanager/docs/stammdaten.md
fds2610-bot 851e8204e9 Phase 3: Budgetplaner und Monatsabschluss
Budgetplaner mit Monatswerten je Kategorie, Monatsabschluss mit Prüflauf,
Snapshot und Buchungssperre. Dazu drei Vorarbeiten in der Oberfläche.

Budgetplaner
- Migration 004: budgets, budget_positionen, monatsabschluesse
- Zeilen sind der Kategoriebaum, Spalten die Monate; die ganze Tabelle wird in
  einem Formular gespeichert, damit mehrere Änderungen zusammen ankommen
- Zwei Ansichten: Verlauf (Jahressumme, abgelaufene Monate zusammengefasst,
  laufender Monat mit Budget/Ist/Saldo, danach Folgemonate) und alle Monate
- Ausgaben ohne Vorzeichen eingeben, es kommt aus der Kategorieart. Saldo ist
  Ist minus Budget: positiv heißt besser als geplant, negativ ist die
  Überschreitung und wird rot ausgewiesen
- Übergeordnete Kategorien summieren ihre Nachfahren und sind nicht beplanbar
- Ein Monat ohne Position ist "nicht geplant" und damit etwas anderes als
  "mit 0,00 geplant"
- Wert auf Folgemonate übertragen, Budget als Kopie ins neue Jahr

Monatsabschluss
- Prüflauf über nicht kategorisierte Buchungen, nicht abgeglichene Umsätze und
  Splitsummen-Differenzen; er hält niemanden auf, sondern zeigt den Stand
- Snapshot der Kontosalden und Kategoriesummen als JSON, bleibt auch nach einer
  Wiedereröffnung stehen
- Abgeschlossene Monate sperren Buchungen in beide Richtungen: weder hinein noch
  heraus verschieben. Abschaltbar über monatsabschluss_sperrt_buchungen

Vorarbeiten
- .knopf.primaer trug einen eigenen margin-top und stand dadurch in jeder
  Knopfleiste tiefer als seine Nachbarn - sichtbar an "Abbrechen" neben
  "Konto anlegen". Der Abstand liegt jetzt allein bei der Knopfleiste
- Kontengruppen werden wie Konten und Kategorien auf einer eigenen
  Formularseite gepflegt statt inline; dort hängt auch die Zuordnung der
  Konten (ankreuzen statt jedes Konto einzeln zu öffnen)
- Der QIF-Export enthält keine Kontengruppen: kein Feld im !Account-Eintrag,
  nichts in der QSD-Datei. Import-Oberfläche und Doku sagen das jetzt
- Die Baum-Einrückung lief über ein style-Attribut und wurde von der
  Content-Security-Policy verworfen; sie steht jetzt als data-ebene im Markup.
  Aus demselben Grund blendete app.js Erfolgsmeldungen nie aus

Tests: 11_BudgetTest, 12_MonatsabschlussTest (76 Prüfungen), E2E planung.spec.js.
Einzelheiten in docs/planung.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 07:31:25 +02:00

4 KiB
Raw Blame History

Stammdaten

Konten, Kontengruppen, Kategorien und Klassen – die Grundlage aller Buchungen und Auswertungen. Die Begriffe entsprechen dem Lexware FinanzManager.

Kontengruppen und Konten

Kontengruppen gliedern die Kontenübersicht (etwa „Anlage“). Konten ohne Gruppe erscheinen unter Nicht gruppiert – das ist keine eigene Gruppe, sondern kontengruppe_id IS NULL. Wird eine Gruppe gelöscht, bleiben ihre Konten erhalten und rutschen dorthin (ON DELETE SET NULL).

Gruppen werden wie Konten und Kategorien auf einer eigenen Formularseite gepflegt (Verwaltung → Kontengruppen). Dort hängt auch die Zuordnung: Die Konten der Gruppe werden angekreuzt, Kontengruppe::kontenZuordnen() setzt sie in einem Zug. Ein Konto gehört zu genau einer Gruppe – wird es hier angehakt, verlässt es seine bisherige.

Der QIF-Export enthält keine Kontengruppen (siehe docs/qif-import.md); nach einem Import stehen deshalb alle Konten unter „Nicht gruppiert“ und werden einmalig zugeordnet.

Kontoarten (Konto::ARTEN) und ihre Herkunft aus dem QIF-Export (Konto::QIF_ARTEN):

Kontoart Bezeichnung QIF-Typ
bank Bank Bank
kreditkarte Kreditkarte CCard
bar Bar Cash
sparkonto Tagesgeld/Sparkonto Oth T
vermoegen Vermögen Oth A
verbindlichkeit Verbindlichkeit Oth L
rente Rentenversicherung Oth P
sonstiges Sonstiges Vermögen Oth E, Oth F
depot Depot Port, Invst

Die Kontenübersicht (Konto::uebersicht()) bündelt nach Gruppe, bildet je Gruppe eine Summe und darunter die Gesamtsumme. Sie führt schon jetzt die drei Saldospalten des FinanzManagers:

  • Online-Saldo – Stand des letzten Bankabrufs, bleibt bis Phase 5 leer
  • Aktueller Saldo – gebuchte Umsätze bis heute
  • Erwarteter Saldo – einschließlich künftig datierter Buchungen

Solange es keine Buchungen gibt (bis Phase 2), entsprechen alle drei dem Anfangssaldo. Die Werte entstehen zentral in Konto::mitSalden(); dort kommen in Phase 2 die Buchungen dazu, ohne dass die Aufrufer sich ändern.

Anfangssalden stehen nicht im QIF-Export. Sie werden nach dem Import je Konto im Kontoformular nachgetragen.

Kategorien

Hierarchisch, Trenner ist : wie im FinanzManager. name hält den Blattnamen, pfad den vollständigen Namen (400 - Leben:B-Essen alleine). Der Pfad steht redundant in der Tabelle, weil praktisch jede Anzeige, jede Auswahl und der gesamte Import darüber laufen; Umbenennen und Verschieben schreiben die Pfade des ganzen Teilbaums neu (Kategorie::pfadeNeuAufbauen()).

Regeln:

  • Die Art (Einnahme/Ausgabe) gilt für den ganzen Ast. Unterkategorien erben sie, und ein Wechsel an der Wurzel zieht alle Nachfahren mit.
  • Ein Name darf keinen Doppelpunkt enthalten – der trennt die Ebenen.
  • Eine Kategorie kann nicht unter ihren eigenen Teilbaum verschoben werden.
  • Zusammenführen hängt die Unterkategorien der Quelle unter das Ziel und löscht die Quelle. Ab Phase 2 wandern dort auch die Buchungen mit.
  • Löschen nimmt die Unterkategorien mit (ON DELETE CASCADE). Wer eine Kategorie nur aus den Auswahllisten nehmen will, setzt sie auf inaktiv.

Die Oberfläche hat die vier Register des Originals: Alle, Einnahmen, Ausgaben, Umbuchungskonten. Umbuchungskonten sind keine Datensätze – dort stehen die Konten, weil sie in der Kategorieauswahl einer Buchung an derselben Stelle erscheinen (in eckigen Klammern).

Klassen

Flach, ohne Hierarchie – die zweite Auswertungsdimension neben der Kategorie (Ehemann, Ehefrau, Haus 1, Projekt …). Im QIF hängen sie mit / an der Kategorie: 400 - Leben:B-Essen alleine/Privat. Kategorie::zerlegeQifAngabe() trennt beides.

Mandantenfähigkeit

Alle Stammdatentabellen führen benutzer_id. Die Oberfläche ist einbenutzerig; die Kennung liefert Mandant::id() – aus der Session, im CLI ersatzweise der erste aktive Benutzer. Mandant::setze() gibt sie in Skripten und Tests fest vor.