Fix #140: Essensbeleg-Vorlage um Eingabezeile ohne USt. (Trinkgeld) erweitert
This commit is contained in:
parent
87ccb00f95
commit
9f61624b40
3 changed files with 99 additions and 0 deletions
|
|
@ -2,6 +2,12 @@
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-07-26 – Feature: Dritte Eingabezeile ohne USt. in der Essensbeleg-Buchungsvorlage (Issue #140)
|
||||||
|
|
||||||
|
- Die Buchungsvorlage „Essensbeleg n. abzugsfähig (nur USt.)" hatte nur Eingabezeilen für 7 % und 19 % USt. – Beträge ohne USt. (z. B. Trinkgeld) ließen sich damit nicht erfassen.
|
||||||
|
- **`migrations/088_buchungsvorlage_essensbeleg_ohne_ust.sql`:** Ergänzt die Vorlage um ein drittes `ust_zeile`-Feld `netto_0` (0 % USt.) sowie eine Buchungsregel, die den eingegebenen Betrag auf Konto 4657 („Nicht abzugsfähige Bewirtungskosten ohne Vorsteuer") bucht – Formular-Rendering (`buchungsvorlagen/modal.php`), Live-Berechnung (`app.js`) und Buchungsausführung (`VorlageBuchungsService`) sind bereits vollständig datengetrieben und benötigten keine Code-Änderung.
|
||||||
|
- **`tests/59_EssensbelegOhneUstTest.php`:** Neuer Test prüft das neue Feld, die zugehörige Regel und die korrekte Buchung auf Konto 4657 bei gleichzeitiger Nutzung aller drei Zeilen.
|
||||||
|
|
||||||
## 2026-07-26 – Feature: Ereignisanzeige aktualisiert sich automatisch (Issue #139)
|
## 2026-07-26 – Feature: Ereignisanzeige aktualisiert sich automatisch (Issue #139)
|
||||||
|
|
||||||
- Die Ereignisanzeige (`/ereignisse/nextcloud-import`) war statisch – neu geloggte Ereignisse erschienen erst nach manuellem Neuladen der Seite.
|
- Die Ereignisanzeige (`/ereignisse/nextcloud-import`) war statisch – neu geloggte Ereignisse erschienen erst nach manuellem Neuladen der Seite.
|
||||||
|
|
|
||||||
21
migrations/088_buchungsvorlage_essensbeleg_ohne_ust.sql
Normal file
21
migrations/088_buchungsvorlage_essensbeleg_ohne_ust.sql
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
-- 088_buchungsvorlage_essensbeleg_ohne_ust.sql
|
||||||
|
-- Ergänzt die Vorlage "Essensbeleg n. abzugsfähig (nur USt.)" um eine dritte
|
||||||
|
-- Eingabezeile für Beträge ohne USt. (z.B. Trinkgeld).
|
||||||
|
-- Idempotent: Feld/Regel werden nur angelegt wenn nicht vorhanden.
|
||||||
|
|
||||||
|
SET @vorlage_name = 'Essensbeleg n. abzugsfähig (nur USt.)';
|
||||||
|
SET @vid = (SELECT id FROM buchungsvorlagen WHERE name = @vorlage_name LIMIT 1);
|
||||||
|
|
||||||
|
INSERT INTO buchungsvorlage_felder (vorlage_id, gruppe_nr, sort_order, feldname, label, typ, ust_satz, meta_key)
|
||||||
|
SELECT @vid, 2, 30, 'netto_0', '0% USt. (z.B. Trinkgeld)', 'ust_zeile', 0.00, NULL
|
||||||
|
WHERE @vid IS NOT NULL
|
||||||
|
AND NOT EXISTS (SELECT 1 FROM buchungsvorlage_felder WHERE vorlage_id = @vid AND feldname = 'netto_0');
|
||||||
|
|
||||||
|
-- Regel: Betrag ohne USt. → nicht abzugsfähige Bewirtungskosten ohne Vorsteuer (Konto 4657)
|
||||||
|
INSERT INTO buchungsvorlage_regeln (vorlage_id, sort_order, bedingung_feld, bedingung_op, buchungen)
|
||||||
|
SELECT @vid, 30, 'netto_0', 'neq_zero',
|
||||||
|
JSON_ARRAY(
|
||||||
|
JSON_OBJECT('betrag_ref', 'netto_0', 'nach_konto', '4657')
|
||||||
|
)
|
||||||
|
WHERE @vid IS NOT NULL
|
||||||
|
AND NOT EXISTS (SELECT 1 FROM buchungsvorlage_regeln WHERE vorlage_id = @vid AND bedingung_feld = 'netto_0');
|
||||||
72
tests/59_EssensbelegOhneUstTest.php
Normal file
72
tests/59_EssensbelegOhneUstTest.php
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
class EssensbelegOhneUstTest extends TestCase
|
||||||
|
{
|
||||||
|
protected string $testName = 'Test 59: Essensbeleg-Vorlage – dritte Zeile ohne USt. (Trinkgeld)';
|
||||||
|
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
$vorlage = \Steuerkram\Database::fetchOne(
|
||||||
|
"SELECT * FROM buchungsvorlagen WHERE name = 'Essensbeleg n. abzugsfähig (nur USt.)' LIMIT 1"
|
||||||
|
);
|
||||||
|
$this->assertNotEmpty($vorlage, 'Seed-Vorlage "Essensbeleg n. abzugsfähig (nur USt.)" vorhanden');
|
||||||
|
$vid = (int)$vorlage['id'];
|
||||||
|
|
||||||
|
// ── Feld netto_0 mit 0% USt. vorhanden ──────────────────────────────
|
||||||
|
$felder = \Steuerkram\Models\Buchungsvorlage::getFelder($vid);
|
||||||
|
$feldNamen = array_column($felder, 'feldname');
|
||||||
|
$this->assert(in_array('netto_0', $feldNamen, true), 'Feld netto_0 (0% USt.) ist Teil der Vorlage');
|
||||||
|
|
||||||
|
$feldNull = current(array_filter($felder, fn($f) => $f['feldname'] === 'netto_0'));
|
||||||
|
$this->assertEquals('ust_zeile', $feldNull['typ'], 'netto_0 ist eine ust_zeile');
|
||||||
|
$this->assertEquals(0.0, (float)$feldNull['ust_satz'], 'netto_0 hat 0% USt.-Satz');
|
||||||
|
|
||||||
|
// ── Regel für netto_0 bucht auf Konto 4657 ──────────────────────────
|
||||||
|
$regeln = \Steuerkram\Models\Buchungsvorlage::getRegeln($vid);
|
||||||
|
$regelNull = current(array_filter($regeln, fn($r) => $r['bedingung_feld'] === 'netto_0'));
|
||||||
|
$this->assertNotEmpty($regelNull, 'Regel für netto_0 vorhanden');
|
||||||
|
$this->assertEquals('4657', $regelNull['buchungen'][0]['nach_konto'], 'netto_0 bucht auf Konto 4657 (ohne Vorsteuer)');
|
||||||
|
|
||||||
|
// ── Buchungsausführung mit allen drei Zeilen (7%, 19%, 0%) ─────────
|
||||||
|
$bankId = \Steuerkram\Database::fetchOne(
|
||||||
|
"SELECT id FROM accounts WHERE kontonummer = '1200' LIMIT 1"
|
||||||
|
);
|
||||||
|
$this->assertNotEmpty($bankId, 'Konto 1200 gefunden');
|
||||||
|
|
||||||
|
$belegNr = 'TEST-ESS-' . uniqid();
|
||||||
|
$belegId = \Steuerkram\Models\Beleg::create([
|
||||||
|
'beleg_nr' => $belegNr,
|
||||||
|
'filename' => 'test-essensbeleg-trinkgeld.pdf',
|
||||||
|
'storage_path' => 'static/uploads/test/test-essensbeleg-trinkgeld.pdf',
|
||||||
|
'mime_type' => 'application/pdf',
|
||||||
|
'file_hash' => hash('sha256', $belegNr),
|
||||||
|
'beleg_datum' => date('Y-m-d'),
|
||||||
|
'belegtyp' => 'Eingangsrechnung',
|
||||||
|
]);
|
||||||
|
$this->assertGreaterThan(0, $belegId, 'Beleg angelegt');
|
||||||
|
|
||||||
|
$svc = new \Steuerkram\Services\VorlageBuchungsService();
|
||||||
|
$ids = $svc->buchen($belegId, $vid, [
|
||||||
|
'netto_7' => '10.00',
|
||||||
|
'ust_7' => '0.70',
|
||||||
|
'netto_19' => '20.00',
|
||||||
|
'ust_19' => '3.80',
|
||||||
|
'netto_0' => '5.00',
|
||||||
|
'zahlungskonto_id' => (int)$bankId['id'],
|
||||||
|
'lieferant' => 'Test-Restaurant',
|
||||||
|
'belegdatum' => date('Y-m-d'),
|
||||||
|
], date('Y-m-d'));
|
||||||
|
|
||||||
|
$this->assertEquals(5, count($ids), '5 Buchungszeilen erzeugt (2x Netto+USt, 1x Trinkgeld ohne USt.)');
|
||||||
|
|
||||||
|
$bookings = \Steuerkram\Models\Booking::forBeleg($belegId);
|
||||||
|
$kontonummern = array_column($bookings, 'kategorie_nr');
|
||||||
|
sort($kontonummern);
|
||||||
|
$this->assertEquals(['1571', '1576', '4654', '4656', '4657'], $kontonummern, 'Buchungen auf Konten 1571, 1576, 4654, 4656 und 4657');
|
||||||
|
|
||||||
|
$trinkgeldBuchung = current(array_filter($bookings, fn($b) => $b['kategorie_nr'] === '4657'));
|
||||||
|
$this->assertEquals(5.0, (float)$trinkgeldBuchung['betrag_netto'], 'Trinkgeld-Betrag korrekt gebucht');
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue