Fix n.n.: Neue Buchungen erhalten automatisch eine laufende Nummer je Konto
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
932d17c128
commit
ae33420478
3 changed files with 73 additions and 0 deletions
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
49
tests/53_BuchungsnummerTest.php
Normal file
49
tests/53_BuchungsnummerTest.php
Normal 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,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue