diff --git a/Changes.md b/Changes.md index 3550cd2..e45ecef 100644 --- a/Changes.md +++ b/Changes.md @@ -18,17 +18,6 @@ --- -## 2026-04-26 – Fix UStVA: Kennziffern auf offizielle ELSTER-Definitionen korrigiert - -### Geändert -- `src/Services/UstvaCalculator.php`: Kz 66 ist jetzt die primäre Inlandsvorsteuer (§§ 14, 14a) – alle Ausgabe-Buchungen mit Vorsteuer fließen direkt in Kz 66 (buchungsbasiert, unabhängig vom USt-Satz). Kz 61 ist jetzt Vorsteuer aus ig. Erwerben (§ 3d) = Kz89×0,19 + Kz93×0,07. Kz 62 (Einfuhrumsatzsteuer) und Kz 67 (§ 13b) werden auf 0 gesetzt. Kz 83 ist jetzt das Ergebnis (Verbleibende Vorauszahlung / Überschuss) statt der USt auf 19 %-Umsätze. Kz 35/44 (veraltet seit Migration 017) und Kz 91/94 (wurden fälschlich als USt-Beträge auf ig. Erwerb genutzt) entfernt. Kz 43 (Ausfuhren) und Kz 48 (steuerfreie Umsätze ohne VSt-Abzug) hinzugefügt. -- `src/Services/ElsterXmlService.php`: Betragsfelder auf korrekte Kz aktualisiert (43/48 statt 35/44); Kz39-Export (Sondervorauszahlung) durch Kz83-Export (Vorauszahlung/Überschuss) ersetzt. -- `src/Views/tax/ustva_show.php`: Abschnitte und Beschriftungen auf korrekte ELSTER-Kennziffern angepasst. -- `src/Views/tax/ustva_kz_bookings.php`: Referenz auf Kz 69 → Kz 83 umgestellt. -- `src/Controllers/UstvaController.php`: Whitelist gültiger Kennziffern aktualisiert. -- `docs/berechnungslogik.md`: UStVA-Abschnitt vollständig neu beschrieben. - ---- ## 2026-04-26 – KI-Diagnose: Erreichbarkeitsprüfung und Fehlerlog für Ollama diff --git a/docs/berechnungslogik.md b/docs/berechnungslogik.md index d6b4bb5..9d4cd07 100644 --- a/docs/berechnungslogik.md +++ b/docs/berechnungslogik.md @@ -43,31 +43,44 @@ Die EÜR basiert auf dem Feld `accounts.kontenart` sowie `accounts.euer_zeile` d Die UStVA kombiniert drei Quellen: -**Quelle 1 – kontobasiert** (`accounts.ustva_kz`): Umsatz- und steuerfreie Konten. Buchungen mit EU-Steuerarten werden hier ausgeschlossen. +**Quelle 1 – kontobasiert** (`accounts.ustva_kz`): reguläre Umsätze. Buchungen mit EU-Steuerarten werden hier ausgeschlossen. Kz 61/62 sind aus dieser Quelle entfernt – `ustva_kz='61'/'62'` wird ignoriert. -**Quelle 2 – buchungsbasiert** (`buchungstyp='Ausgabe'`, `betrag_ust != 0`): Alle inländischen Eingangsrechnungen mit Vorsteuer → **Kz 66** (§§ 14, 14a UStG). Buchungen mit EU-Steuerarten sind ausgenommen. Der Wert `ustva_kz` auf Vorsteuer-Konten wird nicht ausgewertet. +**Quelle 2 – buchungsbasiert** (`bookings.ust_satz`): Vorsteuer Kz 61/62. Alle Ausgabe-Buchungen mit `betrag_ust != 0` fließen anhand ihres `ust_satz` direkt in Kz 61 (19 %) bzw. Kz 62 (7 %) ein, unabhängig davon welches Konto gebucht wurde. Buchungen mit EU-Steuerarten sind ausgenommen. **Quelle 3 – steuerartbasiert** (`bookings.steuerart`): EU-Sonderfälle (ig. Lieferung, Ausfuhr, ig. Erwerb). Diese Buchungen landen unabhängig vom Kategorie-Konto in den richtigen Kennzahlen. ### Kontozuordnung und Kennzahlen -| Kz | ELSTER-Bezeichnung | Quelle | Erläuterung | +| Kz | Bezeichnung | Quelle | Erläuterung | |---|---|---|---| | **81** | Steuerpfl. Umsätze 19 % | `SUM(betrag_netto)` WHERE `ustva_kz='81'` | 8400, 8570, 8720, 8801, 8820, 8922 | +| **83** | USt auf steuerpfl. Umsätze 19 % | `SUM(betrag_ust)` WHERE `ustva_kz='81'` | s.o. | | **86** | Steuerpfl. Umsätze 7 % | `SUM(betrag_netto)` WHERE `ustva_kz='86'` | 8300, 8710, 8921 | -| **41** | Steuerfreie ig. Lieferungen (§ 4 Nr. 1b) | kontobasiert (`ustva_kz='41'`) **+** `steuerart='ig_lieferung'` | 8125; oder Buchung mit steuerart | -| **43** | Steuerfreie Ausfuhren (§ 4 Nr. 1a) | kontobasiert (`ustva_kz='43'`) **+** `steuerart='export'` | 8120; oder Buchung mit steuerart | -| **48** | Steuerfreie Umsätze ohne Vorsteuerabzug | `SUM(betrag_netto)` WHERE `ustva_kz='48'` | 8100, 8105, 8110 | +| **84** | USt auf steuerpfl. Umsätze 7 % | `SUM(betrag_ust)` WHERE `ustva_kz='86'` | s.o. | +| **35** | Steuerfreie Umsätze | `SUM(betrag_netto)` WHERE `ustva_kz='35'` | 8100, 8105, 8110 | +| **41** | Steuerfreie ig. Lieferungen | kontobasiert (`ustva_kz='41'`) **+** `steuerart='ig_lieferung'` | 8125; oder Buchung mit steuerart | +| **44** | Steuerfreie Ausfuhren | kontobasiert (`ustva_kz='44'`) **+** `steuerart='export'` | 8120; oder Buchung mit steuerart | +| **61** | Vorsteuer 19 % | `SUM(betrag_ust)` WHERE `buchungstyp='Ausgabe' AND ROUND(ust_satz)=19` | buchungsbasiert – kein spezielles VSt19-Konto nötig | +| **62** | Vorsteuer 7 % | `SUM(betrag_ust)` WHERE `buchungstyp='Ausgabe' AND ROUND(ust_satz)=7` | buchungsbasiert – kein spezielles VSt7-Konto nötig | | **89** | Ig. Erwerb 19 % – Bemessungsgrundlage | `SUM(betrag_netto)` WHERE `steuerart='ig_erwerb_19'` | kein spezielles Konto nötig | +| **91** | USt auf ig. Erwerb 19 % | `Kz 89 × 0,19` | berechnet | | **93** | Ig. Erwerb 7 % – Bemessungsgrundlage | `SUM(betrag_netto)` WHERE `steuerart='ig_erwerb_7'` | kein spezielles Konto nötig | -| **66** | Vorsteuer aus Lieferungen/Leistungen (§§ 14, 14a) | `SUM(betrag_ust)` WHERE `buchungstyp='Ausgabe' AND betrag_ust != 0` | buchungsbasiert – alle inländischen VSt-Beträge unabhängig vom Satz | -| **61** | Vorsteuer aus ig. Erwerben (§ 3d) | `Kz 89 × 0,19 + Kz 93 × 0,07` | berechnet; ig. Erwerb ist USt-neutral (hebt sich in Kz 83 auf) | -| **62** | Vorsteuer aus Einfuhrumsatzsteuer | 0 | in diesem System nicht vorgesehen | -| **67** | Vorsteuer aus Leistungen nach § 13b | 0 | in diesem System nicht vorgesehen | -| **83** | Verbleibende Umsatzsteuer-Vorauszahlung / Überschuss | `ust19 + ust7 − Kz 66 − Kz 61` | Ergebnis; ust19/ust7 = intern aus `betrag_ust` von 81/86-Konten | +| **94** | USt auf ig. Erwerb 7 % | `Kz 93 × 0,07` | berechnet | -### Kennziffern-Bedeutung (ELSTER) +### Abgeleitete Kennzahlen -Kz 83 ist laut ELSTER-Hilfe das **Ergebnis der Voranmeldung** (Verbleibende Vorauszahlung oder Überschuss), nicht – wie in früheren Systemversionen – die USt auf 19 %-Umsätze. Die ELSTER-Kennziffern 83, 61, 62, 66, 67 wurden mit dieser Änderung (2026-04-26) auf die offiziellen ELSTER-Definitionen korrigiert. +| Kz | Bezeichnung | Berechnung | +|---|---|---| +| **67** | Vorsteuer aus ig. Erwerb | Kz 91 + Kz 94 | +| **66** | Vorsteuerbeträge gesamt | Kz 61 + Kz 62 + Kz 67 | +| **69** | Verbleibende USt-Vorauszahlung / Erstattung | (Kz 83 + Kz 84 + Kz 91 + Kz 94) − Kz 66 | -Kz 35 und Kz 44 wurden in Migration 017 auf Kz 48 (steuerfreie Umsätze ohne VSt-Abzug) bzw. Kz 43 (Ausfuhren) umgestellt und werden nicht mehr verwendet. +### Migration 022 – Vorsteuer-Kz-Aufteilung (historisch) + +Vor Migration 022 trugen alle Vorsteuer-Konten `ustva_kz='66'`. Migration 022 setzte `ustva_kz='61'/'62'` je nach `steuercode`. Diese kontobasierte Zuordnung war erforderlich, weil alle Ausgaben eines Kontos denselben USt-Satz hatten. + +### Buchungsbasierte Vorsteuer (ab 2026) + +Die kontobasierte Zuordnung über `ustva_kz='61'/'62'` wurde zugunsten einer buchungsbasierten Zuordnung aufgegeben: `UstvaCalculator` wertet jetzt direkt `bookings.ust_satz` aus (`buchungstyp='Ausgabe'`, `betrag_ust != 0`). Damit reicht ein einzelnes Aufwandskonto für 19 % und 7 % USt aus. Der Wert `ustva_kz='61'/'62'` auf Konten wird nicht mehr ausgewertet. + +Kz 66 wird weiterhin rechnerisch als `Kz 61 + Kz 62 + Kz 67` aggregiert. diff --git a/src/Controllers/UstvaController.php b/src/Controllers/UstvaController.php index 1cc29eb..059c174 100644 --- a/src/Controllers/UstvaController.php +++ b/src/Controllers/UstvaController.php @@ -104,7 +104,7 @@ class UstvaController $month = (int)$params['month']; $kz = $params['kz'] ?? ''; - $validKz = ['81','86','41','43','48','89','93','66','61','62','67','83']; + $validKz = ['81','83','86','84','35','41','44','89','91','93','94','61','62','67','66','69']; if (!in_array($kz, $validKz, true)) { View::redirect("/tax/ustva/{$year}/{$month}", 'Ungültige Kennzahl.', 'error'); return; diff --git a/src/Services/ElsterXmlService.php b/src/Services/ElsterXmlService.php index 54d2033..d61f249 100644 --- a/src/Services/ElsterXmlService.php +++ b/src/Services/ElsterXmlService.php @@ -114,12 +114,12 @@ class ElsterXmlService $ustva->appendChild($dom->createElement('Steuernummer', $steuernummer)); // Kz-Felder: Bemessungsgrundlagen ganzzahlig, Steuerbeträge mit 2 Dezimalstellen. - // Kz83 (Vorauszahlung/Überschuss) wird aus den Komponenten von ELSTER berechnet, - // muss aber dennoch mit übertragen werden. + // Kz83/Kz84 werden nicht übertragen (serverseitig aus Kz81/Kz86 abgeleitet). + // Kz69 (Zahllast) wird als Kz39 übertragen. $kzBetrag = fn(float $v): string => (string)(int)round($v); $kzSteuer = fn(float $v): string => number_format($v, 2, '.', ''); - $betragsfelder = ['81', '86', '41', '43', '48', '89', '93']; + $betragsfelder = ['81', '86', '35', '41', '44', '89', '93']; foreach ($betragsfelder as $nr) { $val = (float)($kz[$nr]['betrag'] ?? 0.0); if ($val != 0.0) { @@ -127,7 +127,7 @@ class ElsterXmlService } } - $steuerfelder = ['66', '61', '62', '67']; + $steuerfelder = ['61', '62', '67', '66']; foreach ($steuerfelder as $nr) { $val = (float)($kz[$nr]['steuer'] ?? 0.0); if ($val != 0.0) { @@ -135,10 +135,10 @@ class ElsterXmlService } } - // Kz83: Verbleibende Umsatzsteuer-Vorauszahlung (positiv) / Überschuss (negativ) - $kz83val = (float)($kz['83']['steuer'] ?? 0.0); - if ($kz83val != 0.0) { - $ustva->appendChild($dom->createElement('Kz83', $kzSteuer($kz83val))); + // Zahllast → Kz39 (nur bei positivem Wert; bei Erstattung weglassen, da kein Vorzeichen erlaubt) + $zahllast = (float)($kz['69']['steuer'] ?? 0.0); + if ($zahllast > 0.0) { + $ustva->appendChild($dom->createElement('Kz39', $kzSteuer($zahllast))); } return $dom->saveXML(); diff --git a/src/Services/UstvaCalculator.php b/src/Services/UstvaCalculator.php index ad9c253..6349af8 100644 --- a/src/Services/UstvaCalculator.php +++ b/src/Services/UstvaCalculator.php @@ -9,72 +9,76 @@ use Steuerkram\Database; /** * Berechnet alle ELSTER-Kennzahlen (Kz) für die Umsatzsteuervoranmeldung. * - * Drei Quellen fließen in die Berechnung ein: + * Zwei Quellen fließen in die Berechnung ein: * * 1. Kontobasiert (accounts.ustva_kz des Kategorie-Kontos): - * ustva_kz = '81' → Kz 81 (betrag_netto); intern: ust19 (betrag_ust) - * ustva_kz = '86' → Kz 86 (betrag_netto); intern: ust7 (betrag_ust) + * ustva_kz = '81' → Kz 81 (betrag_netto), Kz 83 (betrag_ust) + * ustva_kz = '86' → Kz 86 (betrag_netto), Kz 84 (betrag_ust) + * ustva_kz = '35' → Kz 35 (betrag_netto) * ustva_kz = '41' → Kz 41 (betrag_netto) [steuerfreie ig. Lieferungen via Konto] - * ustva_kz = '43' → Kz 43 (betrag_netto) [steuerfreie Ausfuhren § 4 Nr. 1a] - * ustva_kz = '48' → Kz 48 (betrag_netto) [steuerfreie Umsätze ohne Vorsteuerabzug] + * ustva_kz = '44' → Kz 44 (betrag_netto) [steuerfreie Ausfuhren via Konto] + * (Kz 61/62 werden NICHT mehr über ustva_kz geroutet) * - * 2. Buchungsbasiert (buchungstyp='Ausgabe', betrag_ust ≠ 0): - * Alle inländischen Eingangsrechnungen → Kz 66 (§§ 14, 14a UStG) + * 2. Buchungsbasiert (bookings.ust_satz, für Vorsteuer): + * buchungstyp = 'Ausgabe', ust_satz = 19 → Kz 61 (betrag_ust) + * buchungstyp = 'Ausgabe', ust_satz = 7 → Kz 62 (betrag_ust) + * Damit entfällt die Notwendigkeit separater VSt19/VSt7-Konten. * * 3. Steuerart-basiert (bookings.steuerart, unabhängig vom Konto): * steuerart = 'ig_lieferung' → Kz 41 (betrag_netto) - * steuerart = 'export' → Kz 43 (betrag_netto) - * steuerart = 'ig_erwerb_19' → Kz 89 (betrag_netto) - * steuerart = 'ig_erwerb_7' → Kz 93 (betrag_netto) + * steuerart = 'export' → Kz 44 (betrag_netto) + * steuerart = 'ig_erwerb_19' → Kz 89 (betrag_netto), Kz 91 (netto × 0,19) + * steuerart = 'ig_erwerb_7' → Kz 93 (betrag_netto), Kz 94 (netto × 0,07) * Buchungen mit diesen steuerart-Werten bleiben aus der kontobasierten Berechnung * ausgeschlossen, um Doppelzählung zu vermeiden. + * Buchungen mit EU-Steuerarten fließen ebenfalls NICHT in Kz 61/62. * * Abgeleitete Kennzahlen: - * Kz 61 = Kz89 × 0,19 + Kz93 × 0,07 (Vorsteuer aus ig. Erwerben, § 3d UStG) - * Kz 62 = 0 (Einfuhrumsatzsteuer – in diesem System n.v.) - * Kz 67 = 0 (§ 13b-Vorsteuer – in diesem System n.v.) - * Kz 83 = ust19 + ust7 − Kz66 − Kz61 − Kz62 − Kz67 - * = ust19 + ust7 − Kz66 (ig. Erwerb ist USt-neutral) + * Kz 67 = Kz 91 + Kz 94 (Vorsteuer aus ig. Erwerb) + * Kz 66 = Kz 61 + Kz 62 + Kz 67 (Vorsteuer gesamt) + * Kz 69 = (Kz 83 + Kz 84 + Kz 91 + Kz 94) − Kz 66 (Zahllast) */ class UstvaCalculator { /** Steuerart-Werte die AUSSCHLIESSLICH steuerart-basiert berechnet werden. */ private const EU_STEUERARTEN = ['ig_lieferung', 'export', 'ig_erwerb_19', 'ig_erwerb_7']; + /** Vorsteuer-Kennzahl je USt-Satz (buchungsbasiert). */ + private const VST_SATZ_KZ = [19 => '61', 7 => '62']; + /** - * Kontobasiertes Drill-down-Mapping. - * Kz 83 (Zahllast) enthält auch die Einnahmen-Konten 81/86. + * Welche accounts.ustva_kz-Werte liefern Buchungen für die Drill-down-Ansicht. + * Nur für den kontobasierten Teil; EU-Steuerarten kommen aus KZ_STEUERART_MAP. + * Kz 61/62 sind hier nicht mehr enthalten (buchungsbasiert via VST_SATZ_KZ). */ private const KZ_ACCOUNT_MAP = [ '81' => ['81'], + '83' => ['81'], '86' => ['86'], + '84' => ['86'], + '35' => ['35'], '41' => ['41'], - '43' => ['43'], - '48' => ['48'], - '83' => ['81', '86'], + '44' => ['44'], ]; /** - * Steuerart-basiertes Drill-down-Mapping. + * Welche steuerart-Werte liefern Buchungen für eine Kennzahl. */ private const KZ_STEUERART_MAP = [ '41' => ['ig_lieferung'], - '43' => ['export'], + '44' => ['export'], '89' => ['ig_erwerb_19'], + '91' => ['ig_erwerb_19'], '93' => ['ig_erwerb_7'], - '61' => ['ig_erwerb_19', 'ig_erwerb_7'], - '83' => ['ig_lieferung', 'export', 'ig_erwerb_19', 'ig_erwerb_7'], + '94' => ['ig_erwerb_7'], + '67' => ['ig_erwerb_19', 'ig_erwerb_7'], + '66' => ['ig_erwerb_19', 'ig_erwerb_7'], + '69' => ['ig_lieferung', 'export', 'ig_erwerb_19', 'ig_erwerb_7'], ]; - /** - * Kennzahlen, deren Drill-down alle inländischen Ausgaben mit Vorsteuer enthält. - * (buchungsbasiert: buchungstyp='Ausgabe', betrag_ust != 0, keine EU-Steuerarten) - */ - private const KZ_INCLUDES_VST = ['66', '83']; - public function calculate(int $year, int $month): array { - // ── 1. Kontobasierte Kennzahlen (EU-Steuerarten ausgeschlossen) ────────── + // ── 1. Kontobasierte Kennzahlen (EU-Steuerarten und Kz 61/62 ausgeschlossen) ── $euPlaceholders = implode(',', array_fill(0, count(self::EU_STEUERARTEN), '?')); $accountRows = Database::fetchAll( 'SELECT a.ustva_kz, @@ -85,6 +89,7 @@ class UstvaCalculator JOIN accounts a ON a.id = bk.kategorie_konto_id WHERE fy.year = ? AND MONTH(bk.buchungs_datum) = ? AND a.ustva_kz IS NOT NULL AND a.ustva_kz != \'\' + AND a.ustva_kz NOT IN (\'61\', \'62\') AND (bk.steuerart IS NULL OR bk.steuerart NOT IN (' . $euPlaceholders . ')) GROUP BY a.ustva_kz', array_merge([$year, $month], self::EU_STEUERARTEN) @@ -98,19 +103,26 @@ class UstvaCalculator ]; } - // ── 2. Buchungsbasierte Vorsteuer Kz 66 (alle inländischen Eingangsrechnungen) ── - $vstRow = Database::fetchOne( - 'SELECT SUM(bk.betrag_ust) AS summe_ust + // ── 2. Buchungsbasierte Vorsteuer Kz 61/62 (via ust_satz) ──────────── + $vstRows = Database::fetchAll( + 'SELECT bk.ust_satz, SUM(bk.betrag_ust) AS summe_ust FROM bookings bk JOIN fiscal_years fy ON bk.fiscal_year_id = fy.id WHERE fy.year = ? AND MONTH(bk.buchungs_datum) = ? AND bk.buchungstyp = \'Ausgabe\' AND bk.betrag_ust != 0 - AND (bk.steuerart IS NULL OR bk.steuerart NOT IN (' . $euPlaceholders . '))', + AND (bk.steuerart IS NULL OR bk.steuerart NOT IN (' . $euPlaceholders . ')) + GROUP BY bk.ust_satz', array_merge([$year, $month], self::EU_STEUERARTEN) ); - $byKz['66'] = ['netto' => 0.0, 'ust' => (float)($vstRow['summe_ust'] ?? 0.0)]; + foreach ($vstRows as $row) { + $satz = (int)round((float)$row['ust_satz']); + $kzNr = self::VST_SATZ_KZ[$satz] ?? null; + if ($kzNr !== null) { + $byKz[$kzNr] = ['netto' => 0.0, 'ust' => (float)$row['summe_ust']]; + } + } // ── 3. Steuerart-basierte Kennzahlen ───────────────────────────────── $stRows = Database::fetchAll( @@ -129,41 +141,42 @@ class UstvaCalculator } // ── 4. Kennzahlen zusammensetzen ───────────────────────────────────── - $n = fn(string $kz): float => (float)($byKz[$kz]['netto'] ?? 0.0); - $u = fn(string $kz): float => (float)($byKz[$kz]['ust'] ?? 0.0); - $st = fn(string $art): float => (float)($bySteuerart[$art] ?? 0.0); + $n = fn(string $kz): float => (float)($byKz[$kz]['netto'] ?? 0.0); + $u = fn(string $kz): float => (float)($byKz[$kz]['ust'] ?? 0.0); + $st = fn(string $art): float => (float)($bySteuerart[$art] ?? 0.0); - $kz81 = $n('81'); - $ust19 = $u('81'); // interne USt aus 19 %-Umsätzen (kein eigenständiges ELSTER-Kz) - $kz86 = $n('86'); - $ust7 = $u('86'); // interne USt aus 7 %-Umsätzen (kein eigenständiges ELSTER-Kz) - $kz41 = $n('41') + $st('ig_lieferung'); - $kz43 = $n('43') + $st('export'); - $kz48 = $n('48'); - $kz89 = $st('ig_erwerb_19'); - $kz93 = $st('ig_erwerb_7'); - $kz66 = $u('66'); // § 14, 14a - $kz61 = round($kz89 * 0.19, 2) + round($kz93 * 0.07, 2); // § 3d Satz 1 - $kz62 = 0.0; // Einfuhrumsatzsteuer n.v. - $kz67 = 0.0; // § 13b-Vorsteuer n.v. - // ig. Erwerb-USt gilt gleichzeitig als Output- und als Vorsteuer (kz61) → neutral - $igErwerbUst = round($kz89 * 0.19, 2) + round($kz93 * 0.07, 2); // = kz61 - $kz83 = ($ust19 + $ust7 + $igErwerbUst) - ($kz66 + $kz61 + $kz62 + $kz67); + $kz81 = $n('81'); $kz83 = $u('81'); + $kz86 = $n('86'); $kz84 = $u('86'); + $kz35 = $n('35'); + $kz41 = $n('41') + $st('ig_lieferung'); + $kz44 = $n('44') + $st('export'); + $kz89 = $st('ig_erwerb_19'); + $kz91 = round($kz89 * 0.19, 2); + $kz93 = $st('ig_erwerb_7'); + $kz94 = round($kz93 * 0.07, 2); + $kz61 = $u('61'); + $kz62 = $u('62'); + $kz67 = $kz91 + $kz94; + $kz66 = $kz61 + $kz62 + $kz67; + $kz69 = ($kz83 + $kz84 + $kz91 + $kz94) - $kz66; return [ - '81' => ['name' => 'Steuerpfl. Umsätze 19 %', 'betrag' => round($kz81, 2), 'steuer' => null], - '86' => ['name' => 'Steuerpfl. Umsätze 7 %', 'betrag' => round($kz86, 2), 'steuer' => null], - '43' => ['name' => 'Steuerfreie Ausfuhren (§ 4 Nr. 1a)', 'betrag' => round($kz43, 2), 'steuer' => null], - '48' => ['name' => 'Steuerfreie Umsätze ohne Vorsteuerabzug', 'betrag' => round($kz48, 2), 'steuer' => null], - '41' => ['name' => 'Steuerfreie ig. Lieferungen (§ 4 Nr. 1b)', 'betrag' => round($kz41, 2), 'steuer' => null], - '89' => ['name' => 'Ig. Erwerb 19 % – Bemessungsgrundlage', 'betrag' => round($kz89, 2), 'steuer' => null], - '93' => ['name' => 'Ig. Erwerb 7 % – Bemessungsgrundlage', 'betrag' => round($kz93, 2), 'steuer' => null], - '66' => ['name' => 'Vorsteuer aus Lieferungen/Leistungen (§§ 14, 14a)', 'betrag' => null, 'steuer' => round($kz66, 2)], - '61' => ['name' => 'Vorsteuer aus ig. Erwerben (§ 3d UStG)', 'betrag' => null, 'steuer' => round($kz61, 2)], - '62' => ['name' => 'Vorsteuer aus Einfuhrumsatzsteuer', 'betrag' => null, 'steuer' => round($kz62, 2)], - '67' => ['name' => 'Vorsteuer aus Leistungen nach § 13b UStG', 'betrag' => null, 'steuer' => round($kz67, 2)], - '83' => ['name' => 'Verbleibende Umsatzsteuer-Vorauszahlung / Überschuss', 'betrag' => null, 'steuer' => round($kz83, 2)], - '_ust' => ['name' => 'Umsatzsteuer gesamt (intern)', 'betrag' => null, 'steuer' => round($ust19 + $ust7, 2)], + '81' => ['name' => 'Steuerpfl. Umsätze 19 %', 'betrag' => round($kz81, 2), 'steuer' => null], + '83' => ['name' => 'USt auf steuerpfl. Umsätze 19 %', 'betrag' => null, 'steuer' => round($kz83, 2)], + '86' => ['name' => 'Steuerpfl. Umsätze 7 %', 'betrag' => round($kz86, 2), 'steuer' => null], + '84' => ['name' => 'USt auf steuerpfl. Umsätze 7 %', 'betrag' => null, 'steuer' => round($kz84, 2)], + '35' => ['name' => 'Steuerfreie Umsätze (ohne Vorsteuerabzug)', 'betrag' => round($kz35, 2), 'steuer' => null], + '41' => ['name' => 'Steuerfreie ig. Lieferungen (§ 4 Nr. 1b)', 'betrag' => round($kz41, 2), 'steuer' => null], + '44' => ['name' => 'Steuerfreie Ausfuhren (§ 4 Nr. 1a)', 'betrag' => round($kz44, 2), 'steuer' => null], + '89' => ['name' => 'Ig. Erwerb 19 % – Bemessungsgrundlage', 'betrag' => round($kz89, 2), 'steuer' => null], + '91' => ['name' => 'USt auf ig. Erwerb 19 %', 'betrag' => null, 'steuer' => round($kz91, 2)], + '93' => ['name' => 'Ig. Erwerb 7 % – Bemessungsgrundlage', 'betrag' => round($kz93, 2), 'steuer' => null], + '94' => ['name' => 'USt auf ig. Erwerb 7 %', 'betrag' => null, 'steuer' => round($kz94, 2)], + '61' => ['name' => 'Vorsteuer aus Eingangsrechnungen 19 %', 'betrag' => null, 'steuer' => round($kz61, 2)], + '62' => ['name' => 'Vorsteuer aus Eingangsrechnungen 7 %', 'betrag' => null, 'steuer' => round($kz62, 2)], + '67' => ['name' => 'Vorsteuer aus ig. Erwerb', 'betrag' => null, 'steuer' => round($kz67, 2)], + '66' => ['name' => 'Vorsteuerbeträge gesamt', 'betrag' => null, 'steuer' => round($kz66, 2)], + '69' => ['name' => 'Verbleibende USt-Vorauszahlung/Erstattung', 'betrag' => null, 'steuer' => round($kz69, 2)], ]; } @@ -173,11 +186,13 @@ class UstvaCalculator */ public function fetchBookingsForKz(int $year, int $month, string $kz): array { - $accountKzList = self::KZ_ACCOUNT_MAP[$kz] ?? []; - $steuerartList = self::KZ_STEUERART_MAP[$kz] ?? []; - $includesVst = in_array($kz, self::KZ_INCLUDES_VST, true); + $accountKzList = self::KZ_ACCOUNT_MAP[$kz] ?? []; + $steuerartList = self::KZ_STEUERART_MAP[$kz] ?? []; - if (empty($accountKzList) && empty($steuerartList) && !$includesVst) { + // Kz 61/62: buchungsbasiert via ust_satz + $vstSatz = array_search($kz, self::VST_SATZ_KZ, true); + + if (empty($accountKzList) && empty($steuerartList) && $vstSatz === false) { return []; } @@ -211,14 +226,16 @@ class UstvaCalculator ); } - if ($includesVst) { + if ($vstSatz !== false) { $euPh = implode(',', array_fill(0, count(self::EU_STEUERARTEN), '?')); $parts[] = $select . ' AND bk.buchungstyp = \'Ausgabe\'' . ' AND bk.betrag_ust != 0' + . ' AND ROUND(bk.ust_satz) = ?' . ' AND (bk.steuerart IS NULL OR bk.steuerart NOT IN (' . $euPh . '))'; $params = array_merge($params, [$year, $month], + [$vstSatz], self::EU_STEUERARTEN ); } diff --git a/src/Views/tax/ustva_kz_bookings.php b/src/Views/tax/ustva_kz_bookings.php index 717adb2..fa386d5 100644 --- a/src/Views/tax/ustva_kz_bookings.php +++ b/src/Views/tax/ustva_kz_bookings.php @@ -3,10 +3,10 @@ use Steuerkram\View; $h = fn($v) => View::h($v); $fmtKz = fn($v) => number_format((float)$v, 2, ',', '.') . ' €'; -// Für Kz 83: vorzeichenbehafteter USt-Beitrag zur Zahllast. +// Für Kz 69: vorzeichenbehafteter USt-Beitrag zur Zahllast. // Einnahmen mit USt = positiv, Ausgaben mit Vorsteuer = negativ, // ig_erwerb heben sich gegenseitig auf → 0. -$ustBeitragKz83 = function(array $b): float { +$ustBeitragKz69 = function(array $b): float { $steuerart = $b['steuerart'] ?? 'normal'; $ustSatz = (float)$b['ust_satz']; $betragUst = (float)$b['betrag_ust']; @@ -16,7 +16,7 @@ $ustBeitragKz83 = function(array $b): float { if ($b['buchungstyp'] === 'Ausgabe' && $steuerart === 'normal' && $betragUst != 0) { return -$betragUst; // Vorsteuer → Vorzeichen umkehren } - return 0.0; // steuerfreie Umsätze und ig_erwerb (Netto-Beitrag 0, da neutral) + return 0.0; // steuerfreie Umsätze und ig_erwerb (KZ91-KZ94 = KZ67, Netto-Beitrag 0) }; // Ausgaben werden als negative Beträge angezeigt (Geld fließt ab). @@ -49,7 +49,7 @@ $signedBetrag = fn(array $b, string $field): float =>