diff --git a/backend/app/services/bank_sync.py b/backend/app/services/bank_sync.py index bd6eab1..2485576 100644 --- a/backend/app/services/bank_sync.py +++ b/backend/app/services/bank_sync.py @@ -247,14 +247,15 @@ def schliesse_verbindung(db: Session, user: User, state: str, code: str) -> dict verbindung.valid_until = None uebermittelt = daten.get("accounts") or [] - neu = bekannt = ohne_kennung = 0 + neu = bekannt = 0 + uebergangen: list[dict] = [] for konto in uebermittelt: uid = konto.get("uid") if not uid: - # Nicht stillschweigend verwerfen: Sonst sieht „0 Konten" genauso - # aus, als hätte die Bank gar nichts geschickt – und man sucht den + uebergangen.append(konto) + # Nicht stillschweigend verwerfen: Sonst sieht „3 Konten" genauso + # aus, als hätte die Bank nur drei geschickt – und man sucht den # Fehler bei der Bank statt hier. - ohne_kennung += 1 continue vorhanden = ( db.query(BankAccountLink) @@ -283,7 +284,13 @@ def schliesse_verbindung(db: Session, user: User, state: str, code: str) -> dict "neu": neu, "bekannt": bekannt, "uebermittelt": len(uebermittelt), - "ohne_kennung": ohne_kennung, + "ohne_kennung": len(uebergangen), + # Was genau übergangen wurde. Ohne das bleibt die Frage offen, ob die + # Bank ein Konto gar nicht schickt oder Certain es nicht versteht. + "uebergangen": [ + {k: v for k, v in konto.items() if k != "identification_hashes"} + for konto in uebergangen[:20] + ], "valid_until": verbindung.valid_until.isoformat() if verbindung.valid_until else None, } diff --git a/backend/tests/test_bank.py b/backend/tests/test_bank.py index 104e83e..535db85 100644 --- a/backend/tests/test_bank.py +++ b/backend/tests/test_bank.py @@ -1129,3 +1129,31 @@ def test_abruf_ueber_schon_eingelesene_monate_bucht_nicht_doppelt(admin, fake_ba assert r["neu"] == 1, "der echte Umsatz muss ankommen" # 35.00 einmal (aus der CSV) plus 7.77 neu – nicht 35.00 zweimal. assert admin.get(f"/api/accounts/{konto['id']}").json()["balance_cents"] == -4277 + + +def test_uebergangene_konten_werden_gezeigt_nicht_nur_gezaehlt(admin, fake_bank): + """Ohne die Zahl der uebermittelten Konten laesst sich nicht sagen, ob ein + fehlendes Konto gar nicht kam oder hier haengen blieb – und man sucht an + der falschen Stelle.""" + _app(admin) + gut = f"acc-{secrets.token_hex(4)}" + fake_bank(konten=[ + {"uid": gut, "name": "Girokonto", "currency": "CHF"}, + # So sieht ein Pocket aus, wenn die Kennung fehlt. + {"name": "Sparen", "currency": "CHF", + "account_id": {"other": {"identification": "OTHI 6bdb2e3e", "scheme_name": "OTHI"}}}, + {"name": "Steuern", "currency": "CHF"}, + ]) + state = admin.post("/api/bank/connect", + json={"aspsp_name": f"Pockets-{secrets.token_hex(3)}", + "country": "LT"}).json()["state"] + r = admin.post(f"/api/bank/callback?state={state}&code=guter-code") + assert r.status_code == 200, r.text + daten = r.json() + + assert daten["konten"] == 1 + assert daten["uebermittelt"] == 3, "die Bank hat drei geschickt" + assert daten["ohne_kennung"] == 2 + # Und zwar mitsamt dem, was ankam – sonst raet man, was ihnen fehlt. + namen = {k.get("name") for k in daten["uebergangen"]} + assert namen == {"Sparen", "Steuern"} diff --git a/web/src/locales/de.json b/web/src/locales/de.json index 7dd7cf8..0ad2eee 100644 --- a/web/src/locales/de.json +++ b/web/src/locales/de.json @@ -666,7 +666,10 @@ "toSettings": "Zu den Einstellungen", "noAccounts": "Verbunden, aber die Bank hat kein Konto übermittelt", "noAccountsHint": "Im eingeschränkten Betrieb gibt die Bank nur Konten heraus, die du bei Enable Banking selbst verknüpft hast. Öffne dort deine Anwendung, drück „Activate by linking accounts“ und wähle diese Bank – danach hier noch einmal verbinden.", - "noAccountsDropped": "Die Bank hat {{n}} Einträge geschickt, aber ohne Kennung – damit lässt sich nichts abrufen. Das ist ein Fall für den Support von Enable Banking; schick mir die Meldung, dann formuliere ich die Anfrage." + "noAccountsDropped": "Die Bank hat {{n}} Einträge geschickt, aber ohne Kennung – damit lässt sich nichts abrufen. Das ist ein Fall für den Support von Enable Banking; schick mir die Meldung, dann formuliere ich die Anfrage.", + "uebermittelt": "Die Bank hat {{n}} Konten geschickt.", + "skipped": "{{n}} Konten konnte Certain nicht übernehmen", + "skippedHint": "Ihnen fehlt die Kennung, mit der Salden und Umsätze geholt werden. Das steht unten so, wie es angekommen ist – schick es mir, dann sehe ich, was fehlt." }, "transfers": { "title": "Mögliche Überträge", diff --git a/web/src/locales/en.json b/web/src/locales/en.json index efc4226..b33cc64 100644 --- a/web/src/locales/en.json +++ b/web/src/locales/en.json @@ -666,7 +666,10 @@ "toSettings": "Go to settings", "noAccounts": "Connected, but the bank returned no account", "noAccountsHint": "In restricted mode the bank only releases accounts you linked at Enable Banking yourself. Open your application there, press “Activate by linking accounts” and pick this bank – then connect again here.", - "noAccountsDropped": "The bank sent {{n}} entries but without an identifier, so nothing can be fetched. That is one for Enable Banking support; send me the message and I will draft the question." + "noAccountsDropped": "The bank sent {{n}} entries but without an identifier, so nothing can be fetched. That is one for Enable Banking support; send me the message and I will draft the question.", + "uebermittelt": "The bank sent {{n}} accounts.", + "skipped": "{{n}} accounts could not be taken over", + "skippedHint": "They lack the identifier used to fetch balances and transactions. Below is what arrived, unchanged." }, "transfers": { "title": "Possible transfers", diff --git a/web/src/pages/BankRueckkehr.jsx b/web/src/pages/BankRueckkehr.jsx index 148be0c..2b9bd45 100644 --- a/web/src/pages/BankRueckkehr.jsx +++ b/web/src/pages/BankRueckkehr.jsx @@ -59,10 +59,30 @@ export default function BankRueckkehr() { {!stand.laeuft && !stand.fehler && stand.konten > 0 && (
+ {t("bankReturn.uebermittelt", { n: stand.uebermittelt })} +
{t("bankReturn.next")}
{t("bankReturn.skippedHint")}
+
+ {JSON.stringify(k)}
+
+ ))}
+