Bisher lag sie nur am Eingangs-Eintrag. Das reicht nicht: Der Eintrag ist eine
Zwischenstation und faellt weg, wenn ein Konto geloescht wird oder ein aelteres
Backup ihn nicht kannte. Dann war die Zahlung fuer den naechsten Abruf neu,
obwohl sie laengst gebucht war.
Am schlimmsten bei einem als Uebertrag gebuchten Umsatz: Der ist von der
Aehnlichkeitspruefung ausgenommen, dort griff also gar nichts mehr.
Die Kennung gehoert deshalb an die Buchung (transactions.source_uid, mit der
Quelle davor). Dort ueberlebt sie alles, was mit dem Eingang passiert, und die
Eindeutigkeit haelt die Datenbank selbst durch – nicht erst der pruefende Code
davor. Gestempelt wird an allen drei Buchungswegen: Eingang, Kurzbefehl und
Uebertrag.
Vorhandene Buchungen bekommen die Kennung nachgetragen, solange ihr
Eingangs-Eintrag noch da ist.
Ohne Kennung – von Hand erfasst, aus einer CSV-Datei – bleibt es beim
bisherigen Schutz ueber die Aehnlichkeit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Eine Zahl, die man nicht aufschluesseln kann, muss man glauben. Genau das
war der Streitpunkt: Die Karte nannte fuer Lebensmittel einen Betrag, und
es gab keine Moeglichkeit nachzusehen, welche Zahlungen darin einbezogen
sind und welche nicht.
Jetzt oeffnet ein Klick auf einen Anteil - in der Liste wie in der
Legende des Kreises - die Buchungen dahinter: Datum, Empfaenger, Konto,
Betrag. Die Liste kommt aus derselben Stelle, die auch die Summe bildet
(`budget.expense_rows`), sie kann also gar nicht etwas anderes zeigen als
das, was gezaehlt wurde. Ein Test haelt das fest.
Steht eine Buchung darin, obwohl ihr Datum ausserhalb des Zeitraums
liegt, traegt sie die Kalendermarke: Dann wurde ihr Budget-Monat von Hand
gesetzt, und das ist der Grund.
Nebenbei: Dialoge haengen jetzt am Seitenkoerper. Kacheln der Uebersicht
werden per `transform` positioniert - damit war die Kachel der
Bezugsrahmen fuer `position: fixed`, und der Dialog sass eingeklemmt
darin statt ueber der Seite.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bisher entschied allein das Datum. Bei einem Budget-Monat, der nicht am
Ersten beginnt, faellt das auf: Die Zahlung geht am 24. ab und gehoert
doch zum naechsten Monat, die Rechnung wird verspaetet beglichen und
gehoert zum letzten.
Neu traegt jede Buchung einen Budget-Monat. Leer heisst weiterhin "aus dem
Datum" - der Normalfall, und er bleibt es. Wird einer von Hand gesetzt,
zaehlt die Buchung nur noch dort und in ihrem eigenen Monat NICHT mehr,
sonst stuende sie zweimal da.
Das Aendern liegt bewusst hinter einem Klick und hinter Pfeilen statt
hinter einer Auswahlliste: Es ist der Ausnahmefall, nicht der Normalfall,
und soll sich auch so anfuehlen. Waehlt man genau den Monat, der ohnehin
gilt, bleibt die Buchung automatisch - verschiebt sich das Datum spaeter,
wandert sie mit. In der Liste zeigt eine Marke den Monat, aber nur, wenn
jemand eingegriffen hat.
Der Server nimmt drei Monate in jede Richtung an. Ein Vertipper wie
2019-03 wird abgelehnt: Er liesse die Buchung aus jeder Auswertung
verschwinden, ohne dass irgendwo etwas fehlt.
Geprueft im Browser gegen eine Wegwerf-Datenbank mit Stichtag 25: Die
Karte summiert 25.08.-24.09., eine verschobene Buchung verlaesst diesen
Zeitraum und kehrt beim Zuruecknehmen zurueck.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zwei Dinge, die zusammen die Frage beantworten "zaehlt das wirklich ab
meinem Stichtag, und sind das wirklich zwei Zahlungen?".
Die Karte Ausgaben-Anteile nennt jetzt ihren Zeitraum. Gerechnet hat sie
schon immer ueber den eingestellten Budget-Monat (25.08.-24.09. bei
Starttag 25); nachvollziehen liess sich das nur nicht, weil die Karte
nirgends sagte, worueber sie summiert.
Die Dublettensuche vergleicht nicht mehr stur ueber den Text. Ein krummer
Betrag wie 10.43 kommt an einem Tag kaum zweimal vor - auch wenn zwei
Quellen ihn verschieden benennen, und genau daran scheiterte der
Textvergleich. Bei einem runden Betrag (Vielfaches von 50 Rappen) muss der
Text weiter passen, sonst waeren zwei Zwanziger am selben Tag ein Fund.
Und was die Bank selbst als verschieden gemeldet hat, gilt als geklaert:
Stammen alle Zeilen aus demselben Bankkonto und tragen verschiedene
Kennungen, verschweigt die Karte sie. Das sind die Revolut-Aufrundungen,
die echt sind.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bisher fand man Dubletten nur zufaellig beim Durchscrollen der Buchungsliste –
oder ich habe ein Skript dafuer geschrieben, und der Nutzer musste sich auf
einen Server einloggen, um seine eigenen Zahlen zu reparieren. Beides ist
falsch.
Die Arbeitsliste zeigt sie jetzt: gleiches Konto, gleicher Tag, gleicher
Betrag, gleicher Text. Je Zeile steht die Kennung der Bank dabei, und die
entscheidet die Frage – dieselbe Kennung heisst sicher dieselbe Zahlung,
verschiedene heissen, die Bank hat sie als verschieden gemeldet.
Entschieden wird bewusst NICHTS von selbst. Drei Aufrundungen ueber 1.00 am
selben Tag sind echt, drei gleiche Einkaeufe koennen es auch sein; das weiss
nur der Nutzer. Certain meldet und laesst loeschen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Eingefaerbt war bisher nur die Listen-Darstellung der Ausgaben-Anteile. In der
Kreis-Darstellung blieben die Betraege der Legende grau, und die Summe in der
Mitte sagte gar nichts ueber den Stand.
Jetzt tragen beide die Aussage: gruen im geplanten Rahmen, rot darueber. Faehrt
man ein Segment an, zeigt die Mitte dessen Betrag – dann gilt dort das Budget
dieser Kategorie, sonst das des Ganzen.
Fuer die Mitte liefert der Server jetzt auch das Geplante ueber ALLE
Ausgaben-Einheiten, nicht nur ueber die mit Ausgaben: Der Monatsplan umfasst
auch, wofuer noch nichts ausgegeben wurde.
Ohne Plan bleibt alles, wie es war. Der Donut faerbt nur, wenn ein Segment die
Angabe mitbringt – die Budget-Karte, die dieselbe Komponente benutzt, bleibt
also unberuehrt.
Der Test hat dabei gleich einen Fehler gefunden: ``_units`` ist ein Generator,
und ich lief zweimal darueber – beim zweiten Mal war er leer und das Geplante
immer 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Karte zeigte nur, wie sich die Ausgaben verteilen – nicht, ob sie im
Rahmen liegen. Der Betrag ist jetzt gruen, solange er unter dem Geplanten
bleibt, und rot darueber. Dieselben Farben wie ueberall sonst fuer Einnahme
und Ausgabe.
Ohne Plan bleibt der Betrag gedeckt. "Ueber Budget" waere sonst die Aussage
ueber jede Kategorie, fuer die nie eine Vorgabe gemacht wurde – die Karte
stuende dann fast durchgehend auf Rot und sagte nichts mehr.
Das Geplante kommt aus derselben Quelle wie im Budget-Fortschritt, also
einschliesslich eines Monats-Werts, der die Vorlage uebersteuert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
Buchungen bis einschliesslich des Stichtags zaehlen nicht in den Kontostand –
sie stecken schon im Anfangsbestand. In der Liste stehen sie aber, und in den
Auswertungen zaehlen sie mit. Das ist richtig so, war in der Oberflaeche aber
nirgends zu sehen: Der Unterschied zwischen dem, was man sieht, und dem, was
gerechnet wird, liess sich nicht erklaeren.
Ein Konto, dessen Stichtag nach dem Beginn des eingelesenen Auszugs liegt,
zeigt deshalb einen Kontostand, der zu den sichtbaren Buchungen nicht passt –
und niemand kaeme darauf, warum.
Die Rechnung nennt jetzt Stichtag, Anzahl und Summe der ausgeschlossenen
Buchungen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zwei Sachen aus derselben Wurzel: Wenn ein Saldo nicht stimmt, sieht man nicht,
warum, und kann auch nichts dagegen tun.
Ein Klick auf den Kontostand zeigt jetzt die Rechnung: Anfangsbestand,
Einnahmen, Ausgaben, Uebertraege raus und rein – jeweils mit der Anzahl der
Buchungen – und was daraus wird. Darunter der Saldo der Bank und, einzeln
aufgefuehrt, alle Uebertraege des Kontos. Genau die sind die haeufigste
Ursache und in einer langen Buchungsliste am schwersten zu ueberblicken.
Rechnung und Kontenliste kommen aus EINER Quelle: ``account_balance_cents``
liest jetzt aus der Aufschluesselung. Sonst koennte die Anzeige etwas anderes
behaupten als der Saldo, und man suchte den Fehler im Falschen.
Ausserdem war der Knopf "Saldo der Bank uebernehmen" verschwunden, sobald die
Bank nur einen verfuegbaren Saldo meldet. Das war zu weit gedacht: Nicht
vergleichbar heisst nicht, dass man nicht angleichen duerfte. Der Knopf ist
zurueck, und die Nachfrage sagt in dem Fall, worauf man sich einlaesst – der
verfuegbare Saldo enthaelt Vorgemerktes, das spaeter noch als Buchung kommt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"Weniger als 15 Minuten lassen die Banken nicht zu" stand als Hinweis im
Formular. Das war erfunden. PSD2 verpflichtet die Banken zu VIER
unbeaufsichtigten Abfragen je Konto und Tag – haeufiger duerfen sie ablehnen,
und N26 tut es: "Too many requests", und der Abruf scheitert, bis das
Zeitfenster weiterrueckt.
Bei zehn angebundenen Konten und einem Takt von 15 Minuten waren es tausende
Anfragen am Tag. Der Takt betraegt jetzt mindestens sechs Stunden, also genau
die zugesicherten vier je Tag. Bestehende, zu knappe Einstellungen werden beim
Faelligkeitspruefen mitgebremst – sonst liefe eine gespeicherte 15 weiter
dagegen.
Von Hand abrufen bleibt unbegrenzt: Dabei sitzt der Nutzer davor, und fuer
diesen Fall gilt die Grenze nicht.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Eine verknuepfte Buchung gehoert zu einem Uebertrag und zaehlt in keiner
Auswertung. Trotzdem stand sie unter "Zu erledigen" und wurde in der
Buchungsliste nach einer Kategorie gefragt – Arbeit, die nichts bewirkt, und
ein falsches Signal: Sie sah aus, als fehle noch etwas.
Der Filter fuer offene Buchungen laesst verknuepfte jetzt aus, und in der
Buchungsliste steht bei ihnen ein Strich statt der Auswahl – so wie bei einem
echten Uebertrag.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Erkennung gab es laengst – aber nur auf der Seite "Zu erledigen", in einer
Karte, die man erst finden muss. Wer in der Buchungsliste steht und die zweite
Haelfte eines Uebertrags sieht, greift stattdessen zum ↔-Knopf und legt einen
zweiten Uebertrag an. Genau so ist heute eine Zahlung doppelt verschoben
worden.
Jetzt steht die Frage in der Zeile: "Uebertrag von/nach Revolut CHF?" mit
Verbinden und Ignorieren. Ignorieren wird gemerkt, sonst fragte Certain bei
jedem Laden erneut.
Dafuer gibt es die Suche jetzt auch als reines Nachschlagen: ``finde`` mit
``nur_vorschlaege`` verknuepft nichts, und dahinter liegt GET
/uebertraege/vorschlaege. Eine Ansicht, die bloss fragt, darf beim Hinsehen
nichts veraendern – sonst entschiede das Anschauen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Sperre sah auf dem Zielkonto nur nach Ausgaben und Einnahmen. Steht dort
schon ein UEBERTRAG, der dasselbe Geld zwischen denselben beiden Konten
bewegt, fand sie nichts – und der zweite ging durch.
Genau das passiert im Alltag: Die eine Seite kommt von der Bank, die andere
aus der CSV-Datei, und beide sehen einzeln nach einem Uebertrag aus. Wer beide
umwidmet, hat das Quellkonto doppelt belastet und das Ziel doppelt
gutgeschrieben – bei 1'575 macht das 3'150 Unterschied auf zwei Konten.
Jetzt wird zuerst geprueft, ob zwischen denselben beiden Konten schon ein
Uebertrag ueber denselben Betrag in derselben Woche steht. Die Richtung ist
dabei egal, ein Uebertrag hat kein Vorzeichen. Dieser Fall laesst sich auch
nicht mit "trotzdem" uebergehen: Dasselbe Geld zweimal zu verschieben ist
keine Ansichtssache.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die staendige Meldung "weicht ab" hatte mehrere Quellen, und eine davon war
ueberhaupt keine Abweichung.
1. Ein VERFUEGBARER Saldo enthaelt Vorgemerktes. Certain bucht Vorgemerktes
bewusst nicht – es kaeme spaeter mit anderer Kennung ein zweites Mal. Beides
zu vergleichen musste also dauerhaft danebengehen. Verglichen wird jetzt nur
noch ein GEBUCHTER Saldo (CLBD, ITBD, PRCD); sonst steht dort "verfuegbarer
Saldo, nicht vergleichbar" und keine Abweichung.
2. Die Saldi wurden VOR den Umsaetzen geholt und sofort geschrieben. Brach der
Umsatz-Abruf danach ab, stand ein aktueller Saldo neben altem Bestand – und
die Anzeige meldete eine Abweichung, die nur aus der Reihenfolge kam. Sie
kommen jetzt zuletzt. Ohne Kontozuordnung weiterhin zuerst: Dort gibt es
keine Umsaetze zu holen, und bei mehreren gleich aussehenden Pockets ist der
Betrag das Einzige, woran man sie unterscheidet.
3. Jeder weitere Abruf griff nur drei Tage hinter den letzten zurueck. Banken
buchen mitunter spaeter zurueck; was einmal ausserhalb lag, kam nie wieder.
Jetzt sieben Tage – doppelt holen kostet nichts, die Kennung des Umsatzes
faengt es exakt ab.
Damit ist die Anzeige nicht mehr nur ehrlicher, sondern zeigt auch wieder auf
etwas: Steht dort eine Abweichung, ist sie echt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Wer dieselbe Bank zweimal verbindet, bekommt fuer dieselbe Zahlung zwei
verschiedene Kennungen – Enable Banking fuehrt eine Bank je Land getrennt.
Genau das passiert bei Revolut: Ueber den DE-Eintrag kommen drei Konten, ueber
den LT-Eintrag zusaetzlich die Pockets, also verbindet man beide. Zeigen dann
zwei Bankkonten auf dasselbe Konto in Certain, holt jeder Zugang dieselben
Umsaetze, und der Duplikatschutz kann sie nicht als dieselben erkennen.
Drei Aenderungen:
- Ein Konto in Certain wird nur noch von EINEM Bankkonto gefuellt. Ordnet man
ein zweites zu, wird die alte Zuordnung geloest. Sie ist ohnehin nie richtig,
und stillschweigend doppelt zu buchen ist schlimmer als eine geloeste
Zuordnung.
- Die Ausnahme im Ueberschneidungsschutz gilt nur noch fuer DASSELBE Bankkonto.
Dort entscheidet die Kennung der Bank, und die ist exakt – zwei Aufrundungen
ueber 1.00 duerfen sich nicht verschlucken. Buchungen aus einem ANDEREN
Zugang zaehlen jetzt mit.
- Das Aufraeumskript kennt den Fall: Findet es in einer Gruppe (Konto, Art,
Tag, Betrag) Buchungen aus zwei Zugaengen, bleibt die Fassung EINES Zugangs
stehen. Aufrundungen aus einem einzigen Zugang bleiben unangetastet, auch
wenn sie gleich aussehen.
An nachgestellten Daten geprueft: Aus -579.50 wird -290.50; die drei gleichen
Aufrundungen aus einem Zugang bleiben alle stehen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"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>
"Aelteres nachholen" greift 90 Tage zurueck – mitten in Monate, die schon per
CSV eingelesen sind. Genau davor schuetzt sonst das Startdatum, und der Knopf
haengt es aus. Der Duplikatschutz faengt das nicht: Sein Schluessel enthaelt
den Empfaengertext, und der lautet bei der Bank anders als im Auszug. Ergebnis:
jede Zahlung des Zeitraums zweimal.
Das war mein Fehler – ich habe den Knopf gebaut UND empfohlen, ohne die
Sicherung zu ersetzen, die er aushebelt.
Der Abruf prueft jetzt selbst: Gibt es auf dem Konto schon eine Buchung
gleicher Richtung und gleichen Betrags im Umkreis von drei Tagen, die NICHT
von der Bank kam, ist der Umsatz dieselbe Bewegung und wird uebersprungen.
Jede vorhandene Buchung erklaert dabei hoechstens einen Umsatz – sonst
verschluckte eine Kaffeezahlung alle weiteren desselben Betrags. Die Zahl der
uebersprungenen steht in der Rueckmeldung.
Fuer den bereits angerichteten Schaden gibt es
scripts/raeume_doppelte_bankumsaetze.py: Es findet Bank-Umsaetze, die eine
vorhandene Buchung wiederholen, und entfernt IMMER die von der Bank – die
eigene traegt die Kategorie des Nutzers. Sie wird verworfen, nicht geloescht,
damit kein spaeterer Abruf sie wiederholt. Ohne --wirklich passiert nichts;
mit --wirklich wird zuerst eine Kopie der Datenbank angelegt.
An nachgestellten Daten geprueft: Aus -95.80 wird -48.40, die eigenen
Buchungen samt Kategorie bleiben, der echte neue Umsatz bleibt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Beim ersten Abruf beginnt Certain am Tag NACH der neuesten vorhandenen Buchung
des Kontos, damit es nicht in schon eingelesene Monate zurueckgreift. Liegt
diese Buchung auf heute, ist der Tag danach morgen – und die Schnittstelle
lehnt das rundweg ab: "date_from can not be in the future".
Der Fehler faellt erst beim Umsatz-Abruf an. Die Saldi sind da schon gelesen
und geschrieben, der Abruf bricht danach ab. Von aussen sieht es genau so aus,
wie der Nutzer es beschrieben hat: Der Kontostand aktualisiert sich, die
Buchungen kommen nie – und die Abweichung bleibt bestehen, obwohl man den
Saldo gerade erst von der Bank uebernommen hat. Genau dieses Uebernehmen legt
naemlich keine Buchung an, aber es gibt fast immer eine von heute.
Das Startdatum wird jetzt auf heute begrenzt. Gegenprobe: Ohne die Begrenzung
verlangt der Abruf den 28.08. an einem 27.08.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Eingangs-Abgleich vergleicht Betrag und Datum mit ein paar Tagen
Spielraum – bewusst unscharf, damit eine per Kurzbefehl erfasste Zahlung nicht
ein zweites Mal ankommt. Er merkt sich dabei, welchen Eintrag er schon
verbraucht hat.
Nur ruft der Bankabruf ihn JE ZEILE einzeln auf, und damit begann diese Menge
jedes Mal von vorn: Derselbe Eintrag liess sich beliebig oft verbrauchen. Bei
Revolut-Aufrundungen – dreimal 1.00 in drei Tagen – kam so nur die erste an,
und der Saldo wich ab, ohne dass irgendwo etwas stand.
Zwei Aenderungen:
- Der Aufrufer kann die Menge jetzt ueber mehrere Aufrufe mitfuehren; der
Bankabruf haelt eine je Konto.
- Gegen andere BANK-Eintraege wird gar nicht mehr unscharf verglichen. Zwei
Umsaetze derselben Quelle sind nie Dubletten voneinander – dort entscheidet
die Kennung der Bank, und die ist exakt.
Dazu ein Weg zurueck: Ein verschluckter Umsatz hinterliess keinen Eintrag, der
naechste Abruf haette ihn also wieder geholt – nur liegt er dann vor dem
Fenster des letzten Abrufs. "Aelteres nachholen" gibt es jetzt auch je Konto,
wie beim Postfach.
Nachgestellt und als Test festgehalten: dreimal 1.00 in drei Tagen, alle drei
kommen an, Saldo -3.00.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Regeln greifen beim Import. Alles, was vorher hereinkam – oder hereinkam, bevor
es die Regel gab –, bleibt liegen. Bei einer Bankanbindung passiert genau das
dauernd: Die Umsaetze kommen von selbst, die Regel entsteht spaeter. Die
Revolut-Aufrundungen aufs Sparen-Pocket sind der Fall, an dem es aufgefallen
ist.
Der Knopf steht bei der Transfer-Erkennung und zeigt erst, was passieren
wuerde. Uebertrags-Regeln laufen durch denselben Dienst wie jeder andere
Uebertrag – er lehnt ab, wo die Gegenseite schon gebucht ist, und solche
Buchungen bleiben unangetastet und werden mit Grund gemeldet.
Ohne festes Zielkonto wird es aus dem Buchungstext erraten, aber nur bei GENAU
einem Treffer und nur an Wortgrenzen: "Euro" darf nicht "PayPal Europe"
treffen. Zwei Moeglichkeiten heisst raten, und dann passiert nichts.
Angefasst werden nur Buchungen OHNE Kategorie – sonst ueberschriebe der Knopf
stillschweigend, was von Hand zugeordnet wurde. Ein Uebertrag ist kein Kandidat
mehr, ein zweiter Klick verschiebt das Geld also nicht erneut.
Zwei Dinge fielen beim Testen auf und sind mit behoben:
- Ein fehlgeschlagener Uebertrag verwarf per rollback() auch alles, was im
selben Durchlauf schon gelungen war. Jetzt haelt ein Rettungspunkt je
Uebertrag den Schaden bei dem einen.
- test_neutral_category nahm VORHANDENE Kategorien und stellte eine davon auf
"nicht einrechnen". Benutzten andere Buchungen sie, fielen die mit heraus und
die Rechnung ging um deren Summe daneben – ohne Bezug zum Gepruefften. Der
Test legt sich seine Kategorien jetzt selbst an.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Auslieferung des Frontends nahm den Pfad roh aus der Adresse: "Path /
'../../x'" verlaesst den Ordner klaglos, und die Route liegt VOR jeder
Anmeldepruefung. Gegen die eigene Instanz nachgestellt – roh und
prozentkodiert kam beides Mal die Datei heraus:
GET /../../GEHEIM.txt -> "geheim"
GET /../../backend/app/config.py -> der Quelltext
Damit war alles lesbar, was der Dienst lesen darf: Quelltext, Konfiguration,
und mit der passenden Zahl von Ebenen die Datenbank samt verschluesseltem
Postfach-Passwort und Bank-Schluessel. Der Pfad wird jetzt aufgeloest und
muss im Auslieferungs-Ordner liegen.
Zweitens prueft der Postfach-Abruf jetzt das Zertifikat. Ohne eigenen
SSL-Kontext tut imaplib das NICHT – die Verschluesselung schuetzt dann vor
niemandem, der sich dazwischenhaengt, und das Postfach-Passwort geht mit.
Gilt fuer beide Wege, SSL und STARTTLS.
Drittens warnt der Start, wenn das Sitzungs-Cookie ohne "Secure" ausgeliefert
wird. Die Vorgabe bleibt bewusst aus: Sie umzustellen sperrt jeden aus, der
Certain im Heimnetz ueber HTTP aufruft – und ein Ausgesperrter saehe die
Ursache nirgends.
Die Befunde stammen aus dem /security-review dieser Sitzung und waren seither
offen. Sie wiegen schwerer, seit die Anwendung fuer die Bankanbindung unter
einer oeffentlichen HTTPS-Adresse erreichbar sein muss.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Starttag wird auf den letzten Tag des Monats gekappt – einen 31. Februar
gibt es nicht. period_bounds tat das, period_of nicht: Es verglich stur den
Tag des Monats. Damit fiel der 28. Februar bei Starttag 31 in einen Monat, der
vom 31. Januar bis zum 27. Februar reicht – der Tag lag also in keiner
Auswertung.
Betroffen waren elf Tage in vier Jahren, alle am Ende kurzer Monate, und nur
bei Starttag 29, 30 und 31. Bei allen anderen stimmte es.
Zwei Tests halten es fest: Jeder Tag von 2024 bis 2027 muss bei JEDEM Starttag
in dem Monat liegen, den period_of ihm zuweist – und die Monate muessen
lueckenlos aneinanderstossen, keiner doppelt, keiner dazwischen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
woher sie kommt
Die Meldung nach einem Abruf zaehlte geprueft, neu und unklar – aber nicht
"schon bekannt". Wurden alle Treffer beim vorigen Abruf schon uebernommen,
stand da "0 neu", und es sah aus, als waere nichts passiert, obwohl die
Eintraege im Eingang liegen. Die Zahl steht jetzt dabei.
Und die uebergangenen Mails wurden aufgelistet, die unklaren nicht: nur eine
Zahl, ohne zu sagen, welche Mail gemeint ist oder was ihr fehlt. Jetzt stehen
sie mit Grund da – kein Konto zugeordnet, kein Betrag erkannt, Richtung unklar,
Zahlung noch nicht ausgefuehrt.
Ausserdem traegt jede Buchung jetzt ihre Herkunft: Bank, Mail, Kurzbefehl,
Datei-Import oder von Hand. In der Buchungsliste steht sie als kleines
Kennzeichen unter dem Text. Ermittelt wird sie mit einer Sammelabfrage, nicht
je Zeile.
Bei einem Uebertrag zeigen zwei Eingangs-Eintraege auf dieselbe Buchung; die
Gegenseite hat Certain selbst angelegt, gemeint ist die echte Quelle. Genau
dafuer gibt es einen Test.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Zeitstempel des letzten Abrufs wird auch dann gesetzt, wenn ein Abruf
nichts fand – und danach sucht Certain nur noch ab gestern. Wer das Postfach
einrichtet, nachdem die Mails schon da waren, findet sie nie: Der erste,
ergebnislose Abruf schiebt das Fenster an ihnen vorbei.
Jetzt gibt es "Aelteres nachholen": Es sucht die letzten 90 Tage und uebergeht
den Zeitstempel. Dass dabei nichts doppelt ankommt, sichert wie bisher die
Message-ID.
Ausserdem sagt die Meldung jetzt, AB WANN gesucht wurde. Bisher stand dort
"Stimmt der Ordner?" – die Frage war fast immer die falsche.
Und ein latenter Fehler, der im August nicht auffaellt: Das Suchdatum wurde mit
strftime("%b") gebaut, also mit dem Monatskuerzel in der Sprache des Servers.
IMAP verlangt die englischen; auf einem deutschen System haette die Suche im
Maerz, Mai, Oktober und Dezember nichts gefunden. Die Kuerzel stehen jetzt fest
im Code.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein Franken-in-Euro-Tausch stand zweimal da: die CHF-Seite als Uebertrag nach
Revolut Euro, die EUR-Seite weiterhin als eigene Einnahme. Revolut Euro war
damit doppelt gutgeschrieben. Drei Fehler auf einmal.
Erstens prueft "zum Uebertrag machen" jetzt, ob die Buchung bereits mit ihrer
Gegenseite VERBUNDEN ist. Dann sind beide Seiten gebucht und zaehlen schon in
keiner Auswertung; ein Uebertrag bewegt das Geld auf dem Zielkonto ein zweites
Mal. Das laesst sich auch nicht mit "trotzdem" wegdruecken – es ist nicht
Ansichtssache.
Zweitens wird auf dem Zielkonto nach einer passenden gebuchten Gegenseite
gesehen, auch ohne Verknuepfung: gleiche Tage, passender Betrag, ueber
Waehrungen hinweg mit Spielraum. Findet sich eine, kommt die Warnung samt dem
richtigen Weg – die beiden verbinden statt einen Uebertrag anzulegen. Der
Treffer ist unscharf, deshalb hier mit "trotzdem" uebergehbar.
Drittens der beobachtete Punkt: Der nachtraegliche Weg reichte den
Eingangs-Eintrag nicht durch und rechnete deshalb IMMER mit dem EZB-Kurs, auch
wenn die Bank ihren eigenen genannt hatte. Jetzt wird er nachgeschlagen, und
der Kurs der Bank landet an der Buchung.
Und Loeschen raeumt die Eingangs-Eintraege mit. Der Fremdschluessel setzt sonst
nur ihre Verweisspalte auf NULL, und sie blieben als "gebucht" ohne Buchung
stehen – bei einem Uebertrag sind das zwei.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
'Eingang' und 'Offene Buchungen' zeigten fast dasselbe. Seit angebundene Konten
selbst buchen, ist eine Bank-Buchung sofort gebucht und ohne Kategorie – sie
stand damit in BEIDEN Listen. Die Trennung stammte aus der Zeit, als der
Eingang nur Vorschlaege enthielt.
Jetzt eine Seite 'Zu erledigen' mit allem, was noch eine Hand braucht: offene
Vorschlaege zum Buchen oder Uebertragen und Buchungen ohne Kategorie, egal ob
von Bank, Mail, Kurzbefehl oder Datei. Aelteste zuerst, mit der Herkunft in der
Zeile. Erledigtes verschwindet – die Eingangs-Eintraege bleiben in der
Datenbank, weil der spaetere Import gegen sie abgleicht. /offen leitet um.
Das Haekchen 'Schlagwort merken' aus der alten Seite bleibt: Es ist der Grund,
warum der Stapel mit der Zeit kleiner wird, und der Eingang hatte es nie. Der
Uebertrags-Knopf gilt jetzt auch fuer schon gebuchte Buchungen – sonst haette
in einer gemeinsamen Liste die eine Haelfte der Zeilen ihn gehabt und die
andere nicht.
In der Buchungsliste steht die Kategorie jetzt als Auswahl in der Zeile, dort
wo bisher nur ihr Name stand. Vorher musste man jede Buchung einzeln zum
Bearbeiten oeffnen. Die Zeile aendert sich an Ort und Stelle, die
Bildlaufposition bleibt.
Ausserdem tragen API-Antworten jetzt 'Cache-Control: no-store'. Ohne das darf
ein Browser selbst entscheiden, und der Zurueck-Knopf zeigt Salden von vorhin –
bei Geld ist eine veraltete Anzeige schlimmer als eine langsame.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bei einer Fremdwaehrungs-Zahlung nennt die Bank oft ihren echten Kurs und den
Betrag in der Ausgangswaehrung. Certain warf das weg und naeherte mit dem
EZB-Kurs. Das faellt genau dort auf, wo es teuer ist: Die spaeter gelieferte
Gegenseite eines Uebertrags laesst sich mit einem geschaetzten Betrag nicht als
dieselbe Bewegung wiedererkennen.
Der Uebertrag waehlt jetzt in drei Stufen: der von der Bank genannte
Gegenbetrag (exakt), sonst ihr Kurs, sonst die EZB. Nur die erste Stufe gilt
als bekannt – daran haengt, ob bei einem angebundenen Zielkonto nachgefragt
wird.
Der Parser klopft mehrere Formen ab, weil die Feldnamen je Anbindung
verschieden sind, und setzt still nichts, wenn keine passt. Keine dieser Formen
ist gegen echte Daten geprueft; ein falscher Kurs saehe aus wie ein richtiger,
deshalb wird lieber gar keiner gesetzt.
Ausserdem ein Knopf auf der Kontenseite: den Saldo der Bank als richtig
uebernehmen. Die Differenz wandert in den ANFANGSBESTAND – sie steht fuer
Bewegungen, die Certain nie gesehen hat, und genau dafuer ist er da. Eine
Korrekturbuchung stuende dagegen fuer immer in der Liste und liefe durch jede
Auswertung. Die Buchungen bleiben unangetastet.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein Uebertrag legte auf dem Zielkonto nichts an. Der Duplikatschutz konnte die
Gegenseite deshalb nicht sehen – er vergleicht import_hash, den eine
Uebertrags-Buchung nicht hat, und Eingangs-Eintraege, die es dort nicht gab.
Die schon vorliegende Gegenseite liess sich ein zweites Mal buchen, die
spaeter von der Bank gelieferte kam ungeprueft an: das Geld zweimal auf dem
Zielkonto.
Jetzt entsteht auf dem Zielkonto ein Eingangs-Eintrag, der auf DIESELBE Buchung
zeigt. Liegt dort schon ein passender offener Eintrag, wird dieser verbraucht
statt einen zweiten anzulegen – ueber denselben Abgleich wie beim Import, nicht
ueber eine zweite Vergleichslogik. Damit greift auch der vorhandene Schutz
gegen die spaeter eintreffende Gegenseite, ohne dass etwas Neues dafuer gebaut
werden musste.
Die Uebertrags-Logik liegt dafuer in einem eigenen Dienst. Zwei Wege fuehren
hinein – ein offener Vorschlag und eine schon gebuchte Buchung – und beide
brauchen dieselben vier Regeln. Der PATCH-Weg des Buchungs-Routers taete es
nicht: Er dreht die Richtung bei einer Einnahme nicht um und legt keine
Gegenseite an.
Die Sperre richtet sich nicht mehr nach der Waehrung, sondern danach, ob der
Betrag der Gegenseite BEKANNT oder geschaetzt ist. Bei gleicher Waehrung ist er
exakt, die Gegenseite wird sicher wiedererkannt – dann geht ein Uebertrag auf
ein angebundenes Konto ohne Nachfrage durch. Ueber Waehrungen hinweg bleibt die
Warnung, weil der EZB-Kurs nicht der Kurs der Bank ist.
Und Verwerfen raeumt beide Seiten: Bei einem Uebertrag zeigen zwei Eintraege
auf dieselbe Buchung, und der Fremdschluessel haette die andere als 'gebucht'
ohne Buchung zurueckgelassen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Zeile im Eingang zeigte die Kategorie-Auswahl bedingungslos – auch bei
einem Kontouebertrag, der gar keine bekommt. Die Oberflaeche konnte es auch
nicht wissen: InboxItemOut hatte kein Feld, an dem sich ein Uebertrag
erkennen laesst.
Jetzt liefert der Eintrag transfer_account_id mit – das jeweils ANDERE
Konto, aus seiner Sicht. Steht es, zeigt die Zeile '↔ Kontoname' statt der
Auswahl. Ermittelt wird es mit einer Sammelabfrage, nicht je Zeile: Die Liste
geht bis 200 Eintraege.
Dazu die Luecke dahinter: set_category schrieb die Kategorie auch auf die
Buchung und konnte sie so auf einem TxnType.transfer ablegen – genau das,
was das Buchungsformular beim Anlegen verhindert. Bei einem Uebertrag lehnt
der Endpunkt jetzt ab; bei allem anderen bleibt es, wie es war.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Drei Sachen an der Bankanbindung.
'Umsaetze holen' lief ueber alle Konten einer Verbindung. Seit angebundene
Konten selbst buchen, ist ein Klick damit folgenreich: Er bucht auf zwei
Konten. Der Knopf sitzt jetzt in der Kontozeile; an der Verbindung bleibt
'Alle Konten holen'.
Dabei musste der Zeitstempel mitwandern. last_sync_at hing an der
Verbindung – ein Einzelabruf haette damit das Startdatum der uebrigen Konten
mit vorgeschoben, und deren Umsaetze aus dem uebersprungenen Zeitraum waeren
nie angekommen. Der Stempel gehoert an das Konto, das abgerufen wurde.
Neu ist ein Takt je Verbindung, nach demselben Muster wie beim Postfach: ein
Hintergrund-Thread, der jede Minute nachsieht, ob etwas faellig ist. Bewusst
ein eigener Thread – ein haengender Bankzugang darf den Mail-Abruf nicht
mitreissen. Die Vorgabe ist 0, also aus: Anders als beim Mail-Abruf entstehen
hier Buchungen, das laeuft nicht ungefragt los. Schlaegt ein Abruf fehl, wird
der Stempel trotzdem gesetzt, sonst liefe die Verbindung jede Minute in
denselben Fehler.
Und die Abschnitte heissen jetzt 'Bankkonten Anbindung' und 'Mail Import'.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bisher blieb im Eingang nur, eine Umbuchung als Ausgabe oder Einnahme zu
kategorisieren. Sie zaehlte dann als Ausgabe, obwohl kein Geld weg ist – nur
verschoben.
Jetzt gibt es je Vorschlag den Weg 'Als Uebertrag buchen': Zielkonto waehlen,
fertig. Es entsteht EINE Buchung, die beide Salden bewegt und in keiner
Auswertung zaehlt. Die Richtung kommt aus dem Vorzeichen – ein Abgang geht von
hier weg, ein Zugang kommt vom Gegenkonto her; entsprechend fragt der Dialog
'wohin' oder 'woher'. Bei verschiedenen Waehrungen wird die Seite exakt
gesetzt, die wir wirklich kennen, und die andere umgerechnet.
Der teuerste Fehler an dieser Stelle waere ein Zielkonto, das selbst an einer
Bank haengt: Es meldet den Zugang von allein, eine Gegenbuchung hier haette das
Geld zweimal. Der Server lehnt das mit einer Begruendung ab; wer es besser
weiss, bestaetigt und kommt durch. Das Wissen bleibt an einer Stelle – die
Oberflaeche fragt nicht selbst nach, sie zeigt die Antwort des Servers.
Die Betragslogik ist dafuer aus dem Buchungs-Router in einen Dienst gewandert.
Zwei Kopien derselben Umrechnung waeren genau die Stelle, an der Salden
auseinanderlaufen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bisher legte der Bankabruf Vorschlaege in den Eingang, die man von Hand buchen
musste. Ein angebundenes Konto ist aber die Quelle der Wahrheit: Was die Bank
gebucht hat, IST gebucht. Jetzt wird es sofort gebucht; uebrig bleibt das
Zuordnen der Kategorie.
Drei Dinge mussten dafuer stimmen, sonst haette es Salden verfaelscht:
- Der erste Abruf greift nicht mehr hinter die neueste vorhandene Buchung des
Kontos zurueck. Vorher holte er neunzig Tage – mitten in Monate, die schon
per CSV eingelesen sind. Der Duplikatschutz haette die nicht gefunden: Sein
Schluessel enthaelt den Empfaengertext, und der lautet bei der Bank anders
als im Kontoauszug. Das Startdatum steht in der Rueckmeldung.
- Vorgemerkte Umsaetze werden nicht gebucht. Sie kommen spaeter noch einmal,
dann mit anderer Kennung, weil die Bank beim Buchen eine neue vergibt.
Beides zu nehmen hiesse doppelt buchen. Ihre Zahl wird gemeldet, nicht
verschwiegen.
- Nach dem Buchen wird nach Uebertraegen gesucht. Ein Uebertrag zwischen zwei
angebundenen Konten kommt in EINEM Abruf an – beide Seiten.
Nebenbei schliesst das eine bestehende Luecke: Der Eingangs-Abgleich beim
CSV-Import sieht nur gebuchte Eintraege. Solange Bank-Vorschlaege unbeachtet
liegen blieben, haette ein spaeterer Import derselben Wochen sie verdoppelt.
Das Buchen aus dem Eingang ist dafuer vom Router in einen Dienst gewandert;
zwei Kopien derselben Umrechnung waeren genau die Stelle, an der Salden
auseinanderlaufen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Uebertrags-Dienst und seine fuenf Endpunkte gab es seit Wochen – ohne
einen einzigen Aufrufer in der Oberflaeche. Man konnte also nirgends sagen,
dass zwei Buchungen derselbe Uebertrag sind, und eine gefundene Verknuepfung
auch nicht wieder loesen.
Jetzt: eine Karte "Moegliche Uebertraege" im Eingang mit beiden Seiten
nebeneinander, Verbinden und Ignorieren; in der Buchungsliste eine Marke mit
dem Gegenkonto und ein Knopf zum Loesen. Das Gegenkonto kommt vom Server mit –
die andere Buchung steht oft gar nicht in der gefilterten Liste, und
"Uebertrag" ohne Angabe wohin sagt nichts.
Ausserdem wird nach dem Buchen aus dem Eingang nach Uebertraegen gesucht, so
wie bisher nur nach einem Import. Seit die Bankanbindung ihre Umsaetze in den
Eingang legt, entsteht die Gegenseite naemlich erst dort; ohne diesen Aufruf
wuerde sie nie gefunden. Ein Fehler dabei kippt das Buchen nicht.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Certain rechnet den Saldo bisher ausschliesslich selbst aus: Anfangsbestand
plus alle Buchungen. Stimmt eine Buchung nicht, faellt das erst auf, wenn man
von Hand mit dem Auszug vergleicht.
Der von der Bank gemeldete Saldo wird jetzt mitgefuehrt und danebengestellt.
Weicht er ab, fehlt oder doppelt eine Buchung – und man sieht es auf der
Kontenseite und in den Einstellungen sofort, statt es zu suchen.
Banken melden mehrere Saldi nebeneinander; ausgewaehlt wird der gebuchte, denn
nur der ist mit Certains Rechnung vergleichbar. Ein verfuegbarer Saldo enthaelt
Vorgemerktes oder einen Ueberziehungsrahmen.
Die Saldi kommen auch fuer noch nicht zugeordnete Konten: Bei mehreren
Revolut-Pockets ist der Betrag oft das Einzige, woran man sie unterscheidet.
Ein Fehler bei einem Konto beendet den Durchlauf nicht.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein Revolut-Pocket bringt weder eigene IBAN noch eigenen Namen mit. Certain
hielt bisher nur uid, IBAN, Name und Waehrung fest – mehrere Konten derselben
Bank sahen damit gleich aus, und in der Zeile stand die rohe Kennung.
Jetzt werden Produktbezeichnung und die Kennung fuer Konten ohne IBAN
mitgefuehrt, der angezeigte Name faellt der Reihe nach auf Name, Details,
Produkt, Kennung, IBAN zurueck statt auf die uid, und der uebermittelte
Datensatz laesst sich aufklappen – nachsehen statt raten, wenn zwei Konten
gleich aussehen. Beim Neuverbinden werden die Merkmale aufgefrischt, ohne die
Zuordnung anzutasten.
Fehlt ein Konto in der Waehrung des Bankkontos, steht das jetzt dabei; vorher
war die Auswahl einfach leer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Um eine Verbindung aufzufrischen – etwa nachdem man im Control Panel weitere
Konten verknuepft hat – haette man sie bisher erst loeschen muessen. Dabei
gehen die Kontozuordnungen mit verloren, also genau das, was man behalten
will; ein zweiter Verbindungsversuch haette sonst einen doppelten Eintrag
erzeugt.
Jetzt frischt das Verbinden derselben Bank den bestehenden Eintrag auf: neue
Sitzung, neue Konten, bestehende Zuordnungen bleiben. Der Warntext beim
Trennen sagt ausserdem, dass Trennen dafuer gar nicht noetig ist.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Drei verschiedene Faelle sahen alle gleich aus: Die Bank schickte nichts, sie
schickte Eintraege ohne Kennung (die still verworfen wurden), oder alle Konten
waren schon bekannt – Letzteres meldete faelschlich "0 Konten", obwohl alles
in Ordnung war.
Die Antwort unterscheidet jetzt uebermittelt / neu / bekannt / ohne_kennung.
Die Rueckkehr-Seite zeigt bei null nutzbaren Konten den passenden Hinweis: Im
eingeschraenkten Betrieb gibt eine Bank nur heraus, was zuvor im Control Panel
unter "Activate by linking accounts" verknuepft wurde.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Fehler, den der Nutzer gefunden hat: Die Suche nach "n" lieferte
"genau 200" Treffer und darunter nie N26. Ursache war die Reihenfolge –
alphabetisch sortiert und ERST DANN bei 200 gekuerzt. "N26" liegt hinter
"Aachener Bank", fiel also hinter zweihundert Banken heraus, die irgendwo
ein n im Namen tragen. Die Bank war die ganze Zeit da.
Jetzt wird zuerst bewertet (genauer Name > Namensanfang > Wortanfang >
Teiltreffer > nur BIC/Gruppe) und erst danach gekuerzt. Ausserdem wird die
ECHTE Trefferzahl gemeldet statt der gekuerzten – "genau 200" sah aus wie ein
Suchergebnis, war aber die Obergrenze.
Ein Regressionstest stellt den Fall nach: 300 Banken mit "n" im Namen,
alphabetisch vor N26. Ohne den Fix faellt er um.
Nebenbei geprueft und ausgeschlossen: /aspsps blaettert nicht, die Liste ist
also vollstaendig; Sandbox und alphabetische Kuerzung waren es auch nicht.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Liste ist nicht abgeschnitten – sie reicht von "Aachener Bank" bis
"Oelands Bank" und enthaelt N und R. Damit sind beide bisherigen Vermutungen
widerlegt (Sandbox, alphabetisch gekuerzt), und Raten ueber Namensvarianten
bringt nichts mehr.
Bleibt die Suche ohne Treffer, stehen jetzt alle Eintraege mit demselben
Anfangsbuchstaben da. Damit ist auf einen Blick zu sehen, ob die Bank unter
einem anderen Namen gefuehrt wird – oder ob sie in diesen 815 von ueber 2500
schlicht fehlt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
815 geladene Banken bei ueber 2500 verfuegbaren, und alle Beispiele beginnen
mit A oder B – das deutet auf eine abgeschnittene Liste, nicht auf einen
falschen Suchbegriff. Die Sandbox-Vermutung ist damit widerlegt: "Aachener
Bank" und "BBVA" sind echte Institute.
Die Antwort nennt jetzt den Bereich von/bis und alle vorhandenen
Anfangsbuchstaben. Fehlen N und R, ist die Sache entschieden und die Abfrage
braucht Blaettern – dann suche ich nicht laenger am falschen Ende.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
N26 und Revolut sind bei Enable Banking abgedeckt – in 31 Laendern, unter
genau diesen Namen. Wer sie trotzdem nicht findet, bekommt die falsche Liste,
und der haeufigste Grund ist eine als Sandbox statt Production angelegte
Anwendung: Dann kommen Test-Institute, man sieht also Banken, nur nicht die
echten.
Bleibt die Suche ohne Treffer, stehen jetzt acht Beispiele aus der geladenen
Liste da. Sind das lauter Mock-Institute, ist die Ursache auf einen Blick zu
sehen statt nach Namensvarianten zu raten.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bei der Bank-Suche kam nur "Keine Treffer" – das hiess zweierlei: Die
Schnittstelle lieferte gar keine Liste, oder sie lieferte eine und der
Suchbegriff passte nicht. Beides sieht gleich aus, fuehrt aber an ganz
verschiedene Stellen. Genau diese Verwechslung hat heute schon zweimal Zeit
gekostet.
Die Antwort traegt jetzt die Gesamtzahl mit. Kam nichts, steht der
wahrscheinliche Grund dabei: Die Anwendung bei Enable Banking wird erst
aktiv, wenn man dort die eigenen Konten verknuepft hat.
Ausserdem wird breiter gesucht – auch in BIC und Gruppenname, weil Banken in
so einer Liste nicht immer so heissen wie im Alltag – und die Antwort wird
defensiv gelesen, falls die Liste ohne Schluessel kommt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Unter "Deutschland" liessen sich N26 und Revolut nicht finden – und bei
Revolut kann das gar nicht klappen: Die Bank vergibt deutsche IBANs, ist aber
die Revolut Bank UAB in Litauen. Das Sitzland einer Bank steht nicht in der
IBAN, also ist die Laenderauswahl der falsche Einstieg.
Jetzt ein Suchfeld, das ohne Land ueber alle sucht; das Land ist nur noch ein
optionaler Filter. Der Treffer zeigt sein Land mit an, und verbunden wird mit
dem Land der BANK statt dem des Filters – sonst schluege die Autorisierung
fehl, sobald ohne Land gesucht wurde.
Ohne Land UND ohne Begriff wird abgelehnt: Sonst kaemen alle Banken Europas
ins Formular.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Seit PSD2 muessen EU-Banken eine Schnittstelle anbieten, aber nur fuer
lizenzierte Dienste mit eIDAS-Zertifikat. Enable Banking haelt die Lizenz und
reicht sie weiter: eigene Anwendung registrieren, eigene Konten verknuepfen,
danach genau diese lesen. Deckt N26 und Revolut ab; die Schweiz faellt nicht
unter PSD2, Raiffeisen bleibt beim CSV-Weg.
Es gibt keinen API-Schluessel. Jede Anfrage traegt ein selbst gebautes JWT,
signiert mit dem privaten Schluessel der Anwendung (RS256). Signiert wird mit
cryptography, das ohnehin schon fuer die Verschluesselung im Projekt ist – der
Test prueft die Signatur echt gegen den oeffentlichen Schluessel, denn genau
daran scheitert so eine Anbindung sonst als Erstes.
Abgerufene Umsaetze werden NICHT gebucht. Sie laufen durch detect_rows und
landen als Vorschlag im Eingang – dieselbe Strecke wie Mail und Kurzbefehl,
also greifen Duplikatschutz und Schlagwortregeln ohne Sonderbehandlung. Eine
dritte Quelle, kein dritter Sonderweg.
Bewusst eng gehalten: nur Lesen; Zuordnung Bankkonto -> Konto trifft der
Nutzer; die Zuordnung verlangt dieselbe Waehrung; die Rueckleitungs-Adresse
wird eingetragen statt geraten (hinter einem Proxy sieht der Dienst "http",
obwohl der Browser HTTPS spricht) und muss HTTPS sein.
Der Ablauf der Zustimmung (bis 180 Tage) wird sichtbar gemeldet, damit der
Abruf nicht eines Tages stumm aufhoert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sieben nutzereigene Tabellen aus den Migrationen 0015-0020 standen in keiner
Backup-Liste. Am schwersten wiegt inbox_items: Der Eingang haelt fest, welche
Zahlungen von aussen schon erfasst wurden. Fehlt er nach dem Wiedereinspielen,
erkennt der naechste Kontoauszug sie nicht wieder und bucht sie ein zweites
Mal – genau der Fehler, den die Tabelle verhindern soll.
Aufgenommen: inbox_items, transfer_links, link_ignored, api_tokens.
Bewusst nicht: mail_sources/mail_senders (tragen das verschluesselte
IMAP-Passwort; ein Backup ist eine Datei, die man herumreicht) und
pending_uploads (fluechtige Rohdateien). Beides steht begruendet im Code.
Ein Test laeuft jetzt ueber Base.registry und fordert fuer jedes Modell mit
owner_id eine bewusste Entscheidung – sichern oder begruendet ausnehmen.
Genau diese Pruefung fehlte, weshalb die sieben unbemerkt durchrutschten.
Dazu der tote Code aus dem Transfer-Ausbau: is_counterpart und braucht_ziel
waren feste False, _apply_counterpart_amount damit unerreichbar. Die Tests
sichern dieselbe Garantie jetzt ueber das tatsaechliche Verhalten.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein Uebertrag steht in zwei Auszuegen und wird zweimal gebucht – richtig fuer
die Salden, aber er zaehlt als Ausgabe UND als Einnahme in der Auswertung.
Statt beide zu einer Uebertrags-Buchung zusammenzufuehren (der urspruengliche
Plan) legt Certain nur eine Schicht darueber: transfer_links haelt fest, dass
zwei Buchungen zusammengehoeren. An den Buchungen selbst aendert sich nichts –
Betrag, Konto, Kategorie, Import-Schluessel und Stapel bleiben.
Das haelt alles heraus, was am Zusammenfuehren haette brechen koennen: der
Duplikatschutz verliert keinen Schluessel, undo_batch reisst keine Gegenseite
mit, und eine falsche Paarung ist ein Etikett, das man abzieht.
Die Auswertung ueberspringt verknuepfte Buchungen – nicht umkategorisiert:
Loest man die Verknuepfung, zaehlt die Buchung mit ihrer alten Kategorie
sofort wieder mit.
Automatisch nur, wenn die Zuordnung zwingend ist UND keine Seite eine
Kategorie traegt UND der Text auf einen Uebertrag hindeutet. Sonst Vorschlag.
Waehrungswechsel werden ueber den EZB-Kurs des Tages geprueft (2,5 % Toleranz
fuer den Bankaufschlag) – der Kurs dient nur als Pruefung, gespeichert wird
nichts davon.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bisher brauchte es je Konto einen eigenen Kurzbefehl, weil account_id
Pflicht war. Jetzt ist sie optional: Raiffeisen fuehrt die eigene IBAN in der
Datei mit (Treffer gegen die Erkennungs-Texte der Konten), Revolut die
Waehrung – zusammen mit der erkannten Bank und dem Import-Verlauf reicht das.
Bleibt es mehrdeutig, wird NICHT geraten: Ein Auszug im falschen Konto
verfaelscht zwei Salden auf einmal. Stattdessen nennt die Fehlermeldung die
Konten samt Nummern, sodass man sie im Kurzbefehl nachtragen kann. Hat der
Schluessel ein Standardkonto, gilt das.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Kurzbefehl zeigt das Feld "message" an. Fehlerantworten liefern aber
"detail" – die Mitteilung auf dem Telefon blieb also leer. Man sah nicht
einmal, DASS etwas schiefging: Die Marke wurde als benutzt vermerkt, auf dem
Server kam trotzdem nichts an, und die Ursache war von aussen unsichtbar.
Antworten unter /api/quick liefern jetzt zusaetzlich "message" mit einem
lesbaren Text. Bei fehlenden Pflichtfeldern nennt er sie beim Namen und
erinnert daran, dass der Anfragetext beim Datei-Kurzbefehl 'Formular' sein
muss.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bisher musste man bei jedem Import Trennzeichen, Datumsformat und
Spaltenzuordnung von Hand eintragen – die haeufigste Fehlerquelle ueberhaupt:
Ein falsches Datumsformat liess alle Zeilen durchfallen, ein falscher
Dezimaltrenner verzehnfachte Betraege.
Zuerst wird gegen die Bank-Vorlagen geprueft (Kopfzeilen-Signatur); alle vier
echten Ausaege des Nutzers werden so sicher erkannt. Sonst inhaltsbasiert:
welche Spalte enthaelt Daten, welche Betraege, welche den laengsten Text.
Zwei Fallen, die dabei aufgefallen sind und getestet werden:
- Deutsche Datumsangaben stecken voller Punkte, und viele Auszuege fuehren
Buchungs- UND Valutadatum. Ohne sie herauszurechnen kaeme "." als
Dezimalzeichen heraus und aus 1.204,70 wuerden 1.20.
- parse_date ist absichtlich nachsichtig; beim Erkennen darf es das nicht
sein, sonst gewinnt ein Format mit Uhrzeit gegen das richtige ohne.
Ganzzahlen ohne Vorzeichen zaehlen nur halb, damit Referenznummern und Kurse
nicht als Betragsspalte durchgehen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>