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>
Die offenen Vorgänge „im Bargeld-Tool nicht gefunden“ und „Bargeld-Tool-
Prüfung fehlgeschlagen“ führen in den Buchungsbericht mit dem Filter
„Bargeld-Tool“ – dort steht die Spalte Kategorie/Gegenkonto mit. Die
eigene Liste unter /verwaltung/bargeld/fehler entfällt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In „Depotbuchung erfassen“ ergibt sich bei Kauf und Verkauf aus zwei der drei
Felder Betrag, Stück und Kurs das dritte (Betrag = Stück × Kurs). Der
ausgerechnete Wert ist hervorgehoben und zieht nach, wenn sich die anderen
Felder ändern. Serverseitig rechnet Depotbuchung::dritterWert() dieselbe
Regel für den Weg ohne JavaScript.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Die Wertpapiermaske (Dialog im Kontoblatt und Seite ohne JavaScript) sowie
„Depotbuchung erfassen“ bieten eine Klasse an. Im Kontoblatt ist sie mit der
bisherigen Klasse der Buchung vorbelegt und gilt für die Buchung samt aller
Splitzeilen der Nebenkosten; bei der Depotbuchung steht sie an der erzeugten
Geldbuchung. Unbekannte Klassen werden abgewiesen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Unter den Kategorien stehen überall die aktiven Umbuchungskonten, je
Kontengruppe gruppiert und in deren Reihenfolge (Konto::umbuchungsgruppen()):
Regeln samt Splitzeilen, Umsatzabgleich, Buchungsvorlagen, Regelmäßige
Buchungen, Zahlungsverkehr, Verträge sowie die Filter von Buchungsbericht
und Export. Die Masken nutzen dafür die gemeinsame Liste Kategorie /
Gegenkonto der Buchungsmaske; das getrennte Gegenkonto-Feld der Regel
entfällt.
Regel-Splitzeilen können auf ein Umbuchungskonto zeigen. Zahlungsaufträge
und Verträge bekommen ein Gegenkonto (Migration 030). Ein schon gewähltes
inaktives Konto bleibt sichtbar, damit keine Zuordnung verloren geht.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Neuer Schalter „automatisch abgleichen“ unter „automatisch buchen“
(Vorgabe: eingeschaltet). Gesetzt wird die aus der Reihe entstandene
Buchung als abgeglichen markiert. Die Übersicht erhält die Spalte
„Abgleichen“ zwischen „Auto“ und „Aktiv“.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Neuer Schalter „Bewusst ohne Kategorie“ in der Buchungsmaske für
Abschreibungen und rein rechnerische Solarerträge. Solche Buchungen
erscheinen nicht unter den offenen Vorgängen im Cockpit, nicht im
Prüflauf des Monatsabschlusses, setzen das Konto in der Kontenübersicht
nicht fett und werden von der Regelanwendung sowie dem automatischen
Zusammenführen zu Umbuchungen ausgelassen. Kommt eine Kategorie, ein
Gegenkonto oder eine Splitbuchung hinzu, entfällt die Markierung.
Migration 028_bewusst_ohne_kategorie.sql, Test 59 und E2E-Test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Die comdirect liefert bei Zahlungen mit der Visa-Debitkarte (GVC 700) kein
Namensfeld; der Händler steht nur zwischen „KARTENVERFÜGUNG“ und „KARTE NR.“.
Der Abruf leitet ihn ab, ohne den Fingerabdruck zu ändern; ein erneuter Abruf
und Migration 027 tragen ihn bei vorhandenen Umsätzen und Buchungen nach.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Meldet die Bank nach der TAN 3045 (noch keine Rückmeldung zum Status),
fragt ein Hintergrundprozess nach der Mindestwartezeit aus HIIPSS per
HKIPS nach (höchstens fünfmal). Ausgeführt wird vermerkt, abgelehnt
entfernt die Buchung; ein verbundener Kontoumsatz klärt den Status
ebenfalls. php-fints-Fork v4.1.7 bringt HKIPS/HIIPS/HIIPSS mit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Status „wartet auf Freigabe“, solange die Bank auf TAN/Namensabgleich wartet
- Abbruch der Freigabe (auch durch neuen Sendeversuch) im Übermittlungsprotokoll
als „abgebrochen“ festhalten, Auftrag als fehlgeschlagen vermerken
- Aufträge mit Übermittlungsprotokoll nur stornieren, nicht löschen
- Migration 025, PHP-Test 57, E2E-Spec zahlungsfreigabe
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nennt die Bank bei der TAN-Abfrage einen Startcode für den TAN-Generator,
geht er im Fließtext leicht unter. StartcodeErkennung erkennt ihn über
einen pro Bankverbindung konfigurierbaren Beispielsatz (Ziffernfolge =
Platzhalter für den Code) und zeigt den Fund fett, zentriert und in
eigener Zeile. BankFreitext löst dafür die bisherige Klartext-Aufbereitung
aus FinTsUeberweisung::vopHinweis() heraus, damit TAN-Anfrage und
VoP-Rückmeldung dieselbe HTML-zu-Klartext-Umwandlung nutzen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Die Kachel "Offene Vorgänge" im Cockpit zeigt jetzt auch Buchungen, deren
letzter Abgleich mit dem Bargeld-Tool an einem Abrufproblem gescheitert ist
(bargeld_status = 'fehler'). Ein Klick führt auf die neue, kontoübergreifende
Liste unter Verwaltung -> Bargeld-Tool -> fehlgeschlagene Prüfungen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Depot der Bank wird einem Depot im Finanzmanager zugeordnet (Migration 022)
- Bestand einbuchen: Ein-/Auslieferungen aus dem Bankbestand, Stichtag per Dialog
- Zuordnungsliste: Depots nur noch als Wertpapiergeschäft
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Depotaufstellung (HKWPD, Version 6) unter Wertpapiere mit Vergleich zum eigenen
Bestand; Prüfsumme und Textnachweis für das Übermittlungsprotokoll einer
Überweisung; phpFinTS v4.1.5.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Toggle „Regel anlegen“ in der Buchungsmaske (Fix#94); beim Speichern
entsteht daraus eine Regel (AbgleichRegel::ausBuchung()), die das
Kontoblatt danach in einem modalen Dialog zum Prüfen und Anpassen zeigt.
Abbruch (auch per Escape) verwirft die Regel wieder, Speichern übernimmt
Änderungen. Die Regelfelder sind aus regeln.php in regelfelder.php
ausgelagert, damit beide Formulare dieselbe Bauart teilen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bei einer Splitbuchung zeigt die Klassenspalte jetzt die gemeinsame Klasse
der Splitzeilen. Unterscheiden sie sich, steht dort die Marke „Splitbuchung“,
der Tooltip nennt je Splitzeile Kategorie und Klasse. Ein Klick auf die
Klassenzelle einer Splitbuchung öffnet den Splitdialog.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Liegen zwei Buchungen, die eigentlich derselbe Vorgang sind, zu weit
auseinander oder gehörte eine ursprünglich einem anderen Ursprungskonto,
findet der automatische Abgleich sie nicht – die Umbuchung und ihre
einzeln erfasste Dublette stehen dann dauerhaft nebeneinander im
Kontoblatt.
Buchung::verknuepfen() führt eine Umbuchung (eigene Seite oder
Gegenseite auf diesem Konto) und eine einzeln erfasste Buchung mit
passendem Betrag zusammen: Die Umbuchung bleibt, die Dublette fällt
weg, ihr Bankumsatz hängt sich an die Umbuchung. Im Kontoblatt lässt
sich dafür jetzt auch die Gegenseite einer fremden Umbuchung ankreuzen;
ein neuer Knopf „Verknüpfen“ nutzt dieselbe Auswahl wie „Auswahl
löschen“.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Eine Umbuchung gehört ihrem Ursprungskonto; der automatische Abgleich
suchte eine passende Buchung bisher nur über deren konto_id. Kam der
Kontoauszug der Empfängerseite mit ein paar Tagen Verzug herein, fand
er die schon gebuchte Umbuchung nie und legte sie als eigenständige
Buchung an – die Umbuchung stand danach doppelt im Kontoblatt und
verfälschte den Saldo.
Die Suche berücksichtigt jetzt auch die Gegenkonto-Seite einer
Umbuchung, mit umgekehrtem Vorzeichen wie im Kontoblatt auch.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Der Überweisungsdialog bietet das Häkchen „Echtzeitüberweisung“. SEPA
behandelt sie als eigenes Verfahren: Über FinTS geht der Auftrag als HKIPZ
(SendSEPARealtimeTransfer) statt als HKCCS hinaus, die pain.001-Nachricht
trägt die Zahlungsart LclInstrm/Cd = INST (nur im ISO-Format
pain.001.001.03). Eine Echtzeitüberweisung hat keinen Ausführungstermin;
bietet die Bank sie nicht an, scheitert der Auftrag mit klarer Meldung,
eine stille Umwandlung in eine gewöhnliche Überweisung ist abgeschaltet.
Neue Spalte zahlungsauftraege.echtzeit (Migration 019), Test 43 und ein
E2E-Test für das Sperren des Termins.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Der gesamte FinTS-Dialog (gesendete und empfangene Meldungen) wird je Durchlauf
in bank_protokolle gespeichert, im Erfolgs- wie im Fehlerfall. Im Zahlungsverkehr
öffnet der Status das Protokoll der Überweisung als modalen Dialog; unter
Online-Banking › Protokoll gibt es das Gesamtprotokoll mit Filter nach Bank,
Datum und Freitext.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Das Adressbuch bekommt in der Verwaltung eine eigene Kachel statt nur
über die Verträge erreichbar zu sein, denn es speist auch den
Zahlungsverkehr. Auf der Adressliste klappt zu jeder Adresse ein
<details>-Element ihre letzten Buchungen auf (Buchung::letzteFuerEmpfaenger,
kontenübergreifend nach dem exakten Empfängernamen – die Buchung führt
kein Fremdschlüsselfeld auf die Adresse).
Die Empfängerauswahl im Zahlungsverkehr-Formular ist jetzt ein Typeahead:
kombobox.js (bereits für die Kategorie im Kontoblatt im Einsatz) baut das
<select> in ein gefiltertes Eingabefeld um. Geprüft (PHP- und E2E-Tests),
dass "Empfänger ins Adressbuch übernehmen" beim Erfassen einer
Überweisung tatsächlich eine Adresse anlegt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Das Überweisungsformular fragt nur noch das Auftragskonto ab; die passende
Bankverbindung ermittelt Bankzugang::zugangJeKonto() aus der Kontenzuordnung.
Konten ohne konfigurierte Bank stehen in der Auswahl nicht mehr zur Verfügung.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Beim Zuweisen einer Kategorie fragt der Finanzmanager beim Bargeld-Tool
(FSCash) nach, ob es zum Betrag dort schon eine Buchung gibt.
Eingerichtet wird das unter Verwaltung → Bargeld-Tool: Adresse,
Zugangsdaten (Passwort AES-verschlüsselt), Suchzeitraum und die Auswahl
der abzugleichenden Kategorien. Die Vormerkung steht als
`bargeld_abgleich` an der Kategorie selbst, nicht als Nummernliste in den
Einstellungen – so verschwindet sie mit der Kategorie.
Geprüft wird nur, was geprüft werden soll: Kategorie an der Buchung,
Kategorie vorgemerkt, Adresse konfiguriert. Fällt eines weg, verschwindet
der Status. Gesucht wird rückwärts ab dem Buchungsdatum, weil Bargeld
ausgegeben wird, bevor der Umsatz auf dem Konto ankommt.
Im Kontoblatt steht das Ergebnis zwischen Klasse und Betrag: grauer Kreis,
grüner Haken, rotes X, Ausrufezeichen. Das Ausrufezeichen behält die
Textfarbe des Farbschemas – der Fehler liegt beim Abruf, nicht bei der
Buchung. Ohne hinterlegte Adresse entfällt die Spalte.
Ein Fehlschlag ist ein Ergebnis, kein Abbruch: Die Kategorie wird auch
dann gespeichert, wenn das Bargeld-Tool schweigt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zwei Features an derselben Stelle, die im Arbeitsverzeichnis
nebeneinander lagen und sich dieselben Dateien teilen (Routen,
BankingController, Bankzugang, Zugangsformular, Dokumentation) –
getrennte Commits ließen sich daraus nur mit einem kaputten
Zwischenstand schneiden.
PayPal als zweite Art von Bankverbindung
----------------------------------------
„Bankverbindung anlegen“ führt zur Wahl der Art: HBCI/FinTS oder
PayPal (bank_zugaenge.typ, Migration 014). Die Abfrage läuft über die
Classic-NVP-API (Services\PaypalNvp, TransactionSearch und GetBalance).
Kein Dreischritt, da PayPal genau ein Guthabenkonto führt –
Zugangsdaten und Kontenzuordnung stehen in einem Formular. Konten,
Umsätze, Protokoll, Regeln und Abgleich bleiben dieselben.
Bankleitzahlen-Verzeichnis
--------------------------
Verwaltung → Bankleitzahlen (/verwaltung/bankinstitute, Migration 015)
nimmt die CSV-Institutsliste der Deutschen Kreditwirtschaft auf und
beantwortet damit die eine Angabe, die beim Anlegen einer
FinTS-Verbindung regelmäßig fehlt: den PIN/TAN-Zugangspunkt.
Reine Nachschlagedaten ohne benutzer_id; ein Import ersetzt den
gesamten Bestand, statt ihn zu ergänzen. „Nur prüfen“ und „Übernehmen“
sind zwei Knöpfe an derselben Datei – abgelegt wird sie nicht, ihr
Inhalt steht ja in der Tabelle.
Services\FintsInstituteImport nimmt der Datei ihre Eigenheiten ab:
ISO-8859-1 statt UTF-8, ein Institutsname über zwei Zeilen in
Anführungszeichen, dieselbe Bankleitzahl vielfach (eine Zeile je
Filiale), Hunderte leerer Zeilen am Ende, Text statt Adresse, wo es
keinen PIN/TAN-Zugang gibt. Spalten werden über ihre Überschrift
angesprochen; fehlen BLZ und Institut, bricht der Import ab.
Gesucht wird über Bankleitzahl, BIC, Name und Ort in einem Zug: „1822“
steht bei der 1822direkt im Namen und bei der Frankfurter Sparkasse im
BIC, in keiner der beiden Bankleitzahlen.
Aus der Trefferliste führt „Verbindung anlegen“ ins gefüllte
FinTS-Formular. Die FinTS-Adresse ist damit kein Pflichtfeld mehr –
bleibt sie leer, wird sie zur Bankleitzahl nachgeschlagen. Findet auch
das nichts, weist Bankzugang den Zugang ab, statt ihn ohne Gegenstelle
zu speichern.
Tests: 31_PaypalZugangTest, 32_BankinstituteTest,
e2e/specs/banking.spec.js, e2e/specs/bankinstitute.spec.js.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Umsatzlisten haben jetzt dieselbe Mehrfachauswahl wie ein Kontoblatt:
ein Ankreuzfeld vor jedem Umsatz, eines in der Titelleiste für alle
angezeigten und darüber der Knopf „Auswahl löschen“. Er steht in jedem
Reiter – offen, übernommen und verworfen –, nennt die Anzahl der Auswahl
und bleibt ohne Auswahl gesperrt. Bisher ließ sich ein abgerufener Umsatz
nur übernehmen oder verwerfen; wegräumen ging gar nicht.
Gelöscht wird allein die abgerufene Zeile. Eine daraus entstandene
Buchung gehört ins Kontoblatt und bleibt dort stehen – wer sie loswerden
will, löscht sie dort, und dann kehrt ihr Umsatz ohnehin in die
Vorschlagsliste zurück. Mit dem Umsatz geht aber sein Fingerabdruck: Was
im nächsten Abrufzeitraum liegt, kommt danach wieder herein, bei einem
verworfenen Umsatz also erneut als offen.
- Neue Route POST /banking/umsaetze/loeschen auf
Bankumsatz::mehrereLoeschen(); der Status hängt am Formularziel, sodass
der Weg in denselben Reiter zurückführt. Ohne JavaScript weist der
Controller eine leere Auswahl ab.
- Die Liste ist keine Tabelle, sondern eine Folge von Karten. Die
Kopfzeile, die eine Tabelle von selbst hätte, gibt es deshalb neu als
.listenkopf; die Mechanik dahinter (.alle-waehlen mit data-waehlt) ist
unverändert die des Kontoblatts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Klassenspalte ist anklickbar wie die Zuordnung daneben: Ein Klick
öffnet die Klassenliste in der Zelle, die Auswahl wird sofort über
POST /buchungen/{id}/klasse gespeichert. Buchung::klasseSetzen() lässt
Kategorie, Gegenkonto und Splitzeilen unberührt.
Die Buchungszeilen sind jetzt alle zwei Textzeilen hoch, ihr Inhalt steht
senkrecht in der Mitte. Was nicht auf zwei Zeilen passt, wird
abgeschnitten; den vollständigen Text zeigt der Tooltip – bei Empfänger
und Buchungstext nur dort, wo wirklich etwas fehlt, über dem
Kategoriefeld einer Splitbuchung deren Zeilen mit Kategorie und Betrag.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Eine Regel kann jetzt eine Splitbuchung vorgeben: mehrere Kategorien mit einem
Anteil in Prozent. Greift sie, wird der Umsatz in diesem Verhältnis aufgeteilt –
bei jedem Betrag neu gerechnet, sodass eine Abrechnung über 300 € und eine über
450 € nach demselben Schlüssel gebucht werden.
Das Schema lag bereits im Modell und in der Datenbank, war über die Oberfläche
aber nicht erreichbar; die Dokumentation beschrieb ein Feld, das es nirgends zu
sehen gab.
- Unter jeder Regel klappt „Splitbuchung“ die Zeilen auf: Kategorie, Klasse,
Notiz, Anteil. Dasselbe Formular steht bei „Neue Regel“ – beide binden
src/Views/banking/regelsplits.php ein.
- Die Anteile gelten zueinander, nicht absolut: 60 zu 30 sind zwei Drittel zu
einem Drittel. Bisher hätte die letzte Zeile als Rest 40 statt der
eingetragenen 30 Prozent bekommen, und der Fehler wäre in der fertigen
Buchung nicht mehr zu sehen gewesen.
- Im Abgleichdialog zeigt der Vorschlag die errechneten Zeilen und schickt sie
mit. Zuvor gingen sie beim Knopf „Als neue Buchung“ verloren: Das Formular
kannte nur Kategorie und Klasse, sodass von Hand übernommene Umsätze
ungeteilt im Kontoblatt landeten. Der automatische Lauf war nie betroffen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Name in Bestandsübersicht, Depotbuchungen und Stammdaten führt jetzt auf
/wertpapiere/papier/{id}: Kennzahlen über die ganze Historie, Stammdaten und
Kurs, Bestand je Depot, Wertentwicklung und die Buchungen eines Zeitraums.
Depot::bestand() und Depot::entwicklung() nehmen dafür eine Wertpapiernummer
entgegen – die Detailseite rechnet nicht selbst, sondern bekommt dieselben
Zahlen wie die Übersicht. Neu sind Wertpapier::kurseckwerte() und
Depotbuchung::datumsgrenzen().
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Bankabruf bringt die Wertpapierabrechnung als Umsatz auf dem Girokonto, und
erst dort entscheidet sich, dass es ein Kauf war. Wer die Buchung einem Depot
zuordnete, buchte bisher eine Umbuchung – ohne Stückzahl, ohne Kurs, ohne
Einstand. Die Zuordnungsliste im Kontoblatt kennt jetzt neben Kategorie und
Gegenkonto eine dritte Gruppe "Wertpapiergeschäft im Depot", die statt zu
speichern die Wertpapiermaske öffnet; ohne JavaScript führt derselbe Weg auf
/buchungen/{id}/wertpapier.
Die Maske ist auf den "Wertpapier kaufen"-Dialog des FinanzManagers
zugeschnitten: vorne Vorgangsart, Datum, Wertpapier, Stück und Kurs, dahinter
hinter dem Knopf "Kosten …" die Nebenkosten nach Arten – sechs Gebühren und
sechs Steuern. ISIN und WKN werden aus dem Verwendungszweck gelesen, ein
bekanntes Papier ist damit vorausgewählt. Ein Abfluss vom Konto kann nur ein
Kauf sein, ein Zufluss ein Verkauf oder eine Dividende.
Der Buchungsbetrag ist die feste Größe: Die Nebenkosten werden aus ihm
herausgerechnet, was übrig bleibt ist der Kurswert und damit der
Einstandspreis. Im Kontoblatt entsteht eine Splitbuchung mit je einer Zeile pro
belegter Kostenart und dem Rest als Umbuchung ins Depot; ohne Nebenkosten
bleibt es bei der schlichten Umbuchung. Die Depotbuchung hängt sich an die
vorhandene Buchung, statt eine zweite anzulegen (neue Spalte
depot_buchungen.buchung_erzeugt) – wird sie gelöscht, bleibt die Buchung der
Bank stehen und ist nur wieder unzugeordnet.
Die Kategorien der Kostenarten liegen im Einstellungsdialog unter "Wertpapiere",
einmalig je Art; für "Sonstige Kosten" ist die Einstellung nur die Vorgabe und
im Dialog überschreibbar. Arten ohne Kategorie werden zu Splitzeilen ohne
Zuordnung, nicht zu einem Fehler.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Abrufzeitraum kannte bisher nur Spannen. Der Stichtag steht jetzt an zwei
Stellen: als Vorgabe der Bankverbindung (neuer Abrufzeitraum "Ab Stichtag" mit
Datum in bank_zugaenge.abruf_stichtag) und als einmalige Angabe neben "Umsätze
abrufen", die der Vorgabe vorgeht und nichts speichert.
Der einmalige Stichtag liegt im Abrufzustand, nicht in der Datenbank: Nach einer
TAN-Runde läuft der Abruf im nächsten Request weiter und muss dort denselben
Zeitraum holen wie beim Start.
"Ab Stichtag" ohne Datum und unlesbare Datumsangaben werden abgewiesen; ein
Stichtag in der Zukunft wird auf heute gesetzt, statt den Abruf leer ausgehen zu
lassen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Eine Umbuchung war auf dem Gegenkonto nicht mehr zuzuordnen: Die Zeile trug die
Marke „Umbuchung“, die Kategoriespalte daneben blieb leer. Die Daten waren
richtig, die Anzeige verschwieg sie. In der Kategoriespalte steht jetzt auch in
der Gegensicht das Konto in eckigen Klammern, von dem die Umbuchung kommt – die
Abfrage lieferte es längst mit.
Kategorie und Gegenkonto stehen in einem Feld (`Views/buchungen/zuordnungsliste.php`):
Unter den Kategorien stehen die eigenen Konten in eckigen Klammern, wie im
FinanzManager, dessen Kategoriefeld `[Konto]` annimmt. Eines davon macht die
Buchung zur Umbuchung; die Auswahl „Ausgabe / Einnahme“ bestimmt seither nur
noch die Richtung. Dieselbe Liste steht in den Splitzeilen – eine Splitzeile mit
Gegenkonto ließ sich bisher nur im Import anlegen und ging beim Bearbeiten der
Buchung stillschweigend verloren.
Schnellzuordnung: Ein Klick auf die Kategoriespalte öffnet die Liste in der
Zelle, die Auswahl speichert sofort (POST /buchungen/{id}/zuordnung) und kommt
in dieselbe Ansicht zurück. Die Liste gibt es einmal und wandert in die
angeklickte Zelle – eine Liste je Zeile wären bei hundert Zeilen ebenso viele
vollständige Kategoriebäume im HTML. Feld und Liste sind gleich breit und gleich
hoch, sonst rückte beim Anklicken die halbe Zeile. Ohne JavaScript führt
derselbe Klick in die Buchungsmaske: Die Zelle ist ein Link. Die Gegenseite
einer fremden Umbuchung führt zu ihrer Buchung auf dem anderen Konto.
Der Eintrag „Splitbuchung“ öffnet ein modales Fenster mit Zeilen für Kategorie
oder Gegenkonto, Klasse, Notiz und Betrag; der Restbetrag wird mitgerechnet. Ein
Klick auf eine bereits gesplittete Buchung öffnet direkt den Dialog. „Splitbuchung
löschen“ verwirft alle Zeilen samt ihren Zuordnungen – auch die Gegenseite einer
Splitzeile mit Gegenkonto –, die Buchung steht danach unzugeordnet im Kontoblatt.
Beide Wege gehen über `Buchung::zuordnen()` und `Buchung::splitsErsetzen()`,
achten den Monatsabschluss und lassen den Rest der Buchung unberührt.
`public/static/betrag.js` bündelt das Lesen deutscher Beträge und die
Restbetragsrechnung für Maske und Kontoblatt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein Depot, das nie im FinanzManager geführt wurde, ließ sich bisher nur Buchung
für Buchung nachtragen. `Services\DepotbestandImport` liest stattdessen die
Bestandsliste, die die Bank zum Herunterladen anbietet (erprobt mit der DKB):
Kopfzeile mit Wertpapierbezeichnung, WKN, ISIN, Einstiegskurs, Bewertungskurs,
Stückzahl und Assetklasse; Trennzeichen und Zeichensatz erkennt er selbst,
Beträge wie "1.471,88 €" und Bruchstückzahlen wie 55,6863 liest er, wie sie
kommen.
Der Export kennt keine Historie – er beschreibt einen Stichtag. Je Position
entsteht deshalb *eine* Depotbuchung: ein Kauf zum Stichtag über die volle
Stückzahl zum Einstiegskurs. Der Einstand stimmt damit auf den Cent; frühere
Käufe, Verkäufe und Dividenden bleiben leer und lassen sich nachtragen.
Der Bewertungskurs wird als Kurs des Stichtags hinterlegt, sonst stünde der
frisch übernommene Bestand sofort wieder ohne Bewertung da. Am echten Export
nachgerechnet: 33.176,12 € Einstand, 47.120,25 € Wert – die Bank weist zehn Cent
weniger Gewinn aus, was an ihren auf zwei Stellen gerundeten Kursen liegt.
Kein Geldfluss: Ein Verrechnungskonto ist wählbar, bleibt aber vorbelegt leer.
Das Geld ist vor Jahren geflossen, eine Belastung zum heutigen Tag würde das
Girokonto verfälschen.
Der Ablauf ist zweistufig – hochladen, Vorschau prüfen, übernehmen. Ohne
ausdrückliche Wahl findet der Import das Depot über die Kontonummer, die zur
Depotnummer der Datei passt; ein `import_hash` je Position verhindert, dass
dieselbe Datei zweimal denselben Bestand anlegt. `Buchung::QUELLEN` kennt dafür
jetzt die Herkunft `csv`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Kontenzuordnung als dritter Einrichtungsschritt: Welches Bankkonto gehört zu
welchem eigenen Konto? Umsätze merken sich über `bank_konto_id`, woher sie
stammen, und ziehen mit, wenn die Zuordnung erst nach einem Abruf fällt.
Abgerufene Umsätze buchen sich auf Wunsch selbst (`Services\Bankabgleich`).
Im Kontoblatt lassen sich Buchungen sammelweise löschen; Statusmeldungen liegen
jetzt über der Ansicht, statt den Inhalt springen zu lassen.
Dazu drei Fehler, die zusammen dafür sorgten, dass abgerufene Umsätze spurlos
verschwanden – der Abruf meldete sie als vorhanden, das Kontoblatt zeigte
nichts, und in der Vorschlagsliste standen sie ebenfalls nicht:
- Eine gelöschte Buchung ließ ihren Umsatz auf „uebernommen“ stehen. Der
Fremdschlüssel setzte nur `buchung_id` auf NULL. `Buchung::loeschen()` gibt
den Umsatz jetzt vorher frei, `Bankumsatz::verwaisteOeffnen()` fängt die Wege
ab, die daran vorbeiführen – Kaskaden lösen in MariaDB keine Trigger aus.
- Ein Bankkonto entstand doppelt, wenn die Bank die IBAN nicht bei jedem Dialog
mitliefert. Gesucht wird jetzt über die Kontonummer; eine nachgelieferte IBAN
wird am vorhandenen Eintrag nachgetragen.
- Der Fingerabdruck hing an der IBAN und kippte mit ihr. Er nimmt jetzt die
`bank_konto_id`, die fest steht, solange es den Bankzugang gibt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bisher entschied das erste Verfahren, das die Bank meldet – wer chipTAN
nutzt, kam über eine App-Freigabe nicht weiter. Die Wahl steht jetzt auf
einer eigenen Seite am Zugang.
Abgefragt statt eingetippt: Die Kennungen sind bankspezifisch, und
getTanModes() kommt ohne Anmeldung aus, verlangt also selbst keine TAN.
Behoben: Das Speichern des Zugangsformulars setzte Verfahren und
TAN-Medium zurück, weil beide Felder darin nicht vorkommen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Damit ist der geplante Funktionsumfang beisammen.
Phase 4 abgeschlossen
- Konfigurierbare Cockpit-Kacheln; abgewählte werden nicht berechnet
- Einnahmen/Ausgaben je Monat als Balkenpaare mit Saldolinie, aufgesetzt auf
den Summenbericht statt auf eine eigene Abfrage
- Meine Ausgaben als Ring auf der obersten Kategorieebene
- Offene Vorgänge aus allen Modulen
Phase 5 – Online-Banking
- nemiah/php-fints als Fork auf Codeberg, psr/log direkt eingebaut: die
Anwendung hängt an keinem fremden Update-Zyklus
- PIN AES-256-GCM-verschlüsselt; Schlüssel aus APP_KEY oder aus
data/schluessel/app_key, den der Entrypoint einmalig erzeugt
- TAN-Dialog über mehrere Requests (FinTs::persist plus serialisierte Aktion
in der Sitzung) – ein wartender Prozess wäre mit php-fpm der falsche Weg
- Abgleich statt Direktbuchung: verbinden, übernehmen oder verwerfen
- Regeln mit vier Vergleichsarten, Betragsgrenzen und Split-Schema
Phase 6 – Wertpapiere
- Depotbuchung und Geldbuchung als zwei Seiten eines Geschäfts; betrag ist
der Bruttowert, Nebenkosten stehen daneben
- Einstand nach gleitendem Durchschnitt, realisierte Gewinne, Erträge
- Kursabruf über Leeway oder FMP, täglicher Lauf per Cron
- QIF-Import für !Type:Invst
Dabei behoben: Der Import buchte den Geldfluss jedes Wertpapiergeschäfts als
Abgang – auch bei Verkäufen und Dividenden; und er erkannte das
Verrechnungskonto nicht, wenn dem Konto im L-Feld eine Kategorie vorangeht
(bei Verkäufen also immer).
Phase 7 – Nebenmodule und Zahlungsverkehr
- Buchungsvorlagen inklusive QIF-Import, Splits werden mitskaliert
- Regelmäßige Buchungen mit Fälligkeitslauf, Finanzkalender, Erinnerungen
- Adressen mit IBAN-Prüfung, Verträge mit Kündigungsfrist, Sparziele
- Kredite mit gerechnetem Tilgungsplan
- Überweisungen über FinTS; die Buchung entsteht erst nach Annahme durch die
Bank. Die pain.001-Nachricht erzeugt SepaXml selbst
Nebenbei: .dockerignore ergänzt (ohne sie brach der Build an data/mariadb ab),
PlatzhalterController entfernt, zwei Inline-Handler beseitigt, die die
Content-Security-Policy ohnehin blockierte.
888 PHP-Prüfungen und 45 E2E-Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Fünf Berichtstypen wie im FinanzManager – Summen-, Buchungs-, Vergleichs-,
Kontostands- und Budgetbericht – mit Filterleiste, gespeicherten Berichten in
Berichtsgruppen, Drilldown in die Buchungen und CSV-Export.
Ein Bericht speichert nur seine Frage; die Zahlen entstehen bei jedem Aufruf neu
aus den Buchungen. Gezählt werden Bewegungen (gesplittete Buchungen über ihre
Splitzeilen), Umbuchungen bleiben außen vor, Unkategorisiertes bekommt eine
eigene Zeile. Im Ausgabenabschnitt steht der Betrag ohne Minus wie im Original,
die Schlusszeile rechnet mit den echten Vorzeichen.
Einzelheiten in docs/auswertungen.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Kachel war ein Platzhalter und zeigt jetzt die Kontostände der
letzten zwölf Monate je Monatsende – ein Balken pro Monat, ein Farbton
pro Konto. Gezählt wird, was auch in der Kontenübersicht in die Summe
zählt: Konten mit Σ-Kennzeichen.
Der Schalter „nur aktive“ oben rechts blendet stillgelegte Konten aus
und merkt sich seinen Zustand über die Einstellungen. Mehr Konten als
Farbtöne fasst „Übrige Konten (n)“ zusammen – zwei Konten in derselben
Farbe wären in der Legende nicht auseinanderzuhalten.
Eigenes SVG, keine Diagrammbibliothek. Die Farben stehen als Klasse am
Element und folgen damit dem hellen wie dem dunklen Thema.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Abgelaufene Monate werden nicht mehr zusammengefasst – alle zwölf Monate
stehen einzeln da und bleiben beplanbar. Statt Verlauf und alle Monate
gibt es Alles, Nur Budget und Nur IST; die Budgetspalte ist überall dort
editierbar, wo sie steht.
Das Zahnrad vor jedem Feld verteilt dessen Wert auf das ganze oder das
restliche Jahr. Es arbeitet auf den Eingabefeldern statt auf der
Datenbank: Das Ergebnis ist vor dem Speichern zu sehen und geht mit
demselben Knopf weg wie jede andere Änderung.
Nebenbei: app.js war doppelt eingebunden, jeder Handler lief zweimal.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Budgetplaner mit Monatswerten je Kategorie, Monatsabschluss mit Prüflauf,
Snapshot und Buchungssperre. Dazu drei Vorarbeiten in der Oberfläche.
Budgetplaner
- Migration 004: budgets, budget_positionen, monatsabschluesse
- Zeilen sind der Kategoriebaum, Spalten die Monate; die ganze Tabelle wird in
einem Formular gespeichert, damit mehrere Änderungen zusammen ankommen
- Zwei Ansichten: Verlauf (Jahressumme, abgelaufene Monate zusammengefasst,
laufender Monat mit Budget/Ist/Saldo, danach Folgemonate) und alle Monate
- Ausgaben ohne Vorzeichen eingeben, es kommt aus der Kategorieart. Saldo ist
Ist minus Budget: positiv heißt besser als geplant, negativ ist die
Überschreitung und wird rot ausgewiesen
- Übergeordnete Kategorien summieren ihre Nachfahren und sind nicht beplanbar
- Ein Monat ohne Position ist "nicht geplant" und damit etwas anderes als
"mit 0,00 geplant"
- Wert auf Folgemonate übertragen, Budget als Kopie ins neue Jahr
Monatsabschluss
- Prüflauf über nicht kategorisierte Buchungen, nicht abgeglichene Umsätze und
Splitsummen-Differenzen; er hält niemanden auf, sondern zeigt den Stand
- Snapshot der Kontosalden und Kategoriesummen als JSON, bleibt auch nach einer
Wiedereröffnung stehen
- Abgeschlossene Monate sperren Buchungen in beide Richtungen: weder hinein noch
heraus verschieben. Abschaltbar über monatsabschluss_sperrt_buchungen
Vorarbeiten
- .knopf.primaer trug einen eigenen margin-top und stand dadurch in jeder
Knopfleiste tiefer als seine Nachbarn - sichtbar an "Abbrechen" neben
"Konto anlegen". Der Abstand liegt jetzt allein bei der Knopfleiste
- Kontengruppen werden wie Konten und Kategorien auf einer eigenen
Formularseite gepflegt statt inline; dort hängt auch die Zuordnung der
Konten (ankreuzen statt jedes Konto einzeln zu öffnen)
- Der QIF-Export enthält keine Kontengruppen: kein Feld im !Account-Eintrag,
nichts in der QSD-Datei. Import-Oberfläche und Doku sagen das jetzt
- Die Baum-Einrückung lief über ein style-Attribut und wurde von der
Content-Security-Policy verworfen; sie steht jetzt als data-ebene im Markup.
Aus demselben Grund blendete app.js Erfolgsmeldungen nie aus
Tests: 11_BudgetTest, 12_MonatsabschlussTest (76 Prüfungen), E2E planung.spec.js.
Einzelheiten in docs/planung.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein nicht angehaktes Ankreuzfeld steht nicht im POST. KontenController::
formulardaten() reichte "in_summe" gar nicht durch, also griff im Model der
Standardwert "zählt zur Summe" – die Anwendung meldete "Konto gespeichert",
geändert hatte sich nichts.
formulardaten() nimmt das POST-Array jetzt als Parameter und ist damit ohne
HTTP prüfbar; die Ankreuzfelder werden ausdrücklich auf true/false abgebildet.
Der Standard bleibt für Aufrufe ohne den Schlüssel bestehen – der QIF-Import
gibt das Feld nicht an.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>