feat: Rueckkehr von der Bank sagt, was ankam und was liegen blieb
"3 Konten gefunden" beantwortet die entscheidende Frage nicht: Hat die Bank nur drei geschickt, oder hat Certain die uebrigen verworfen? Der Server rechnet beides laengst aus, die Seite zeigte es nur, wenn ueberhaupt kein Konto ankam. Jetzt steht immer dabei, wie viele die Bank geschickt hat. Und Konten, die Certain nicht uebernehmen konnte, werden nicht mehr bloss gezaehlt, sondern mitsamt dem gezeigt, was von ihnen ankam – uebersprungen werden sie, weil die Kennung fehlt, mit der sich Salden und Umsaetze holen lassen. Anlass: Fuenf Revolut-Pockets sind im Control Panel freigeschaltet und wurden bei der Autorisierung ausdruecklich mitgewaehlt, kommen in Certain aber nicht an. Ohne diese Zahlen laesst sich nicht sagen, wo sie verloren gehen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
@@ -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"}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -59,10 +59,30 @@ export default function BankRueckkehr() {
|
||||
{!stand.laeuft && !stand.fehler && stand.konten > 0 && (
|
||||
<div className="alert" style={{ display: "block" }}>
|
||||
<strong>{t("bankReturn.ok", { n: stand.konten })}</strong>
|
||||
{/* Wie viele die Bank GESCHICKT hat. Ohne diese Zahl lässt sich
|
||||
nicht sagen, ob ein fehlendes Konto gar nicht kam oder hier
|
||||
hängen blieb – und man sucht an der falschen Stelle. */}
|
||||
<p className="muted small">
|
||||
{t("bankReturn.uebermittelt", { n: stand.uebermittelt })}
|
||||
</p>
|
||||
<p className="muted small">{t("bankReturn.next")}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!stand.laeuft && (stand.uebergangen || []).length > 0 && (
|
||||
<div className="alert warn" style={{ display: "block" }}>
|
||||
<strong>{t("bankReturn.skipped", { n: stand.uebergangen.length })}</strong>
|
||||
<p className="muted small">{t("bankReturn.skippedHint")}</p>
|
||||
<div className="selectable small muted">
|
||||
{stand.uebergangen.map((k, i) => (
|
||||
<pre key={i} style={{ whiteSpace: "pre-wrap", margin: "4px 0" }}>
|
||||
{JSON.stringify(k)}
|
||||
</pre>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!stand.laeuft && !stand.fehler && stand.konten === 0 && (
|
||||
// Drei verschiedene Ursachen sahen bisher alle gleich aus.
|
||||
<div className="alert error" style={{ display: "block" }}>
|
||||
|
||||
Reference in New Issue
Block a user