114 lines
5.4 KiB
PHP
114 lines
5.4 KiB
PHP
<?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 enthält alle inländischen Ausgaben mit Vorsteuer (buchungsbasiert).
|
||
// Original: +19, Storno: -19 → Summe = 0 (oder weniger als andere Tests einbringen).
|
||
// Da weitere Tests parallel laufen können, prüfen wir nur, dass die Storno-Buchung
|
||
// als eigenständige Zeile in fetchBookingsForKz erscheint.
|
||
$ustvaCalc = new \Steuerkram\Services\UstvaCalculator();
|
||
$bookings = $ustvaCalc->fetchBookingsForKz($year, $month, '66');
|
||
|
||
$reversalFound = false;
|
||
foreach ($bookings as $b) {
|
||
if ((int)$b['id'] === $reversalId) {
|
||
$reversalFound = true;
|
||
$this->assertEquals(1, (int)$b['is_reversal'], 'UStVA-Drilldown: Stornobuchung is_reversal = 1');
|
||
$this->assertEquals(-19.00, round((float)$b['betrag_ust'], 2), 'UStVA-Drilldown: Storno betrag_ust = -19');
|
||
break;
|
||
}
|
||
}
|
||
$this->assert($reversalFound, 'UStVA-Drilldown Kz 66: Stornobuchung erscheint in Detailansicht');
|
||
}
|
||
}
|