findAccountId('1200'); $ausgabeId = $this->findAccountId('4120'); if (!$zahlungsId || !$ausgabeId) { $this->assert(false, 'Benötigte Konten nicht gefunden (1200, 4120)'); return; } $this->assert(true, 'Konten 1200, 4120 vorhanden'); $belegId = Beleg::create([ 'beleg_nr' => 'BK-TEST-' . uniqid(), 'filename' => 'bk-test.pdf', 'storage_path' => '', 'mime_type' => 'application/pdf', 'file_hash' => hash('sha256', 'bk-test-' . uniqid()), 'beleg_datum' => date('Y-m-d'), 'belegtyp' => 'Eingangsrechnung', ]); $this->testNurHauptbuchung($belegId, $ausgabeId, $zahlungsId); $this->testMitVorsteuerZeile($belegId, $ausgabeId, $zahlungsId); $this->testMitIgErwerbKindzeilen($belegId, $ausgabeId, $zahlungsId); } /** Buchung ohne 7/19%-USt und ohne ig. Erwerb → genau eine Zeile. */ private function testNurHauptbuchung(int $belegId, int $ausgabeId, int $zahlungsId): void { $bookingId = Booking::create([ 'beleg_id' => $belegId, 'buchungs_datum' => date('Y-m-d'), 'buchungstyp' => 'Ausgabe', 'kategorie_konto_id' => $ausgabeId, 'zahlungskonto_id' => $zahlungsId, 'betrag_netto' => 42.00, 'ust_satz' => 0.0, 'buchungstext' => 'Test ohne USt-Zeile', ]); $rows = Database::fetchAll('SELECT * FROM bookings WHERE beleg_id = ? AND id = ?', [$belegId, $bookingId]); $this->assertEquals(1, count($rows), 'Buchung ohne 7/19%-USt erzeugt genau eine Zeile'); $kinder = Database::fetchAll('SELECT * FROM bookings WHERE parent_booking_id = ?', [$bookingId]); $this->assertEquals(0, count($kinder), 'Buchung ohne 7/19%-USt erzeugt keine Kindzeilen'); } /** Normale Buchung mit 19% USt → Hauptbuchung plus VSt-Korrekturzeile. */ private function testMitVorsteuerZeile(int $belegId, int $ausgabeId, int $zahlungsId): void { $bookingId = Booking::create([ 'beleg_id' => $belegId, 'buchungs_datum' => date('Y-m-d'), 'buchungstyp' => 'Ausgabe', 'kategorie_konto_id' => $ausgabeId, 'zahlungskonto_id' => $zahlungsId, 'betrag_netto' => 100.00, 'ust_satz' => 19.0, 'buchungstext' => 'Test mit VSt-Zeile', ]); $kinder = Database::fetchAll( 'SELECT bk.*, a.kontonummer FROM bookings bk JOIN accounts a ON bk.kategorie_konto_id = a.id WHERE bk.parent_booking_id = ?', [$bookingId] ); $this->assertEquals(1, count($kinder), 'Buchung mit 19% USt erzeugt genau eine VSt-Korrekturzeile'); $vstZeile = $kinder[0] ?? null; $this->assert($vstZeile !== null, 'VSt-Korrekturzeile vorhanden'); if ($vstZeile !== null) { $this->assertEquals('1576', $vstZeile['kontonummer'], 'VSt-Korrekturzeile bucht auf Konto 1576 (VSt 19%)'); $this->assertEquals(19.00, round((float)$vstZeile['betrag_netto'], 2), 'VSt-Korrekturzeile: Betrag = 19,00 €'); $this->assertEquals($bookingId, (int)$vstZeile['parent_booking_id'], 'VSt-Korrekturzeile referenziert die Hauptbuchung über parent_booking_id'); } } /** ig. Erwerb 19% → zwei Kindzeilen (VST_IGE_19 und UST_IGE_19). */ private function testMitIgErwerbKindzeilen(int $belegId, int $ausgabeId, int $zahlungsId): void { $bookingId = Booking::create([ 'beleg_id' => $belegId, 'buchungs_datum' => date('Y-m-d'), 'buchungstyp' => 'Ausgabe', 'kategorie_konto_id' => $ausgabeId, 'zahlungskonto_id' => $zahlungsId, 'betrag_netto' => 1000.00, 'ust_satz' => 0.0, 'steuerart' => 'ig_erwerb_19', 'buchungstext' => 'Test ig. Erwerb 19%', ]); $kinder = Database::fetchAll( 'SELECT bk.*, a.kontonummer FROM bookings bk JOIN accounts a ON bk.kategorie_konto_id = a.id WHERE bk.parent_booking_id = ? ORDER BY a.kontonummer', [$bookingId] ); $this->assertEquals(2, count($kinder), 'ig. Erwerb 19% erzeugt genau zwei Kindzeilen'); $summeKinder = 0.0; foreach ($kinder as $kind) { $this->assertEquals($bookingId, (int)$kind['parent_booking_id'], 'Kindzeile referenziert die Hauptbuchung'); $summeKinder += (float)$kind['betrag_netto']; } $this->assertEquals(380.00, round($summeKinder, 2), 'Summe der Kindzeilen = 2 × 19% von 1000 € = 380 €'); } }