feat: Transfer-Schlagwort mit festem Zielkonto (z. B. REVOLUT -> Konto Revolut)

- Transfer-Regel kann direkt ein Zielkonto tragen (target_account_id); ohne ->
  weiterhin Auto-Erkennung aus dem Buchungstext (Konto-Texte)
- Migration 0010; Endpunkt aktualisiert bestehendes Wort statt Konflikt
- Import bevorzugt das feste Zielkonto, sonst _guess_target_account
- Konten-Seite: Transfer-Erkennung mit Zielkonto-Auswahl + Anzeige am Chip
- Test: festes Zielkonto greift ohne Konto-Texte (75 grün)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Guido
2026-08-20 19:06:24 +02:00
co-authored by Claude Opus 4.8
parent 794a6aeb91
commit c44892ff72
9 changed files with 96 additions and 12 deletions
+21
View File
@@ -249,6 +249,27 @@ def test_transfer_rule_and_target_guess(admin):
assert rows[1]["to_account_id"] is None
def test_transfer_keyword_fixed_target(admin):
giro = _account(admin, name="Giro FT")
ziel = _account(admin, name="Revolut Konto")
# Transfer-Schlagwort „revolut" MIT festem Zielkonto (ohne Konto-Texte).
r = admin.post("/api/categories/transfer-keywords",
json={"word": "revolut", "target_account_id": ziel["id"]})
assert r.status_code == 201, r.text
assert r.json()["target_account_id"] == ziel["id"]
csv = "Datum;Betrag;Empfaenger;Zweck\n01.03.2026;-25,00;Einkauf REVOLUT;Karte\n"
rows = _preview_csv(admin, giro["id"], csv, COLMAP)
assert rows[0]["type"] == "transfer"
assert rows[0]["to_account_id"] == ziel["id"]
# Erneutes Anlegen desselben Worts aktualisiert das Zielkonto (kein Konflikt).
r2 = admin.post("/api/categories/transfer-keywords",
json={"word": "revolut", "target_account_id": giro["id"]})
assert r2.status_code == 201, r2.text
assert r2.json()["target_account_id"] == giro["id"]
def test_same_word_across_kinds_allowed(admin):
a, b = _expense_cats(admin, 2)
inc = _income_cat(admin)