Steuerkram/tests/18_StornoBuchungTest.php

122 lines
5.9 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 18: Stornobuchungen in UStVA und EÜR.
*
* Prüft, dass eine stornierte Buchung korrekt mit negativem Betrag angelegt wird
* und sich mit der Originalbuchung in den Berichten gegenseitig auf null aufhebt.
*/
class StornoBuchungTest extends TestCase
{
protected string $testName = 'Test 18: Stornobuchungen in UStVA und EÜR';
public function run(): void
{
$year = (int)date('Y');
$month = (int)date('n');
$datum = date('Y-m-d');
$zahlungsId = $this->findAccountId('1200'); // Bank
$ausgabeId = $this->findAccountId('4920'); // Telefon (ustva_kz=61)
if (!$zahlungsId || !$ausgabeId) {
$this->assert(false, 'Benötigte Konten nicht gefunden – SKR03-Seed vorhanden?');
return;
}
// ── EÜR: Konto-Stand VOR den Test-Buchungen ermitteln ─────────
$euerCalcPre = new \Steuerkram\Services\EuerCalculator();
$euerPre = $euerCalcPre->calculate($year);
$kontoNettoPre = 0.0;
foreach ($euerPre['ausgaben'] as $row) {
if ((int)$row['id'] === (int)$ausgabeId) {
$kontoNettoPre = (float)$row['netto'];
break;
}
}
// ── Beleg anlegen ──────────────────────────────────────────────
$belegId = \Steuerkram\Models\Beleg::create([
'beleg_nr' => 'STORNO-TEST-' . uniqid(),
'filename' => 'storno-test.pdf',
'storage_path' => '',
'mime_type' => 'application/pdf',
'file_hash' => hash('sha256', 'storno-test-' . uniqid()),
'beleg_datum' => $datum,
'belegtyp' => 'Ausgangsrechnung',
]);
// ── Ausgabe-Buchung anlegen (Netto=100, USt 19%=19, Brutto=119) ─
$bookingId = \Steuerkram\Models\Booking::create([
'beleg_id' => $belegId,
'buchungs_datum' => $datum,
'buchungstyp' => 'Ausgabe',
'kategorie_konto_id' => $ausgabeId,
'zahlungskonto_id' => $zahlungsId,
'betrag_netto' => 100.00,
'ust_satz' => 19.0,
'buchungstext' => 'Test-Ausgabe für Storno',
]);
$original = \Steuerkram\Models\Booking::find($bookingId);
$this->assertEquals(100.00, round((float)$original['betrag_netto'], 2), 'Originalbuchung: betrag_netto = 100');
$this->assertEquals(19.00, round((float)$original['betrag_ust'], 2), 'Originalbuchung: betrag_ust = 19');
$this->assertEquals(119.00, round((float)$original['betrag_brutto'], 2),'Originalbuchung: betrag_brutto = 119');
// ── Stornieren ────────────────────────────────────────────────
$reversalId = \Steuerkram\Models\Booking::reverse($bookingId, 'Testfall Storno');
$reversal = \Steuerkram\Models\Booking::find($reversalId);
$this->assertEquals(1, (int)$reversal['is_reversal'], 'Stornobuchung: is_reversal = 1');
$this->assertEquals(-100.00, round((float)$reversal['betrag_netto'], 2), 'Stornobuchung: betrag_netto = -100');
$this->assertEquals(-19.00, round((float)$reversal['betrag_ust'], 2), 'Stornobuchung: betrag_ust = -19');
$this->assertEquals(-119.00, round((float)$reversal['betrag_brutto'], 2), 'Stornobuchung: betrag_brutto = -119');
// ── EÜR: Storno + Original heben sich auf (Konto-Saldo unverändert) ─
// Vergleich mit dem Stand vor den Test-Buchungen, da auf dem Produktivsystem
// bereits echte Buchungen auf dem Konto existieren können.
$euerCalc = new \Steuerkram\Services\EuerCalculator();
$euer = $euerCalc->calculate($year);
$kontoNetto = 0.0;
foreach ($euer['ausgaben'] as $row) {
if ((int)$row['id'] === (int)$ausgabeId) {
$kontoNetto = (float)$row['netto'];
break;
}
}
$this->assertEquals(
round($kontoNettoPre, 2),
round($kontoNetto, 2),
'EÜR: Storno + Original = 0 auf Ausgabe-Konto'
);
// ── UStVA: Vorsteuer-KZ hebt sich auf ─────────────────────────
// Kz 66 wird kontobasiert über VSt-Buchungszeilen (Konten 1571/1576) ermittelt.
// Zur Original-Ausgabe gehört eine VSt-Zeile (+19), zum Storno eine VSt-Storno-Zeile (-19).
// Wir prüfen, dass die VSt-Storno-Zeile im Drill-down für Kz 66 erscheint.
$vstReversalRow = \Steuerkram\Database::fetchOne(
'SELECT * FROM bookings WHERE parent_booking_id = ? AND is_reversal = 1',
[$reversalId]
);
$this->assert($vstReversalRow !== false, 'VSt-Stornobuchung wurde zu Storno angelegt');
if ($vstReversalRow) {
$this->assertEquals(-19.00, round((float)$vstReversalRow['betrag_netto'], 2), 'VSt-Storno: betrag_netto = -19');
}
$ustvaCalc = new \Steuerkram\Services\UstvaCalculator();
$bookings = $ustvaCalc->fetchBookingsForKz($year, $month, '66');
$vstReversalFound = false;
foreach ($bookings as $b) {
if ($vstReversalRow && (int)$b['id'] === (int)$vstReversalRow['id']) {
$vstReversalFound = true;
$this->assertEquals(1, (int)$b['is_reversal'], 'UStVA-Drilldown: VSt-Stornobuchung is_reversal = 1');
$this->assertEquals(-19.00, round((float)$b['betrag_netto'], 2), 'UStVA-Drilldown: VSt-Storno betrag_netto = -19');
break;
}
}
$this->assert($vstReversalFound, 'UStVA-Drilldown Kz 66: VSt-Stornobuchung erscheint in Detailansicht');
}
}