118 lines
4.7 KiB
PHP
118 lines
4.7 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
/**
|
||
* Test 31: Kz 81 und Kz 89 werden auf volle Euro abgerundet (floor).
|
||
*
|
||
* Buchungen mit Cent-Beträgen dürfen in der UStVA nur als ganzer Euro-Betrag
|
||
* erscheinen; die USt wird auf dem abgerundeten Wert berechnet.
|
||
*/
|
||
class UstvaFloorKz81_89Test extends TestCase
|
||
{
|
||
protected string $testName = 'Test 31: UStVA Kz 81/89 – floor auf volle Euro';
|
||
|
||
public function run(): void
|
||
{
|
||
$year = (int)date('Y');
|
||
$month = (int)date('n');
|
||
$datum = date('Y-m-d');
|
||
|
||
$erloesId = $this->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;
|
||
}
|
||
}
|