Steuerkram/tests/07_UstvaAuslandTest.php

210 lines
8.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
/**
* Test 7: UStVA-Kennzahlen für Auslandsumsätze und ig. Erwerb.
*
* Prüft, dass steuerart-Buchungen korrekt in die UStVA-Kennzahlen
* 41, 44, 89, 91, 93, 94 und 67 einfließen.
*/
class UstvaAuslandTest extends TestCase
{
protected string $testName = 'Test 7: UStVA Auslandsumsätze und ig. Erwerb';
public function run(): void
{
$year = (int)date('Y');
$month = (int)date('n');
$datum = date('Y-m-d');
// Konten aus SKR03
$erloesId = $this->findKonto('Betriebseinnahme');
$ausgabeId = $this->findKonto('Betriebsausgabe');
$zahlungId = $this->findKonto('Zahlungskonto');
if (!$erloesId || !$ausgabeId || !$zahlungId) {
$this->assert(false, 'Benötigte Konten nicht gefunden – SKR03-Seed vorhanden?');
return;
}
$this->assert(true, 'Konten vorhanden');
// Zweites Zahlungskonto für Ausgabe-Buchungen
$bankId = \Steuerkram\Database::fetchOne(
"SELECT id FROM accounts WHERE kontenart = 'Zahlungskonto' AND aktiv = 1 AND id != ? LIMIT 1",
[$zahlungId]
);
$bankId = $bankId ? (int)$bankId['id'] : $zahlungId;
// ── 1. Steuerfreie ig. Lieferung → Kz 41 ──────────────────────────
$belegIgL = \Steuerkram\Models\Beleg::create([
'beleg_nr' => 'TEST-IGL-' . uniqid(),
'filename' => 'test-igl.pdf',
'storage_path' => '',
'mime_type' => 'application/pdf',
'file_hash' => hash('sha256', 'test-igl'),
'beleg_datum' => $datum,
'eingangs_datum' => $datum,
'belegtyp' => 'Ausgangsrechnung',
]);
\Steuerkram\Models\Booking::create([
'beleg_id' => $belegIgL,
'buchungs_datum' => $datum,
'buchungstyp' => 'Einnahme',
'steuerart' => 'ig_lieferung',
'kategorie_konto_id' => $erloesId,
'zahlungskonto_id' => $zahlungId,
'betrag_netto' => 1000.00,
'ust_satz' => 0.0,
'buchungstext' => 'Test ig. Lieferung EU',
]);
// ── 2. Steuerfreie Ausfuhr → Kz 44 ───────────────────────────────
$belegExp = \Steuerkram\Models\Beleg::create([
'beleg_nr' => 'TEST-EXP-' . uniqid(),
'filename' => 'test-exp.pdf',
'storage_path' => '',
'mime_type' => 'application/pdf',
'file_hash' => hash('sha256', 'test-exp'),
'beleg_datum' => $datum,
'eingangs_datum' => $datum,
'belegtyp' => 'Ausgangsrechnung',
]);
\Steuerkram\Models\Booking::create([
'beleg_id' => $belegExp,
'buchungs_datum' => $datum,
'buchungstyp' => 'Einnahme',
'steuerart' => 'export',
'kategorie_konto_id' => $erloesId,
'zahlungskonto_id' => $zahlungId,
'betrag_netto' => 2000.00,
'ust_satz' => 0.0,
'buchungstext' => 'Test Ausfuhr Drittland',
]);
// ── 3. Ig. Erwerb 19 % → Kz 89/91/67 ─────────────────────────────
$belegIgE19 = \Steuerkram\Models\Beleg::create([
'beleg_nr' => 'TEST-IGE19-' . uniqid(),
'filename' => 'test-ige19.pdf',
'storage_path' => '',
'mime_type' => 'application/pdf',
'file_hash' => hash('sha256', 'test-ige19'),
'beleg_datum' => $datum,
'eingangs_datum' => $datum,
'belegtyp' => 'Eingangsrechnung',
]);
\Steuerkram\Models\Booking::create([
'beleg_id' => $belegIgE19,
'buchungs_datum' => $datum,
'buchungstyp' => 'Ausgabe',
'steuerart' => 'ig_erwerb_19',
'kategorie_konto_id' => $ausgabeId,
'zahlungskonto_id' => $bankId,
'betrag_netto' => 500.00,
'ust_satz' => 0.0,
'buchungstext' => 'Test ig. Erwerb 19%',
]);
// ── 4. Ig. Erwerb 7 % → Kz 93/94/67 ──────────────────────────────
$belegIgE7 = \Steuerkram\Models\Beleg::create([
'beleg_nr' => 'TEST-IGE7-' . uniqid(),
'filename' => 'test-ige7.pdf',
'storage_path' => '',
'mime_type' => 'application/pdf',
'file_hash' => hash('sha256', 'test-ige7'),
'beleg_datum' => $datum,
'eingangs_datum' => $datum,
'belegtyp' => 'Eingangsrechnung',
]);
\Steuerkram\Models\Booking::create([
'beleg_id' => $belegIgE7,
'buchungs_datum' => $datum,
'buchungstyp' => 'Ausgabe',
'steuerart' => 'ig_erwerb_7',
'kategorie_konto_id' => $ausgabeId,
'zahlungskonto_id' => $bankId,
'betrag_netto' => 300.00,
'ust_satz' => 0.0,
'buchungstext' => 'Test ig. Erwerb 7%',
]);
// ── UStVA berechnen und Kennzahlen prüfen ─────────────────────────
$calc = new \Steuerkram\Services\UstvaCalculator();
$kz = $calc->calculate($year, $month);
// Kz 41: ig. Lieferung 1000 €
$this->assert(
(float)$kz['41']['betrag'] >= 1000.00,
'Kz 41 (ig. Lieferung): Betrag ≥ 1.000 €'
);
// Kz 44: Ausfuhr 2000 €
$this->assert(
(float)$kz['44']['betrag'] >= 2000.00,
'Kz 44 (Ausfuhr): Betrag ≥ 2.000 €'
);
// Kz 89: ig. Erwerb 19% Bemessungsgrundlage 500 €
$this->assert(
(float)$kz['89']['betrag'] >= 500.00,
'Kz 89 (ig. Erwerb 19% Bmgl.): Betrag ≥ 500 €'
);
// Kz 91: USt auf ig. Erwerb 19% = 500 * 0.19 = 95 €
$this->assertEquals(
round(500.00 * 0.19, 2),
(float)$kz['91']['steuer'],
'Kz 91 (USt ig. Erwerb 19%): Steuer = 95,00 €'
);
// Kz 93: ig. Erwerb 7% Bemessungsgrundlage 300 €
$this->assert(
(float)$kz['93']['betrag'] >= 300.00,
'Kz 93 (ig. Erwerb 7% Bmgl.): Betrag ≥ 300 €'
);
// Kz 94: USt auf ig. Erwerb 7% = 300 * 0.07 = 21 €
$this->assertEquals(
round(300.00 * 0.07, 2),
(float)$kz['94']['steuer'],
'Kz 94 (USt ig. Erwerb 7%): Steuer = 21,00 €'
);
// Kz 67: Vorsteuer aus ig. Erwerb = Kz 91 + Kz 94 = 116 €
$erwartetKz67 = round((float)$kz['91']['steuer'] + (float)$kz['94']['steuer'], 2);
$this->assertEquals(
$erwartetKz67,
(float)$kz['67']['steuer'],
'Kz 67 (Vorsteuer ig. Erwerb) = Kz 91 + Kz 94'
);
// Kz 69 Plausibilitätsprüfung: ig. Erwerb neutralisiert sich durch Kz 67
// USt auf Umsätze (83+84) + ig. Erwerb (91+94) - Vorsteuer (66) = 69
$ust = (float)$kz['83']['steuer'] + (float)$kz['84']['steuer']
+ (float)$kz['91']['steuer'] + (float)$kz['94']['steuer'];
$erwartetKz69 = round($ust - (float)$kz['66']['steuer'], 2);
$this->assertEquals(
$erwartetKz69,
(float)$kz['69']['steuer'],
'Kz 69 (Zahllast) korrekt berechnet'
);
// ig. Erwerb darf NICHT in Kz 35 oder Kz 61/62 landen
// (kz35 enthält nur normale 0%-Einnahmen, kz61 nur normale Vorsteuer)
// Wir buchten keine normalen 0%-Einnahmen, also muss Kz 35 = 0 sein
$this->assertEquals(
0.0,
(float)$kz['35']['betrag'],
'Kz 35 (steuerfreie Inlandsumsätze) = 0 (kein normaler 0%-Umsatz gebucht)'
);
}
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;
}
}