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>
102 lines
4.4 KiB
Markdown
102 lines
4.4 KiB
Markdown
# QIF-Import
|
||
|
||
Der Lexware FinanzManager exportiert erweitertes Quicken-QIF. Die `.QDF`-Datei ist
|
||
verschlüsselt und damit keine Migrationsquelle – der QIF-Export ist der einzige Weg.
|
||
|
||
Stand: Klassen, Kategorien und Konten werden übernommen (Phase 1). Buchungen, Splits,
|
||
Umbuchungen und Wertpapierbuchungen folgen in Phase 2 und 6.
|
||
|
||
## Aufbau der Datei
|
||
|
||
```
|
||
!Option:MDY Datumsformat für die gesamte Datei
|
||
!Type:Class Klassen
|
||
!Type:Cat Kategorien
|
||
!Option:AutoSwitch Beginn der Kontenliste
|
||
!Account ein Konto je Eintrag
|
||
!Clear:AutoSwitch Ende der Kontenliste
|
||
!Account / !Type:… ab hier abwechselnd Konto und dessen Buchungen
|
||
```
|
||
|
||
Ein Eintrag endet mit `^`. Jede Zeile beginnt mit einem Feldbuchstaben, der Rest ist der
|
||
Wert. Felder dürfen mehrfach auftreten (Splitzeilen, Adresszeilen), deshalb hält
|
||
`QifParser` jeden Eintrag als Liste von Paaren und bietet `feld()`, `felder()` und
|
||
`hatFeld()`.
|
||
|
||
**Die Datei ist zustandsbehaftet.** Der Kontobezug einer Buchung steckt allein darin,
|
||
welcher `!Account`-Abschnitt zuletzt kam – nach Sektionstypen gruppiert gelesen wäre er
|
||
verloren. Der Parser liefert daher eine flache Liste in Dateireihenfolge, jeder Eintrag mit
|
||
Sektionstyp und aktuellem Konto.
|
||
|
||
Jeder Kontoeintrag setzt zugleich das aktuelle Konto. In der Kontenliste folgen mehrere
|
||
aufeinander, ohne dass Buchungen dazwischenstehen; das schadet nicht und deckt zugleich die
|
||
zweite Schreibweise ab, bei der ein einzelner `!Account` den Kontowechsel bedeutet.
|
||
|
||
## Felder der Stammdaten
|
||
|
||
| Sektion | Feld | Bedeutung |
|
||
|---|---|---|
|
||
| `!Type:Class` | `N` / `D` | Name, Beschreibung |
|
||
| `!Type:Cat` | `N` | vollständiger Pfad mit `:` |
|
||
| | `D` | Beschreibung |
|
||
| | `I` / `E` | Einnahme bzw. Ausgabe (Marker ohne Wert) |
|
||
| | `T` | steuerrelevant (Marker ohne Wert) |
|
||
| | `R` | Kennziffer des Steuerformulars |
|
||
| `!Account` | `N` / `T` | Name, Kontotyp (siehe `docs/stammdaten.md`) |
|
||
| | `D` | Beschreibung; `Kontonr. 12345` wird als Kontonummer übernommen |
|
||
| | `L` | Kreditlimit im US-Format |
|
||
|
||
## Fallstricke
|
||
|
||
1. **Zeichensatz ISO-8859-1, Zeilenenden CRLF.** `QifParser::nachUtf8()` prüft erst, ob
|
||
schon UTF-8 vorliegt – eine zweite Konvertierung zerstörte die Umlaute.
|
||
2. **Beträge im US-Format**: `-1,241.04`. Das Komma ist Tausendertrenner.
|
||
3. **Datum laut Kopfzeile**, meist `MDY` mit zweistelligem Jahr: `D3.18.26` ist der
|
||
18.03.2026. Jahreszahlen ab 70 gelten als 19xx.
|
||
4. **Kategorie und Klasse in einer Zeile**: `L400 - Leben:B-Essen alleine/Privat`.
|
||
5. **Unterkategorien ohne genannte Elternkategorie.** Der Import legt fehlende
|
||
Zwischenstufen selbst an (`Kategorie::findenOderAnlegenNachPfad()`).
|
||
6. **Konten stehen zweimal in der Datei** – einmal in der Kontenliste, einmal als Kopf
|
||
ihrer Buchungen. Der zweite Treffer ist keine Dublette.
|
||
7. **Umbuchungen erscheinen doppelt**, einmal je beteiligtem Konto, und müssen in Phase 2
|
||
zu einer Buchung zusammengeführt werden.
|
||
8. **Anfangssalden fehlen im Export** und werden je Konto nachgetragen.
|
||
|
||
## Arbeitsweise des Importeurs
|
||
|
||
`QifStammdatenImport` ist **idempotent**: Was es schon gibt, wird gezählt und übersprungen,
|
||
nie doppelt angelegt. Ein zweiter Lauf derselben Datei ändert nichts.
|
||
|
||
Der echte Lauf liegt in einer Transaktion – ein Abbruch mitten in der Kategorieliste
|
||
hinterließe sonst einen halben Baum. Der **Trockenlauf** schreibt gar nicht, sondern zählt
|
||
mit einer Menge bereits bekannter Pfade mit; auch die Zwischenstufen, die der Import selbst
|
||
anlegen würde, erscheinen dort in der Vorschau.
|
||
|
||
## Bedienung
|
||
|
||
Im Dialog unter *Verwaltung → QIF-Import*: Datei hochladen, Trockenlauf, dann übernehmen.
|
||
Hochgeladene Dateien bleiben im Importverzeichnis (`data/import`), damit derselbe Export
|
||
erst geprüft und dann übernommen werden kann.
|
||
|
||
Auf der Kommandozeile:
|
||
|
||
```bash
|
||
docker compose exec -u www-data php php scripts/qif-import.php data/import/Export.QIF
|
||
docker compose exec -u www-data php php scripts/qif-import.php --uebernehmen data/import/Export.QIF
|
||
```
|
||
|
||
Ohne `--uebernehmen` läuft nur der Trockenlauf. `--benutzer=NAME` wählt den Mandanten,
|
||
sonst gilt der erste aktive Benutzer.
|
||
|
||
## Prüfung gegen den echten Export
|
||
|
||
Der Trockenlauf gegen `Export-Migration-Beispiel.QIF` liefert die Zahlen der Voranalyse:
|
||
|
||
```
|
||
Datei enthält Class: 17 · Cat: 105 · Account: 73 · Bank: 572 · Cash: 61 ·
|
||
Oth T: 31 · Oth A: 154 · Invst: 16 · Memorized: 579
|
||
|
||
Klassen 17 neu
|
||
Kategorien 105 neu
|
||
Konten 37 neu, 36 vorhanden (die Zweitnennung je Konto)
|
||
```
|