fix: Ein Umsatz unter neuer Kennung kam ein zweites Mal herein

Der Bankabruf nahm die ERSTE Kennung, die ein Umsatz mitbringt – meist die
Referenz der Bank. Vergibt die Bank sie beim Buchen neu (aus vorgemerkt wird
gebucht), ist es fuer Certain ein anderer Umsatz, und dieselbe Zahlung steht
zweimal da. Genau so sind zwei Mietbuchungen ueber 288 Euro am selben Tag
entstanden.

Zwei Aenderungen:

- Geprueft wird gegen ALLE Kennungen des Umsatzes, nicht nur gegen eine. Damit
  treffen auch Eintraege, die frueher unter einer anderen abgelegt wurden.
- Gespeichert wird die bestaendigste: die eigene Kennung der Schnittstelle
  bleibt gleich, wenn die Bank ihre Referenz austauscht.

Das ist eine von vier Stellen, an denen Certain Dubletten erkennt – neben dem
Import-Schluessel, dem unscharfen Eingangs-Abgleich und dem
Ueberschneidungsschutz. Diese vier gehoeren zusammengefuehrt; das ist ein
eigener Umbau und nicht Teil dieser Korrektur.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Guido
2026-08-30 13:51:50 +02:00
co-authored by Claude Opus 5
parent 67a32bdda9
commit 1509695760
2 changed files with 55 additions and 5 deletions
+16 -5
View File
@@ -651,20 +651,31 @@ def hole_umsaetze(db: Session, user: User, verbindung: BankConnection,
# Eingang und niemand weiss, warum.
vorgemerkt += 1
continue
kennung = (umsatz.get("entry_reference") or umsatz.get("transaction_id")
or umsatz.get("uid"))
if not kennung:
# ALLE Kennungen, die der Umsatz mitbringt – nicht nur die erste.
# Liefert die Bank denselben Umsatz spaeter unter einer anderen
# (etwa weil aus vorgemerkt gebucht wurde), waeren es sonst zwei.
kennungen = [
f"{verknuepfung.remote_uid}:{wert}"[:255]
# Reihenfolge nach Bestaendigkeit: Die eigene Kennung der
# Schnittstelle bleibt gleich, wenn die Bank ihre Referenz beim
# Buchen neu vergibt. Gespeichert wird die erste – geprueft
# wird gegen alle, damit auch aeltere Eintraege noch treffen.
for feld in ("transaction_id", "internal_transaction_id",
"entry_reference", "uid")
if (wert := umsatz.get(feld))
]
if not kennungen:
continue # ohne Kennung kein Schutz vor Doppelabruf
kennung = f"{verknuepfung.remote_uid}:{kennung}"[:255]
schon = (
db.query(InboxItem.id)
.filter(InboxItem.owner_id == user.id,
InboxItem.source == InboxSource.bank,
InboxItem.external_id == kennung)
InboxItem.external_id.in_(kennungen))
.first()
)
if schon is not None:
continue
kennung = kennungen[0]
cents = _betrag_cents(umsatz)
tag = _datum(umsatz)