Neuer Schalter „Bewusst ohne Kategorie“ in der Buchungsmaske für
Abschreibungen und rein rechnerische Solarerträge. Solche Buchungen
erscheinen nicht unter den offenen Vorgängen im Cockpit, nicht im
Prüflauf des Monatsabschlusses, setzen das Konto in der Kontenübersicht
nicht fett und werden von der Regelanwendung sowie dem automatischen
Zusammenführen zu Umbuchungen ausgelassen. Kommt eine Kategorie, ein
Gegenkonto oder eine Splitbuchung hinzu, entfällt die Markierung.
Migration 028_bewusst_ohne_kategorie.sql, Test 59 und E2E-Test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Aus der Kachel QIF-Import wird Import/Export mit je einem Knopf für beide
Richtungen; davor steht die Wahl des Dateiformats (QIF oder CSV), die als
Dialog und ohne Skript als eigene Seite funktioniert.
- CsvBuchungsImport/CsvTabelle: Buchungen samt Splitzeilen, Spalten über die
Kopfzeile, dieselbe Dublettenerkennung und der Trockenlauf wie beim QIF.
- BuchungsExport/ExportController: Filter nach Zeitraum, Konto, Kategorie und
Klasse; die Datei entsteht im Speicher, ein Exportverzeichnis gibt es nicht.
- Housekeeping: Hochgeladene Importdateien und data/tmp werden nach der
eingestellten Frist gelöscht (Vorgabe 14 Tage, 0 schaltet ab).
Migration 013, Test 29 sowie E2E-Spec importexport.spec.js.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Kontenzuordnung als dritter Einrichtungsschritt: Welches Bankkonto gehört zu
welchem eigenen Konto? Umsätze merken sich über `bank_konto_id`, woher sie
stammen, und ziehen mit, wenn die Zuordnung erst nach einem Abruf fällt.
Abgerufene Umsätze buchen sich auf Wunsch selbst (`Services\Bankabgleich`).
Im Kontoblatt lassen sich Buchungen sammelweise löschen; Statusmeldungen liegen
jetzt über der Ansicht, statt den Inhalt springen zu lassen.
Dazu drei Fehler, die zusammen dafür sorgten, dass abgerufene Umsätze spurlos
verschwanden – der Abruf meldete sie als vorhanden, das Kontoblatt zeigte
nichts, und in der Vorschlagsliste standen sie ebenfalls nicht:
- Eine gelöschte Buchung ließ ihren Umsatz auf „uebernommen“ stehen. Der
Fremdschlüssel setzte nur `buchung_id` auf NULL. `Buchung::loeschen()` gibt
den Umsatz jetzt vorher frei, `Bankumsatz::verwaisteOeffnen()` fängt die Wege
ab, die daran vorbeiführen – Kaskaden lösen in MariaDB keine Trigger aus.
- Ein Bankkonto entstand doppelt, wenn die Bank die IBAN nicht bei jedem Dialog
mitliefert. Gesucht wird jetzt über die Kontonummer; eine nachgelieferte IBAN
wird am vorhandenen Eintrag nachgetragen.
- Der Fingerabdruck hing an der IBAN und kippte mit ihr. Er nimmt jetzt die
`bank_konto_id`, die fest steht, solange es den Bankzugang gibt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
Konten, Kontengruppen, Kategorien und Klassen samt Übernahme aus dem
QIF-Export des Lexware FinanzManagers.
Kontenübersicht nach Kontengruppen gebündelt, mit Gruppensummen und
Gesamtsumme; die drei Saldospalten (Online-Saldo, aktueller und erwarteter
Saldo) sind angelegt und werden bis Phase 2 aus dem Anfangssaldo gespeist.
Kategorien sind hierarchisch mit ":" als Trenner. Der vollständige Pfad
steht redundant in der Tabelle, weil jede Anzeige und der gesamte Import
darüber laufen; Umbenennen und Verschieben schreiben den Teilbaum neu. Die
Art (Einnahme/Ausgabe) gilt für den ganzen Ast. Register wie im Original:
Alle, Einnahmen, Ausgaben, Umbuchungskonten.
QifParser liest zustandsbehaftet und sequenziell, wandelt ISO-8859-1 nach
UTF-8 und versteht US-Beträge sowie das Datumsformat aus der Kopfzeile.
QifStammdatenImport ist idempotent und bietet Trockenlauf und Protokoll -
im Dialog unter Verwaltung sowie über scripts/qif-import.php. Am echten
Export geprüft: 17 Klassen, 105 Kategorien, 37 Konten.
Enthält außerdem die Korrektur der englischen Monatsnamen im
Einstellungsdialog: date('F') ist sprachlich nicht umschaltbar, deshalb
liegen die Namen jetzt zentral als View::MONATE vor. Die Änderung ließ
sich nicht als eigener Commit trennen, weil sie dieselben Dateien berührt
wie Phase 1.
Tests: 227 PHP-Prüfungen und 14 Playwright-Tests, alle grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>