diff --git a/migrations/081_buchungsvorlage_standard_lieferant.sql b/migrations/081_buchungsvorlage_standard_lieferant.sql new file mode 100644 index 0000000..298fa8d --- /dev/null +++ b/migrations/081_buchungsvorlage_standard_lieferant.sql @@ -0,0 +1,11 @@ +-- 081_buchungsvorlage_standard_lieferant.sql +-- Standard-Lieferant pro Vorlage; wird im Buchungsdialog vorbelegt. + +ALTER TABLE buchungsvorlagen + ADD COLUMN IF NOT EXISTS standard_lieferant VARCHAR(255) NULL DEFAULT NULL AFTER beschreibung; + +-- Bestehende Vorlage "Essensbeleg" mit Standardlieferant "Lebensmittel" vorbelegen. +UPDATE buchungsvorlagen +SET standard_lieferant = 'Lebensmittel' +WHERE name = 'Essensbeleg n. abzugsfähig (nur USt.)' + AND (standard_lieferant IS NULL OR standard_lieferant = ''); diff --git a/public/static/js/app.js b/public/static/js/app.js index 31277e0..cb668b8 100644 --- a/public/static/js/app.js +++ b/public/static/js/app.js @@ -524,10 +524,11 @@ document.addEventListener('input', function(e) { if (!inp.matches('#vorlage-modal .vorlage-netto, #vorlage-modal .vorlage-brutto')) return; const row = inp.closest('.vorlage-ust-row'); if (!row) return; - const satz = parseFloat(row.dataset.ustSatz) / 100; - const netto = row.querySelector('.vorlage-netto'); - const brutto = row.querySelector('.vorlage-brutto'); - const ust = row.querySelector('.vorlage-ust'); + const satz = parseFloat(row.dataset.ustSatz) / 100; + const netto = row.querySelector('.vorlage-netto'); + const brutto = row.querySelector('.vorlage-brutto'); + const ust = row.querySelector('.vorlage-ust'); + const ustAnzeige = row.querySelector('.vorlage-ust-anzeige'); if (inp.classList.contains('vorlage-netto')) { const n = parseFloat(netto.value) || 0; brutto.value = (n * (1 + satz)).toFixed(2); @@ -538,6 +539,7 @@ document.addEventListener('input', function(e) { netto.value = n.toFixed(2); ust.value = (b - n).toFixed(2); } + if (ustAnzeige) ustAnzeige.textContent = parseFloat(ust.value).toFixed(2).replace('.', ','); vorlageUpdateBruttoGesamt(); }); @@ -548,19 +550,11 @@ function vorlageUpdateBruttoGesamt() { const summe = Array.from(bruttoFelder).reduce((s, el) => s + (parseFloat(el.value) || 0), 0); const anzeige = modal.querySelector('[data-feldname="brutto_gesamt"]'); if (anzeige) anzeige.textContent = summe.toFixed(2).replace('.', ',') + ' €'; - // Auch das buchungs_datum-Hidden synchronisieren mit belegdatum-Feld falls vorhanden - const datumFeld = modal.querySelector('input[name="belegdatum"]'); - const datumHidden = modal.querySelector('input[name="buchungs_datum"]'); - if (datumFeld && datumHidden && datumFeld.value) { - datumHidden.value = datumFeld.value; - } } -// Datum-Feld Änderung → buchungs_datum synchronisieren +// Zahldatum-Feld Änderung → buchungs_datum-Hidden synchronisieren document.addEventListener('change', function(e) { - if (!e.target.matches('#vorlage-modal input[name="belegdatum"]')) return; - const modal = document.getElementById('vorlage-modal'); - if (!modal) return; - const hidden = modal.querySelector('input[name="buchungs_datum"]'); + if (!e.target.matches('#vorlage-modal #vorlage-zahldatum')) return; + const hidden = document.getElementById('vorlage-buchungs-datum'); if (hidden) hidden.value = e.target.value; }); diff --git a/src/Controllers/BuchungsvorlageController.php b/src/Controllers/BuchungsvorlageController.php index 00670b5..14fb73d 100644 --- a/src/Controllers/BuchungsvorlageController.php +++ b/src/Controllers/BuchungsvorlageController.php @@ -141,14 +141,20 @@ class BuchungsvorlageController extends BaseController $zahlungskonten = Account::all(['kontenart' => 'Zahlungskonto', 'aktiv' => 1]); $zahlungskonten = array_filter($zahlungskonten, fn($a) => (int)$a['kontonummer'] >= 1200 && (int)$a['kontonummer'] <= 1299); + $bankTxId = (int)($_GET['bank_tx'] ?? 0); + $bankTxDatum = ''; $hatBankbuchung = false; if ($beleg) { $linked = BankTransaction::findByBelegId((int)$beleg['id']); $hatBankbuchung = !empty($linked); - if (!$hatBankbuchung && !empty($_GET['bank_tx'])) { + if (!$hatBankbuchung && $bankTxId > 0) { $hatBankbuchung = true; } } + if ($bankTxId > 0) { + $bankTx = BankTransaction::find($bankTxId); + $bankTxDatum = $bankTx['wertstellung'] ?? ''; + } echo $this->renderView('buchungsvorlagen/modal', [ 'vorlage' => $vorlage, @@ -157,6 +163,8 @@ class BuchungsvorlageController extends BaseController 'belegId' => $belegId, 'zahlungskonten' => array_values($zahlungskonten), 'hatBankbuchung' => $hatBankbuchung, + 'bankTxId' => $bankTxId, + 'bankTxDatum' => $bankTxDatum, ]); } @@ -170,17 +178,24 @@ class BuchungsvorlageController extends BaseController $beleg = Beleg::find($belegId); if (!$beleg) { http_response_code(404); return; } - $datum = !empty($_POST['buchungs_datum']) ? $_POST['buchungs_datum'] : date('Y-m-d'); + $datum = !empty($_POST['buchungs_datum']) ? $_POST['buchungs_datum'] : date('Y-m-d'); + $bankTxId = (int)($_POST['bank_tx_id'] ?? 0); try { $svc = new VorlageBuchungsService(); $svc->buchen($belegId, $vorlageId, $_POST, $datum); + + if ($bankTxId > 0) { + $totalBrutto = \Steuerkram\Models\Booking::sumBruttoForBeleg($belegId); + BankTransaction::linkBeleg($bankTxId, $belegId, $totalBrutto); + } } catch (\RuntimeException $e) { View::redirect("/belege/{$belegId}", $e->getMessage(), 'error'); return; } - View::redirect("/belege/{$belegId}", 'Buchungen aus Vorlage erfasst.'); + $msg = $bankTxId > 0 ? 'Buchungen aus Vorlage erfasst und Bankbuchung verknüpft.' : 'Buchungen aus Vorlage erfasst.'; + View::redirect("/belege/{$belegId}", $msg); } // ── Hilfsmethoden ────────────────────────────────────────────────────── diff --git a/src/Models/Buchungsvorlage.php b/src/Models/Buchungsvorlage.php index 60da401..064be85 100644 --- a/src/Models/Buchungsvorlage.php +++ b/src/Models/Buchungsvorlage.php @@ -54,11 +54,12 @@ class Buchungsvorlage public static function create(array $data): int { Database::execute( - 'INSERT INTO buchungsvorlagen (name, beschreibung, aktiv, sort_order) - VALUES (?, ?, ?, ?)', + 'INSERT INTO buchungsvorlagen (name, beschreibung, standard_lieferant, aktiv, sort_order) + VALUES (?, ?, ?, ?, ?)', [ trim($data['name']), $data['beschreibung'] ?? null, + $data['standard_lieferant'] !== '' ? trim($data['standard_lieferant'] ?? '') : null, isset($data['aktiv']) ? (int)$data['aktiv'] : 1, (int)($data['sort_order'] ?? 0), ] @@ -70,11 +71,12 @@ class Buchungsvorlage { Database::execute( 'UPDATE buchungsvorlagen - SET name = ?, beschreibung = ?, aktiv = ?, sort_order = ? + SET name = ?, beschreibung = ?, standard_lieferant = ?, aktiv = ?, sort_order = ? WHERE id = ?', [ trim($data['name']), $data['beschreibung'] ?? null, + $data['standard_lieferant'] !== '' ? trim($data['standard_lieferant'] ?? '') : null, isset($data['aktiv']) ? (int)$data['aktiv'] : 1, (int)($data['sort_order'] ?? 0), $id, diff --git a/src/Views/buchungsvorlagen/form.php b/src/Views/buchungsvorlagen/form.php index 5c44ac3..cf7520b 100644 --- a/src/Views/buchungsvorlagen/form.php +++ b/src/Views/buchungsvorlagen/form.php @@ -27,6 +27,11 @@ $bedOptn = ['neq_zero' => 'wenn ≠ 0', 'always' => 'immer']; +
+ + +
diff --git a/src/Views/buchungsvorlagen/modal.php b/src/Views/buchungsvorlagen/modal.php index e431642..79e5ea7 100644 --- a/src/Views/buchungsvorlagen/modal.php +++ b/src/Views/buchungsvorlagen/modal.php @@ -7,13 +7,17 @@ $gruppe1 = array_filter($felder, fn($f) => $f['gruppe_nr'] == 1); $gruppe2 = array_filter($felder, fn($f) => $f['gruppe_nr'] == 2); $gruppe3 = array_filter($felder, fn($f) => $f['gruppe_nr'] == 3); -// Vorbelegen aus Beleg-Metadaten +// Vorbelegen: Vorlage-Standard-Lieferant hat Vorrang vor Beleg-Lieferant +$standardLieferant = trim($vorlage['standard_lieferant'] ?? ''); $vorbelegt = [ - 'lieferant' => $beleg['supplier_name'] ?? '', + 'lieferant' => $standardLieferant !== '' ? $standardLieferant : ($beleg['supplier_name'] ?? ''), 'rechnungsnr' => $beleg['rechnungs_nr'] ?? '', 'belegdatum' => $beleg['beleg_datum'] ?? date('Y-m-d'), ]; +// Zahldatum: Bankbuchungs-Wertstellung, Fallback heute +$zahldatum = ($bankTxDatum ?? '') ?: date('Y-m-d'); + // Vorauswahl Zahlungskonto $defaultKontonummer = $hatBankbuchung ? '1200' : '1210'; $defaultKontoId = 0; @@ -35,7 +39,10 @@ if (!$defaultKontoId && !empty($zahlungskonten)) {
-
+
+ style="width:150px" class="form-control form-control-sm"> + + + +
@@ -78,7 +91,7 @@ if (!$defaultKontoId && !empty($zahlungskonten)) { Steuer Netto (€) Brutto (€) - USt (€) + USt (€) @@ -105,11 +118,10 @@ if (!$defaultKontoId && !empty($zahlungskonten)) { style="text-align:right;width:110px" placeholder="0,00"> - - + + 0,00 + diff --git a/src/version.txt b/src/version.txt index 7976f90..d7504ca 100644 --- a/src/version.txt +++ b/src/version.txt @@ -1 +1 @@ -1-260528 +1-260530