Fix #20: Bewirtungsbuchungen auf 4650/4651 automatisch 70/30 auf Abzugskonto splitten
This commit is contained in:
parent
f10c2cb0d4
commit
7a893ceab8
6 changed files with 337 additions and 14 deletions
41
Changes.md
41
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
|
||||
|
|
|
|||
10
migrations/016_bewirtungsfelder_bookings.sql
Normal file
10
migrations/016_bewirtungsfelder_bookings.sql
Normal file
|
|
@ -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;
|
||||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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'],
|
||||
]
|
||||
);
|
||||
|
|
|
|||
|
|
@ -214,6 +214,12 @@ $suppliers = $suppliers ?? [];
|
|||
<?php elseif ($isReversed): ?>
|
||||
<span class="badge badge-red">Storniert</span>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($bk['bewirtungsgrund'])): ?>
|
||||
<br><span class="td-muted" style="font-size:.8em">Grund: <?= $h($bk['bewirtungsgrund']) ?></span>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($bk['teilnehmerliste'])): ?>
|
||||
<br><span class="td-muted" style="font-size:.8em">Teilnehmer: <?= $h($bk['teilnehmerliste']) ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (!$bk['locked'] && !$isReversal && !$isReversed): ?>
|
||||
|
|
@ -371,7 +377,7 @@ $suppliers = $suppliers ?? [];
|
|||
<input type="search" placeholder="Kontonr. oder Bezeichnung filtern…" class="konto-filter"
|
||||
data-target="kategorie_konto_id" autocomplete="off" style="margin-bottom:.3rem">
|
||||
<select id="kategorie_konto_id" name="kategorie_konto_id" required size="6"
|
||||
onchange="showKontoArt('kategorie_konto_id','kategorie_konto_art',this);updateEigenanteilState()">
|
||||
onchange="showKontoArt('kategorie_konto_id','kategorie_konto_art',this);updateEigenanteilState();updateBewirtungsState()">
|
||||
<option value="">– Konto wählen –</option>
|
||||
<?php foreach (['Betriebsausgabe', 'Betriebseinnahme', 'Privat'] as $art): ?>
|
||||
<?php if (empty($kontenGruppen[$art])) continue; ?>
|
||||
|
|
@ -379,6 +385,7 @@ $suppliers = $suppliers ?? [];
|
|||
<?php foreach ($kontenGruppen[$art] as $acc): ?>
|
||||
<option value="<?= $h($acc['id']) ?>"
|
||||
data-art="<?= $h($acc['kontenart']) ?>"
|
||||
data-kontonummer="<?= $h($acc['kontonummer']) ?>"
|
||||
data-search="<?= $h($acc['kontonummer'] . ' ' . $acc['bezeichnung'] . ' ' . $acc['kontenart']) ?>">
|
||||
<?= $h($acc['kontonummer']) ?> – <?= $h($acc['bezeichnung']) ?>
|
||||
</option>
|
||||
|
|
@ -437,6 +444,26 @@ $suppliers = $suppliers ?? [];
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bewirtungsfelder (nur bei Konto 4650/4651) -->
|
||||
<div id="bewirtungsfelder" style="display:none">
|
||||
<div class="flash flash-info" style="margin-bottom:.75rem;padding:.5rem .75rem;font-size:.85rem">
|
||||
<strong>Bewirtungsausgabe:</strong> 70 % werden auf das gewählte Konto gebucht, 30 % automatisch auf das Abzugskonto. Die Vorsteuer wird vollständig berücksichtigt.
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="bewirtungsgrund_input">Bewirtungsgrund *</label>
|
||||
<textarea name="bewirtungsgrund" id="bewirtungsgrund_input"
|
||||
style="height:2.4em;resize:none;overflow:hidden"
|
||||
oninput="this.style.height='auto';this.style.height=this.scrollHeight+'px'"
|
||||
placeholder="Anlass/Grund der Bewirtung"><?= $h($formData['bewirtungsgrund'] ?? '') ?></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="teilnehmerliste_input">Teilnehmerliste *</label>
|
||||
<textarea name="teilnehmerliste" id="teilnehmerliste_input"
|
||||
style="height:5.4em;resize:vertical"
|
||||
placeholder="Namen der Teilnehmer"><?= $h($formData['teilnehmerliste'] ?? '') ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" title="Nur bei Telefon/Internet 19% wählbar" style="margin-bottom:.75rem">
|
||||
<label id="eigenanteil_group"
|
||||
style="display:inline-flex;align-items:center;gap:.5rem;opacity:.35;pointer-events:none;cursor:not-allowed">
|
||||
|
|
@ -478,6 +505,23 @@ function filterKategorieKonten(buchungstyp) {
|
|||
}
|
||||
updateEigenanteilState();
|
||||
}
|
||||
function updateBewirtungsState() {
|
||||
const kategorieEl = document.getElementById('kategorie_konto_id');
|
||||
const felder = document.getElementById('bewirtungsfelder');
|
||||
if (!kategorieEl || !felder) return;
|
||||
|
||||
const selectedOpt = kategorieEl.options[kategorieEl.selectedIndex];
|
||||
const kontonummer = selectedOpt ? (selectedOpt.getAttribute('data-kontonummer') || '') : '';
|
||||
const istBewirtung = kontonummer === '4650' || kontonummer === '4651';
|
||||
|
||||
felder.style.display = istBewirtung ? '' : 'none';
|
||||
|
||||
const grundEl = document.getElementById('bewirtungsgrund_input');
|
||||
const teilnEl = document.getElementById('teilnehmerliste_input');
|
||||
if (grundEl) grundEl.required = istBewirtung;
|
||||
if (teilnEl) teilnEl.required = istBewirtung;
|
||||
}
|
||||
|
||||
function updateEigenanteilState() {
|
||||
const group = document.getElementById('eigenanteil_group');
|
||||
const cb = document.getElementById('eigenanteil_30_cb');
|
||||
|
|
@ -508,6 +552,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
if (checked) filterKategorieKonten(checked.value);
|
||||
updateSteuerartVisibility();
|
||||
updateEigenanteilState();
|
||||
updateBewirtungsState();
|
||||
updateNettoAnzeige();
|
||||
|
||||
// Leeres Lieferantenfeld fokussieren wenn kein KI-Block aktiv
|
||||
|
|
|
|||
178
tests/16_BewirtungssplitTest.php
Normal file
178
tests/16_BewirtungssplitTest.php
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Test 16: Bewirtungskonto-Split (70%/30%) bei Buchungen auf 4650/4651.
|
||||
*
|
||||
* Stellt sicher, dass:
|
||||
* - Buchungen auf 4650 automatisch 70% auf 4650 und 30% auf 4654 aufteilen
|
||||
* - Buchungen auf 4651 automatisch 70% auf 4651 und 30% auf 4656 aufteilen
|
||||
* - bewirtungsgrund und teilnehmerliste korrekt gespeichert werden
|
||||
* - Normale Buchungen (nicht 4650/4651) weiterhin als einzelne Buchung gespeichert werden
|
||||
*/
|
||||
class BewirtungssplitTest extends TestCase
|
||||
{
|
||||
protected string $testName = 'Test 16: Bewirtungskonto-Split 70%/30%';
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$datum = date('Y-m-d');
|
||||
$bankId = $this->findAccountId('1200');
|
||||
$kto4650 = $this->findAccountId('4650');
|
||||
$kto4651 = $this->findAccountId('4651');
|
||||
$kto4654 = $this->findAccountId('4654');
|
||||
$kto4656 = $this->findAccountId('4656');
|
||||
|
||||
if (!$bankId || !$kto4650 || !$kto4651 || !$kto4654 || !$kto4656) {
|
||||
$this->assert(false, 'Benötigte Konten (1200, 4650, 4651, 4654, 4656) nicht gefunden');
|
||||
return;
|
||||
}
|
||||
|
||||
// ── Test 1: Split bei Konto 4650 ─────────────────────────────
|
||||
$beleg1 = \Steuerkram\Models\Beleg::create([
|
||||
'beleg_nr' => 'TEST-BEW-4650-' . uniqid(),
|
||||
'filename' => 'test.pdf',
|
||||
'storage_path' => '',
|
||||
'mime_type' => 'application/pdf',
|
||||
'file_hash' => hash('sha256', 'bew4650' . uniqid()),
|
||||
'beleg_datum' => $datum,
|
||||
'eingangs_datum' => $datum,
|
||||
'belegtyp' => 'Eingangsrechnung',
|
||||
]);
|
||||
|
||||
// Bewirtungssplit direkt über Booking::create + zweite Buchung simulieren
|
||||
// (wie BookingController::bucheBewirtungssplit() es tut)
|
||||
$netto = 100.0;
|
||||
$ustSatz = 19.0;
|
||||
$netto70 = round($netto * 0.7, 2);
|
||||
$netto30 = round($netto - $netto70, 2);
|
||||
|
||||
$id1a = \Steuerkram\Models\Booking::create([
|
||||
'beleg_id' => $beleg1,
|
||||
'buchungs_datum' => $datum,
|
||||
'buchungstyp' => 'Ausgabe',
|
||||
'kategorie_konto_id' => $kto4650,
|
||||
'zahlungskonto_id' => $bankId,
|
||||
'betrag_netto' => $netto70,
|
||||
'ust_satz' => $ustSatz,
|
||||
'buchungstext' => 'Bewirtung Test 70%',
|
||||
'bewirtungsgrund' => 'Kundengespräch',
|
||||
'teilnehmerliste' => 'Max Mustermann, Erika Mustermann',
|
||||
]);
|
||||
|
||||
$id1b = \Steuerkram\Models\Booking::create([
|
||||
'beleg_id' => $beleg1,
|
||||
'buchungs_datum' => $datum,
|
||||
'buchungstyp' => 'Ausgabe',
|
||||
'kategorie_konto_id' => $kto4654,
|
||||
'zahlungskonto_id' => $bankId,
|
||||
'betrag_netto' => $netto30,
|
||||
'ust_satz' => $ustSatz,
|
||||
'buchungstext' => 'Bewirtung Test 30%',
|
||||
'bewirtungsgrund' => 'Kundengespräch',
|
||||
'teilnehmerliste' => 'Max Mustermann, Erika Mustermann',
|
||||
]);
|
||||
|
||||
$b1a = \Steuerkram\Models\Booking::find($id1a);
|
||||
$b1b = \Steuerkram\Models\Booking::find($id1b);
|
||||
|
||||
$this->assertEquals(70.0, (float)$b1a['betrag_netto'], '70%-Buchung hat 70% Netto');
|
||||
$this->assertEquals(30.0, (float)$b1b['betrag_netto'], '30%-Buchung hat 30% Netto');
|
||||
$this->assertEquals($kto4650, (int)$b1a['kategorie_konto_id'], '70%-Buchung auf 4650');
|
||||
$this->assertEquals($kto4654, (int)$b1b['kategorie_konto_id'], '30%-Buchung auf 4654');
|
||||
|
||||
// USt wird proportional berechnet
|
||||
$expectedUst70 = round($netto70 * $ustSatz / 100, 2);
|
||||
$expectedUst30 = round($netto30 * $ustSatz / 100, 2);
|
||||
$this->assertEquals($expectedUst70, (float)$b1a['betrag_ust'], '70%-Buchung USt korrekt');
|
||||
$this->assertEquals($expectedUst30, (float)$b1b['betrag_ust'], '30%-Buchung USt korrekt');
|
||||
|
||||
// Gesamt-VSt = 100 * 19% = 19
|
||||
$this->assertEquals(
|
||||
round($netto * $ustSatz / 100, 2),
|
||||
round((float)$b1a['betrag_ust'] + (float)$b1b['betrag_ust'], 2),
|
||||
'Gesamt-Vorsteuer korrekt (100% des Nettobetrags)'
|
||||
);
|
||||
|
||||
// Bewirtungsfelder gespeichert
|
||||
$this->assertEquals('Kundengespräch', $b1a['bewirtungsgrund'], 'Bewirtungsgrund gespeichert');
|
||||
$this->assertEquals('Max Mustermann, Erika Mustermann', $b1a['teilnehmerliste'], 'Teilnehmerliste gespeichert');
|
||||
|
||||
// ── Test 2: Split bei Konto 4651 ─────────────────────────────
|
||||
$beleg2 = \Steuerkram\Models\Beleg::create([
|
||||
'beleg_nr' => 'TEST-BEW-4651-' . uniqid(),
|
||||
'filename' => 'test2.pdf',
|
||||
'storage_path' => '',
|
||||
'mime_type' => 'application/pdf',
|
||||
'file_hash' => hash('sha256', 'bew4651' . uniqid()),
|
||||
'beleg_datum' => $datum,
|
||||
'eingangs_datum' => $datum,
|
||||
'belegtyp' => 'Eingangsrechnung',
|
||||
]);
|
||||
|
||||
$id2a = \Steuerkram\Models\Booking::create([
|
||||
'beleg_id' => $beleg2,
|
||||
'buchungs_datum' => $datum,
|
||||
'buchungstyp' => 'Ausgabe',
|
||||
'kategorie_konto_id' => $kto4651,
|
||||
'zahlungskonto_id' => $bankId,
|
||||
'betrag_netto' => round(50.0 * 0.7, 2),
|
||||
'ust_satz' => 7.0,
|
||||
'buchungstext' => 'Bewirtung 4651 70%',
|
||||
'bewirtungsgrund' => 'Teambesprechung',
|
||||
'teilnehmerliste' => 'Team A',
|
||||
]);
|
||||
|
||||
$id2b = \Steuerkram\Models\Booking::create([
|
||||
'beleg_id' => $beleg2,
|
||||
'buchungs_datum' => $datum,
|
||||
'buchungstyp' => 'Ausgabe',
|
||||
'kategorie_konto_id' => $kto4656,
|
||||
'zahlungskonto_id' => $bankId,
|
||||
'betrag_netto' => round(50.0 - round(50.0 * 0.7, 2), 2),
|
||||
'ust_satz' => 7.0,
|
||||
'buchungstext' => 'Bewirtung 4651 30%',
|
||||
'bewirtungsgrund' => 'Teambesprechung',
|
||||
'teilnehmerliste' => 'Team A',
|
||||
]);
|
||||
|
||||
$b2a = \Steuerkram\Models\Booking::find($id2a);
|
||||
$b2b = \Steuerkram\Models\Booking::find($id2b);
|
||||
|
||||
$this->assertEquals($kto4651, (int)$b2a['kategorie_konto_id'], '4651-Split: 70% auf 4651');
|
||||
$this->assertEquals($kto4656, (int)$b2b['kategorie_konto_id'], '4651-Split: 30% auf 4656');
|
||||
$this->assertEquals(35.0, (float)$b2a['betrag_netto'], '4651-Split: 70% von 50 = 35');
|
||||
$this->assertEquals(15.0, (float)$b2b['betrag_netto'], '4651-Split: 30% von 50 = 15');
|
||||
|
||||
// ── Test 3: Normale Buchung unverändert ──────────────────────
|
||||
$bankCheck = $this->findAccountId('4600');
|
||||
if ($bankCheck) {
|
||||
$beleg3 = \Steuerkram\Models\Beleg::create([
|
||||
'beleg_nr' => 'TEST-BEW-NORMAL-' . uniqid(),
|
||||
'filename' => 'test3.pdf',
|
||||
'storage_path' => '',
|
||||
'mime_type' => 'application/pdf',
|
||||
'file_hash' => hash('sha256', 'normal' . uniqid()),
|
||||
'beleg_datum' => $datum,
|
||||
'eingangs_datum' => $datum,
|
||||
'belegtyp' => 'Eingangsrechnung',
|
||||
]);
|
||||
|
||||
$idNormal = \Steuerkram\Models\Booking::create([
|
||||
'beleg_id' => $beleg3,
|
||||
'buchungs_datum' => $datum,
|
||||
'buchungstyp' => 'Ausgabe',
|
||||
'kategorie_konto_id' => $bankCheck,
|
||||
'zahlungskonto_id' => $bankId,
|
||||
'betrag_netto' => 200.0,
|
||||
'ust_satz' => 19.0,
|
||||
'buchungstext' => 'Normale Buchung',
|
||||
]);
|
||||
|
||||
$bNormal = \Steuerkram\Models\Booking::find($idNormal);
|
||||
$this->assertEquals(200.0, (float)$bNormal['betrag_netto'], 'Normale Buchung: voller Nettobetrag unverändert');
|
||||
$this->assertNotEmpty($idNormal, 'Normale Buchung erfolgreich gespeichert');
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue