diff --git a/Changes.md b/Changes.md
index 77a48a4..311b149 100644
--- a/Changes.md
+++ b/Changes.md
@@ -2,6 +2,47 @@
---
+## 2026-04-01 – Feature: Bewirtungsbelege (Konten 4650/4651) mit automatischem Split
+
+### Neu
+- Buchungen auf Konto 4650 (Bewirtungskosten VSt. 19%) oder 4651 (Bewirtungskosten VSt. 7%) werden automatisch aufgeteilt: 70 % auf das gewählte Konto, 30 % auf das Abzugskonto (4654 bzw. 4656)
+- Neue Felder `bewirtungsgrund` und `teilnehmerliste` in der `bookings`-Tabelle (Migration 016)
+- Im Buchungsformular erscheinen die beiden Felder automatisch, wenn 4650/4651 als Kategorie gewählt wird
+- Vorhandene Buchungen zeigen Bewirtungsgrund und Teilnehmerliste in der Buchungsübersicht an
+
+## 2026-04-01 – Bugfix: Nicht abzugsfähige Kosten (4654/4656) separat in EÜR unter KZ 165
+
+### Behoben
+- Konten mit `euer_zeile = '51'` (4654, 4656, 4635, 4636, 4289) fließen nicht mehr in `total_ausgaben` und `gewinn` ein
+- Sie erscheinen in einem eigenen Abschnitt „Nicht abzugsfähige Betriebsausgaben (KZ 165)" in Web und PDF
+- Migration 015 setzt `euer_zeile = '51'` für Konto 4656 (fehlte bisher)
+
+---
+
+## 2026-03-30 – Bugfix: 30 % Eigenanteil fließt jetzt korrekt in UStVA KZ 81/83
+
+### Behoben
+- `Booking::upsertEigenanteil30`: statt zwei Buchungen (8922 Netto + 1776 USt-Korrektur) wird
+ nur noch eine einzige Buchung auf 8922 mit echtem `ust_satz` und `betrag_ust` erzeugt
+- `upsertKorrekturbuchung`: neue Parameter `ustSatz` und `betragUst`; UPDATE und INSERT setzen
+ jetzt `betrag_ust` und `betrag_brutto` korrekt
+- Vorher: `betrag_ust = 0` auf 8922 → KZ 83 blieb leer; 1776-Buchung hatte keine UStVA-Wirkung
+
+---
+
+## 2026-03-30 – Kontenrahmen-Reset: DATEV SKR03 2026 (IST-Versteuerung)
+
+### Geändert
+- Alle Buchungen und Belege gelöscht (Testdaten)
+- Gesamter Kontenrahmen durch DATEV SKR03 2026 (gültig ab 2026-01-01) ersetzt
+- Neue Spalte `euer_zeile` in Tabelle `accounts`: Zeilennummer der Anlage EÜR
+- 145 Konten neu angelegt: Klassen 0, 1, 3, 4, 8 (ohne Klasse 9 / ohne Verbindlichkeiten)
+- Verfahren: IST-Versteuerung; Konto 1390 „Verrechnungskonto Ist-Versteuerung" enthalten
+- UStVA-Kennzeichen korrekt nach DATEV: 81/86 (Umsätze), 61/62 (Vorsteuer), 35/41 (steuerfrei)
+- Migration: `013_reset_kontenrahmen_skr03_2026.sql`
+
+---
+
## 2026-03-30 – KI-gestützte Belegerkennung (experimentell) + 30 % Eigenanteil Telefon/Internet
### Neu
diff --git a/migrations/016_bewirtungsfelder_bookings.sql b/migrations/016_bewirtungsfelder_bookings.sql
new file mode 100644
index 0000000..3cfad23
--- /dev/null
+++ b/migrations/016_bewirtungsfelder_bookings.sql
@@ -0,0 +1,10 @@
+-- Migration 016: Bewirtungsfelder in bookings-Tabelle
+-- Speichert Bewirtungsgrund und Teilnehmerliste für Buchungen auf
+-- Konten 4650/4651 (Bewirtungskosten 70 % abzugsfähig).
+ALTER TABLE bookings
+ ADD COLUMN IF NOT EXISTS bewirtungsgrund TEXT NULL
+ COMMENT 'Anlass/Grund der Bewirtung (§ 4 Abs. 5 Nr. 2 EStG)'
+ AFTER buchungstext,
+ ADD COLUMN IF NOT EXISTS teilnehmerliste TEXT NULL
+ COMMENT 'Teilnehmer der Bewirtung (§ 4 Abs. 5 Nr. 2 EStG)'
+ AFTER bewirtungsgrund;
diff --git a/src/Controllers/BookingController.php b/src/Controllers/BookingController.php
index 636dabd..dcef41f 100644
--- a/src/Controllers/BookingController.php
+++ b/src/Controllers/BookingController.php
@@ -109,21 +109,33 @@ class BookingController
try {
$data['beleg_id'] = $belegId;
- Booking::create($data);
- $eigenanteil = isset($data['eigenanteil_30']) ? 1 : 0;
- \Steuerkram\Database::execute(
- 'UPDATE belege SET eigenanteil_30 = ?, updated_at = NOW() WHERE id = ?',
- [$eigenanteil, $belegId]
+ // Bewirtungskonto-Split: 4650→4654, 4651→4656
+ $konto = \Steuerkram\Database::fetchOne(
+ 'SELECT kontonummer FROM accounts WHERE id = ?',
+ [(int)$data['kategorie_konto_id']]
);
+ $kontonummer = $konto['kontonummer'] ?? '';
- if ($eigenanteil === 1) {
- Booking::upsertEigenanteil30(
- $belegId,
- (float)$data['betrag_netto'],
- (float)($data['ust_satz'] ?? 0),
- $data['buchungs_datum']
+ if ($kontonummer === '4650' || $kontonummer === '4651') {
+ $this->bucheBewirtungssplit($data, $kontonummer);
+ } else {
+ Booking::create($data);
+
+ $eigenanteil = isset($data['eigenanteil_30']) ? 1 : 0;
+ \Steuerkram\Database::execute(
+ 'UPDATE belege SET eigenanteil_30 = ?, updated_at = NOW() WHERE id = ?',
+ [$eigenanteil, $belegId]
);
+
+ if ($eigenanteil === 1) {
+ Booking::upsertEigenanteil30(
+ $belegId,
+ (float)$data['betrag_netto'],
+ (float)($data['ust_satz'] ?? 0),
+ $data['buchungs_datum']
+ );
+ }
}
View::redirect("/belege/{$belegId}", 'Buchung erfasst.');
@@ -156,6 +168,40 @@ class BookingController
]);
}
+ private function bucheBewirtungssplit(array $data, string $kontonummer): void
+ {
+ // Abzugskonto ermitteln
+ $abzugskontonummer = $kontonummer === '4650' ? '4654' : '4656';
+ $abzugskonto = \Steuerkram\Database::fetchOne(
+ 'SELECT id FROM accounts WHERE kontonummer = ?',
+ [$abzugskontonummer]
+ );
+ if (!$abzugskonto) {
+ throw new \RuntimeException("Abzugskonto {$abzugskontonummer} nicht gefunden.");
+ }
+
+ $nettoGesamt = round((float)$data['betrag_netto'], 2);
+ $ustSatz = (float)($data['ust_satz'] ?? 0);
+
+ $netto70 = round($nettoGesamt * 0.7, 2);
+ $netto30 = round($nettoGesamt - $netto70, 2);
+
+ // Buchung 1: 70 % auf Bewirtungskonto (abzugsfähig)
+ Booking::create(array_merge($data, [
+ 'betrag_netto' => $netto70,
+ 'bewirtungsgrund' => $data['bewirtungsgrund'] ?? null,
+ 'teilnehmerliste' => $data['teilnehmerliste'] ?? null,
+ ]));
+
+ // Buchung 2: 30 % auf Abzugskonto (nicht abzugsfähig, § 4 Abs. 5 EStG)
+ Booking::create(array_merge($data, [
+ 'kategorie_konto_id' => $abzugskonto['id'],
+ 'betrag_netto' => $netto30,
+ 'bewirtungsgrund' => $data['bewirtungsgrund'] ?? null,
+ 'teilnehmerliste' => $data['teilnehmerliste'] ?? null,
+ ]));
+ }
+
public function destroy(array $params): void
{
if (!Setting::isTestMode()) {
diff --git a/src/Models/Booking.php b/src/Models/Booking.php
index dfafd98..b04cec5 100644
--- a/src/Models/Booking.php
+++ b/src/Models/Booking.php
@@ -104,8 +104,9 @@ class Booking
Database::execute(
'INSERT INTO bookings (buchungs_nr, beleg_id, buchungs_datum, buchungstyp,
kategorie_konto_id, zahlungskonto_id,
- betrag_netto, ust_satz, steuerart, betrag_ust, betrag_brutto, buchungstext, fiscal_year_id)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
+ betrag_netto, ust_satz, steuerart, betrag_ust, betrag_brutto,
+ buchungstext, bewirtungsgrund, teilnehmerliste, fiscal_year_id)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
[
$nr,
(int)$data['beleg_id'],
@@ -119,6 +120,8 @@ class Booking
$ust,
$brutto,
$data['buchungstext'],
+ $data['bewirtungsgrund'] ?? null,
+ $data['teilnehmerliste'] ?? null,
$fy['id'],
]
);
diff --git a/src/Views/belege/detail.php b/src/Views/belege/detail.php
index 45962db..4e43b1b 100644
--- a/src/Views/belege/detail.php
+++ b/src/Views/belege/detail.php
@@ -214,6 +214,12 @@ $suppliers = $suppliers ?? [];
Storniert
+
+
Grund: = $h($bk['bewirtungsgrund']) ?>
+
+
+
Teilnehmer: = $h($bk['teilnehmerliste']) ?>
+