Neuer Schalter „Ohne Bargeld-Abgleich“ in der Buchungsmaske für Sammelbuchungen und Differenzausgleiche. Solche Buchungen werden nicht gegen das Bargeld-Tool geprüft, ein früherer Status wird gelöscht, und sie erscheinen nicht mehr unter den offenen Vorgängen im Cockpit. Kontoblatt und Buchungsbericht zeigen einen leeren grauen Kreis. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
355 lines
21 KiB
Markdown
355 lines
21 KiB
Markdown
# Buchungen
|
||
|
||
Kontoblatt, Buchungsmaske und die Saldenrechnung.
|
||
|
||
## Umbuchungen: ein Datensatz, zwei Sichten
|
||
|
||
Eine Umbuchung wird **einmal** gespeichert – als Buchung auf dem Ausgangskonto mit
|
||
`gegenkonto_id`. Das Kontoblatt des Gegenkontos zeigt sie mit umgekehrtem Vorzeichen.
|
||
|
||
Der Grund ist nicht nur Sparsamkeit: Zwei gespiegelte Datensätze laufen früher oder später
|
||
auseinander (einer wird geändert, der andere nicht). Und der QIF-Export macht es genauso –
|
||
dort steht jede Umbuchung genau einmal, die Gegenseite nur als `L[Zielkonto]`.
|
||
|
||
`Buchung::kontoblatt()` vereinigt deshalb drei Mengen:
|
||
|
||
1. Buchungen mit `konto_id = X` (eigene Sicht)
|
||
2. Buchungen mit `gegenkonto_id = X` ohne Splitzeilen, Betrag negiert
|
||
3. Splitzeilen mit `gegenkonto_id = X`, Betrag negiert
|
||
|
||
Zeilen aus 2 und 3 tragen `gegensicht = true`. Sie sind nicht bearbeitbar – das geht auf
|
||
dem Ursprungskonto –, damit eine Umbuchung nicht aus zwei Richtungen widersprüchlich
|
||
geändert wird.
|
||
|
||
**Beide Sichten nennen das Gegenüber.** In der Kategoriespalte steht das jeweils andere
|
||
Konto in eckigen Klammern: auf dem Ausgangskonto das Ziel, auf dem Gegenkonto das
|
||
Ursprungskonto. In der Gegensicht liefert die Abfrage dafür `b.konto_id` als
|
||
`gegenkonto_id` – dieselbe Spalte, aus der anderen Richtung gelesen. Ohne diese Angabe
|
||
stünde auf dem Gegenkonto eine Zeile, die sich „Umbuchung“ nennt und verschweigt, woher
|
||
sie kommt.
|
||
|
||
Dieselbe Dreiteilung gilt für die Salden (`Buchung::saldenJeKonto()`), die alle Konten mit
|
||
sechs Abfragen auf einmal berechnet statt je Konto einzeln.
|
||
|
||
## Mehrfachauswahl im Kontoblatt
|
||
|
||
Vor dem Datum steht je Zeile ein Ankreuzfeld, in der Titelzeile eines für alle gerade
|
||
angezeigten Buchungen. *Auswahl löschen* in der Aktionsleiste schickt die Auswahl an
|
||
`POST /konten/{id}/buchungen/loeschen`.
|
||
|
||
Zwei Punkte, die sich nicht ändern dürfen:
|
||
|
||
* Der Knopf steht **über** der Tabelle, die Ankreuzfelder stehen **in** ihr. Verbunden sind
|
||
sie über `form="buchungsauswahl"`, nicht über Verschachtelung – ein Formular um die ganze
|
||
Tabelle würde das Filterformular umschließen.
|
||
* Zeilen mit `gegensicht = true` bekommen kein Ankreuzfeld, und der Controller prüft
|
||
zusätzlich `konto_id`. Die Gegenseite einer fremden Umbuchung wird nur auf ihrem
|
||
Ursprungskonto gelöscht – dieselbe Regel wie beim Bearbeiten.
|
||
|
||
Filter und Seite hängen an der Abfragezeichenfolge des Formularziels. Der Controller baut
|
||
den Weg zurück aus den bekannten Feldern neu zusammen, statt ein mitgeschicktes Ziel zu
|
||
übernehmen; so lässt sich kein fremder Weiterleitungsort einschleusen.
|
||
|
||
## Kategorie und Gegenkonto in einem Feld
|
||
|
||
Eine Buchung ist entweder kategorisiert **oder** eine Umbuchung – beides zugleich gibt es
|
||
nicht. Deshalb stehen Kategorien und Konten in derselben Auswahlliste; die Konten unten,
|
||
in eckigen Klammern, wie das Kategoriefeld im FinanzManager sie schreibt. Das eigene Konto
|
||
fehlt in der Liste.
|
||
|
||
Die Liste steht in `Views/buchungen/zuordnungsliste.php`. Sie wird nicht nur in der
|
||
Buchungsmaske, deren Splitzeilen, der Schnellzuordnung im Kontoblatt und im Splitdialog
|
||
eingebunden, sondern überall, wo eine Kategorie gewählt wird (#124): Regeln samt ihren
|
||
Splitzeilen, Umsatzabgleich, Buchungsvorlagen, Regelmäßige Buchungen, Zahlungsverkehr und
|
||
Verträge. Die Werte tragen ein Präfix, das `BuchungenController::zuordnungAus()` wieder
|
||
auseinandernimmt (`zuordnungAusFormular()` nimmt ersatzweise die versteckten Einzelfelder
|
||
`kategorie_id`/`gegenkonto_id` einer Tabellenzeile, `zuordnungswert()` baut den Wert für die
|
||
Vorauswahl):
|
||
|
||
| Wert | Bedeutung |
|
||
|---|---|
|
||
| `` (leer) | keine Zuordnung |
|
||
| `kategorie:12` | Kategorie 12 |
|
||
| `konto:7` | Umbuchung mit Gegenkonto 7 |
|
||
| `split` | Splitdialog öffnen (nur im Kontoblatt) |
|
||
| `depot:7` | Wertpapiergeschäft im Depot 7 (Kontoblatt und Buchungsmaske) |
|
||
|
||
Die Auswahl *Ausgabe / Einnahme* bestimmt seither nur noch die Richtung des Betrags.
|
||
|
||
Angeboten werden nur **aktive** Umbuchungskonten, je Kontengruppe in einer eigenen Gruppe
|
||
(„Umbuchungskonten – Liquide Mittel“, ohne Kontengruppen schlicht „Umbuchungskonten“) und
|
||
in der Reihenfolge der Kontengruppen (`Konto::umbuchungsgruppen()`). Ein inaktives Konto,
|
||
das schon gewählt ist, bleibt sichtbar stehen – sonst ginge die Zuordnung beim nächsten
|
||
Speichern verloren. Alle übrigen inaktiven Konten stehen als verborgene Einträge
|
||
(`<option hidden>`) in der Liste, damit `kontoblatt.js` eine bestehende Splitzeile damit
|
||
vorbelegen kann; die Kombobox zeigt sie nur an, solange sie gewählt sind.
|
||
|
||
Die Filter von Buchungsbericht und Export führen die Umbuchungskonten ebenfalls unter den
|
||
Kategorien (siehe `docs/auswertungen.md` und `docs/import-export.md`).
|
||
|
||
Ein Depot steht **zweimal** in der Liste: als gewöhnliche Umbuchung (`konto:7`) und in der
|
||
Gruppe *Wertpapiergeschäft im Depot* (`depot:7`). Beides gibt es wirklich – auf ein Depot
|
||
lässt sich Geld überweisen, ohne dass etwas gekauft wird. `depot:7` speichert keine
|
||
Zuordnung, sondern öffnet die Wertpapiermaske; daraus wird am Ende meist eine Splitbuchung
|
||
(siehe `docs/wertpapiere.md`, *Geschäft aus einer Kontobuchung*). In den **Splitzeilen**
|
||
fehlt die Gruppe: Dort steht der Betrag der Zeile schon fest, und die Umbuchung ins Depot
|
||
ist genau das, was gebraucht wird.
|
||
|
||
## Schnellzuordnung im Kontoblatt
|
||
|
||
Ein Klick auf die Kategoriespalte öffnet die Liste in der Zelle; die Auswahl geht an
|
||
`POST /buchungen/{id}/zuordnung`, der Eintrag *Splitbuchung* öffnet stattdessen den
|
||
Splitdialog (`POST /buchungen/{id}/splitbuchung`). Beide Wege gehen über
|
||
`Buchung::zuordnen()` und `Buchung::splitsErsetzen()`, die den Rest der Buchung unberührt
|
||
lassen und den Monatsabschluss achten.
|
||
|
||
Drei Punkte, die sich nicht ändern dürfen:
|
||
|
||
* Die Auswahlliste gibt es **einmal**; `kontoblatt.js` hängt sie in die angeklickte Zelle
|
||
und danach zurück. Eine Liste je Zeile wären bei hundert Zeilen ebenso viele
|
||
vollständige Kategoriebäume im HTML.
|
||
* Ohne JavaScript führt derselbe Klick in die Buchungsmaske – die Zelle ist ein Link, kein
|
||
Knopf.
|
||
* Zeilen mit `gegensicht = true` führen zu ihrer Buchung, statt die Auswahl zu öffnen: Sie
|
||
werden auf ihrem Ursprungskonto geändert, wie beim Bearbeiten und Löschen.
|
||
`kontoblatt.js` erkennt sie an der Klasse `gegenseite`.
|
||
* Feld und Auswahlliste sind **gleich breit** (`13rem`), und die Zelle zeigt nichts an, was
|
||
nicht auch in der Liste stünde – kein „zuordnen …“. Sonst rückt beim Anklicken die halbe
|
||
Zeile: Die Spalte wüchse auf die Breite der längsten Kategorie, und der Empfänger daneben
|
||
bräche um. Senkrecht rückt nichts, weil die Zeilenhöhe ohnehin feststeht (siehe unten).
|
||
|
||
Die Auswahl eines Depots (`depot:7`) öffnet statt beider den **Wertpapierdialog**; ohne
|
||
JavaScript führt sie auf `/buchungen/{id}/wertpapier?depot=7`, wo dieselben Felder als
|
||
gewöhnliches Formular stehen. Auch die Buchungsmaske leitet dorthin, nachdem sie die
|
||
Buchung gespeichert hat.
|
||
|
||
Eine schon gesplittete Buchung öffnet auf Klick **direkt den Splitdialog**, nicht die
|
||
Auswahlliste: Deren einziger sinnvoller Eintrag wäre für sie ohnehin *Splitbuchung*
|
||
gewesen. Wer eine Aufteilung wieder in eine einzelne Zuordnung wandeln will, löscht sie
|
||
im Dialog und ordnet die dann unzugeordnete Buchung anschließend zu – oder geht über die
|
||
Buchungsmaske.
|
||
|
||
### Typeahead (Feature #41)
|
||
|
||
Sowohl der Kategorie-Filter oben im Kontoblatt als auch die Auswahlliste der
|
||
Schnellzuordnung tragen `data-kombobox`. `static/kombobox.js` baut ein so markiertes
|
||
`<select>` beim Laden der Seite in ein Eingabefeld mit darunter aufklappender, gefilterter
|
||
Liste um – Optgroups bleiben als Überschriften erhalten. Das ursprüngliche `<select>`
|
||
bleibt unsichtbar im Formular stehen, Wert, Name und `change`-Ereignis ändern sich nicht;
|
||
`kontoblatt.js` liest und setzt weiterhin nur `select.value`.
|
||
|
||
Beim Öffnen der Schnellzuordnung ruft `kontoblatt.js` `select._kombobox.oeffnen()` statt
|
||
`showPicker()` auf – ein verstecktes `<select>` ließe sich weder fokussieren noch mit
|
||
`showPicker()` öffnen. Die Klassen-Auswahl bleibt bewusst ein gewöhnliches `<select>` ohne
|
||
`data-kombobox`: Ihre Liste ist kurz, ein Typeahead brächte dort nichts.
|
||
|
||
## Klasse im Kontoblatt
|
||
|
||
Die Klassenspalte ist nach derselben Bauart anklickbar: eine zweite Liste
|
||
(`#klassenauswahl`), die `kontoblatt.js` in die angeklickte Zelle hängt. Ihr erster Eintrag
|
||
*— keine —* löscht die vorhandene Klasse, jeder andere setzt sie; gespeichert wird sofort
|
||
beim Anklicken, über `POST /buchungen/{id}/klasse` und `Buchung::klasseSetzen()`.
|
||
|
||
Die Klasse steht **neben** der Zuordnung, nicht in ihr: Sie ist die zweite
|
||
Auswertungsdimension. Anders als `Buchung::zuordnen()` rührt `klasseSetzen()` deshalb weder
|
||
Kategorie noch Gegenkonto noch Splitzeilen an – auch eine gesplittete Buchung bleibt beim
|
||
Wechsel der Klasse gesplittet. Den Monatsabschluss achtet die Methode wie alle anderen.
|
||
|
||
Bei einer **Splitbuchung** zählen die Klassen ihrer Zeilen (`Buchung::splitKlasse()`):
|
||
Tragen alle Zeilen dieselbe Klasse, steht sie in der Spalte; unterscheiden sie sich – eine
|
||
Zeile ohne Klasse zählt dabei als eigene Angabe –, steht dort die Marke *Splitbuchung*, und
|
||
der Tooltip nennt je Zeile Kategorie (oder Gegenkonto) und Klasse. Hat keine Zeile eine
|
||
Klasse, bleibt es bei der Klasse der Buchung selbst. Ein Klick auf die Klassenzelle einer
|
||
Splitbuchung öffnet den Splitdialog statt der Klassenliste (`data-split`): Dort stehen ihre
|
||
Klassen.
|
||
|
||
## Zeilenhöhe und Tooltips im Kontoblatt
|
||
|
||
Jede Buchungszeile ist **zwei Textzeilen hoch**, gleich wie viel in ihr steht, und ihr
|
||
Inhalt steht senkrecht in der Mitte. Eine Zeile, die mit ihrem Text wächst, ließe die Liste
|
||
beim Blättern hüpfen; eine, die auf eine Zeile schrumpft, machte lange Empfänger unlesbar.
|
||
Die Höhe hängt an `table.kontoblatt td`, das Abschneiden an `.zellentext` (zwei Zeilen,
|
||
danach Auslassungspunkte). Empfänger und Buchungstext stehen deshalb in einem `<div>` und
|
||
nicht unmittelbar in der Zelle: Abschneiden kann nur ein Element, das kein Tabellenfeld ist.
|
||
|
||
Die Marke der Umbuchungs-Gegenseite steht **neben** dem abgeschnittenen Kasten
|
||
(`.zellenreihe`), nicht darin – sonst zählte sie als eine der beiden Zeilen und die Zeile
|
||
würde höher als die übrigen.
|
||
|
||
Den vollständigen Text zeigt der Tooltip:
|
||
|
||
* **Empfänger und Buchungstext**: `kontoblatt.js` setzt den Tooltip nach dem Laden und nach
|
||
jeder Größenänderung des Fensters – aber nur dort, wo wirklich etwas abgeschnitten ist.
|
||
Ob das der Fall ist, weiß erst der Browser nach dem Umbruch, und das hängt an der
|
||
Fensterbreite. Ein Tooltip, der bloß wiederholt, was ohnehin dasteht, wäre lästig.
|
||
* **Kategorie und Klasse** tragen ihren Tooltip vom Server. Bei einer **Splitbuchung** nennt
|
||
er die Zeilen der Aufteilung: je Zeile Kategorie (oder Gegenkonto) und Betrag, sonst
|
||
nichts. Notiz und Klasse stünden nur im Weg; die Klassen nennt bei verschiedenen Klassen
|
||
der Tooltip der Klassenspalte (siehe oben).
|
||
|
||
## Splitbuchungen
|
||
|
||
Eine Buchung ist entweder einfach zugeordnet **oder** gesplittet. Sobald Splitzeilen
|
||
vorliegen, räumt das Model `kategorie_id` und `gegenkonto_id` der Buchung; die Zuordnung
|
||
steckt dann ausschließlich in den Zeilen.
|
||
|
||
Die Summe der Zeilen muss dem Buchungsbetrag entsprechen – geprüft im Model (Toleranz ein
|
||
halber Cent, für Rundungen aus der Betragsumrechnung) und in beiden Masken als
|
||
Restbetragsanzeige. Beide rechnen mit `public/static/betrag.js`; die Regel für das
|
||
deutsche Zahlenformat steht damit einmal im Browser und einmal in PHP, nicht dreimal. Eine
|
||
Splitzeile darf ein Gegenkonto tragen; dann erscheint auf jenem Konto nur der Betrag dieser
|
||
Zeile. Auf das eigene Konto darf sie nicht zeigen – die Buchung zählte dort doppelt.
|
||
|
||
In der **Buchungsmaske** sperren sich beide Wege gegenseitig (`public/static/buchungsmaske.js`):
|
||
Sobald in einer Splitzeile irgendetwas steht, sind *Kategorie / Gegenkonto* und *Klasse*
|
||
gesperrt; steht dort umgekehrt eine Kategorie, ein Gegenkonto oder eine Klasse, sind alle
|
||
Splitzeilen gesperrt. Gesperrte Felder schickt der Browser nicht mit. Stehen beim Öffnen
|
||
beide Seiten voll, gilt wie im Model die Splitbuchung. Der Knopf *Splitbuchungen löschen*
|
||
rechts über der Splittabelle erscheint, sobald eine Splitzeile belegt ist; er leert alle
|
||
Zeilen und gibt die direkten Felder wieder frei. Gespeichert wird erst mit dem Formular.
|
||
|
||
Der Knopf *Splitbuchung löschen* im Dialog schickt `POST /buchungen/{id}/splitbuchung` mit
|
||
`aktion=loeschen`; der Controller ruft dann `Buchung::splitsErsetzen($id, [])`, ganz gleich
|
||
was in den Feldern steht. Gelöscht werden die Zeilen samt Zuordnung, nicht die Buchung –
|
||
sie steht danach mit ihrem Betrag und ohne Kategorie im Kontoblatt, und die Gegenseite
|
||
einer Zeile mit Gegenkonto verschwindet von jenem Konto.
|
||
|
||
## Bewusst ohne Kategorie
|
||
|
||
Manche Buchungen sollen absichtlich keine Kategorie bekommen (#134): Abschreibungen etwa –
|
||
als Ausgabe kategorisiert belasteten sie die Auswertung ein zweites Mal neben dem
|
||
gesunkenen Wert des Kontos – oder Solarerträge, die nur rechnerisch existieren. Der
|
||
Schalter **Bewusst ohne Kategorie** in der Buchungsmaske setzt `buchungen.bewusst_ohne_kategorie`
|
||
(Migration `028_bewusst_ohne_kategorie.sql`).
|
||
|
||
Solche Buchungen gelten nicht als offene Arbeit: Sie fehlen unter den offenen Vorgängen
|
||
im Cockpit, im Prüflauf des Monatsabschlusses, im Fettdruck der Kontenübersicht
|
||
(`Buchung::unkategorisierteJeKonto()`), bei *Regeln auf Buchungen ohne Kategorie anwenden*
|
||
(`Buchung::ohneKategorie()`) und als Kandidat für das automatische Zusammenführen zu einer
|
||
Umbuchung. Das Kontoblatt zeigt in der Zuordnungsspalte „bewusst ohne Kategorie“. Saldo
|
||
und Auswertungen bleiben unverändert – im Buchungsbericht stehen sie wie bisher unter
|
||
„Nicht kategorisiert“.
|
||
|
||
Die Markierung gilt nur, solange die Buchung nichts zugeordnet hat. Das Model
|
||
(`Buchung::normalisiere()`) lässt sie fallen, sobald eine Kategorie, ein Gegenkonto oder
|
||
Splitzeilen dazukommen – eine Zuordnung geht nie verloren. Dasselbe gilt für die
|
||
Schnellzuordnung im Kontoblatt (`Buchung::zuordnen()`); wird dort die Zuordnung nur
|
||
geleert, bleibt die Markierung stehen. In der Maske sperrt der gesetzte Schalter
|
||
*Kategorie / Gegenkonto* und die Splitzeilen, umgekehrt lässt er sich nur setzen, solange
|
||
dort nichts steht. Die Klasse bleibt frei.
|
||
|
||
## Salden
|
||
|
||
| Spalte | Bedeutung |
|
||
|---|---|
|
||
| Online-Saldo | Stand des letzten Bankabrufs (`konten.saldo_online`, ab Phase 5) |
|
||
| Aktueller Saldo | Anfangssaldo plus alle Buchungen bis heute |
|
||
| Erwarteter Saldo | zusätzlich die künftig datierten Buchungen |
|
||
|
||
In die **Summe der Kontostände** zählen nur Konten mit `in_summe = 1` – das entspricht der
|
||
Σ-Spalte im FinanzManager. Durchlaufende Auslagen und Rentenversicherungen bleiben so
|
||
außen vor, erscheinen aber weiter in der Liste. Der QIF-Export kennt das Kennzeichen
|
||
nicht; es wird im Kontoformular gepflegt.
|
||
|
||
## Beträge in der Oberfläche
|
||
|
||
Eingegeben wird immer ein **positiver** Betrag; die Richtung bestimmt die Auswahl
|
||
*Ausgabe / Einnahme*. `KontenController::zahl()` liest das deutsche Format und
|
||
entscheidet bei einem Punkt ohne Komma nach der Stellenzahl: drei Ziffern dahinter heißt
|
||
Tausendertrenner (`1.500`), sonst Dezimaltrenner (`1234.56`).
|
||
|
||
## Bestätigungen und die Content-Security-Policy
|
||
|
||
Die CSP erlaubt keine Inline-Skripte (`script-src 'self'`). Rückfragen vor dem Löschen
|
||
dürfen deshalb **nicht** als `onsubmit="return confirm(…)"` im HTML stehen – der Browser
|
||
verwirft sie stillschweigend, und gelöscht wird ohne Nachfrage. Stattdessen:
|
||
|
||
```html
|
||
<form method="post" action="…" data-bestaetigen="Buchung wirklich löschen?">
|
||
```
|
||
|
||
`public/static/app.js` hängt den Dialog daran. Ein E2E-Test besteht auf dem Dialog, damit
|
||
das nicht unbemerkt zurückfällt.
|
||
|
||
## Abgleich mit dem Bargeld-Tool
|
||
|
||
Bargeldausgaben werden in einem zweiten Programm (FSCash) erfasst; im Finanzmanager kommen
|
||
sie als Kartenumsatz oder Abhebung an. Wer einer solchen Buchung eine Kategorie zuweist,
|
||
soll sehen, ob sie dort schon steht.
|
||
|
||
**Eingerichtet wird das unter Verwaltung → Bargeld-Tool**: Adresse, Benutzerkennung,
|
||
Passwort (AES-verschlüsselt wie die FinTS-PIN), Suchzeitraum in Tagen und die Auswahl der
|
||
Kategorien, die überhaupt abgeglichen werden. Die Auswahl steht als `bargeld_abgleich` an
|
||
der Kategorie selbst und nicht als Liste von Nummern in den Einstellungen – so verschwindet
|
||
sie mit der Kategorie, statt als tote Nummer liegenzubleiben. Die übrigen Angaben liegen im
|
||
Einstellungsbereich `bargeld`, der bewusst keinen Reiter im Einstellungsdialog hat; er steht
|
||
dafür in `Einstellung::EIGENE_SEITEN` (Test 02 prüft, dass jeder Bereich erreichbar bleibt).
|
||
|
||
**Geprüft wird beim Zuweisen einer Kategorie** – aus der Schnellzuordnung des Kontoblatts
|
||
ebenso wie aus der Buchungsmaske. `Services\BargeldAbgleich::pruefe()` verlangt vier Dinge:
|
||
eine Kategorie an der Buchung (keine Umbuchung, keine Splitbuchung), diese Kategorie
|
||
vorgemerkt, die Buchung nicht als „Ohne Bargeld-Abgleich“ markiert, eine Adresse konfiguriert. Fällt eines weg, wird der Status gelöscht – auch beim
|
||
Umkategorisieren, sonst bliebe ein alter Haken an einer Buchung stehen, die niemand mehr
|
||
abgleicht. Gesucht wird über `Services\BargeldTool` mit dem Betrag der Buchung, rückwärts ab
|
||
ihrem Datum: Bargeld wird ausgegeben, bevor der Umsatz auf dem Konto ankommt, nie danach.
|
||
|
||
Das Ergebnis steht als `bargeld_status`, `bargeld_hinweis` und `bargeld_geprueft_am` an der
|
||
Buchung. Das Kontoblatt liest es von dort und geht nicht bei jedem Blättern erneut übers
|
||
Netz. In der schmalen Spalte zwischen Klasse und Betrag steht:
|
||
|
||
| Symbol | Status | Bedeutung |
|
||
|---|---|---|
|
||
| ● grau | `NULL` | Die Buchung wird nicht abgeglichen |
|
||
| ○ grau | `NULL` | Die Buchung ist bewusst ohne Bargeld-Abgleich gebucht (#136) |
|
||
| ✓ grün | `gefunden` | Im Bargeld-Tool steht eine Buchung mit demselben Betrag |
|
||
| ✗ rot | `fehlt` | Dort steht keine |
|
||
| ! | `fehler` | Der Abruf ist gescheitert |
|
||
|
||
Das Ausrufezeichen behält ausdrücklich die Textfarbe des Farbschemas: Der Fehler liegt beim
|
||
Abruf, nicht bei der Buchung – rot oder grün wäre eine Aussage über die Buchung, die niemand
|
||
treffen kann. Der Tooltip nennt den Treffer bzw. die Meldung der Gegenstelle. Ist keine
|
||
Adresse hinterlegt, entfällt die Spalte ganz; sie zeigte sonst in jeder Zeile denselben
|
||
grauen Kreis.
|
||
|
||
Buchungen mit dem Status `fehler` zählen im Cockpit als offener Vorgang „Bargeld-Tool-Prüfung
|
||
fehlgeschlagen“ (siehe `docs/cockpit.md`) – ein Klick führt in den Buchungsbericht über den
|
||
gesamten Zeitraum, gefiltert auf „Bargeld-Tool: Abruf gescheitert“. Buchungen mit dem Status
|
||
`fehlt` zählen als eigener offener Vorgang „im Bargeld-Tool nicht gefunden“ und führen in
|
||
denselben Bericht mit dem Filter „nicht gefunden“. Der Bericht zeigt Konto, Kategorie bzw.
|
||
Gegenkonto und Klasse; die Meldung der Gegenstelle steht im Tooltip der Spalte „Bar“. Eine
|
||
eigene Liste dafür gibt es nicht mehr (#131).
|
||
|
||
**Ohne Bargeld-Abgleich (#136).** Sammelbuchungen und Differenzausgleiche tragen eine
|
||
vorgemerkte Kategorie, stehen aber absichtlich nicht im Bargeld-Tool. Der Schalter **Ohne
|
||
Bargeld-Abgleich** in der Buchungsmaske setzt `buchungen.ohne_bargeld_abgleich`; die Buchung
|
||
wird dann nicht geprüft, ein früherer Status (`fehlt`, `fehler`) wird beim Speichern
|
||
gelöscht, und sie erscheint nicht mehr unter den offenen Vorgängen im Cockpit. Die
|
||
Schnellzuordnung lässt den Schalter stehen. Er erscheint nur, wenn eine Adresse hinterlegt
|
||
ist; ohne Bargeld-Tool trägt die Maske einen gesetzten Wert unsichtbar weiter.
|
||
|
||
**Ein Fehlschlag ist ein Ergebnis, kein Abbruch.** Weder ein abgeschaltetes Bargeld-Tool
|
||
noch ein Netzfehler darf verhindern, dass die Kategorie gespeichert wird; der Abruf bricht
|
||
nach acht Sekunden ab. Null Treffer sind ausdrücklich kein Fehler – ein 404 dagegen schon,
|
||
denn er kann ebenso gut heißen, dass es den Endpunkt nicht gibt.
|
||
|
||
### Die Schnittstelle
|
||
|
||
Zwei lesende Aufrufe, beschrieben im Ticket „automatischer Abgleich mit Bargeld-Tool“:
|
||
|
||
```
|
||
GET {adresse}/api/v1/buchungen?von=2026-08-09&bis=2026-08-19&betrag=-12.50&waehrung=EUR&limit=20
|
||
GET {adresse}/api/v1/status
|
||
```
|
||
|
||
Beide mit HTTP Basic Auth. Die Suche antwortet mit `{"anzahl": n, "buchungen": [...]}`; je
|
||
Buchung sind `id`, `datum` und `betrag` nötig, `zweck`, `empfaenger`, `waehrung`, `kategorie`
|
||
und `konto` gehen in den Tooltip. Der Statusaufruf ist freiwillig – kennt die Gegenstelle ihn
|
||
nicht (404), prüft der Verbindungstest über eine Suchabfrage.
|
||
|
||
Der Betrag geht vorzeichenbehaftet über die Leitung, so wie er im Finanzmanager steht:
|
||
Ausgaben negativ. Führt das Bargeld-Tool seine Beträge positiv, muss es umrechnen.
|
||
|
||
`{adresse}` ist die Basisadresse **ohne** Schnittstellenpfad. Steht am Ende der eingetragenen
|
||
Adresse trotzdem `/api` oder `/api/v1`, kürzt der Finanzmanager sie beim Speichern – die
|
||
Adresse aus der Browserzeile zu kopieren ist der naheliegende Weg und führte sonst zu
|
||
`/api/v1/api/v1/status` und einem 404 im Verbindungstest.
|