diff --git a/Changes.md b/Changes.md index 2f05b8f..b729359 100644 --- a/Changes.md +++ b/Changes.md @@ -11,6 +11,10 @@ - Neue Buchungen ohne Nummer erhalten beim Anlegen die nächste laufende Nummer ihres Kontos (höchste rein numerische Nummer + 1, `Buchung::naechsteNummer()`). Vorgegebene Nummern (QIF, CSV, Formular) bleiben, bestehende Buchungen werden nicht verändert; die interne ID bleibt verborgen. - Test: `53_BuchungsnummerTest.php`. +## Regelmäßige Buchungen: Buchen zum gewählten Datum (01.10.2026) + +- „Buchen“ in „Jetzt fällig“ schlug mit einer Fehlermeldung fehl, weil das Formular ein leeres Datum schickte. Jetzt ist „Fällig am“ per Klick editierbar; „Buchen“ bucht zu diesem Datum. Die Änderung gilt nur für diese Buchung und verändert die Reihe nicht. Ein leeres Datum fällt auf den Termin zurück, ein ungültiges wird abgewiesen. + ## „+ Neu“ öffnet das Formular als Dialog (01.10.2026) - Das Formular zur Neuanlage stand in elf Ansichten unter der Liste. Jetzt öffnet der Knopf „+ Neu“ es als modalen Dialog (`app.js`, `.neudialog`); nach dem Speichern erscheint die Liste wieder, mit dem neuen Eintrag. Betroffen: Klassen, Buchungsvorlagen, Regelmäßige Buchungen, Erinnerungen, Verträge, Adressen, Sparziele, Kredite, Abgleichregeln, Budgets, Berichtsgruppen. diff --git a/public/static/reihenliste.js b/public/static/reihenliste.js index 87c55ca..73f9c4a 100644 --- a/public/static/reihenliste.js +++ b/public/static/reihenliste.js @@ -5,8 +5,8 @@ (function () { 'use strict'; - const tabelle = document.querySelector('table.reihen'); - if (!tabelle) { + const tabellen = document.querySelectorAll('table.reihen, table.faellig'); + if (tabellen.length === 0) { return; } @@ -59,6 +59,7 @@ anzeige.hidden = false; } + tabellen.forEach(function (tabelle) { tabelle.querySelectorAll('.feld').forEach(function (feld) { const anzeige = feld.querySelector('.anzeige'); const steuer = feld.querySelector('input, select'); @@ -99,6 +100,7 @@ } }); }); + }); function geaendert(e) { const zeile = e.target.closest('tr'); @@ -107,6 +109,8 @@ knopf.hidden = false; } } - tabelle.addEventListener('input', geaendert); - tabelle.addEventListener('change', geaendert); + tabellen.forEach(function (tabelle) { + tabelle.addEventListener('input', geaendert); + tabelle.addEventListener('change', geaendert); + }); })(); diff --git a/src/Models/RegelmaessigeBuchung.php b/src/Models/RegelmaessigeBuchung.php index a8b22cd..8cddcb8 100644 --- a/src/Models/RegelmaessigeBuchung.php +++ b/src/Models/RegelmaessigeBuchung.php @@ -169,7 +169,14 @@ class RegelmaessigeBuchung throw new \RuntimeException('Die regelmäßige Buchung gibt es nicht.'); } - $datum = (string)($abweichungen['datum'] ?? $reihe['naechste_faelligkeit'] ?? date('Y-m-d')); + $datum = trim((string)($abweichungen['datum'] ?? '')); + if ($datum === '') { + $datum = (string)($reihe['naechste_faelligkeit'] ?? date('Y-m-d')); + } + $pruef = \DateTimeImmutable::createFromFormat('!Y-m-d', $datum); + if ($pruef === false || $pruef->format('Y-m-d') !== $datum) { + throw new \InvalidArgumentException('Ungültiges Datum.'); + } $betrag = array_key_exists('betrag', $abweichungen) && $abweichungen['betrag'] !== '' ? round((float)$abweichungen['betrag'], 2) : (float)$reihe['betrag']; diff --git a/src/Views/termine/index.php b/src/Views/termine/index.php index 9dfc497..c26ac25 100644 --- a/src/Views/termine/index.php +++ b/src/Views/termine/index.php @@ -42,7 +42,13 @@ include __DIR__ . '/../layout/kopf.php';
| Fällig am | Name | Konto | Betrag | Art | Aktion |
|---|---|---|---|---|---|
| = View::h(View::datum($reihe['naechste_faelligkeit'])) ?> | +
+
+ = View::h(View::datum($reihe['naechste_faelligkeit'])) ?>
+
+
+ |
= View::h($reihe['name']) ?> | = View::h($reihe['kontoname']) ?> | @@ -62,10 +75,8 @@ include __DIR__ . '/../layout/kopf.php'; : 'auf Bestätigung' ?> | - + |