Merge pull request 'Fix n.n.: Neue Buchungen erhalten automatisch eine laufende Nummer je Konto' (#107) from fds2610-bot/Finanzmanager:main into main

Reviewed-on: https://codeberg.org/fds2610/Finanzmanager/pulls/107
This commit is contained in:
fds2610 2026-10-01 10:22:13 +02:00
commit 895d65ef7a
3 changed files with 73 additions and 0 deletions

View file

@ -1,5 +1,10 @@
# Änderungen # Änderungen
## Automatische Buchungsnummer (01.10.2026)
- 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`.
## „+ Neu“ öffnet das Formular als Dialog (01.10.2026) ## „+ 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. - 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.

View file

@ -99,6 +99,9 @@ class Buchung
Monatsabschluss::verlangeOffen($felder['datum']); Monatsabschluss::verlangeOffen($felder['datum']);
return (int)Database::transaktion(static function () use ($felder, $splits, $adressen): int { return (int)Database::transaktion(static function () use ($felder, $splits, $adressen): int {
if ($felder['nummer'] === '') {
$felder['nummer'] = self::naechsteNummer($felder['konto_id']);
}
Database::execute( Database::execute(
'INSERT INTO buchungen 'INSERT INTO buchungen
(benutzer_id, konto_id, datum, valuta, betrag, empfaenger, iban, bankname, buchungstext, (benutzer_id, konto_id, datum, valuta, betrag, empfaenger, iban, bankname, buchungstext,
@ -121,6 +124,22 @@ class Buchung
}); });
} }
/**
* Laufende Nummer je Konto: die höchste rein numerische Nummer plus eins.
* Vorhandene Nummern (etwa Schecknummern aus dem QIF-Import) bleiben unberührt.
*/
private static function naechsteNummer(int $kontoId): string
{
$hoechste = Database::fetchValue(
"SELECT MAX(CAST(nummer AS UNSIGNED)) FROM buchungen
WHERE konto_id = ? AND nummer REGEXP '^[0-9]{1,9}$'",
[$kontoId],
0
);
return (string)((int)$hoechste + 1);
}
/** /**
* @param array<string,mixed> $daten * @param array<string,mixed> $daten
* @param list<array<string,mixed>> $splits * @param list<array<string,mixed>> $splits

View file

@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
use Finanzmanager\Models\Buchung;
use Finanzmanager\Models\Konto;
/**
* Neue Buchungen ohne Nummer bekommen automatisch die nächste laufende Nummer
* ihres Kontos; eine vorgegebene Nummer bleibt erhalten.
*/
class BuchungsnummerTest extends TestCase
{
protected string $testName = 'Test 53: Automatische Buchungsnummer';
public function run(): void
{
$this->mandantAnlegen();
$a = Konto::anlegen(['name' => 'Nummer A', 'kontoart' => 'bank', 'anfangssaldo' => 0, 'aktiv' => 1]);
$b = Konto::anlegen(['name' => 'Nummer B', 'kontoart' => 'bank', 'anfangssaldo' => 0, 'aktiv' => 1]);
$erste = $this->buche($a);
$this->assertEquals('1', Buchung::find($erste)['nummer'], 'Die erste Buchung eines Kontos bekommt die 1');
$zweite = $this->buche($a);
$this->assertEquals('2', Buchung::find($zweite)['nummer'], 'Die nächste zählt hoch');
$this->assertEquals('1', Buchung::find($this->buche($b))['nummer'], 'Jedes Konto zählt für sich');
$fest = $this->buche($a, '603');
$this->assertEquals('603', Buchung::find($fest)['nummer'], 'Eine vorgegebene Nummer bleibt');
$this->assertEquals('604', Buchung::find($this->buche($a))['nummer'], 'Danach geht es hinter der höchsten weiter');
$this->buche($a, 'Scheck-A');
$this->assertEquals('605', Buchung::find($this->buche($a))['nummer'], 'Nichtnumerische Nummern stören nicht');
Buchung::speichern($erste, [
'konto_id' => $a, 'datum' => '2026-05-01', 'betrag' => -1.0, 'nummer' => '',
]);
$this->assertEquals('', Buchung::find($erste)['nummer'], 'Beim Ändern wird nichts nachvergeben');
}
private function buche(int $konto, string $nummer = ''): int
{
return Buchung::anlegen([
'konto_id' => $konto, 'datum' => '2026-05-01', 'betrag' => -1.0,
'empfaenger' => 'Test', 'nummer' => $nummer,
]);
}
}