130 lines
5.5 KiB
PHP
130 lines
5.5 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
use Steuerkram\Models\Beleg;
|
||
use Steuerkram\Models\Booking;
|
||
use Steuerkram\Database;
|
||
|
||
/**
|
||
* Test 89: Booking::create() – die drei Schreibpfade (Fix #159).
|
||
*
|
||
* Deckt die aus create() extrahierten Teilschritte ab:
|
||
* - insertHauptbuchung(): einfache Buchung ohne 7/19%-USt und ohne ig. Erwerb
|
||
* - insertVorsteuerUmsatzsteuerZeile(): normale Buchung mit 19% USt/VSt
|
||
* - insertIgErwerbReverseCharge(): ig. Erwerb 19% mit zwei Kindzeilen
|
||
*/
|
||
class BookingCreatePfadeTest extends TestCase
|
||
{
|
||
protected string $testName = 'Test 89: Booking::create() – Schreibpfade';
|
||
|
||
public function run(): void
|
||
{
|
||
$zahlungsId = $this->findAccountId('1200');
|
||
$ausgabeId = $this->findAccountId('4120');
|
||
|
||
if (!$zahlungsId || !$ausgabeId) {
|
||
$this->assert(false, 'Benötigte Konten nicht gefunden (1200, 4120)');
|
||
return;
|
||
}
|
||
$this->assert(true, 'Konten 1200, 4120 vorhanden');
|
||
|
||
$belegId = Beleg::create([
|
||
'beleg_nr' => 'BK-TEST-' . uniqid(),
|
||
'filename' => 'bk-test.pdf',
|
||
'storage_path' => '',
|
||
'mime_type' => 'application/pdf',
|
||
'file_hash' => hash('sha256', 'bk-test-' . uniqid()),
|
||
'beleg_datum' => date('Y-m-d'),
|
||
'belegtyp' => 'Eingangsrechnung',
|
||
]);
|
||
|
||
$this->testNurHauptbuchung($belegId, $ausgabeId, $zahlungsId);
|
||
$this->testMitVorsteuerZeile($belegId, $ausgabeId, $zahlungsId);
|
||
$this->testMitIgErwerbKindzeilen($belegId, $ausgabeId, $zahlungsId);
|
||
}
|
||
|
||
/** Buchung ohne 7/19%-USt und ohne ig. Erwerb → genau eine Zeile. */
|
||
private function testNurHauptbuchung(int $belegId, int $ausgabeId, int $zahlungsId): void
|
||
{
|
||
$bookingId = Booking::create([
|
||
'beleg_id' => $belegId,
|
||
'buchungs_datum' => date('Y-m-d'),
|
||
'buchungstyp' => 'Ausgabe',
|
||
'kategorie_konto_id' => $ausgabeId,
|
||
'zahlungskonto_id' => $zahlungsId,
|
||
'betrag_netto' => 42.00,
|
||
'ust_satz' => 0.0,
|
||
'buchungstext' => 'Test ohne USt-Zeile',
|
||
]);
|
||
|
||
$rows = Database::fetchAll('SELECT * FROM bookings WHERE beleg_id = ? AND id = ?', [$belegId, $bookingId]);
|
||
$this->assertEquals(1, count($rows), 'Buchung ohne 7/19%-USt erzeugt genau eine Zeile');
|
||
|
||
$kinder = Database::fetchAll('SELECT * FROM bookings WHERE parent_booking_id = ?', [$bookingId]);
|
||
$this->assertEquals(0, count($kinder), 'Buchung ohne 7/19%-USt erzeugt keine Kindzeilen');
|
||
}
|
||
|
||
/** Normale Buchung mit 19% USt → Hauptbuchung plus VSt-Korrekturzeile. */
|
||
private function testMitVorsteuerZeile(int $belegId, int $ausgabeId, int $zahlungsId): void
|
||
{
|
||
$bookingId = Booking::create([
|
||
'beleg_id' => $belegId,
|
||
'buchungs_datum' => date('Y-m-d'),
|
||
'buchungstyp' => 'Ausgabe',
|
||
'kategorie_konto_id' => $ausgabeId,
|
||
'zahlungskonto_id' => $zahlungsId,
|
||
'betrag_netto' => 100.00,
|
||
'ust_satz' => 19.0,
|
||
'buchungstext' => 'Test mit VSt-Zeile',
|
||
]);
|
||
|
||
$kinder = Database::fetchAll(
|
||
'SELECT bk.*, a.kontonummer FROM bookings bk
|
||
JOIN accounts a ON bk.kategorie_konto_id = a.id
|
||
WHERE bk.parent_booking_id = ?',
|
||
[$bookingId]
|
||
);
|
||
$this->assertEquals(1, count($kinder), 'Buchung mit 19% USt erzeugt genau eine VSt-Korrekturzeile');
|
||
|
||
$vstZeile = $kinder[0] ?? null;
|
||
$this->assert($vstZeile !== null, 'VSt-Korrekturzeile vorhanden');
|
||
if ($vstZeile !== null) {
|
||
$this->assertEquals('1576', $vstZeile['kontonummer'], 'VSt-Korrekturzeile bucht auf Konto 1576 (VSt 19%)');
|
||
$this->assertEquals(19.00, round((float)$vstZeile['betrag_netto'], 2), 'VSt-Korrekturzeile: Betrag = 19,00 €');
|
||
$this->assertEquals($bookingId, (int)$vstZeile['parent_booking_id'], 'VSt-Korrekturzeile referenziert die Hauptbuchung über parent_booking_id');
|
||
}
|
||
}
|
||
|
||
/** ig. Erwerb 19% → zwei Kindzeilen (VST_IGE_19 und UST_IGE_19). */
|
||
private function testMitIgErwerbKindzeilen(int $belegId, int $ausgabeId, int $zahlungsId): void
|
||
{
|
||
$bookingId = Booking::create([
|
||
'beleg_id' => $belegId,
|
||
'buchungs_datum' => date('Y-m-d'),
|
||
'buchungstyp' => 'Ausgabe',
|
||
'kategorie_konto_id' => $ausgabeId,
|
||
'zahlungskonto_id' => $zahlungsId,
|
||
'betrag_netto' => 1000.00,
|
||
'ust_satz' => 0.0,
|
||
'steuerart' => 'ig_erwerb_19',
|
||
'buchungstext' => 'Test ig. Erwerb 19%',
|
||
]);
|
||
|
||
$kinder = Database::fetchAll(
|
||
'SELECT bk.*, a.kontonummer FROM bookings bk
|
||
JOIN accounts a ON bk.kategorie_konto_id = a.id
|
||
WHERE bk.parent_booking_id = ?
|
||
ORDER BY a.kontonummer',
|
||
[$bookingId]
|
||
);
|
||
$this->assertEquals(2, count($kinder), 'ig. Erwerb 19% erzeugt genau zwei Kindzeilen');
|
||
|
||
$summeKinder = 0.0;
|
||
foreach ($kinder as $kind) {
|
||
$this->assertEquals($bookingId, (int)$kind['parent_booking_id'], 'Kindzeile referenziert die Hauptbuchung');
|
||
$summeKinder += (float)$kind['betrag_netto'];
|
||
}
|
||
$this->assertEquals(380.00, round($summeKinder, 2), 'Summe der Kindzeilen = 2 × 19% von 1000 € = 380 €');
|
||
}
|
||
}
|