From 1dbc848cd1b24aad8167f4d81fd2811dacf444fe Mon Sep 17 00:00:00 2001
From: fds2610-bot
Date: Mon, 10 Aug 2026 16:40:31 +0200
Subject: [PATCH] Phase 2: Buchungen, Kontoblatt und QIF-Buchungsimport
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Der Plan ging davon aus, Umbuchungen stünden zweimal im Export und müssten
zusammengeführt werden. Der Vollexport zeigt das Gegenteil: 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 hat keine ein zweites Vorkommen. Mit erzeugter Gegenseite stimmen
acht gegen den FinanzManager geprüfte Kontosalden auf den Cent.
Datenmodell: Migration 003 mit buchungen, buchung_splits und buchungsadressen.
Eine Umbuchung ist ein Datensatz mit gegenkonto_id, kein gespiegeltes Paar -
zwei Zeilen laufen früher oder später auseinander. Das Kontoblatt des
Gegenkontos zeigt sie mit umgekehrtem Vorzeichen. Auch einzelne Splitzeilen
dürfen ein Gegenkonto tragen. Konten führen zusätzlich in_summe, die
Sigma-Spalte der Kontenübersicht, und saldo_online für Phase 5.
Oberfläche: 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, mit Splitzeilen und
Restbetragsanzeige.
Import: QifBuchungsImport arbeitet mit Stichtag. Alles davor wird je Konto zum
Anfangssaldo aufsummiert, Gegenbuchungen eingerechnet; alles danach bis zum
Importtag kommt einzeln in die Datenbank. Spätere Buchungen sind
Vorausberechnungen des FinanzManagers und bleiben draußen. Wertpapiergeschäfte
schlagen vorerst nur mit ihrem Geldfluss auf dem Verrechnungskonto zu Buche.
Am Vollexport geprüft: 833 Buchungen ab 01.01.2026, 7946 in die Anfangssalden
von 35 Konten verrechnet.
Behoben: Die confirm()-Rückfragen vor dem Löschen waren wirkungslos.
public/static/app.js brachte den Mechanismus mit, war aber nie im Layout
eingebunden; die ersatzweise gesetzten onsubmit-Attribute verstoßen gegen die
eigene Content-Security-Policy und wurden vom Browser verworfen - gelöscht
wurde ohne Rückfrage. Ein E2E-Test besteht jetzt auf dem Dialog.
Tests: 307 PHP-Prüfungen und 21 Playwright-Tests, alle grün.
Co-Authored-By: Claude Opus 5
---
Changes.md | 53 ++
PLAN.md | 70 ++-
README.md | 15 +-
docs/buchungen.md | 69 +++
docs/qif-import.md | 73 ++-
migrations/003_buchungen.sql | 100 ++++
public/index.php | 9 +
public/static/app.css | 69 +++
public/static/app.js | 19 +-
public/static/buchungsmaske.js | 107 ++++
scripts/qif-import.php | 79 ++-
src/Controllers/BuchungenController.php | 237 +++++++++
src/Controllers/EinstellungenController.php | 2 +-
src/Controllers/ImportController.php | 30 +-
src/Models/Buchung.php | 408 ++++++++++++++++
src/Models/Konto.php | 83 +++-
src/Services/QifBuchungsImport.php | 511 ++++++++++++++++++++
src/Views/buchungen/formular.php | 198 ++++++++
src/Views/buchungen/kontoblatt.php | 175 +++++++
src/Views/cockpit/index.php | 3 +-
src/Views/einstellungen/index.php | 12 +-
src/Views/konten/formular.php | 13 +-
src/Views/konten/uebersicht.php | 11 +-
src/Views/layout/kopf.php | 1 +
src/Views/verwaltung/import.php | 74 ++-
src/Views/verwaltung/kategorie-formular.php | 4 +-
src/Views/verwaltung/klassen.php | 2 +-
src/Views/verwaltung/kontengruppen.php | 2 +-
tests/09_BuchungenTest.php | 298 ++++++++++++
tests/10_QifBuchungsImportTest.php | 201 ++++++++
tests/e2e/specs/buchungen.spec.js | 189 ++++++++
tests/e2e/specs/stammdaten.spec.js | 6 +-
32 files changed, 3008 insertions(+), 115 deletions(-)
create mode 100644 docs/buchungen.md
create mode 100644 migrations/003_buchungen.sql
create mode 100644 public/static/buchungsmaske.js
create mode 100644 src/Controllers/BuchungenController.php
create mode 100644 src/Models/Buchung.php
create mode 100644 src/Services/QifBuchungsImport.php
create mode 100644 src/Views/buchungen/formular.php
create mode 100644 src/Views/buchungen/kontoblatt.php
create mode 100644 tests/09_BuchungenTest.php
create mode 100644 tests/10_QifBuchungsImportTest.php
create mode 100644 tests/e2e/specs/buchungen.spec.js
diff --git a/Changes.md b/Changes.md
index 2527bbe..3d1b156 100644
--- a/Changes.md
+++ b/Changes.md
@@ -1,5 +1,58 @@
# Änderungen
+## 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**
diff --git a/PLAN.md b/PLAN.md
index 3ec8749..1a0f724 100644
--- a/PLAN.md
+++ b/PLAN.md
@@ -29,8 +29,8 @@ Randbedingungen aus der Aufgabenstellung:
|---|---|
| `FELIX2018.QDF` ist **vollständig verschlüsselt** (Entropie ≈ 8 bit/Byte über alle 258 Blöcke, keine Klartext-Treffer für Kategorie- oder Kontonamen) | Aus der QDF ist nichts zu holen. Datenquelle ist der **QIF-Export**. |
| `FELIX2018.QSD` enthält im Klartext nur Bankleitzahlen, Spaltenlayouts und Berichtsnamen | Nur als Referenz für Berichtsdefinitionen brauchbar, keine Stammdaten. |
-| `Export-Migration-Beispiel.QIF` (342 KB, ISO-8859-1, CRLF) enthält alles Nötige: 17 Klassen, 105 Kategorien, 37 Konten, 572 Bank-, 154 Sonstige-, 16 Wertpapierbuchungen, 579 Buchungsvorlagen | **Der QIF-Import ist der Migrationsweg.** |
-| Der Beispielexport umfasst nur 02.01.–07.08.2026 und enthält **keine Eröffnungssalden** | Für die echte Migration braucht es einen Vollexport über alle Jahre; Anfangssalden werden je Konto aus der Kontenübersicht ergänzt. |
+| `Export-Migration-Beispiel.QIF` (1,8 MB, ISO-8859-1, CRLF) enthält alles Nötige: 17 Klassen, 105 Kategorien, 37 Konten, 8780 Buchungen von 2017 bis 2026, 172 Wertpapierbuchungen, 579 Buchungsvorlagen | **Der QIF-Import ist der Migrationsweg.** |
+| Der Vollexport reicht bis 2017 zurück; gebraucht wird nur der Zeitraum ab 2026 | **Stichtagsimport**: alles davor wird je Konto zum Anfangssaldo verrechnet (siehe Kapitel 4). Eröffnungssalden stehen als Buchung „Eröffnungssaldo“ mit `L[eigenes Konto]` in der Datei. |
| **Budgets sind im QIF nicht enthalten** | Budgetdaten müssen separat aus dem Budgetplaner exportiert (Export-Symbol oben rechts) oder einmalig neu erfasst werden. |
| `nemiah/php-fints` hängt nur an `psr/log` | Sehr schlank — als Fork gut beherrschbar. |
@@ -167,16 +167,43 @@ Das Lexware-QIF ist erweitertes Quicken-QIF. Fallstricke, die der Parser beherrs
Umbuchung: `L[DKB Girokonto alt]`, ebenfalls mit optionaler Klasse.
6. **Splitbuchungen** als Tripel `S` (Kategorie), `E` (Notiz), `$` (Betrag) — mehrfach je
Buchung.
-7. **Umbuchungen erscheinen doppelt** (einmal je beteiligtem Konto) und müssen zu *einer*
- Buchung zusammengeführt werden — sonst zählt jeder Übertrag zweimal.
+7. **Umbuchungen stehen nur einmal in der Datei** — in dem Konto, in dem sie erfasst
+ wurden. Die Gegenseite ist allein durch `L[Zielkonto]` benannt und **muss beim Import
+ erzeugt werden**; sonst fehlt sie auf dem Gegenkonto und dessen Saldo stimmt nicht.
+ (Am Vollexport verifiziert: von 965 Umbuchungen hat keine ein zweites Vorkommen; mit
+ erzeugter Gegenseite stimmen acht geprüfte Kontosalden auf den Cent mit dem
+ FinanzManager überein.) Auch **Splitzeilen** können ein Umbuchungsziel tragen
+ (`S[Konto]`) — dann entsteht die Gegenbuchung je Splitzeile.
+ Eine Buchung, die auf **ihr eigenes Konto** verweist (`L[eigenes Konto]`, Empfänger
+ „Eröffnungssaldo“), ist die Eröffnungsbuchung und bekommt keine Gegenseite.
8. **Wertpapierbuchungen** (`!Type:Invst`) mit `Y`/`~`/`@`/`&`/`I`/`Q`/`O`/`B`; `O` ist ein
- Array aus 12 `|`-getrennten Beträgen (Gebühren, Steuern, Zuschläge).
+ Array aus 12 `|`-getrennten Beträgen (Gebühren, Steuern, Zuschläge). Das
+ Verrechnungskonto steht in `L|[Konto]`, der dort gebuchte Betrag in `$`.
9. **Idempotenz:** Wiederholter Import derselben Datei darf keine Dubletten erzeugen
(Hash aus Konto + Datum + Betrag + Nummer + Buchungstext).
+10. **Das Feld `C` ist der Abgleichstatus** (`X` = abgeglichen), **kein** Kennzeichen für
+ vorausberechnete Buchungen: sämtliche Wertpapierbuchungen führen es nie. Wer geplante
+ Buchungen aussortieren will, filtert über das Datum.
Der Import läuft als CLI-Skript **und** über eine Weboberfläche mit Vorschau, Trockenlauf
und Protokoll (importiert / übersprungen / fehlerhaft je Zeile). Nach dem Import wird der User pro Konto gefragt, ob der jeweilige Eröffnungssaldo beibehalten oder geändert werden soll. Der User kann den Saldo jeweils eintragen oder übernehmen, wie er aktuell ist.
+### Stichtag statt Vollhistorie
+
+Übernommen wird nur der Zeitraum **ab dem 01.01.2026**. Alles davor fließt nicht als
+Buchung ein, sondern wird je Konto zum **Anfangssaldo** aufsummiert — inklusive der
+erzeugten Gegenbuchungen aus Umbuchungen. Die Salden stimmen dadurch exakt, ohne dass
+neun Jahrgänge mitgeschleppt werden.
+
+Ebenfalls übersprungen werden **vorausberechnete Buchungen**, also solche mit einem Datum
+nach dem Importtag: sie stammen nicht von der Bank, sondern aus der Vorausschau des
+FinanzManagers.
+
+Was damit entfällt: Auswertungen über die Jahre vor 2026. Was bleibt: sämtliche Salden,
+das komplette Jahr 2026 und die Budgetplanung für 2027. Für die **Depots** reicht ein
+Saldo nicht — dort werden Bestand und Einstandswert je Wertpapier zum Stichtag gebildet
+(Phase 6).
+
## 5. Phasen
### Phase 0 — Projektgerüst *(erledigt)*
@@ -207,7 +234,7 @@ und Protokoll (importiert / übersprungen / fehlerhaft je Zeile). Nach dem Impor
* *Ergebnis:* 17 Klassen, 105 Kategorien und 37 Konten sind aus dem Export übernommen und
in der Oberfläche gepflegt. Einzelheiten in `docs/stammdaten.md` und `docs/qif-import.md`.
-### Phase 2 — Buchungen
+### Phase 2 — Buchungen *(erledigt)*
* Migrationen `buchungen`, `buchung_splits`, `buchungsadressen`.
* **Kontoblatt** je Konto: Tabelle mit Datum, Nummer, Empfänger, Buchungstext, Kategorie,
Klasse, Betrag, Saldo, Abgleich-Status; Sortierung, Filter, Volltextsuche.
@@ -285,15 +312,17 @@ und Protokoll (importiert / übersprungen / fehlerhaft je Zeile). Nach dem Impor
## 6. Was du beisteuern musst
-1. **Vollständiger QIF-Export** aus dem laufenden FinanzManager über *alle* Jahre
- (der vorliegende Beispielexport deckt nur 2026 ab).
-2. **Anfangssalden je Konto** — werden nach dem Import im Dialog je Konto bestätigt oder
- korrigiert (siehe Kapitel 4); als Referenz genügt ein Blick in die Kontenübersicht des
- FinanzManagers.
-3. **Budgetdaten**: Export aus dem Budgetplaner (Symbol oben rechts in der Werkzeugleiste),
+1. ~~**Vollständiger QIF-Export** über alle Jahre~~ — liegt vor (8780 Buchungen, 2017–2026).
+2. ~~**Anfangssalden je Konto**~~ — entfällt: sie werden aus dem Zeitraum vor dem Stichtag
+ berechnet und stimmen gegen den FinanzManager auf den Cent. Nachträglich änderbar bleibt
+ jeder Wert im Kontoformular.
+3. **Σ-Kennzeichen je Konto prüfen**: Welche Konten in die Summe der Kontostände zählen,
+ steht nicht im Export. Nach dem Import einmal durch die Kontenübersicht gehen (Vorgabe:
+ alle zählen mit).
+4. **Budgetdaten**: Export aus dem Budgetplaner (Symbol oben rechts in der Werkzeugleiste),
sonst wird das Jahresbudget 2027 einmalig neu erfasst.
-4. Zugangsdaten der Bankverbindungen (erst in Phase 5, Eingabe direkt in der Anwendung).
-5. **API-Key für den Kursdienst** (Leeway.tech oder FMP, erst in Phase 6, Eingabe im
+5. Zugangsdaten der Bankverbindungen (erst in Phase 5, Eingabe direkt in der Anwendung).
+6. **API-Key für den Kursdienst** (Leeway.tech oder FMP, erst in Phase 6, Eingabe im
Einstellungsdialog).
## 7. Verifikation
@@ -305,10 +334,15 @@ Je Phase, nicht erst am Ende:
gegen Ausschnitte des Beispielexports als Fixture.
* **E2E-Tests** `tests/e2e/run.sh` — Login, Buchung anlegen mit Split, Kategorie zuordnen,
Budgetwert inline ändern, Monatsabschluss durchführen, Bericht aufrufen.
-* **Migrations-Abgleich als Härtetest:** Nach dem Vollimport müssen die Kontosalden und die
- Jahressummen Einnahmen/Ausgaben exakt den Werten aus dem FinanzManager entsprechen
- (Cockpit 2026: Einnahmen 148.060,18 € / Ausgaben 58.457,07 €; Summe Kontostände
- 503.430,75 €). Ein Testfall vergleicht die berechneten Summen gegen diese Sollwerte.
+* **Migrations-Abgleich als Härtetest:** Nach dem Import müssen die Kontosalden exakt den
+ Werten aus der Kontenübersicht des FinanzManagers entsprechen. Geprüft an acht Konten,
+ deren Werte aus den Screenshots vorliegen — sie stimmen auf den Cent (Stand Phase 2).
+
+ Die **Summe der Kontostände** (503.430,75 € laut Screenshot) lässt sich erst vollständig
+ vergleichen, wenn zwei Dinge stehen: die Σ-Kennzeichen je Konto (welche Konten zählen
+ überhaupt mit — im Export nicht enthalten) und die Depotbewertung aus Phase 6. Die
+ Jahressummen Einnahmen/Ausgaben (Cockpit 2026: 148.060,18 € / 58.457,07 €) hängen an
+ denselben Voraussetzungen und werden mit den Auswertungen in Phase 4 abgeglichen.
* **Manuell**: Anwendung unter `http://localhost:8000` aufrufen, Kontenübersicht,
Kontoblatt, Budgetplaner und Summenbericht mit den Screenshots aus `Altdaten/` vergleichen.
diff --git a/README.md b/README.md
index 4b2f048..014189b 100644
--- a/README.md
+++ b/README.md
@@ -10,10 +10,11 @@ Haushalt wird beides parallel genutzt.
## Stand
-Phase 0 (Grundgerüst) und Phase 1 (Stammdaten) sind gebaut: Anmeldung, zentraler
-Einstellungsdialog, Debug-Log, Migrationsmechanik, Test-Harness sowie Konten,
-Kontengruppen, Kategorien, Klassen und der QIF-Stammdatenimport. Buchungen folgen in
-Phase 2 nach `PLAN.md`.
+Phase 0 bis 2 sind gebaut: Anmeldung, zentraler Einstellungsdialog, Debug-Log,
+Migrationsmechanik und Test-Harness; Konten, Kontengruppen, Kategorien und Klassen;
+Kontoblatt, Buchungsmaske mit Splitbuchungen und Umbuchungen sowie der QIF-Import für
+Stammdaten und Buchungen. Als Nächstes folgt nach `PLAN.md` der Budgetplaner mit dem
+Monatsabschluss (Phase 3).
## Technik
@@ -64,8 +65,9 @@ verschlüsselt und nicht auswertbar. Der Importer liest Klassen, Kategorien, Kon
Buchungen samt Splits sowie Wertpapierbuchungen. Einzelheiten zum Format und den
Fallstricken stehen in `PLAN.md`, Kapitel 4.
-Klassen, Kategorien und Konten lassen sich bereits übernehmen – im Dialog unter
-*Verwaltung → QIF-Import* oder auf der Kommandozeile:
+Klassen, Kategorien, Konten und Buchungen lassen sich übernehmen – im Dialog unter
+*Verwaltung → QIF-Import* oder auf der Kommandozeile. Buchungen ab dem Stichtag kommen
+einzeln in die Datenbank, alles davor wird je Konto zum Anfangssaldo verrechnet:
```bash
docker compose exec -u www-data php php scripts/qif-import.php data/import/Export.QIF
@@ -80,4 +82,5 @@ Ohne `--uebernehmen` läuft nur der Trockenlauf.
- `CLAUDE.md` – Entwicklungsregeln
- `Changes.md` – Änderungsprotokoll
- `docs/stammdaten.md` – Konten, Kontengruppen, Kategorien, Klassen
+- `docs/buchungen.md` – Kontoblatt, Umbuchungen, Splitbuchungen, Salden
- `docs/qif-import.md` – Aufbau des QIF-Exports und Arbeitsweise des Importeurs
diff --git a/docs/buchungen.md b/docs/buchungen.md
new file mode 100644
index 0000000..3dd4d21
--- /dev/null
+++ b/docs/buchungen.md
@@ -0,0 +1,69 @@
+# Buchungen
+
+Kontoblatt, Buchungsmaske und die Saldenrechnung.
+
+## Umbuchungen: ein Datensatz, zwei Sichten
+
+Eine Umbuchung wird **einmal** gespeichert – als Buchung auf dem Ausgangskonto mit
+`gegenkonto_id`. Das Kontoblatt des Gegenkontos zeigt sie mit umgekehrtem Vorzeichen.
+
+Der Grund ist nicht nur Sparsamkeit: Zwei gespiegelte Datensätze laufen früher oder später
+auseinander (einer wird geändert, der andere nicht). Und der QIF-Export macht es genauso –
+dort steht jede Umbuchung genau einmal, die Gegenseite nur als `L[Zielkonto]`.
+
+`Buchung::kontoblatt()` vereinigt deshalb drei Mengen:
+
+1. Buchungen mit `konto_id = X` (eigene Sicht)
+2. Buchungen mit `gegenkonto_id = X` ohne Splitzeilen, Betrag negiert
+3. Splitzeilen mit `gegenkonto_id = X`, Betrag negiert
+
+Zeilen aus 2 und 3 tragen `gegensicht = true`. Sie sind nicht bearbeitbar – das geht auf
+dem Ursprungskonto –, damit eine Umbuchung nicht aus zwei Richtungen widersprüchlich
+geändert wird.
+
+Dieselbe Dreiteilung gilt für die Salden (`Buchung::saldenJeKonto()`), die alle Konten mit
+sechs Abfragen auf einmal berechnet statt je Konto einzeln.
+
+## Splitbuchungen
+
+Eine Buchung ist entweder einfach zugeordnet **oder** gesplittet. Sobald Splitzeilen
+vorliegen, räumt das Model `kategorie_id` und `gegenkonto_id` der Buchung; die Zuordnung
+steckt dann ausschließlich in den Zeilen.
+
+Die Summe der Zeilen muss dem Buchungsbetrag entsprechen – geprüft im Model (Toleranz ein
+halber Cent, für Rundungen aus der Betragsumrechnung) und in der Maske als
+Restbetragsanzeige. Eine Splitzeile darf ein Gegenkonto tragen; dann erscheint auf jenem
+Konto nur der Betrag dieser Zeile.
+
+## Salden
+
+| Spalte | Bedeutung |
+|---|---|
+| Online-Saldo | Stand des letzten Bankabrufs (`konten.saldo_online`, ab Phase 5) |
+| Aktueller Saldo | Anfangssaldo plus alle Buchungen bis heute |
+| Erwarteter Saldo | zusätzlich die künftig datierten Buchungen |
+
+In die **Summe der Kontostände** zählen nur Konten mit `in_summe = 1` – das entspricht der
+Σ-Spalte im FinanzManager. Durchlaufende Auslagen und Rentenversicherungen bleiben so
+außen vor, erscheinen aber weiter in der Liste. Der QIF-Export kennt das Kennzeichen
+nicht; es wird im Kontoformular gepflegt.
+
+## Beträge in der Oberfläche
+
+Eingegeben wird immer ein **positiver** Betrag; die Richtung bestimmt die Auswahl
+*Ausgabe / Einnahme / Umbuchung*. `KontenController::zahl()` liest das deutsche Format und
+entscheidet bei einem Punkt ohne Komma nach der Stellenzahl: drei Ziffern dahinter heißt
+Tausendertrenner (`1.500`), sonst Dezimaltrenner (`1234.56`).
+
+## Bestätigungen und die Content-Security-Policy
+
+Die CSP erlaubt keine Inline-Skripte (`script-src 'self'`). Rückfragen vor dem Löschen
+dürfen deshalb **nicht** als `onsubmit="return confirm(…)"` im HTML stehen – der Browser
+verwirft sie stillschweigend, und gelöscht wird ohne Nachfrage. Stattdessen:
+
+```html
+
+
+
+
+ Buchungen ab diesem Tag werden übernommen. Alles davor fließt je Konto in den
+ Anfangssaldo – die Salden stimmen also, ohne dass die ganze Historie mitkommt.
+ Buchungen mit einem Datum nach dem Importtag sind Vorausberechnungen des
+ FinanzManagers und bleiben draußen.
+
@@ -125,7 +135,7 @@ include __DIR__ . '/../layout/kopf.php';
+ data-bestaetigen="Alle Logdateien löschen?">
diff --git a/src/Views/konten/formular.php b/src/Views/konten/formular.php
index d73df2a..629330c 100644
--- a/src/Views/konten/formular.php
+++ b/src/Views/konten/formular.php
@@ -83,6 +83,17 @@ include __DIR__ . '/../layout/kopf.php';
Konto ist aktiv
+
+
+ Entspricht der Σ-Spalte im FinanzManager. Konten, die kein eigenes Vermögen
+ darstellen – durchlaufende Auslagen etwa –, bleiben so aus der Gesamtsumme heraus,
+ erscheinen aber weiter in der Übersicht.
+
+
Abbrechen
@@ -91,7 +102,7 @@ include __DIR__ . '/../layout/kopf.php';
- Online-Saldo und die Trennung zwischen aktuellem und erwartetem Saldo füllen sich,
- sobald Buchungen (Phase 2) und der Bankabruf (Phase 5) da sind. Bis dahin zeigen die
- Spalten den Anfangssaldo.
+ In die Summen zählen nur Konten mit Σ-Kennzeichen – wie im FinanzManager. Der
+ Online-Saldo kommt mit dem Bankabruf in Phase 5, Depotwerte mit Phase 6.
+ Ein Klick auf den Kontonamen öffnet das Kontoblatt.
+ vor dem Stichtag – in den Anfangssaldo von
+ = (int)$buchungen['anfangssalden']['konten'] ?> Konten verrechnet
+
+
= (int)$buchungen['buchungen']['vor_stichtag'] ?>
+
+
+
nach dem Enddatum – vorausberechnet, verworfen
+
= (int)$buchungen['buchungen']['zukunft'] ?>
+
+
+
darunter Wertpapiergeschäfte (nur Geldfluss)
+
= (int)$buchungen['buchungen']['wertpapier'] ?>
+
+
+
Fehler
+
+ = (int)$buchungen['buchungen']['fehler'] ?>
+
+
+
+
+
+ Zeitraum = View::datum($buchungen['stichtag']) ?> bis = View::datum($buchungen['bis']) ?>.
+ Alles davor ist nicht verloren: es steckt im Anfangssaldo der Konten.
+
- Buchungen und Buchungsvorlagen werden in Phase 2 übernommen – dieser Lauf
- betrifft ausschließlich Klassen, Kategorien und Konten.
+ Buchungsvorlagen (Memorized) folgen in Phase 7, Wertpapierbestände
+ in Phase 6.
@@ -88,18 +132,21 @@ include __DIR__ . '/../layout/kopf.php';
+
+
- Die Anfangssalden stehen nicht im Export. Sie werden je Konto in der
- Kontenübersicht nachgetragen.
+ Die Anfangssalden wurden aus dem Zeitraum vor dem Stichtag berechnet. In der
+ Kontenübersicht lässt sich jeder Wert nachträglich ändern – ebenso das
+ Kennzeichen, ob ein Konto zur Summe der Kontostände zählt.
@@ -124,6 +171,13 @@ include __DIR__ . '/../layout/kopf.php';
Vorhandene Dateien
+
+ Übernommen werden Buchungen ab = View::datum($stichtag) ?> bis
+ = View::datum($bis) ?>. Alles davor fließt in den Anfangssaldo der
+ Konten, alles danach gilt als Vorausberechnung des FinanzManagers und bleibt draußen.
+ Der Stichtag steht in den Einstellungen.
+
+
Noch keine Datei in = View::h($verzeichnis) ?>.
@@ -144,18 +198,22 @@ include __DIR__ . '/../layout/kopf.php';
+
+