findAccountId('1200'); $einnahmeId = $this->findAccountId('8400'); $konto1776 = \Steuerkram\Database::fetchOne( "SELECT id FROM accounts WHERE kontonummer = '1776' AND aktiv = 1" ); $konto1771 = \Steuerkram\Database::fetchOne( "SELECT id FROM accounts WHERE kontonummer = '1771' AND aktiv = 1" ); if (!$zahlungsId || !$einnahmeId || !$konto1776 || !$konto1771) { $this->assert(false, 'Benötigte Konten nicht gefunden (1200, 8400, 1771, 1776)'); return; } $this->assert(true, 'Konten 1200, 8400, 1771, 1776 vorhanden'); // ── UStVA-Stand vor den Testbuchungen ───────────────────────── $calc = new \Steuerkram\Services\UstvaCalculator(); $kzPre = $calc->calculate($year, $month); // ── Beleg anlegen ────────────────────────────────────────────── $belegId = \Steuerkram\Models\Beleg::create([ 'beleg_nr' => 'UST-TEST-' . uniqid(), 'filename' => 'ust-test.pdf', 'storage_path' => '', 'mime_type' => 'application/pdf', 'file_hash' => hash('sha256', 'ust-test-' . uniqid()), 'beleg_datum' => $datum, 'belegtyp' => 'Ausgangsrechnung', ]); // ── Einnahme-Buchung 19 % (Netto=500, USt=95) ───────────────── $bookingId19 = \Steuerkram\Models\Booking::create([ 'beleg_id' => $belegId, 'buchungs_datum' => $datum, 'buchungstyp' => 'Einnahme', 'kategorie_konto_id' => $einnahmeId, 'zahlungskonto_id' => $zahlungsId, 'betrag_netto' => 500.00, 'ust_satz' => 19.0, 'buchungstext' => 'Test USt 19%', ]); // USt-Buchungszeile muss auf 1776 angelegt worden sein $ustRow19 = \Steuerkram\Database::fetchOne( 'SELECT bk.*, a.kontonummer FROM bookings bk JOIN accounts a ON bk.kategorie_konto_id = a.id WHERE bk.parent_booking_id = ?', [$bookingId19] ); $this->assert($ustRow19 !== false, 'USt-Buchungszeile für 19%-Buchung angelegt'); $this->assertEquals('1776', $ustRow19['kontonummer'] ?? '', 'USt-Buchungszeile auf Konto 1776'); $this->assertEquals(95.00, round((float)($ustRow19['betrag_netto'] ?? 0), 2), 'USt betrag_netto = 95'); $this->assertEquals(0.00, round((float)($ustRow19['betrag_ust'] ?? 0), 2), 'USt betrag_ust = 0'); // ── Einnahme-Buchung 7 % (Netto=200, USt=14) ────────────────── $bookingId7 = \Steuerkram\Models\Booking::create([ 'beleg_id' => $belegId, 'buchungs_datum' => $datum, 'buchungstyp' => 'Einnahme', 'kategorie_konto_id' => $einnahmeId, 'zahlungskonto_id' => $zahlungsId, 'betrag_netto' => 200.00, 'ust_satz' => 7.0, 'buchungstext' => 'Test USt 7%', ]); $ustRow7 = \Steuerkram\Database::fetchOne( 'SELECT bk.*, a.kontonummer FROM bookings bk JOIN accounts a ON bk.kategorie_konto_id = a.id WHERE bk.parent_booking_id = ?', [$bookingId7] ); $this->assert($ustRow7 !== false, 'USt-Buchungszeile für 7%-Buchung angelegt'); $this->assertEquals('1771', $ustRow7['kontonummer'] ?? '', 'USt-Buchungszeile auf Konto 1771'); $this->assertEquals(14.00, round((float)($ustRow7['betrag_netto'] ?? 0), 2), 'USt betrag_netto = 14'); // ── UStVA: Kz 83 (Vorauszahlung) aus USt-Konten ────────────── // Kz 83 = (Summe USt-Konten 1771+1774+1776) - Kz66 - Kz61 // Nach 19%-Einnahme (+95 auf 1776) und 7%-Einnahme (+14 auf 1771): // Kz83 stieg um mindestens 95 € (19%-Anteil) $kzMit = $calc->calculate($year, $month); $this->assert( round((float)$kzMit['83']['steuer'] - (float)$kzPre['83']['steuer'], 2) >= 95.00, 'UStVA Kz 83 stieg durch 19%-Buchung um ≥ 95 €' ); // ── Drill-down Kz 83 enthält die USt-Buchungszeile (1776) ───── $drilldown = $calc->fetchBookingsForKz($year, $month, '83'); $ustFound = false; foreach ($drilldown as $b) { if ((int)$b['id'] === (int)$ustRow19['id']) { $ustFound = true; break; } } $this->assert($ustFound, 'Drill-down Kz 83 enthält die USt-Buchungszeile (1776)'); // ── Storno: USt-Zeile muss mitaufgehoben werden ─────────────── $reversalId = \Steuerkram\Models\Booking::reverse($bookingId19, 'Testfall USt-Storno'); $ustStornoRow = \Steuerkram\Database::fetchOne( 'SELECT * FROM bookings WHERE parent_booking_id = ? AND is_reversal = 1', [$reversalId] ); $this->assert($ustStornoRow !== false, 'USt-Stornobuchung wurde angelegt'); $this->assertEquals(-95.00, round((float)($ustStornoRow['betrag_netto'] ?? 0), 2), 'USt-Storno betrag_netto = -95'); // Original-USt-Zeile muss als storniert markiert sein $ustOriginal = \Steuerkram\Database::fetchOne( 'SELECT reversed_by FROM bookings WHERE id = ?', [(int)$ustRow19['id']] ); $this->assert(!empty($ustOriginal['reversed_by']), 'Original-USt-Buchungszeile hat reversed_by gesetzt'); // Kz 83 nach Storno der 19%-Buchung: nur noch 7%-USt (14 €) verbleibt $kzNach = $calc->calculate($year, $month); $delta83 = round((float)$kzNach['83']['steuer'] - (float)$kzPre['83']['steuer'], 2); $this->assertEquals(14.00, $delta83, 'Kz 83: Netto-Delta = 14 € nach Storno der 19%-Buchung'); } }