fix: Ein Saldo-Abgleich, der nicht mehr gilt, sagt das jetzt

Der Abgleich wird einmal serverseitig gerechnet, beim Erzeugen der
Vorschau. Wer danach eine Zeile von Hand umstellt, erreicht ihn nicht –
das gruene "stimmt" blieb stehen, obwohl es sich auf eine andere
Leserichtung bezog.

Mit der neuen Sammelaktion "Richtung umdrehen" waere das leicht
passiert: ein Klick, und die Bestaetigung darueber stimmt nicht mehr.

Nachgerechnet wird nicht – das waere eine zweite Wahrheit neben der
ersten. Stattdessen sagt der Hinweis, dass seine Aussage veraltet ist.
Beim Einlesen kommt die Art aus dem Vorzeichen; jede Abweichung ist
also nachweislich eine Handaenderung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-30 20:59:48 +02:00
co-authored by Claude Opus 5
parent 2891270ac2
commit 35c5d2c84a
3 changed files with 20 additions and 3 deletions
+1
View File
@@ -479,6 +479,7 @@
"skipCurrency": "andere Währung", "skipCurrency": "andere Währung",
"colBalance": "Kontostand (laufend)", "colBalance": "Kontostand (laufend)",
"reconOk": "Saldo-Abgleich stimmt: alle {{n}} Schritte passen zur Kontostand-Spalte der Datei.", "reconOk": "Saldo-Abgleich stimmt: alle {{n}} Schritte passen zur Kontostand-Spalte der Datei.",
"reconStale": "Der Saldo-Abgleich gilt für die ursprünglich gelesene Richtung. Seitdem wurden Zeilen von Hand umgestellt – er sagt über den jetzigen Stand nichts mehr.",
"reconDiff": "Der Kontostand geht nicht auf. Die Datei endet bei {{file}}, aus den Zeilen errechnet sich aber {{app}} – es fehlen bzw. sind {{diff}} zu viel.", "reconDiff": "Der Kontostand geht nicht auf. Die Datei endet bei {{file}}, aus den Zeilen errechnet sich aber {{app}} – es fehlen bzw. sind {{diff}} zu viel.",
"reconFirst": "Ab dem {{date}} laufen beide auseinander, bei „{{payee}}“: Die Kontostand-Spalte der Datei springt um {{expected}}, die Zeile selbst weist {{actual}} aus.", "reconFirst": "Ab dem {{date}} laufen beide auseinander, bei „{{payee}}“: Die Kontostand-Spalte der Datei springt um {{expected}}, die Zeile selbst weist {{actual}} aus.",
"reconOpening": "Vor der ersten Zeile stand die Datei bei {{value}}. Trage das beim Konto als Anfangssaldo ein, mit einem Stichtag am Tag davor.", "reconOpening": "Vor der ersten Zeile stand die Datei bei {{value}}. Trage das beim Konto als Anfangssaldo ein, mit einem Stichtag am Tag davor.",
+1
View File
@@ -479,6 +479,7 @@
"skipCurrency": "other currency", "skipCurrency": "other currency",
"colBalance": "Balance (running)", "colBalance": "Balance (running)",
"reconOk": "Balance check passes: all {{n}} steps match the file's balance column.", "reconOk": "Balance check passes: all {{n}} steps match the file's balance column.",
"reconStale": "The balance check applies to the direction originally read. Rows have been changed by hand since — it no longer says anything about the current state.",
"reconDiff": "The balance doesn't add up. The file ends at {{file}}, but the rows add up to {{app}} – {{diff}} missing or too much.", "reconDiff": "The balance doesn't add up. The file ends at {{file}}, but the rows add up to {{app}} – {{diff}} missing or too much.",
"reconFirst": "They start to diverge on {{date}} at “{{payee}}”: the file's balance column moves by {{expected}}, while the row itself states {{actual}}.", "reconFirst": "They start to diverge on {{date}} at “{{payee}}”: the file's balance column moves by {{expected}}, while the row itself states {{actual}}.",
"reconOpening": "Before the first row the file stood at {{value}}. Enter that as the account's opening balance, dated the day before.", "reconOpening": "Before the first row the file stood at {{value}}. Enter that as the account's opening balance, dated the day before.",
+18 -3
View File
@@ -390,6 +390,18 @@ export default function Import() {
const includeCount = rows ? rows.filter((r) => r.include).length : 0; const includeCount = rows ? rows.filter((r) => r.include).length : 0;
// Der Saldo-Abgleich wird EINMAL serverseitig gerechnet, beim Erzeugen der
// Vorschau. Eine von Hand geaenderte Richtung erreicht ihn nicht – das
// gruene „stimmt" bliebe stehen, obwohl es nicht mehr gilt.
//
// Nachrechnen waere die zweite Wahrheit neben der ersten. Stattdessen sagen
// wir, dass die Aussage veraltet ist: Beim Parsen kommt die Art aus dem
// Vorzeichen, jede Abweichung ist also eine Handaenderung.
const abgleichVeraltet = (rows || []).some(
(r) => r.include && r.valid && r.type !== "transfer"
&& Math.sign(r.amount_cents || 0) !== richtung(r),
);
// Summe je Richtung ueber die Zeilen, die wirklich gebucht werden. // Summe je Richtung ueber die Zeilen, die wirklich gebucht werden.
// //
// Eine gespiegelte Datei sieht man daran auf einen Blick: Ein Kartenauszug // Eine gespiegelte Datei sieht man daran auf einen Blick: Ein Kartenauszug
@@ -935,10 +947,13 @@ export default function Import() {
</div> </div>
)} )}
{recon?.available && ( {recon?.available && (
<div className={`alert ${recon.ok ? "ok" : "error"}`} style={{ marginBottom: "var(--sp-3)" }}> <div className={`alert ${abgleichVeraltet ? "" : recon.ok ? "ok" : "error"}`}
<Icon name={recon.ok ? "check" : "alert"} size={16} /> style={{ marginBottom: "var(--sp-3)" }}>
<Icon name={abgleichVeraltet ? "alert" : recon.ok ? "check" : "alert"} size={16} />
<div> <div>
{recon.ok ? ( {abgleichVeraltet ? (
<span>{t("import.reconStale")}</span>
) : recon.ok ? (
<span>{t("import.reconOk", { n: recon.checked })}</span> <span>{t("import.reconOk", { n: recon.checked })}</span>
) : ( ) : (
<> <>