Steuerkram/docs/berechnungslogik.md

197 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Berichte – Zuordnungsregeln
Dieses Dokument beschreibt, wie Buchungen in die beiden steuerlichen Berichte einfließen.
**Bei Änderungen an `EuerCalculator.php`, `UstvaCalculator.php` oder `ElsterXmlService.php` muss dieses Dokument mit aktualisiert werden.**
---
## EÜR (Einnahmen-Überschuss-Rechnung)
**Datei:** `src/Services/EuerCalculator.php`
Die EÜR basiert auf dem Feld `accounts.kontenart` sowie `accounts.euer_zeile` des Kategorie-Kontos. Das Feld `buchungstyp` wird nicht ausgewertet. Stornobuchungen (`is_reversal = 1`) werden **nicht** explizit ausgefiltert – sie tragen negative Beträge und heben damit die ursprüngliche Buchung automatisch auf (Summe = 0).
### Spaltenauswahl nach Kontenart und euer_zeile
Maßgeblich für die Summenbildung ist allein `kontenart`. `euer_zeile` wird von
`EuerCalculator` nur an einer Stelle ausgewertet – beim Wert `'74'`, der eine
Betriebsausgabe in den Abschnitt „nicht abzugsfähig" umlenkt. Alle übrigen
Zeilennummern sind dokumentarisch: sie erscheinen in der Kontenliste und
benennen die Position der amtlichen Anlage EÜR, ändern aber nichts an der
Berechnung.
| kontenart | euer_zeile | EÜR-Abschnitt |
|---|---|---|
| `Betriebseinnahme` | beliebig | Betriebseinnahmen |
| `Betriebsausgabe` | `≠ '74'` | Betriebsausgaben (fließen in `total_ausgaben` und `gewinn` ein) |
| `Betriebsausgabe` | `'74'` | Nicht abzugsfähige Betriebsausgaben – eigener Abschnitt, **nicht** in `total_ausgaben` oder `gewinn` |
| `Anlagevermögen` | beliebig | nicht in EÜR (die Anschaffung wirkt nur über die AfA) |
| `Privat` | beliebig | nicht in EÜR (Privatentnahmen/-einlagen beeinflussen den Gewinn nicht) |
| `Zahlungskonto`, `Verbindlichkeit` | beliebig | nicht in EÜR |
Die EÜR wird nach der **Bruttomethode** gerechnet: Die Umsatzsteuer läuft als Einnahme bzw. Ausgabe mit. Dafür sind drei Kontengruppen umklassifiziert:
| Konten | kontenart | euer_zeile | Bedeutung |
|---|---|---|---|
| 1770, 1771, 1774, 1776 | `Betriebseinnahme` | `17` | Vereinnahmte Umsatzsteuer (Migration 076) |
| 1571, 1574, 1576 | `Betriebsausgabe` | `57` | Gezahlte Vorsteuer, ELSTER-Kennzahl 185 (Migration 095) |
| 1780, 1781 | `Betriebsausgabe` | `58` | An das Finanzamt gezahlte USt (Migration 077) |
Bei Reverse-Charge (`steuerart = 'ig_erwerb_19'`) tragen die beiden Kindzeilen auf
1574 (Vorsteuer) und 1774 (Erwerbsteuer) denselben Betrag; als Betriebsausgabe und
Betriebseinnahme heben sie sich im Gewinn auf. Deshalb müssen beide Konten
klassifiziert sein – bliebe eines davon `Zahlungskonto`, wäre die Buchung nicht
mehr ergebnisneutral.
Die Vorsteuerbeträge stammen aus den VSt-Buchungszeilen, die `Booking::create()` als Kindzeile (`parent_booking_id`) zu jeder Ausgabe mit 7 % oder 19 % anlegt.
**EÜR-Zeile 74** entspricht den „Nicht abziehbaren Betriebsausgaben nach § 4 Abs. 5 EStG" (z.B. nicht abzugsfähige Bewirtungskosten auf Konten 4654, 4656, 4657; nicht abzugsfähige Geschenke auf 4635, 4636; nicht abzugsfähiger Arbeitszimmeranteil auf 4289; seit Migration 075). Diese Konten werden im EÜR-Bericht unterhalb der Betriebsausgaben in einem separaten Abschnitt angezeigt.
### Vorzeichen
`betrag_netto` wird ohne `abs()` direkt summiert:
- Positiver Wert → addiert zur jeweiligen Spalte
- Negativer Wert → mindert die jeweilige Spalte (z.B. Gutschriften, Erlösschmälerungen)
### Sortierung und Ergebnis
- Gruppierung: je Kategorie-Konto (`accounts.id`), ein Eintrag pro Konto
- Sortierung: nach `accounts.kontonummer` aufsteigend
- Ergebnis: `total_einnahmen − total_ausgaben = gewinn`
### Dashboard-Kacheln
Die Kacheln „Umsatz", „Ausgaben" und „Gewinn / Verlust" verwenden dieselben Regeln. `EuerCalculator::summary($jahr, $monat = null)` liefert die Summen, `fetchBookingsForBucket()` die Einzelbuchungen für die Detailansicht dahinter. Beide leiten ihre Bedingung aus denselben Konstanten ab wie `calculate()`, damit Dashboard und EÜR nicht auseinanderlaufen (Issue #167 – zuvor summierte das Dashboard nach `bookings.buchungstyp` und wich dadurch von der EÜR ab).
- Zeitraum: das Jahr immer über `fiscal_years.year`, ein Monat zusätzlich über `MONTH(bookings.buchungs_datum)`
- Gruppen: `einnahmen`, `ausgaben`, `ergebnis` (`ergebnis` = Einnahmen und abzugsfähige Ausgaben zusammen, Ausgaben in der Anzeige mit negativem Vorzeichen)
- Der Buchungstyp `AfA` zählt wie jede andere Buchung nach der Kontenart des Kategorie-Kontos, also als Betriebsausgabe
---
## UStVA (Umsatzsteuervoranmeldung)
**Dateien:** `src/Services/UstvaCalculator.php`, `src/Services/ElsterXmlService.php`
Diese Berechnung wird ausschließlich für **monatliche** Voranmeldungen unterstützt.
### Implementierte Kennzahlen
| Kz | Bezeichnung | Quelle | Berechnung |
|---|---|---|---|
| **81** | Steuerpflichtige Umsätze zum Steuersatz von 19 % | Konto | `floor(SUM(betrag_netto))` WHERE `ustva_kz='81'`, EU-Steuerarten ausgeschlossen – **auf volle Euro abgerundet (floor)** |
| **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 | `ust81 + ust89 − Kz 66 − Kz 61` |
Zusätzlich werden zwei **reine Anzeigefelder** berechnet (erscheinen im Bericht, aber **nicht** im XML):
| Feld | Bezeichnung | Berechnung |
|---|---|---|
| ust81 | Abzuführende USt aus Kz 81 (19 %) | `round(Kz 81 × 0,19, 2)` (Kz 81 ist bereits abgerundet) |
| ust89 | Abzuführende USt aus Kz 89 (19 %) | `round(Kz 89 × 0,19, 2)` (Kz 89 ist bereits abgerundet) |
### Datenquellen
`UstvaCalculator::calculate(year, month)` kombiniert zwei Quellen:
**Quelle 1 – kontobasiert** (`accounts.ustva_kz` des Kategorie-Kontos)
EU-Steuerarten (`ig_lieferung`, `export`, `ig_erwerb_19`, `ig_erwerb_7`) werden aus der kontobasierten Abfrage ausgeschlossen, um Doppelzählung mit Quelle 2 zu vermeiden.
**Quelle 2 – steuerartbasiert** (`bookings.steuerart = 'ig_erwerb_19'`)
Nur ig_erwerb_19 fließt als Bemessungsgrundlage in Kz 89 ein. Kz 61 wird daraus rechnerisch abgeleitet (nicht mehr kontobasiert über 1574).
### Automatische Kindzeilen (Buchungslogik)
Beim Anlegen einer Buchung erzeugt `Booking::create()` automatisch Kindzeilen auf den Steuerkonten:
| Buchungstyp | Steuersatz | Kindzeile Konto | Kz |
|---|---|---|---|
| Ausgabe, steuerart=normal | 19 % | 1576 (ustva_kz='66') | Kz 66 |
| Ausgabe, steuerart=normal | 7 % | 1571 (ustva_kz='66') | Kz 66 |
| Einnahme, steuerart=normal | 19 % | 1776 (ustva_kz='83') | Summand Kz 83 |
| Einnahme, steuerart=normal | 7 % | 1771 (ustva_kz='83') | Summand Kz 83 |
| Ausgabe, steuerart=ig_erwerb_19 | – | 1574 (netto×0,19, ustva_kz='61') | Kz 61 |
| Ausgabe, steuerart=ig_erwerb_19 | – | 1774 (netto×0,19, ustva_kz='83') | Summand Kz 83 |
### Kontozuordnung im SKR03-Kontenrahmen (Stand Migration 048)
| ustva_kz | Konten | Bedeutung |
|---|---|---|
| **81** | 8400, 8510, 8570, 8720, 8801, 8820, 8922 | Inlandsumsätze 19 % |
| **66** | 1571, 1576 | Vorsteuer 7 % und 19 % (Inland + Buchungszeilen) |
| **61** | 1574 | Vorsteuer aus ig. Erwerb 19 % |
| **83** | 1771, 1774, 1776 | USt-Buchungszeilen (7 %, ig. Erwerb, 19 %) |
---
## ELSTER-XML-Export
**Datei:** `src/Services/ElsterXmlService.php`
### Schema und Format
- **Namespace:** `http://finkonsens.de/elster/elsteranmeldung/ustva/v{Jahr}` – ELSTER-Schema „Anmeldungssteuern Upload" (kein ERiC-Client erforderlich, der Upload erfolgt manuell über *Mein ELSTER → Datentransfer → Elster-XML*)
- **Wurzelelement:** `<Anmeldungssteuern version="{Jahr}">`
- **Encoding:** UTF-8
- **Format:** mit `formatOutput=true` lesbar eingerückt
### Pflichtelemente
```
Anmeldungssteuern
├── DatenLieferant (Name, Strasse, PLZ, Ort, Telefon, Email)
├── Erstellungsdatum (Ymd)
└── Steuerfall
├── Berater (alle Felder leer, da Selbstabgabe)
├── Mandant (Name = Nachname, Vorname, MandantenNr leer, Bearbeiterkennzeichen leer)
├── Unternehmer (Bezeichnung = Firma, Name, Vorname, Str, Hausnummer, PLZ, Ort, Land=Deutschland, …)
└── Umsatzsteuervoranmeldung
├── Jahr
├── Zeitraum (zweistellig, "01"–"12")
├── Steuernummer (nur Ziffern, ohne Trennzeichen oder Bindestriche)
└── Kz-Felder (siehe unten)
```
### Mapping interner Kennzahlen → XML-Tags
| intern (UstvaCalculator) | XML-Tag | Format | Bemerkung |
|---|---|---|---|
| `Kz 81` (Bemessungsgrundlage 19 %) | `<Kz81>` | ganzzahlig | Wert 0 → Tag wird weggelassen |
| `Kz 89` (ig. Erwerb Bemessungsgrundlage) | `<Kz89>` | ganzzahlig | Wert 0 → Tag wird weggelassen |
| `Kz 66` (Vorsteuerbeträge gesamt) | `<Kz66>` | 2 Dezimalstellen | – |
| `Kz 61` (Vorsteuerbeträge ig. Erwerb) | `<Kz61>` | 2 Dezimalstellen | – |
| `Kz 83` (Vorauszahlung / Überschuss) | `<Kz83>` | 2 Dezimalstellen | **nur bei Zahllast > 0**; bei Erstattung kein Tag |
| `ust81`, `ust89` (Anzeigefelder) | – | – | **nicht übertragen** |
### Rundungs- und Formatregeln
- **Bemessungsgrundlagen** werden mit `(int)round($v)` ganzzahlig ausgegeben (`Kz81`, `Kz89`).
- **Steuerbeträge** werden mit `number_format($v, 2, '.', '')` ausgegeben (`Kz66`, `Kz61`, `Kz83`).
- **Felder mit Wert 0 werden weggelassen** – ELSTER toleriert fehlende Tags.
- **Steuernummer**: alle Nicht-Ziffern werden via `preg_replace('/[^0-9]/', '', …)` entfernt.
### Persistenz
Beim Speichern (`POST /tax/ustva/{year}/{month}/save`) wird die berechnete UStVA in `ustva_submissions` als `(year, month, xml_content, field_values)` per UPSERT abgelegt. Beim Download (`GET /tax/ustva/{year}/{month}/xml`) wird das XML stets neu berechnet, nicht aus der Tabelle gelesen.
---
## Offene Punkte / Bekannte Einschränkungen
Diese Punkte sind **nicht** abgedeckt und können je nach Sachverhalt zu fehlerhaften Voranmeldungen führen. Vor Abgabe an das Finanzamt manuell prüfen:
| Bereich | Fehlt | Folge |
|---|---|---|
| **Steuerfreie Umsätze** (§ 4 Nr. 1a/1b, Nr. 8–29) | Kein separater Ausweis (ig. Lieferung, Ausfuhr, steuerfreie Inlandsumsätze) | Buchungen mit `steuerart='ig_lieferung'` / `'export'` gehen nicht in Kz 81 ein, werden aber auch nicht separat ausgewiesen |
| **Dauerfristverlängerung / Sondervorauszahlung** | Keine Eingabe vorgesehen | Kz 83 enthält den vollen Zahlbetrag ohne Anrechnung einer Sondervorauszahlung |
| **Quartals- und Jahres-UStVA** | Nur Monat möglich (`MONTH(buchungs_datum)`) | Quartals- oder Jahresanmelder müssen Werte manuell aggregieren |
| **Berichtigte Anmeldung** (§ 153 AO) | Kein Kennzeichen in `ustva_submissions` | XML enthält keinen Berichtigungs-Hinweis |
| **Nullmeldung** | Bei leerer UStVA werden alle Tags weggelassen | Mindestens `<Kz81>0</Kz81>` sollte gesetzt sein, falls ELSTER eine leere Meldung ablehnt |
### Verifikation vor Abgabe
1. Im Bericht (`/tax/ustva/{year}/{month}`) jede Kennzahl per Drill-down auf zugrundeliegende Buchungen prüfen.
2. XML herunterladen und im **ELSTER-Validator** (https://portal.e-rechnung-bund.de gibt es nur für E-Rechnung – für die UStVA-XML in *Mein ELSTER → Voranmeldungen → Datei hochladen* die Vorprüfung nutzen) testen.
3. Bei Auslandssachverhalten oder § 13b-Fällen die Werte mit dem amtlichen UStVA-Vordruck abgleichen.