From b28ac191faa0f55ff10bf1c7040679a3fa9e977e Mon Sep 17 00:00:00 2001 From: fds2610-bot Date: Thu, 14 May 2026 19:22:42 +0200 Subject: [PATCH] Feature: UStVA Kz 83 = ust81 + ust89 - Kz66 - Kz61 (nicht mehr kontobasiert) --- Changes.md | 5 ++++ docs/berechnungslogik.md | 2 +- src/Services/UstvaCalculator.php | 4 ++-- tests/29_UmsatzsteuerkontenTest.php | 36 +++++++++++++++-------------- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/Changes.md b/Changes.md index 804acc2..b4b0248 100644 --- a/Changes.md +++ b/Changes.md @@ -2,6 +2,11 @@ --- +## 2026-05-14 – Feature: UStVA Kz 83 = ust81 + ust89 − Kz66 − Kz61 + +- `UstvaCalculator`: Kz 83 wird nun als `ust81 + ust89 − Kz66 − Kz61` berechnet (nicht mehr kontobasiert via ustva_kz='83') +- Test 29: angepasst (7%-Buchung auf korrektes Konto 8300; delta83-Erwartung aktualisiert) + ## 2026-05-14 – Feature: UStVA Kz 61 aus ust89 abgeleitet (ReverseCharge-Symmetrie) - `UstvaCalculator`: Kz 61 = ust89 (nicht mehr kontobasiert via Konto 1574) – fachlich korrekt, da VSt ig. Erwerb = USt ig. Erwerb diff --git a/docs/berechnungslogik.md b/docs/berechnungslogik.md index 498dc25..5045956 100644 --- a/docs/berechnungslogik.md +++ b/docs/berechnungslogik.md @@ -51,7 +51,7 @@ Diese Berechnung wird ausschließlich für **monatliche** Voranmeldungen unterst | **89** | Steuerpfl. innergemeinschaftliche Erwerbe 19 % | Steuerart | `floor(SUM(betrag_netto))` WHERE `steuerart='ig_erwerb_19'` – **auf volle Euro abgerundet (floor)** | | **66** | Gesamte Vorsteuerbeträge | Konto | `SUM(betrag_netto)` WHERE `ustva_kz='66'` (Konten 1571, 1576) | | **61** | Vorsteuerbeträge i.g. Erwerb | abgeleitet | `ust89` (= `round(Kz 89 × 0,19, 2)`) – ReverseCharge-Symmetrie: VSt ig. Erwerb = USt ig. Erwerb | -| **83** | Vorauszahlung / Überschuss | abgeleitet | `(Summe ustva_kz='83') − Kz 66 − Kz 61` | +| **83** | Vorauszahlung / Überschuss | abgeleitet | `ust81 + ust89 − Kz 66 − Kz 61` | Zusätzlich werden zwei **reine Anzeigefelder** berechnet (erscheinen im Bericht, aber **nicht** im XML): diff --git a/src/Services/UstvaCalculator.php b/src/Services/UstvaCalculator.php index aba5d3e..57ce422 100644 --- a/src/Services/UstvaCalculator.php +++ b/src/Services/UstvaCalculator.php @@ -20,7 +20,7 @@ use Steuerkram\Database; * Abgeleitete Kennzahlen: * ust89 = round(Kz 89 × 0,19, 2) (abzuführende USt aus Kz 89) * Kz 61 = ust89 (VSt ig. Erwerb = USt ig. Erwerb, ReverseCharge-Symmetrie) - * Kz 83 = (Summe ustva_kz='83') − Kz 66 − Kz 61 (Vorauszahlung / Überschuss) + * Kz 83 = ust81 + ust89 − Kz 66 − Kz 61 (Vorauszahlung / Überschuss) * * Nur-Anzeige (kein XML-Export): * ust81 = round(Kz 81 × 0,19, 2) (abzuführende USt aus Kz 81) @@ -84,7 +84,7 @@ class UstvaCalculator $ust89 = round($kz89 * 0.19, 2); // Kz 61 (VSt ig. Erwerb) = ust89: ReverseCharge ist immer symmetrisch zur USt aus Kz 89 $kz61 = $ust89; - $kz83 = $n('83') - $kz66 - $kz61; + $kz83 = $ust81 + $ust89 - $kz66 - $kz61; return [ '81' => ['name' => 'Steuerpflichtige Umsätze zum Steuersatz von 19 %', 'betrag' => $kz81, 'steuer' => null, 'xml' => true, 'ganze_euro' => true], diff --git a/tests/29_UmsatzsteuerkontenTest.php b/tests/29_UmsatzsteuerkontenTest.php index b34701a..d90d646 100644 --- a/tests/29_UmsatzsteuerkontenTest.php +++ b/tests/29_UmsatzsteuerkontenTest.php @@ -6,8 +6,8 @@ declare(strict_types=1); * Test 29: USt-Buchungszeilen für Ausgangsrechnungen. * * Prüft, dass Einnahme-Buchungen mit USt 7 % / 19 % automatisch eine - * USt-Buchungszeile auf 1771 / 1776 erhalten, die UStVA Kz 83/84 daraus - * kontobasiert ableitet und ein Storno die USt-Zeilen mitaufhebt. + * USt-Buchungszeile auf 1771 / 1776 erhalten und ein Storno die USt-Zeilen + * mitaufhebt. Kz 83 = ust81 + ust89 − Kz66 − Kz61 (abgeleitet, nicht kontobasiert). */ class UmsatzsteuerkontenTest extends TestCase { @@ -19,20 +19,21 @@ class UmsatzsteuerkontenTest extends TestCase $month = (int)date('n'); $datum = date('Y-m-d'); - $zahlungsId = $this->findAccountId('1200'); - $einnahmeId = $this->findAccountId('8400'); - $konto1776 = \Steuerkram\Database::fetchOne( + $zahlungsId = $this->findAccountId('1200'); + $einnahmeId = $this->findAccountId('8400'); // Erlöse 19 % USt (ustva_kz='81') + $einnahme7Id = $this->findAccountId('8300'); // Erlöse 7 % USt (ustva_kz=NULL) + $konto1776 = \Steuerkram\Database::fetchOne( "SELECT id FROM accounts WHERE kontonummer = '1776' AND aktiv = 1" ); - $konto1771 = \Steuerkram\Database::fetchOne( + $konto1771 = \Steuerkram\Database::fetchOne( "SELECT id FROM accounts WHERE kontonummer = '1771' AND aktiv = 1" ); - if (!$zahlungsId || !$einnahmeId || !$konto1776 || !$konto1771) { - $this->assert(false, 'Benötigte Konten nicht gefunden (1200, 8400, 1771, 1776)'); + if (!$zahlungsId || !$einnahmeId || !$einnahme7Id || !$konto1776 || !$konto1771) { + $this->assert(false, 'Benötigte Konten nicht gefunden (1200, 8300, 8400, 1771, 1776)'); return; } - $this->assert(true, 'Konten 1200, 8400, 1771, 1776 vorhanden'); + $this->assert(true, 'Konten 1200, 8300, 8400, 1771, 1776 vorhanden'); // ── UStVA-Stand vor den Testbuchungen ───────────────────────── $calc = new \Steuerkram\Services\UstvaCalculator(); @@ -73,12 +74,12 @@ class UmsatzsteuerkontenTest extends TestCase $this->assertEquals(95.00, round((float)($ustRow19['betrag_netto'] ?? 0), 2), 'USt betrag_netto = 95'); $this->assertEquals(0.00, round((float)($ustRow19['betrag_ust'] ?? 0), 2), 'USt betrag_ust = 0'); - // ── Einnahme-Buchung 7 % (Netto=200, USt=14) ────────────────── + // ── Einnahme-Buchung 7 % (Netto=200, USt=14) auf korrektem 7%-Konto 8300 $bookingId7 = \Steuerkram\Models\Booking::create([ 'beleg_id' => $belegId, 'buchungs_datum' => $datum, 'buchungstyp' => 'Einnahme', - 'kategorie_konto_id' => $einnahmeId, + 'kategorie_konto_id' => $einnahme7Id, 'zahlungskonto_id' => $zahlungsId, 'betrag_netto' => 200.00, 'ust_satz' => 7.0, @@ -95,10 +96,10 @@ class UmsatzsteuerkontenTest extends TestCase $this->assertEquals('1771', $ustRow7['kontonummer'] ?? '', 'USt-Buchungszeile auf Konto 1771'); $this->assertEquals(14.00, round((float)($ustRow7['betrag_netto'] ?? 0), 2), 'USt betrag_netto = 14'); - // ── UStVA: Kz 83 (Vorauszahlung) aus USt-Konten ────────────── - // Kz 83 = (Summe USt-Konten 1771+1774+1776) - Kz66 - Kz61 - // Nach 19%-Einnahme (+95 auf 1776) und 7%-Einnahme (+14 auf 1771): - // Kz83 stieg um mindestens 95 € (19%-Anteil) + // ── UStVA: Kz 83 = ust81 + ust89 − Kz66 − Kz61 ───────────── + // Nach 19%-Einnahme (500 netto → floor(500+X)*0,19 steigt um 95) und + // 7%-Einnahme auf 8300 (ustva_kz=NULL → kein Einfluss auf Kz 81/83): + // Kz 83 stieg um mindestens 95 € $kzMit = $calc->calculate($year, $month); $this->assert( @@ -134,9 +135,10 @@ class UmsatzsteuerkontenTest extends TestCase ); $this->assert(!empty($ustOriginal['reversed_by']), 'Original-USt-Buchungszeile hat reversed_by gesetzt'); - // Kz 83 nach Storno der 19%-Buchung: nur noch 7%-USt (14 €) verbleibt + // Kz 83 nach Storno der 19%-Buchung: kz81 zurück auf Baseline → delta83 = 0 + // (7%-Buchung auf 8300 hat ustva_kz=NULL und beeinflusst Kz 81/83 nicht) $kzNach = $calc->calculate($year, $month); $delta83 = round((float)$kzNach['83']['steuer'] - (float)$kzPre['83']['steuer'], 2); - $this->assertEquals(14.00, $delta83, 'Kz 83: Netto-Delta = 14 € nach Storno der 19%-Buchung'); + $this->assertEquals(0.00, $delta83, 'Kz 83: zurück auf Ausgangswert nach Storno der 19%-Buchung'); } }