Ein nicht angehaktes Ankreuzfeld steht nicht im POST. KontenController:: formulardaten() reichte "in_summe" gar nicht durch, also griff im Model der Standardwert "zählt zur Summe" – die Anwendung meldete "Konto gespeichert", geändert hatte sich nichts. formulardaten() nimmt das POST-Array jetzt als Parameter und ist damit ohne HTTP prüfbar; die Ankreuzfelder werden ausdrücklich auf true/false abgebildet. Der Standard bleibt für Aufrufe ohne den Schlüssel bestehen – der QIF-Import gibt das Feld nicht an. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
154 lines
8.6 KiB
Markdown
154 lines
8.6 KiB
Markdown
# Änderungen
|
||
|
||
## Korrektur – Σ-Kennzeichen ließ sich nicht abschalten (10.08.2026)
|
||
|
||
Das Kennzeichen *Zählt zur Summe der Kontostände* blieb beim Speichern eines Kontos
|
||
unverändert stehen, obwohl die Anwendung „Konto gespeichert“ meldete.
|
||
|
||
- Ursache: `KontenController::formulardaten()` reichte `in_summe` gar nicht durch. Ein
|
||
nicht angehaktes Ankreuzfeld steht nicht im POST, also griff im Model der Standardwert
|
||
„zählt mit“ – gespeichert wurde ein Ja, das niemand angegeben hatte.
|
||
- `formulardaten()` nimmt das POST-Array jetzt als Parameter und ist damit ohne HTTP
|
||
prüfbar; die Ankreuzfelder werden ausdrücklich auf `true`/`false` abgebildet.
|
||
- Der Standard „zählt zur Summe“ bleibt für Aufrufe ohne den Schlüssel bestehen – der
|
||
QIF-Import gibt das Feld nicht an und soll es auch nicht.
|
||
- `07_KontenTest` prüft die Formularabbildung und den Weg durch das Model; E2E
|
||
`stammdaten.spec.js` hakt das Kennzeichen in der Oberfläche ab, setzt es wieder und
|
||
sieht in beiden Fällen nach, statt der Erfolgsmeldung zu glauben.
|
||
|
||
## Phase 2 – Buchungen, Kontoblatt und Buchungsimport (10.08.2026)
|
||
|
||
**Erkenntnis aus dem Vollexport**
|
||
|
||
Der Plan ging davon aus, Umbuchungen stünden zweimal in der Datei und müssten
|
||
zusammengeführt werden. Das Gegenteil ist der Fall: Eine Umbuchung steht **einmal**, in
|
||
dem Konto, in dem sie erfasst wurde; die Gegenseite ist nur durch `L[Zielkonto]` benannt
|
||
und muss beim Import erzeugt werden. Von 965 Umbuchungen im Export hat keine ein zweites
|
||
Vorkommen. Mit erzeugter Gegenseite stimmen acht gegen den FinanzManager geprüfte
|
||
Kontosalden auf den Cent.
|
||
|
||
**Datenmodell**
|
||
- Migration `003_buchungen.sql`: `buchungen`, `buchung_splits`, `buchungsadressen`
|
||
- Eine Umbuchung ist ein Datensatz mit `gegenkonto_id`, kein gespiegeltes Paar – das
|
||
Kontoblatt des Gegenkontos zeigt sie mit umgekehrtem Vorzeichen
|
||
- Auch einzelne Splitzeilen dürfen ein Gegenkonto tragen
|
||
- Konten führen `in_summe` (die Σ-Spalte des FinanzManagers) sowie `saldo_online`
|
||
|
||
**Kontoblatt und Buchungsmaske**
|
||
- Kontoblatt mit laufendem Saldo, Filter auf Zeitraum, Kategorie, Klasse und Abgleich,
|
||
Volltextsuche und Seitenblättern
|
||
- Buchungsmaske für Einnahme, Ausgabe und Umbuchung in beide Richtungen; Splitzeilen mit
|
||
Restbetragsanzeige, geprüft auch serverseitig
|
||
- Aktueller und erwarteter Saldo; in die Summen zählen nur Konten mit Σ-Kennzeichen
|
||
|
||
**QIF-Buchungsimport**
|
||
- `QifBuchungsImport` mit Stichtag: alles davor wird je Konto zum Anfangssaldo
|
||
aufsummiert – einschließlich der erzeugten Gegenbuchungen –, alles danach importiert
|
||
- Buchungen mit Datum nach dem Importtag gelten als Vorausberechnung und bleiben draußen
|
||
- Eröffnungsbuchungen (`L[eigenes Konto]`) werden nicht zu Umbuchungen
|
||
- Wertpapiergeschäfte schlagen vorerst nur mit ihrem Geldfluss auf dem Verrechnungskonto
|
||
zu Buche; Bestände folgen in Phase 6
|
||
- Idempotent über einen Fingerabdruck je Buchung, der auch echte Doppelbuchungen am
|
||
selben Tag auseinanderhält
|
||
- Am Vollexport geprüft: 833 Buchungen ab 01.01.2026, 7946 in die Anfangssalden von 35
|
||
Konten verrechnet, eine vorausberechnete verworfen
|
||
|
||
**Behoben**
|
||
- Die `confirm()`-Rückfragen vor dem Löschen waren wirkungslos. `public/static/app.js`
|
||
brachte den Mechanismus (`data-bestaetigen`) von Anfang an mit, war aber nie im Layout
|
||
eingebunden; ersatzweise standen Inline-Handler (`onsubmit`) im HTML, und die verstoßen
|
||
gegen die eigene Content-Security-Policy (`script-src 'self'`) – der Browser verwarf
|
||
sie stillschweigend, gelöscht wurde ohne Rückfrage. Jetzt ist das Skript eingebunden,
|
||
die Inline-Handler sind raus, und ein E2E-Test besteht auf dem Dialog.
|
||
|
||
**Tests**
|
||
- `09_BuchungenTest` – Umbuchungen mit zwei Sichten, Splitzeilen samt Summenprüfung,
|
||
Splitzeile mit Gegenkonto, aktueller und erwarteter Saldo, Σ-Kennzeichen, Filter
|
||
- `10_QifBuchungsImportTest` – Stichtag, Anfangssalden aus der Vorgeschichte, erzeugte
|
||
Gegenbuchung, Eröffnungsbuchung, Zukunftsfilter, zweiter Lauf ohne Wirkung
|
||
- E2E `buchungen.spec.js` – Ausgabe, Umbuchung auf beiden Kontoblättern, Splitbuchung,
|
||
abgewiesene Splitsumme, Suche, Löschbestätigung
|
||
|
||
## Phase 1 – Stammdaten und QIF-Stammdatenimport (09.08.2026)
|
||
|
||
**Datenmodell**
|
||
- Migration `002_stammdaten.sql`: `kontengruppen`, `konten`, `kategorien`, `klassen`
|
||
- Alle Tabellen führen `benutzer_id`; `Mandant::id()` liefert die Kennung aus der Session
|
||
oder – im CLI – vom ersten aktiven Benutzer
|
||
|
||
**Konten**
|
||
- Kontenübersicht nach Kontengruppen gebündelt, mit Gruppensummen und Gesamtsumme
|
||
- Die drei Saldospalten des FinanzManagers (Online-Saldo, aktueller und erwarteter Saldo)
|
||
sind angelegt und werden bis Phase 2 aus dem Anfangssaldo gespeist
|
||
- Kontoarten des FinanzManagers samt Zuordnung zu den QIF-Typen
|
||
- Kontenpflege mit Anfangssaldo, Kreditlimit, IBAN/BIC, Kontengruppe, aktiv/inaktiv
|
||
- Kontengruppen anlegen, umbenennen, sortieren, löschen – die Konten bleiben erhalten
|
||
|
||
**Kategorien und Klassen**
|
||
- Hierarchische Kategorien mit `:` als Trenner; der vollständige Pfad wird mitgeführt und
|
||
beim Umbenennen oder Verschieben für den ganzen Teilbaum neu geschrieben
|
||
- Art (Einnahme/Ausgabe) gilt für den ganzen Ast und vererbt sich an Unterkategorien
|
||
- Verschieben, Zusammenführen und Löschen; Verschieben in den eigenen Teilbaum wird
|
||
abgewiesen
|
||
- Register *Alle / Einnahmen / Ausgaben / Umbuchungskonten* wie im Original
|
||
- Klassen als flache zweite Auswertungsdimension, in der Liste direkt bearbeitbar
|
||
|
||
**QIF-Import**
|
||
- `QifParser`: zustandsbehaftetes, sequenzielles Lesen; ISO-8859-1 nach UTF-8, US-Beträge,
|
||
Datumsformat aus der Kopfzeile, Mehrfachfelder für spätere Splitzeilen
|
||
- `QifStammdatenImport` für Klassen, Kategorien und Konten – idempotent, mit Trockenlauf
|
||
und Protokoll; fehlende Zwischenstufen im Kategoriepfad entstehen selbsttätig
|
||
- Dialog unter *Verwaltung → QIF-Import* mit Upload, Trockenlauf und Übernahme
|
||
- `scripts/qif-import.php` für dieselbe Aufgabe auf der Kommandozeile
|
||
- Geprüft am echten Export: 17 Klassen, 105 Kategorien, 37 Konten
|
||
|
||
**Tests**
|
||
- `06_KategorienTest` – Hierarchie, Pfadpflege, Artvererbung, Verschieben, Zusammenführen
|
||
- `07_KontenTest` – Kontoarten, Gruppierung und Summen, Betragseingabe
|
||
- `08_QifImportTest` – Parser, Zeichensatz, Beträge und Datum, Import, Trockenlauf,
|
||
Prüfung der Dateinamen
|
||
- E2E `stammdaten.spec.js` – Konto, Kategorie mit Unterkategorie, Register, Klasse,
|
||
QIF-Upload mit Trockenlauf
|
||
|
||
## Korrektur – Monatsnamen auf Deutsch (09.08.2026)
|
||
|
||
- Der Einstellungsdialog zeigte unter *Buchhaltung* englische Monatsnamen, weil
|
||
`date('F')` sprachlich nicht umschaltbar ist.
|
||
- Monatsnamen liegen jetzt zentral als `View::MONATE` und `View::MONATE_KURZ` vor,
|
||
abrufbar über `View::monat()`. Budgetplaner und Auswertungen greifen später darauf zu.
|
||
- `05_DarstellungTest` prüft Monatsnamen, Betrags- und Datumsformat gegen eine feste
|
||
Sollliste – der Vergleich gegen `date('F')` allein würde April, August, September und
|
||
November nicht auffallen lassen.
|
||
|
||
## Phase 0 – Projektgerüst (09.08.2026)
|
||
|
||
Grundgerüst der Anwendung. Fachliche Module folgen ab Phase 1.
|
||
|
||
**Betrieb**
|
||
- Docker Compose mit drei Services: `nginx` (Port 8000), `php` (php-fpm 8.3), `db`
|
||
(MariaDB 11)
|
||
- `docker-entrypoint.sh` legt Datenverzeichnisse an und spielt Migrationen ein
|
||
- `scripts/migrate.php` – nummerierte SQL-Migrationen, idempotent, mit Journal-Tabelle
|
||
- `scripts/update.sh` – Update für den Produktionsserver: Backup, `git pull`,
|
||
Image-Neubau bei Bedarf, Migrationen, Rechte, Tests
|
||
- `scripts/backup.sh` – Datenbank- und Dateisicherung mit Rotation (7 Tage / 4 Wochen /
|
||
12 Monate), gegen Parallelläufe per `flock` abgesichert
|
||
|
||
**Anwendung**
|
||
- `Config`, `Database` (PDO-Wrapper, verschachtelbare Transaktionen), `Router`
|
||
(Platzhalter-Routen, CSRF-Prüfung für alle verändernden Requests), `View`, `Auth`
|
||
- Anmeldung mit Session-Härtung, Ersteinrichtung des ersten Benutzers
|
||
- Zentraler Einstellungsdialog mit Reitern (Allgemein, Darstellung, Buchhaltung,
|
||
Online-Banking, Import/Export, Wertpapiere, Diagnose); Werte in Tabelle
|
||
`einstellungen`
|
||
- Debug-Log, ein- und ausschaltbar, mit Maskierung von PINs, Passwörtern, TANs und
|
||
API-Keys; Ausnahmen werden immer protokolliert
|
||
- Layout nach Vorbild des FinanzManagers: feste Navigation links, Werkzeugleiste oben,
|
||
Tab-Leiste; Farbschema hell/dunkel/System
|
||
|
||
**Tests**
|
||
- Test-Harness mit Transaktions-Rollback und Aufräumen temporärer Pfade
|
||
- `01_AuthTest` – Anmeldung, Passwort-Hashing, CSRF, Cookie-Attribute
|
||
- `02_EinstellungenTest` – Lesen/Schreiben, Cache-Invalidierung, Bereichsabdeckung
|
||
- `03_RouterTest` – Pfad-Muster, Platzhalter, keine Treffer über Pfadgrenzen
|
||
- `04_DebugLogTest` – Schalter, Maskierung, Fehlerprotokollierung
|