feat: Phase 4 – CSV-Import (Templates, Prüfansicht, Duplikat/Transfer-Erkennung, Undo)

Backend:
- Modelle + Migration 0005: import_templates, import_batches, categorization_rules;
  transactions um import_batch_id + import_hash erweitert.
- services/csv_import: Datei parsen (Trennzeichen, Dezimal-/Datumsformat, Kodierung,
  Header/Skip, Vorzeichen vs. Soll/Haben), Vorschau mit Duplikat-Erkennung (Hash),
  interner-Transfer-Erkennung via IBAN, lernender Auto-Kategorisierung; Buchen mit
  Batch und Undo.
- routers/imports: Templates (CRUD), Roh-Vorschau, Prüf-Vorschau, Buchen, Verlauf,
  Rückgängig. pytest: Parsing, Duplikate, Transfer, Buchen, Undo, Lernen.

Frontend:
- Import-Seite: Konto+Datei, Format/Spaltenzuordnung (mit Roh-Vorschau),
  editierbare Prüfansicht (Kategorie/Typ/Zielkonto, Duplikate markiert),
  Buchen, Import-Verlauf mit Undo; Vorlagen speichern; i18n DE/EN.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Guido
2026-08-19 20:06:50 +02:00
co-authored by Claude Opus 4.8
parent a31ba0c785
commit 1381967aae
14 changed files with 1366 additions and 2 deletions
+47
View File
@@ -195,5 +195,52 @@
"incomeLabel": "Bezeichnung",
"incomeCategory": "Kategorie",
"targetAccount": "Zielkonto"
},
"import": {
"title": "CSV-Import",
"step1": "1 · Konto & Datei",
"step2": "2 · Format",
"step3": "3 · Spalten zuordnen",
"step4": "4 · Prüfen & buchen",
"account": "Zielkonto",
"file": "CSV-Datei",
"template": "Vorlage",
"templateManual": "Manuell einstellen",
"delimiter": "Trennzeichen",
"decimal": "Dezimaltrenner",
"dateFormat": "Datumsformat",
"encoding": "Kodierung",
"amountMode": "Betragsspalten",
"skipRows": "Zeilen überspringen",
"hasHeader": "Erste Zeile ist Kopfzeile",
"modeSigned": "Ein Betrag (mit Vorzeichen)",
"modeDebitCredit": "Getrennte Soll-/Haben-Spalten",
"modeAbsExpense": "Ein Betrag (immer Ausgabe)",
"readFile": "Datei einlesen",
"makePreview": "Vorschau erstellen",
"saveTemplate": "Als Vorlage speichern",
"templateName": "Vorlagenname",
"colDate": "Datum",
"colAmount": "Betrag",
"colDebit": "Soll (Ausgang)",
"colCredit": "Haben (Eingang)",
"colPayee": "Empfänger",
"colPurpose": "Verwendungszweck",
"colIban": "Gegen-IBAN",
"makePreviewHint": "Ordne mindestens Datum und Betrag zu.",
"commit": "{{n}} Buchungen übernehmen",
"imported": "{{n}} Buchungen importiert.",
"importedCount": "{{n}} gebucht",
"typeCol": "Typ",
"payeeCol": "Empfänger / Zweck",
"badDate": "Datum?",
"duplicate": "Duplikat",
"chooseAccount": "Konto wählen",
"history": "Import-Verlauf",
"undo": "Rückgängig",
"undoConfirm": "Alle Buchungen aus {{file}} wieder entfernen?",
"undone": "rückgängig gemacht",
"needFile": "Bitte zuerst eine CSV-Datei wählen.",
"needFileAccount": "Bitte Konto und Datei wählen."
}
}
+47
View File
@@ -195,5 +195,52 @@
"incomeLabel": "Label",
"incomeCategory": "Category",
"targetAccount": "Target account"
},
"import": {
"title": "CSV import",
"step1": "1 · Account & file",
"step2": "2 · Format",
"step3": "3 · Map columns",
"step4": "4 · Review & import",
"account": "Target account",
"file": "CSV file",
"template": "Template",
"templateManual": "Configure manually",
"delimiter": "Delimiter",
"decimal": "Decimal separator",
"dateFormat": "Date format",
"encoding": "Encoding",
"amountMode": "Amount columns",
"skipRows": "Skip rows",
"hasHeader": "First row is a header",
"modeSigned": "Single amount (signed)",
"modeDebitCredit": "Separate debit/credit columns",
"modeAbsExpense": "Single amount (always expense)",
"readFile": "Read file",
"makePreview": "Build preview",
"saveTemplate": "Save as template",
"templateName": "Template name",
"colDate": "Date",
"colAmount": "Amount",
"colDebit": "Debit (out)",
"colCredit": "Credit (in)",
"colPayee": "Payee",
"colPurpose": "Purpose",
"colIban": "Counterparty IBAN",
"makePreviewHint": "Map at least date and amount.",
"commit": "Import {{n}} transactions",
"imported": "Imported {{n}} transactions.",
"importedCount": "{{n}} imported",
"typeCol": "Type",
"payeeCol": "Payee / purpose",
"badDate": "Date?",
"duplicate": "Duplicate",
"chooseAccount": "Choose account",
"history": "Import history",
"undo": "Undo",
"undoConfirm": "Remove all transactions from {{file}}?",
"undone": "undone",
"needFile": "Please choose a CSV file first.",
"needFileAccount": "Please choose an account and a file."
}
}