157 lines
6.9 KiB
PHP
157 lines
6.9 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
/**
|
||
* Test 100: Gezahlte Vorsteuer als Betriebsausgabe in der EÜR.
|
||
*
|
||
* Die EÜR wird nach der Bruttomethode gerechnet: vereinnahmte USt ist
|
||
* Betriebseinnahme (Zeile 17), an das Finanzamt gezahlte USt ist
|
||
* Betriebsausgabe (Zeile 58) – und die gezahlte Vorsteuer gehört als
|
||
* Betriebsausgabe in Zeile 57 (ELSTER-Kennzahl 185, Migration 095).
|
||
*
|
||
* Maßgeblich für die Summenbildung ist dabei `kontenart`; `euer_zeile` wertet
|
||
* der EuerCalculator nur beim Wert '74' aus. Der Test prüft trotzdem beides,
|
||
* weil die Zeilennummer die Position der amtlichen Anlage EÜR dokumentiert.
|
||
*/
|
||
class VorsteuerEuerZeileTest extends TestCase
|
||
{
|
||
protected string $testName = 'Test 100: Vorsteuer in EÜR-Zeile 57 (Kz 185)';
|
||
|
||
public function run(): void
|
||
{
|
||
// ── 1. Kontenstamm: Vorsteuerkonten sind Betriebsausgabe, Zeile 57 ──
|
||
foreach (['1571', '1574', '1576'] as $nr) {
|
||
$kto = \Steuerkram\Database::fetchOne(
|
||
'SELECT kontenart, euer_zeile FROM accounts WHERE kontonummer = ?',
|
||
[$nr]
|
||
);
|
||
$this->assertNotEmpty($kto, "Vorsteuerkonto $nr existiert");
|
||
$this->assertEquals('Betriebsausgabe', $kto['kontenart'] ?? null, "Konto $nr ist Betriebsausgabe");
|
||
$this->assertEquals('57', $kto['euer_zeile'] ?? null, "Konto $nr hat euer_zeile=57");
|
||
}
|
||
|
||
// ── 2. Auswahlliste im Kontenformular führt Zeile 57 mit Kennzahl 185 ──
|
||
$form = (string)file_get_contents(__DIR__ . '/../src/Views/accounts/form.php');
|
||
$this->assert(
|
||
str_contains($form, "'57' => '57 (Kz 185)"),
|
||
'Kontenformular bietet EÜR-Zeile 57 mit ELSTER-Kennzahl 185 an'
|
||
);
|
||
$this->assert(
|
||
str_contains($form, "(string)\$val ? ' selected' : ''"),
|
||
'Gespeicherte EÜR-Zeile wird im Formular vorausgewählt (String-Vergleich)'
|
||
);
|
||
|
||
// ── 3. Vorsteuer einer Ausgabe landet in der EÜR-Ausgabenspalte ──────
|
||
$datum = date('Y-m-d');
|
||
$jahr = (int)date('Y');
|
||
$bankId = $this->findAccountId('1200');
|
||
$kostenId = $this->findAccountId('4600');
|
||
|
||
if (!$bankId || !$kostenId) {
|
||
$this->assert(false, 'Benötigte Konten (1200, 4600) nicht gefunden');
|
||
return;
|
||
}
|
||
|
||
$vorher = (new \Steuerkram\Services\EuerCalculator())->calculate($jahr);
|
||
|
||
$beleg = \Steuerkram\Models\Beleg::create([
|
||
'beleg_nr' => 'TEST-VST185-' . uniqid(),
|
||
'filename' => 'test.pdf',
|
||
'storage_path' => '',
|
||
'mime_type' => 'application/pdf',
|
||
'file_hash' => hash('sha256', 'vst185' . uniqid()),
|
||
'beleg_datum' => $datum,
|
||
'belegtyp' => 'Eingangsrechnung',
|
||
]);
|
||
\Steuerkram\Models\Booking::create([
|
||
'beleg_id' => $beleg,
|
||
'buchungs_datum' => $datum,
|
||
'buchungstyp' => 'Ausgabe',
|
||
'kategorie_konto_id' => $kostenId,
|
||
'zahlungskonto_id' => $bankId,
|
||
'betrag_netto' => 1000.00,
|
||
'ust_satz' => 19.0,
|
||
'buchungstext' => 'Test Ausgabe mit Vorsteuer',
|
||
]);
|
||
|
||
$nachher = (new \Steuerkram\Services\EuerCalculator())->calculate($jahr);
|
||
|
||
$ausKonten = array_column($nachher['ausgaben'], 'kontonummer');
|
||
$this->assert(
|
||
in_array('1576', $ausKonten, true),
|
||
'Konto 1576 erscheint als Betriebsausgabe in der EÜR'
|
||
);
|
||
|
||
// Netto 1000 + Vorsteuer 190 = 1190 mehr Betriebsausgaben
|
||
$delta = round((float)$nachher['total_ausgaben'] - (float)$vorher['total_ausgaben'], 2);
|
||
$this->assertEquals(1190.00, $delta, 'Betriebsausgaben steigen um Netto + Vorsteuer');
|
||
|
||
// Vorsteuer darf nicht im Abschnitt "nicht abzugsfähig" landen
|
||
$naKonten = array_column($nachher['nicht_abzugsfaehig'], 'kontonummer');
|
||
$this->assert(
|
||
!in_array('1576', $naKonten, true),
|
||
'Konto 1576 erscheint nicht unter den nicht abzugsfähigen Ausgaben'
|
||
);
|
||
|
||
// ── 4. Reverse-Charge bleibt ergebnisneutral ────────────────────────
|
||
// Die Kindzeilen auf 1574 (Vorsteuer) und 1774 (Erwerbsteuer) tragen
|
||
// denselben Betrag: als Betriebsausgabe bzw. Betriebseinnahme heben sie
|
||
// sich auf. Bliebe 1574 ein Zahlungskonto, wäre der Gewinn zu hoch.
|
||
$ige = \Steuerkram\Database::fetchOne(
|
||
"SELECT kontenart, euer_zeile FROM accounts WHERE kontonummer = '1774'"
|
||
);
|
||
$this->assertEquals('Betriebseinnahme', $ige['kontenart'] ?? null, 'Konto 1774 ist Betriebseinnahme');
|
||
|
||
$vorIge = (new \Steuerkram\Services\EuerCalculator())->calculate($jahr);
|
||
|
||
$belegIge = \Steuerkram\Models\Beleg::create([
|
||
'beleg_nr' => 'TEST-IGE185-' . uniqid(),
|
||
'filename' => 'test.pdf',
|
||
'storage_path' => '',
|
||
'mime_type' => 'application/pdf',
|
||
'file_hash' => hash('sha256', 'ige185' . uniqid()),
|
||
'beleg_datum' => $datum,
|
||
'belegtyp' => 'Eingangsrechnung',
|
||
]);
|
||
\Steuerkram\Models\Booking::create([
|
||
'beleg_id' => $belegIge,
|
||
'buchungs_datum' => $datum,
|
||
'buchungstyp' => 'Ausgabe',
|
||
'kategorie_konto_id' => $kostenId,
|
||
'zahlungskonto_id' => $bankId,
|
||
'betrag_netto' => 500.00,
|
||
'ust_satz' => 0.0,
|
||
'steuerart' => 'ig_erwerb_19',
|
||
'buchungstext' => 'Test ig. Erwerb',
|
||
]);
|
||
|
||
$nachIge = (new \Steuerkram\Services\EuerCalculator())->calculate($jahr);
|
||
|
||
// Nur die Netto-Ausgabe von 500 € darf den Gewinn mindern, die 95 €
|
||
// Erwerbsteuer stehen auf beiden Seiten.
|
||
$this->assertEquals(
|
||
round((float)$vorIge['gewinn'] - 500.00, 2),
|
||
round((float)$nachIge['gewinn'], 2),
|
||
'Erwerbsteuer und Vorsteuer aus ig. Erwerb heben sich im Gewinn auf'
|
||
);
|
||
$this->assertEquals(
|
||
round((float)$vorIge['total_einnahmen'] + 95.00, 2),
|
||
round((float)$nachIge['total_einnahmen'], 2),
|
||
'Erwerbsteuer (1774) erhöht die Betriebseinnahmen um 95 €'
|
||
);
|
||
$this->assertEquals(
|
||
round((float)$vorIge['total_ausgaben'] + 595.00, 2),
|
||
round((float)$nachIge['total_ausgaben'], 2),
|
||
'Netto + Vorsteuer ig. Erwerb (1574) erhöhen die Betriebsausgaben um 595 €'
|
||
);
|
||
|
||
// ── 5. Dashboard-Kacheln (summary) rechnen identisch ────────────────
|
||
$summary = (new \Steuerkram\Services\EuerCalculator())->summary($jahr);
|
||
$this->assertEquals(
|
||
(float)$nachIge['total_ausgaben'],
|
||
(float)$summary['ausgaben'],
|
||
'summary() und calculate() liefern dieselben Betriebsausgaben'
|
||
);
|
||
}
|
||
}
|