From 4eb622fa7d44509ec7a547d98661a94d072b5fb1 Mon Sep 17 00:00:00 2001 From: fds2610-bot Date: Sat, 23 May 2026 15:23:56 +0200 Subject: [PATCH 1/2] Fix: Belegsumme und Bankzuordnung nach Storno korrekt berechnen --- src/Controllers/BookingController.php | 14 ++++++++++++++ src/Models/Beleg.php | 6 +++--- src/Models/Booking.php | 2 +- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Controllers/BookingController.php b/src/Controllers/BookingController.php index fa1d4e8..a300927 100644 --- a/src/Controllers/BookingController.php +++ b/src/Controllers/BookingController.php @@ -198,6 +198,12 @@ class BookingController extends BaseController $ustSatz = (float)($data['ust_satz'] ?? 0); $brutto = round($netto * (1 + $ustSatz / 100), 2); BankTransaction::linkBeleg($bankTxId, $belegId, $brutto); + } else { + // Falls Beleg bereits verknüpft ist (z.B. nach Storno + Neubuchung), Betrag aktualisieren + $existingBt = BankTransaction::findByBelegId($belegId); + if ($existingBt) { + BankTransaction::linkBeleg((int)$existingBt['id'], $belegId, $totalBrutto); + } } if ($newAssetId !== null) { @@ -308,6 +314,14 @@ class BookingController extends BaseController try { Booking::reverse($id, $reason); $booking = Booking::find($id); + // Bankzuordnung auf neue (stornierte) Buchungssumme setzen + if (!empty($booking['beleg_id'])) { + $existingBt = BankTransaction::findByBelegId((int)$booking['beleg_id']); + if ($existingBt) { + $newSum = Booking::sumBruttoForBeleg((int)$booking['beleg_id']); + BankTransaction::linkBeleg((int)$existingBt['id'], (int)$booking['beleg_id'], $newSum); + } + } View::redirect("/belege/{$booking['beleg_id']}", 'Buchung wurde storniert.'); } catch (\PDOException $e) { error_log('[Steuerkram] PDO-Fehler in BookingController::reverse(): ' . $e->getMessage()); diff --git a/src/Models/Beleg.php b/src/Models/Beleg.php index 1341d6e..6e71924 100644 --- a/src/Models/Beleg.php +++ b/src/Models/Beleg.php @@ -47,7 +47,7 @@ class Beleg $offset = ($page - 1) * $perPage; $sql = 'SELECT b.*, (SELECT SUM(bk.betrag_brutto) FROM bookings bk - WHERE bk.beleg_id = b.id AND bk.is_reversal = 0 AND bk.parent_booking_id IS NULL + WHERE bk.beleg_id = b.id AND bk.is_reversal = 0 AND bk.parent_booking_id IS NULL AND bk.reversed_by IS NULL ) AS betrag_brutto, fy.year as fiscal_year_nr, s.name as supplier_name, @@ -78,7 +78,7 @@ class Beleg 'SELECT b.*, COALESCE( (SELECT SUM(bk.betrag_brutto) FROM bookings bk - WHERE bk.beleg_id = b.id AND bk.is_reversal = 0 AND bk.parent_booking_id IS NULL), + WHERE bk.beleg_id = b.id AND bk.is_reversal = 0 AND bk.parent_booking_id IS NULL AND bk.reversed_by IS NULL), b.betrag_brutto ) AS betrag_brutto, fy.year as fiscal_year_nr, @@ -121,7 +121,7 @@ class Beleg return Database::fetchOne( 'SELECT b.*, (SELECT SUM(bk.betrag_brutto) FROM bookings bk - WHERE bk.beleg_id = b.id AND bk.is_reversal = 0 AND bk.parent_booking_id IS NULL + WHERE bk.beleg_id = b.id AND bk.is_reversal = 0 AND bk.parent_booking_id IS NULL AND bk.reversed_by IS NULL ) AS betrag_brutto, fy.year as fiscal_year_nr, s.name as supplier_name, diff --git a/src/Models/Booking.php b/src/Models/Booking.php index 0f1011f..59683d3 100644 --- a/src/Models/Booking.php +++ b/src/Models/Booking.php @@ -433,7 +433,7 @@ class Booking $row = Database::fetchOne( 'SELECT COALESCE(SUM(betrag_brutto), 0) AS total FROM bookings - WHERE beleg_id = ? AND is_reversal = 0 AND parent_booking_id IS NULL', + WHERE beleg_id = ? AND is_reversal = 0 AND parent_booking_id IS NULL AND reversed_by IS NULL', [$belegId] ); return round((float)($row['total'] ?? 0), 2); From 1e2c8cf498dd365d73ffa41fc8e6b88385e00abe Mon Sep 17 00:00:00 2001 From: fds2610-bot Date: Sat, 23 May 2026 16:50:20 +0200 Subject: [PATCH 2/2] Fix: Belegsumme blendet steuerliche Umbuchungen auf Konto 1800 aus --- src/Models/Beleg.php | 8 +- tests/40_BelegBruttoBereinigungTest.php | 111 ++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 tests/40_BelegBruttoBereinigungTest.php diff --git a/src/Models/Beleg.php b/src/Models/Beleg.php index 6e71924..aea9bc0 100644 --- a/src/Models/Beleg.php +++ b/src/Models/Beleg.php @@ -19,7 +19,8 @@ class Beleg OR s.name LIKE ? OR b.bewirtungsgrund LIKE ? OR b.teilnehmerliste LIKE ? OR (SELECT CAST(SUM(bk2s.betrag_brutto) AS CHAR) FROM bookings bk2s - WHERE bk2s.beleg_id = b.id AND bk2s.is_reversal = 0 AND bk2s.parent_booking_id IS NULL) LIKE ?)'; + WHERE bk2s.beleg_id = b.id AND bk2s.is_reversal = 0 AND bk2s.parent_booking_id IS NULL + AND NOT EXISTS (SELECT 1 FROM accounts az WHERE az.id = bk2s.zahlungskonto_id AND az.kontonummer = \'1800\')) LIKE ?)'; $s = '%' . $filter['search'] . '%'; $sBrutto = '%' . str_replace(',', '.', $filter['search']) . '%'; $params = array_merge($params, [$s, $s, $s, $s, $s, $s, $s, $s, $sBrutto]); @@ -48,6 +49,7 @@ class Beleg $sql = 'SELECT b.*, (SELECT SUM(bk.betrag_brutto) FROM bookings bk WHERE bk.beleg_id = b.id AND bk.is_reversal = 0 AND bk.parent_booking_id IS NULL AND bk.reversed_by IS NULL + AND NOT EXISTS (SELECT 1 FROM accounts az WHERE az.id = bk.zahlungskonto_id AND az.kontonummer = \'1800\') ) AS betrag_brutto, fy.year as fiscal_year_nr, s.name as supplier_name, @@ -78,7 +80,8 @@ class Beleg 'SELECT b.*, COALESCE( (SELECT SUM(bk.betrag_brutto) FROM bookings bk - WHERE bk.beleg_id = b.id AND bk.is_reversal = 0 AND bk.parent_booking_id IS NULL AND bk.reversed_by IS NULL), + WHERE bk.beleg_id = b.id AND bk.is_reversal = 0 AND bk.parent_booking_id IS NULL AND bk.reversed_by IS NULL + AND NOT EXISTS (SELECT 1 FROM accounts az WHERE az.id = bk.zahlungskonto_id AND az.kontonummer = \'1800\')), b.betrag_brutto ) AS betrag_brutto, fy.year as fiscal_year_nr, @@ -122,6 +125,7 @@ class Beleg 'SELECT b.*, (SELECT SUM(bk.betrag_brutto) FROM bookings bk WHERE bk.beleg_id = b.id AND bk.is_reversal = 0 AND bk.parent_booking_id IS NULL AND bk.reversed_by IS NULL + AND NOT EXISTS (SELECT 1 FROM accounts az WHERE az.id = bk.zahlungskonto_id AND az.kontonummer = \'1800\') ) AS betrag_brutto, fy.year as fiscal_year_nr, s.name as supplier_name, diff --git a/tests/40_BelegBruttoBereinigungTest.php b/tests/40_BelegBruttoBereinigungTest.php new file mode 100644 index 0000000..89d06ab --- /dev/null +++ b/tests/40_BelegBruttoBereinigungTest.php @@ -0,0 +1,111 @@ +findAccountId('1200'); + $umbuchungId = $this->findAccountId('1800'); + $ausgabeId = $this->findAccountId('4920'); + + if (!$bankId || !$umbuchungId || !$ausgabeId) { + $this->assert(false, 'Benötigte Konten (1200, 1800, 4920) fehlen – SKR03-Seed vorhanden?'); + return; + } + + $datum = date('Y-m-d'); + $belegId = Beleg::create([ + 'beleg_nr' => 'TEST-1800-' . uniqid(), + 'filename' => 'umbuchung-test.pdf', + 'storage_path' => '', + 'mime_type' => 'application/pdf', + 'file_hash' => hash('sha256', 'umbuchung-test-' . uniqid()), + 'beleg_datum' => $datum, + 'belegtyp' => 'Eingangsrechnung', + ]); + $this->assertGreaterThan(0, $belegId, 'Beleg angelegt'); + + // Normale Buchung: 100 € netto + 19 % = 119 € brutto + Booking::create([ + 'beleg_id' => $belegId, + 'buchungs_datum' => $datum, + 'buchungstyp' => 'Ausgabe', + 'kategorie_konto_id' => $ausgabeId, + 'zahlungskonto_id' => $bankId, + 'betrag_netto' => 100.00, + 'ust_satz' => 19.0, + 'buchungstext' => 'Normale Buchung', + ]); + + // Steuerliche Umbuchung auf Konto 1800 (darf nicht in Belegsumme einfließen) + Booking::create([ + 'beleg_id' => $belegId, + 'buchungs_datum' => $datum, + 'buchungstyp' => 'Ausgabe', + 'kategorie_konto_id' => $ausgabeId, + 'zahlungskonto_id' => $umbuchungId, + 'betrag_netto' => 50.00, + 'ust_satz' => 0.0, + 'buchungstext' => 'Steuerliche Umbuchung 1800', + ]); + + // Beleg::find() darf nur 119,00 liefern (nicht 169,00) + $beleg = Beleg::find($belegId); + $this->assertEquals( + 119.00, + round((float)($beleg['betrag_brutto'] ?? 0), 2), + 'Beleg::find() – betrag_brutto = 119,00 (ohne Konto-1800-Umbuchung)' + ); + + // Beleg::all() – dieselbe Filterung in der Listenansicht + $result = Beleg::all([], 1, 9999); + $found = null; + foreach ($result['rows'] as $row) { + if ((int)$row['id'] === $belegId) { + $found = $row; + break; + } + } + $this->assert($found !== null, 'Beleg erscheint in Beleg::all()'); + $this->assertEquals( + 119.00, + round((float)($found['betrag_brutto'] ?? 0), 2), + 'Beleg::all() – betrag_brutto = 119,00 (ohne Konto-1800-Umbuchung)' + ); + + // Brutto-Suche findet den Beleg über 119,00 – nicht über 169,00 + $resHit = Beleg::all(['search' => '119.00'], 1, 9999); + $foundByBrutto = false; + foreach ($resHit['rows'] as $row) { + if ((int)$row['id'] === $belegId) { + $foundByBrutto = true; + break; + } + } + $this->assert($foundByBrutto, 'Brutto-Suche nach 119.00 findet den Beleg'); + + $resMiss = Beleg::all(['search' => '169.00'], 1, 9999); + $foundByWrong = false; + foreach ($resMiss['rows'] as $row) { + if ((int)$row['id'] === $belegId) { + $foundByWrong = true; + break; + } + } + $this->assert(!$foundByWrong, 'Brutto-Suche nach 169.00 findet den Beleg NICHT'); + } +}