render('layout/base.php', [ 'pageTitle' => 'Buchungsvorlagen', 'topbarActions' => 'Neue Vorlage', 'content' => $this->renderView('buchungsvorlagen/index', ['vorlagen' => $vorlagen]), ]); } public function create(array $params): void { $view = new View(); $view->render('layout/base.php', [ 'pageTitle' => 'Neue Buchungsvorlage', 'content' => $this->renderView('buchungsvorlagen/form', [ 'vorlage' => null, 'felder' => [], 'regeln' => [], 'errors' => [], ]), ]); } public function store(array $params): void { $data = $_POST; $errors = $this->validate($data); if ($errors) { $view = new View(); $view->render('layout/base.php', [ 'pageTitle' => 'Neue Buchungsvorlage', 'content' => $this->renderView('buchungsvorlagen/form', [ 'vorlage' => $data, 'felder' => $this->parseFelderFromPost($data), 'regeln' => $this->parseRegelnFromPost($data), 'errors' => $errors, ]), ]); return; } $id = Buchungsvorlage::create($data); Buchungsvorlage::saveFelderForVorlage($id, $this->parseFelderFromPost($data)); Buchungsvorlage::saveRegelnForVorlage($id, $this->parseRegelnFromPost($data)); View::redirect('/einstellungen/buchungsvorlagen', 'Vorlage gespeichert.'); } public function edit(array $params): void { $id = (int)$params['id']; $vorlage = Buchungsvorlage::find($id); if (!$vorlage) { http_response_code(404); return; } $view = new View(); $view->render('layout/base.php', [ 'pageTitle' => 'Vorlage bearbeiten', 'content' => $this->renderView('buchungsvorlagen/form', [ 'vorlage' => $vorlage, 'felder' => Buchungsvorlage::getFelder($id), 'regeln' => Buchungsvorlage::getRegeln($id), 'errors' => [], ]), ]); } public function update(array $params): void { $id = (int)$params['id']; $vorlage = Buchungsvorlage::find($id); if (!$vorlage) { http_response_code(404); return; } $data = $_POST; $errors = $this->validate($data); if ($errors) { $view = new View(); $view->render('layout/base.php', [ 'pageTitle' => 'Vorlage bearbeiten', 'content' => $this->renderView('buchungsvorlagen/form', [ 'vorlage' => array_merge($vorlage, $data), 'felder' => $this->parseFelderFromPost($data), 'regeln' => $this->parseRegelnFromPost($data), 'errors' => $errors, ]), ]); return; } Buchungsvorlage::update($id, $data); Buchungsvorlage::saveFelderForVorlage($id, $this->parseFelderFromPost($data)); Buchungsvorlage::saveRegelnForVorlage($id, $this->parseRegelnFromPost($data)); View::redirect('/einstellungen/buchungsvorlagen', 'Vorlage aktualisiert.'); } public function destroy(array $params): void { $id = (int)$params['id']; Buchungsvorlage::delete($id); View::redirect('/einstellungen/buchungsvorlagen', 'Vorlage gelöscht.'); } // ── AJAX: Modal-HTML ─────────────────────────────────────────────────── public function modal(array $params): void { $vorlageId = (int)$params['id']; $belegId = (int)($_GET['beleg_id'] ?? 0); $vorlage = Buchungsvorlage::find($vorlageId); if (!$vorlage || !$vorlage['aktiv']) { http_response_code(404); echo '

Vorlage nicht gefunden.

'; return; } $beleg = $belegId > 0 ? Beleg::find($belegId) : null; $felder = Buchungsvorlage::getFelder($vorlageId); $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 && $bankTxId > 0) { $hatBankbuchung = true; } } if ($bankTxId > 0) { $bankTx = BankTransaction::find($bankTxId); $bankTxDatum = $bankTx['wertstellung'] ?? ''; } echo $this->renderView('buchungsvorlagen/modal', [ 'vorlage' => $vorlage, 'felder' => $felder, 'beleg' => $beleg, 'belegId' => $belegId, 'zahlungskonten' => array_values($zahlungskonten), 'hatBankbuchung' => $hatBankbuchung, 'bankTxId' => $bankTxId, 'bankTxDatum' => $bankTxDatum, ]); } // ── Buchungen ausführen ──────────────────────────────────────────────── public function buchen(array $params): void { $belegId = (int)$params['belegId']; $vorlageId = (int)$params['vorlageId']; $beleg = Beleg::find($belegId); if (!$beleg) { http_response_code(404); return; } $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; } $msg = $bankTxId > 0 ? 'Buchungen aus Vorlage erfasst und Bankbuchung verknüpft.' : 'Buchungen aus Vorlage erfasst.'; View::redirect("/belege/{$belegId}", $msg); } // ── Hilfsmethoden ────────────────────────────────────────────────────── private function validate(array $data): array { $errors = []; if (empty(trim($data['name'] ?? ''))) { $errors['name'] = 'Name ist ein Pflichtfeld.'; } return $errors; } private function parseFelderFromPost(array $data): array { $felder = []; $raws = $data['felder'] ?? []; foreach ($raws as $f) { if (empty(trim($f['feldname'] ?? ''))) continue; $felder[] = [ 'gruppe_nr' => (int)($f['gruppe_nr'] ?? 1), 'sort_order' => (int)($f['sort_order'] ?? 0), 'feldname' => trim($f['feldname']), 'label' => trim($f['label'] ?? ''), 'typ' => $f['typ'] ?? 'text', 'ust_satz' => $f['ust_satz'] ?? '', 'meta_key' => trim($f['meta_key'] ?? ''), ]; } return $felder; } private function parseRegelnFromPost(array $data): array { $regeln = []; $raws = $data['regeln'] ?? []; foreach ($raws as $r) { if (empty(trim($r['bedingung_feld'] ?? ''))) continue; $buchungen = []; foreach (($r['buchungen'] ?? []) as $b) { if (empty(trim($b['betrag_ref'] ?? '')) || empty(trim($b['nach_konto'] ?? ''))) continue; $buchungen[] = [ 'betrag_ref' => trim($b['betrag_ref']), 'nach_konto' => trim($b['nach_konto']), ]; } $regeln[] = [ 'sort_order' => (int)($r['sort_order'] ?? 0), 'bedingung_feld' => trim($r['bedingung_feld']), 'bedingung_op' => $r['bedingung_op'] ?? 'neq_zero', 'buchungen' => $buchungen, ]; } return $regeln; } }