test: Duplikaterkennung ueber Monatsgrenzen abgesichert

Der uebliche Ablauf ist, Mitte Monat einzulesen und Ende Monat den ganzen
Monat noch einmal. Die Tests halten fest, dass bereits gebuchte Zeilen
nicht erneut in den Saldo laufen, neue ankommen – und dass zwei bzw. drei
echte gleich aussehende Buchungen desselben Tages erhalten bleiben.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Guido
2026-08-22 18:56:43 +02:00
co-authored by Claude Opus 5
parent 18368e6e93
commit 9d6a53a224
+69
View File
@@ -622,3 +622,72 @@ def test_verlauf_merkt_sich_die_bank_vorlage(admin):
verlauf = admin.get("/api/imports/batches").json()
meins = [b for b in verlauf if b["account_id"] == konto["id"]]
assert meins[0]["preset"] == "Raiffeisen (CH)"
def _csv(*zeilen):
return "Datum;Betrag;Empfaenger;Zweck;GegenIBAN\n" + "".join(z + "\n" for z in zeilen)
def _lies(admin, konto_id, text):
return admin.post(
"/api/imports/preview",
files={"file": ("a.csv", io.BytesIO(text.encode("utf-8")), "text/csv")},
data={"account_id": str(konto_id), "delimiter": ";", "decimal_sep": ",",
"date_format": "%d.%m.%Y", "encoding": "utf-8", "has_header": "true",
"skip_rows": "0", "amount_mode": "signed", "column_map": COLMAP},
).json()
def test_monatsauszug_ueber_bereits_gebuchte_zeilen_hinweg(admin):
"""Der übliche Ablauf: Mitte Monat einlesen, Ende Monat den ganzen Monat.
Die bereits gebuchten Zeilen dürfen nicht erneut in den Saldo laufen, die
neuen müssen ankommen. Zwei echte, gleich aussehende Buchungen desselben
Tages bleiben dabei beide erhalten – sie sind kein Duplikat.
"""
konto = _account(admin, name="Monatskonto", currency="CHF")
bis_18 = _csv(
"05.08.2026;-20,00;Coop;Einkauf;",
"12.08.2026;-7,50;Kiosk;Snack;",
"12.08.2026;-7,50;Kiosk;Snack;", # echte zweite Buchung, kein Duplikat
"18.08.2026;3.000,00;Arbeitgeber;Lohn;",
)
v = _lies(admin, konto["id"], bis_18)
assert sum(1 for r in v["rows"] if r["include"]) == 4
admin.post("/api/imports/commit", json={
"account_id": konto["id"], "filename": "aug-teil.csv",
"rows": [r for r in v["rows"] if r["include"]],
})
stand = lambda: admin.get(f"/api/accounts/{konto['id']}").json()["balance_cents"]
assert stand() == 296500 # -2000 -750 -750 +300000
ganzer_august = bis_18 + "".join(z + "\n" for z in (
"22.08.2026;-45,00;Migros;Einkauf;",
"29.08.2026;-12,00;SBB;Billett;",
))
v2 = _lies(admin, konto["id"], ganzer_august)
dubletten = [r for r in v2["rows"] if r["is_duplicate"]]
neue = [r for r in v2["rows"] if r["include"]]
assert len(dubletten) == 4, [r["payee"] for r in dubletten]
assert [r["payee"] for r in neue] == ["Migros", "SBB"]
admin.post("/api/imports/commit", json={
"account_id": konto["id"], "filename": "aug-ganz.csv",
"rows": neue,
})
assert stand() == 296500 - 4500 - 1200
def test_dritte_gleiche_buchung_gilt_nicht_als_dublette(admin):
"""Kommt am selben Tag eine DRITTE gleiche Buchung dazu, ist sie echt."""
konto = _account(admin, name="Dreimal", currency="CHF")
zwei = _csv("03.08.2026;-5,00;Bäckerei;Brot;", "03.08.2026;-5,00;Bäckerei;Brot;")
v = _lies(admin, konto["id"], zwei)
admin.post("/api/imports/commit", json={
"account_id": konto["id"], "filename": "zwei.csv",
"rows": [r for r in v["rows"] if r["include"]]})
drei = zwei + "03.08.2026;-5,00;Bäckerei;Brot;\n"
v2 = _lies(admin, konto["id"], drei)
assert sum(1 for r in v2["rows"] if r["is_duplicate"]) == 2
assert sum(1 for r in v2["rows"] if r["include"]) == 1