findAccountByNr('8400'); // Erlöse 19 % USt → ustva_kz=81 $ausgabeId = $this->findKonto('Betriebsausgabe'); $zahlungId = $this->findKonto('Zahlungskonto'); if (!$erloesId || !$ausgabeId || !$zahlungId) { $this->assert(false, 'Benötigte Konten nicht gefunden'); return; } $calc = new \Steuerkram\Services\UstvaCalculator(); $kzPre = $calc->calculate($year, $month); // Kz-81-Buchung mit Cent-Betrag: 100,77 € netto $belegId = \Steuerkram\Models\Beleg::create([ 'beleg_nr' => 'TEST-FLOOR81-' . uniqid(), 'filename' => 'test-floor81.pdf', 'storage_path' => '', 'mime_type' => 'application/pdf', 'file_hash' => hash('sha256', 'test-floor81-' . uniqid()), 'beleg_datum' => $datum, 'belegtyp' => 'Ausgangsrechnung', ]); \Steuerkram\Models\Booking::create([ 'beleg_id' => $belegId, 'buchungs_datum' => $datum, 'buchungstyp' => 'Einnahme', 'steuerart' => null, 'ust_satz' => 19.0, 'kategorie_konto_id' => $erloesId, 'zahlungskonto_id' => $zahlungId, 'betrag_netto' => 100.77, 'buchungstext' => 'Test Floor Kz 81', ]); // Kz-89-Buchung mit Cent-Betrag: 200,55 € netto (ig. Erwerb 19 %) $belegId2 = \Steuerkram\Models\Beleg::create([ 'beleg_nr' => 'TEST-FLOOR89-' . uniqid(), 'filename' => 'test-floor89.pdf', 'storage_path' => '', 'mime_type' => 'application/pdf', 'file_hash' => hash('sha256', 'test-floor89-' . uniqid()), 'beleg_datum' => $datum, 'belegtyp' => 'Eingangsrechnung', ]); \Steuerkram\Models\Booking::create([ 'beleg_id' => $belegId2, 'buchungs_datum' => $datum, 'buchungstyp' => 'Ausgabe', 'steuerart' => 'ig_erwerb_19', 'ust_satz' => 0.0, 'kategorie_konto_id' => $ausgabeId, 'zahlungskonto_id' => $zahlungId, 'betrag_netto' => 200.55, 'buchungstext' => 'Test Floor Kz 89', ]); $kz = $calc->calculate($year, $month); // Kz 81: Delta muss exakt 100,00 sein (floor von 100,77) $delta81 = round((float)$kz['81']['betrag'] - (float)$kzPre['81']['betrag'], 2); $this->assertEquals(100.00, $delta81, 'Kz 81: floor(100,77) = 100,00'); // USt Kz 81: 100 * 0,19 = 19,00 (nicht 100,77 * 0,19 = 19,15) $deltaUst81 = round((float)$kz['ust81']['steuer'] - (float)$kzPre['ust81']['steuer'], 2); $this->assertEquals(19.00, $deltaUst81, 'USt Kz 81: 100 × 0,19 = 19,00'); // Kz 89: Delta muss exakt 200,00 sein (floor von 200,55) $delta89 = round((float)$kz['89']['betrag'] - (float)$kzPre['89']['betrag'], 2); $this->assertEquals(200.00, $delta89, 'Kz 89: floor(200,55) = 200,00'); // USt Kz 89: 200 * 0,19 = 38,00 (nicht 200,55 * 0,19 = 38,10) $deltaUst89 = round((float)$kz['ust89']['steuer'] - (float)$kzPre['ust89']['steuer'], 2); $this->assertEquals(38.00, $deltaUst89, 'USt Kz 89: 200 × 0,19 = 38,00'); // ganze_euro-Flag muss gesetzt sein $this->assert($kz['81']['ganze_euro'] === true, 'Kz 81 hat ganze_euro=true'); $this->assert($kz['89']['ganze_euro'] === true, 'Kz 89 hat ganze_euro=true'); $this->assert($kz['ust81']['ganze_euro'] === false, 'ust81 hat ganze_euro=false'); } private function findKonto(string $kontenart): ?int { $row = \Steuerkram\Database::fetchOne( "SELECT id FROM accounts WHERE kontenart = ? AND aktiv = 1 LIMIT 1", [$kontenart] ); return $row ? (int)$row['id'] : null; } private function findAccountByNr(string $nr): ?int { $row = \Steuerkram\Database::fetchOne( "SELECT id FROM accounts WHERE kontonummer = ? AND aktiv = 1 LIMIT 1", [$nr] ); return $row ? (int)$row['id'] : null; } }