- Migration 044: Konten 1574 (VSt i.g.E. 19%) und 1774 (USt i.g.E. 19%) anlegen - Migration 045: Konten 1571/1576 anlegen, ustva_kz='61'/'62' setzen, altes DATEV-Routing (ustva_kz '61'/'62' auf Betriebsausgabe-Konten) entfernen, parent_booking_id-Spalte, VSt-Buchungszeilen für Bestandsbuchungen migrieren - Booking::create(): automatisch VSt-Zeile auf 1576/1571 für Ausgaben mit 7/19 % - Booking::reverse(): VSt-Zeilen beim Storno mitaufheben (reversed_by setzen) - BookingController::destroy(): VSt-Kindzeilen beim Löschen (Testmodus) mit löschen - UstvaCalculator: Kz 61/62 jetzt kontobasiert via 1576/1571 (betrag_netto), Step 2 (buchungsbasiert via ust_satz) entfernt - Beleg::all/find: betrag_brutto-Aggregation und Suche schließen VSt-Zeilen aus - Tests 12, 18 angepasst; Test 28 neu
148 lines
6.8 KiB
PHP
148 lines
6.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Test 28: Vorsteuerkonten-Buchungszeilen.
|
|
*
|
|
* Prüft, dass Ausgabe-Buchungen mit USt 7 % / 19 % automatisch eine
|
|
* VSt-Buchungszeile auf 1571 / 1576 erhalten, die UStVA Kz 61/62 daraus
|
|
* kontobasiert ableitet und ein Storno die VSt-Zeilen mitaufhebt.
|
|
*/
|
|
class VorsteuerkontenTest extends TestCase
|
|
{
|
|
protected string $testName = 'Test 28: Vorsteuerkonten-Buchungszeilen';
|
|
|
|
public function run(): void
|
|
{
|
|
$year = (int)date('Y');
|
|
$month = (int)date('n');
|
|
$datum = date('Y-m-d');
|
|
|
|
$zahlungsId = $this->findAccountId('1200');
|
|
$ausgabeId = $this->findAccountId('4920');
|
|
$konto1576 = \Steuerkram\Database::fetchOne(
|
|
"SELECT id FROM accounts WHERE kontonummer = '1576' AND aktiv = 1"
|
|
);
|
|
$konto1571 = \Steuerkram\Database::fetchOne(
|
|
"SELECT id FROM accounts WHERE kontonummer = '1571' AND aktiv = 1"
|
|
);
|
|
|
|
if (!$zahlungsId || !$ausgabeId || !$konto1576 || !$konto1571) {
|
|
$this->assert(false, 'Benötigte Konten nicht gefunden (1200, 4920, 1571, 1576)');
|
|
return;
|
|
}
|
|
$this->assert(true, 'Konten 1200, 4920, 1571, 1576 vorhanden');
|
|
|
|
// ── UStVA-Stand vor den Testbuchungen ─────────────────────────
|
|
$calc = new \Steuerkram\Services\UstvaCalculator();
|
|
$kzPre = $calc->calculate($year, $month);
|
|
|
|
// ── Beleg anlegen ──────────────────────────────────────────────
|
|
$belegId = \Steuerkram\Models\Beleg::create([
|
|
'beleg_nr' => 'VST-TEST-' . uniqid(),
|
|
'filename' => 'vst-test.pdf',
|
|
'storage_path' => '',
|
|
'mime_type' => 'application/pdf',
|
|
'file_hash' => hash('sha256', 'vst-test-' . uniqid()),
|
|
'beleg_datum' => $datum,
|
|
'belegtyp' => 'Eingangsrechnung',
|
|
]);
|
|
|
|
// ── Ausgabe-Buchung 19 % (Netto=200, VSt=38) ──────────────────
|
|
$bookingId19 = \Steuerkram\Models\Booking::create([
|
|
'beleg_id' => $belegId,
|
|
'buchungs_datum' => $datum,
|
|
'buchungstyp' => 'Ausgabe',
|
|
'kategorie_konto_id' => $ausgabeId,
|
|
'zahlungskonto_id' => $zahlungsId,
|
|
'betrag_netto' => 200.00,
|
|
'ust_satz' => 19.0,
|
|
'buchungstext' => 'Test VSt 19%',
|
|
]);
|
|
|
|
// VSt-Buchungszeile muss auf 1576 angelegt worden sein
|
|
$vstRow19 = \Steuerkram\Database::fetchOne(
|
|
'SELECT bk.*, a.kontonummer FROM bookings bk
|
|
JOIN accounts a ON bk.kategorie_konto_id = a.id
|
|
WHERE bk.parent_booking_id = ?',
|
|
[$bookingId19]
|
|
);
|
|
$this->assert($vstRow19 !== false, 'VSt-Buchungszeile für 19%-Buchung angelegt');
|
|
$this->assertEquals('1576', $vstRow19['kontonummer'] ?? '', 'VSt-Buchungszeile auf Konto 1576');
|
|
$this->assertEquals(38.00, round((float)($vstRow19['betrag_netto'] ?? 0), 2), 'VSt betrag_netto = 38');
|
|
$this->assertEquals(0.00, round((float)($vstRow19['betrag_ust'] ?? 0), 2), 'VSt betrag_ust = 0');
|
|
|
|
// ── Ausgabe-Buchung 7 % (Netto=100, VSt=7) ────────────────────
|
|
$bookingId7 = \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' => 7.0,
|
|
'buchungstext' => 'Test VSt 7%',
|
|
]);
|
|
|
|
$vstRow7 = \Steuerkram\Database::fetchOne(
|
|
'SELECT bk.*, a.kontonummer FROM bookings bk
|
|
JOIN accounts a ON bk.kategorie_konto_id = a.id
|
|
WHERE bk.parent_booking_id = ?',
|
|
[$bookingId7]
|
|
);
|
|
$this->assert($vstRow7 !== false, 'VSt-Buchungszeile für 7%-Buchung angelegt');
|
|
$this->assertEquals('1571', $vstRow7['kontonummer'] ?? '', 'VSt-Buchungszeile auf Konto 1571');
|
|
$this->assertEquals(7.00, round((float)($vstRow7['betrag_netto'] ?? 0), 2), 'VSt betrag_netto = 7');
|
|
|
|
// ── UStVA: Kz 61 und 62 aus Konten lesen ──────────────────────
|
|
$kzMit = $calc->calculate($year, $month);
|
|
|
|
$this->assert(
|
|
round((float)$kzMit['61']['steuer'] - (float)$kzPre['61']['steuer'], 2) >= 38.00,
|
|
'UStVA Kz 61 stieg durch 19%-Buchung um ≥ 38 €'
|
|
);
|
|
$this->assert(
|
|
round((float)$kzMit['62']['steuer'] - (float)$kzPre['62']['steuer'], 2) >= 7.00,
|
|
'UStVA Kz 62 stieg durch 7%-Buchung um ≥ 7 €'
|
|
);
|
|
$this->assert(
|
|
round((float)$kzMit['66']['steuer'] - (float)$kzPre['66']['steuer'], 2) >= 45.00,
|
|
'UStVA Kz 66 stieg um ≥ 45 €'
|
|
);
|
|
|
|
// ── Drill-down Kz 61 enthält die VSt-Buchungszeile ────────────
|
|
$drilldown = $calc->fetchBookingsForKz($year, $month, '61');
|
|
$vstFound = false;
|
|
foreach ($drilldown as $b) {
|
|
if ((int)$b['id'] === (int)$vstRow19['id']) {
|
|
$vstFound = true;
|
|
break;
|
|
}
|
|
}
|
|
$this->assert($vstFound, 'Drill-down Kz 61 enthält die VSt-Buchungszeile');
|
|
|
|
// ── Storno: VSt-Zeile muss mitaufgehoben werden ───────────────
|
|
$reversalId = \Steuerkram\Models\Booking::reverse($bookingId19, 'Testfall VSt-Storno');
|
|
|
|
$vstStornoRow = \Steuerkram\Database::fetchOne(
|
|
'SELECT * FROM bookings WHERE parent_booking_id = ? AND is_reversal = 1',
|
|
[$reversalId]
|
|
);
|
|
$this->assert($vstStornoRow !== false, 'VSt-Stornobuchung wurde angelegt');
|
|
$this->assertEquals(-38.00, round((float)($vstStornoRow['betrag_netto'] ?? 0), 2), 'VSt-Storno betrag_netto = -38');
|
|
|
|
// Original-VSt-Zeile muss als storniert markiert sein
|
|
$vstOriginal = \Steuerkram\Database::fetchOne(
|
|
'SELECT reversed_by FROM bookings WHERE id = ?',
|
|
[(int)$vstRow19['id']]
|
|
);
|
|
$this->assert(!empty($vstOriginal['reversed_by']), 'Original-VSt-Buchungszeile hat reversed_by gesetzt');
|
|
|
|
// UStVA Kz 61 nach Storno: netto Änderung gegenüber vor den Testbuchungen = 0
|
|
// (die 19%-Buchung und ihr Storno heben sich auf; 7%-Buchung geht in Kz 62)
|
|
$kzNach = $calc->calculate($year, $month);
|
|
$delta61 = round((float)$kzNach['61']['steuer'] - (float)$kzPre['61']['steuer'], 2);
|
|
$this->assertEquals(0.00, $delta61, 'Kz 61: Buchung+Storno heben sich gegenüber Ausgangslage auf');
|
|
}
|
|
}
|