diff --git a/Changes.md b/Changes.md index 73b8508..0a9fc3e 100644 --- a/Changes.md +++ b/Changes.md @@ -2,6 +2,18 @@ --- +## 2026-05-15 – Feature: Bankbuchung auf mehrere Belege aufteilen + +- Migration 053: Junction-Tabelle `bank_transaction_belege` (bank_tx_id, beleg_id, betrag); `bank_transactions.beleg_id` entfernt; Status-ENUM um `teilweise` erweitert; bestehende Verknüpfungen automatisch migriert +- Neuer Status `teilweise`: wird gesetzt wenn mind. ein Beleg verknüpft ist, aber noch Restbetrag offen bleibt +- Standardfilter in der Bankübersicht zeigt jetzt „Offen & Teilweise" +- `bank/show.php`: Sektion „Verknüpfte Belege" mit Betrag je Beleg und Entfernen-Button; Restsaldo-Anzeige; Betrag-Eingabefeld pro Beleg in der Offene-Belege-Liste +- Beim Verknüpfen wird der zugeordnete Betrag an die Buchungsmaske weitergegeben (`alloc_betrag`) +- `BankTransaction::linkBeleg()` schreibt jetzt in Junction-Tabelle mit Betrag; `recalcStatus()` setzt Status automatisch; `unlinkBeleg()` entfernt Verknüpfung; `getLinkedBelege()` / `getRemainingBetrag()` neu +- Neue Route `POST /bank/{id}/unlink` + +--- + ## 2026-05-15 – Feature: Dublettenprüfung beim Bank-Import - Nach dem Upload wird geprüft, welche Buchungen bereits in der DB vorhanden sind (Abgleich über Buchungstag, Wertstellung, Betrag, Buchungstext) diff --git a/migrations/053_bank_transaction_belege.sql b/migrations/053_bank_transaction_belege.sql new file mode 100644 index 0000000..f992f92 --- /dev/null +++ b/migrations/053_bank_transaction_belege.sql @@ -0,0 +1,24 @@ +-- n:m-Verknüpfung Bankbuchung <-> Belege mit zugewiesenem Betrag +CREATE TABLE IF NOT EXISTS bank_transaction_belege ( + id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + bank_tx_id INT UNSIGNED NOT NULL, + beleg_id INT UNSIGNED NOT NULL, + betrag DECIMAL(12,2) NOT NULL DEFAULT 0.00, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE KEY uq_tx_beleg (bank_tx_id, beleg_id), + FOREIGN KEY (bank_tx_id) REFERENCES bank_transactions(id) ON DELETE CASCADE, + FOREIGN KEY (beleg_id) REFERENCES belege(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Bestehende 1:1-Verknüpfungen migrieren +INSERT IGNORE INTO bank_transaction_belege (bank_tx_id, beleg_id, betrag) +SELECT bt.id, bt.beleg_id, ABS(bt.wert) +FROM bank_transactions bt +WHERE bt.beleg_id IS NOT NULL; + +-- Neuer Status 'teilweise' +ALTER TABLE bank_transactions + MODIFY COLUMN status ENUM('offen','teilweise','gebucht','ignoriert') NOT NULL DEFAULT 'offen'; + +-- Altes Einzelfeld entfernen +ALTER TABLE bank_transactions DROP COLUMN beleg_id; diff --git a/public/index.php b/public/index.php index 5e87e91..5a3e530 100644 --- a/public/index.php +++ b/public/index.php @@ -72,6 +72,7 @@ $router->post('/bank/upload/confirm', fn($p) => (new BankController())->up $router->get('/bank/{id}', fn($p) => (new BankController())->show($p)); $router->post('/bank/{id}/status', fn($p) => (new BankController())->updateStatus($p)); $router->post('/bank/{id}/link', fn($p) => (new BankController())->linkBeleg($p)); +$router->post('/bank/{id}/unlink', fn($p) => (new BankController())->unlinkBeleg($p)); $router->post('/bank/{id}/beleg', fn($p) => (new BankController())->uploadBeleg($p)); // ── Buchungen ──────────────────────────────────────────────── diff --git a/src/Controllers/BankController.php b/src/Controllers/BankController.php index c28325c..47a9f11 100644 --- a/src/Controllers/BankController.php +++ b/src/Controllers/BankController.php @@ -19,7 +19,7 @@ class BankController { $filter = $_GET; if (!isset($filter['status'])) { - $filter['status'] = 'offen'; + $filter['status'] = 'pending'; } $page = max(1, (int)($_GET['page'] ?? 1)); @@ -159,15 +159,18 @@ class BankController View::redirect('/bank', 'Buchung nicht gefunden.', 'error'); } - // Offene Belege (noch nicht gebucht) - $offeneBelege = Beleg::all(['booked' => '0'], 1, 200); + $linkedBelege = BankTransaction::getLinkedBelege($id); + $remainingBetrag = BankTransaction::getRemainingBetrag($id); + $offeneBelege = Beleg::all(['booked' => '0'], 1, 200); $view = new View(); $view->render('layout/base.php', [ 'pageTitle' => 'Bankbuchung zuordnen', 'content' => $this->renderView('bank/show', [ - 'transaction' => $transaction, - 'offeneBelege' => $offeneBelege['rows'], + 'transaction' => $transaction, + 'linkedBelege' => $linkedBelege, + 'remainingBetrag' => $remainingBetrag, + 'offeneBelege' => $offeneBelege['rows'], ]), ]); } @@ -177,7 +180,7 @@ class BankController $id = (int)($params['id'] ?? 0); $status = $_POST['status'] ?? ''; - if (!in_array($status, ['offen', 'gebucht', 'ignoriert'], true)) { + if (!in_array($status, ['offen', 'teilweise', 'gebucht', 'ignoriert'], true)) { View::redirect('/bank', 'Ungültiger Status.', 'error'); } @@ -190,13 +193,28 @@ class BankController { $id = (int)($params['id'] ?? 0); $belegId = (int)($_POST['beleg_id'] ?? 0); + $betrag = round((float)str_replace(',', '.', $_POST['alloc_betrag'] ?? ''), 2); if (!$belegId) { View::redirect("/bank/$id", 'Kein Beleg ausgewählt.', 'error'); } + if ($betrag <= 0) { + View::redirect("/bank/$id", 'Bitte einen gültigen Betrag eingeben.', 'error'); + } - BankTransaction::linkBeleg($id, $belegId); - View::redirect('/bank', 'Beleg verknüpft und Buchung als gebucht markiert.'); + View::redirect("/belege/$belegId?bank_tx=$id&alloc_betrag=$betrag"); + } + + public function unlinkBeleg(array $params): void + { + $id = (int)($params['id'] ?? 0); + $belegId = (int)($_POST['beleg_id'] ?? 0); + $redirectTo = $_POST['redirect_to'] ?? ''; + + BankTransaction::unlinkBeleg($id, $belegId); + + $safe = (preg_match('#^/[a-zA-Z0-9/_-]#', $redirectTo)) ? $redirectTo : "/bank/$id"; + View::redirect($safe, 'Beleg-Verknüpfung entfernt.'); } public function uploadBeleg(array $params): void @@ -228,28 +246,29 @@ class BankController View::redirect("/bank/$id", 'Nicht erlaubtes Dateiformat.', 'error'); } - $ext = $allowedMime[$mime]; - $hash = hash_file('sha256', $file['tmp_name']); - $filename = $hash . '.' . $ext; - $dir = BASE_DIR . '/storage/belege/'; - if (!is_dir($dir)) mkdir($dir, 0755, true); - $dest = $dir . $filename; - if (!file_exists($dest)) { - move_uploaded_file($file['tmp_name'], $dest); - } + $ext = $allowedMime[$mime]; + $belegNr = Beleg::generateBelegNr(); + $year = date('Y', strtotime($transaction['wertstellung'])); + $relDir = "static/uploads/{$year}/{$belegNr}"; + $absDir = dirname(__DIR__, 2) . "/public/{$relDir}"; + if (!is_dir($absDir)) mkdir($absDir, 0755, true); + + $storagePath = "{$relDir}/original.{$ext}"; + $absPath = dirname(__DIR__, 2) . "/public/{$storagePath}"; + move_uploaded_file($file['tmp_name'], $absPath); + $hash = hash_file('sha256', $absPath); $belegId = Beleg::create([ - 'beleg_nr' => Beleg::generateBelegNr(), + 'beleg_nr' => $belegNr, 'filename' => $file['name'], - 'storage_path' => 'storage/belege/' . $filename, + 'storage_path' => $storagePath, 'mime_type' => $mime, 'file_hash' => $hash, 'beleg_datum' => $transaction['wertstellung'], 'belegtyp' => (float)$transaction['wert'] >= 0 ? 'Ausgangsrechnung' : 'Eingangsrechnung', ]); - BankTransaction::linkBeleg($id, $belegId); - View::redirect('/bank', 'Beleg hochgeladen und Buchung als gebucht markiert.'); + View::redirect("/bank/$id", 'Beleg hochgeladen – bitte jetzt verknüpfen.'); } private function renderView(string $name, array $data = []): string diff --git a/src/Controllers/BelegController.php b/src/Controllers/BelegController.php index 1ddd7d1..a61f229 100644 --- a/src/Controllers/BelegController.php +++ b/src/Controllers/BelegController.php @@ -223,12 +223,15 @@ class BelegController if (preg_match('/Auftraggeber:\s*(.*?)(?:\s*Buchungstext|\s*$)/si', $bankTx['buchungstext'], $m)) { $bankTxSupplier = trim($m[1]); } - $bankTxBrutto = abs((float)$bankTx['wert']); + // alloc_betrag aus URL hat Vorrang (Teilbetrag bei Aufteilung), sonst voller Betrag + $allocBetrag = isset($_GET['alloc_betrag']) ? round((float)$_GET['alloc_betrag'], 2) : 0.0; + $bankTxBrutto = $allocBetrag > 0 ? $allocBetrag : abs((float)$bankTx['wert']); $netto = round($bankTxBrutto / 1.19, 2); $bankFormData = [ 'buchungs_datum' => $bankTx['wertstellung'], 'betrag_netto' => number_format($netto, 2, '.', ''), + 'alloc_betrag' => number_format($bankTxBrutto, 2, '.', ''), 'zahlungs_kontonummer'=> '1200', ]; diff --git a/src/Controllers/BookingController.php b/src/Controllers/BookingController.php index 7c30884..d3c8cbe 100644 --- a/src/Controllers/BookingController.php +++ b/src/Controllers/BookingController.php @@ -183,10 +183,21 @@ class BookingController } } + // Belegbetrag in Metadaten aktualisieren + $totalBrutto = Booking::sumBruttoForBeleg($belegId); + \Steuerkram\Database::execute( + 'UPDATE belege SET betrag_brutto = ?, updated_at = NOW() WHERE id = ?', + [$totalBrutto, $belegId] + ); + // Bankbuchung verknüpfen wenn aus Bank-Kontext $bankTxId = (int)($data['bank_tx_id'] ?? 0); if ($bankTxId > 0) { - BankTransaction::linkBeleg($bankTxId, $belegId); + // Tatsächlich gebuchten Bruttobetrag aus Buchungsdaten berechnen + $netto = abs((float)$data['betrag_netto']); + $ustSatz = (float)($data['ust_satz'] ?? 0); + $brutto = round($netto * (1 + $ustSatz / 100), 2); + BankTransaction::linkBeleg($bankTxId, $belegId, $brutto); } if ($newAssetId !== null) { @@ -210,19 +221,29 @@ class BookingController $bookings = \Steuerkram\Models\Booking::forBeleg($belegId); $accounts = \Steuerkram\Models\Account::all(['aktiv' => 1]); $integrity = \Steuerkram\Models\Beleg::verifyIntegrity($belegId); - $assets = \Steuerkram\Models\Asset::all(); + $assets = \Steuerkram\Models\Asset::all(); + $linked = BankTransaction::findByBelegId($belegId); + + // Bank-Kontext aus POST-Daten wiederherstellen (damit alloc_betrag nach Validierungsfehler erhalten bleibt) + $bankTx = null; + if (!empty($formData['bank_tx_id'])) { + $bankTx = BankTransaction::find((int)$formData['bank_tx_id']); + } $view = new View(); $view->render('layout/base.php', [ 'pageTitle' => 'Beleg ' . ($beleg['beleg_nr'] ?? ''), 'content' => $this->renderView('belege/detail', [ - 'beleg' => $beleg, - 'bookings' => $bookings, - 'integrity' => $integrity, - 'accounts' => $accounts, - 'assets' => $assets, - 'formErrors' => $errors, - 'formData' => $formData, + 'beleg' => $beleg, + 'bookings' => $bookings, + 'integrity' => $integrity, + 'accounts' => $accounts, + 'assets' => $assets, + 'formErrors' => $errors, + 'formData' => $formData, + 'bankTx' => $bankTx, + 'bankTxBrutto' => $bankTx ? (float)($formData['alloc_betrag'] ?: abs((float)$bankTx['wert'])) : 0.0, + 'linkedBankTx' => $linked, ]), ]); } diff --git a/src/Models/BankTransaction.php b/src/Models/BankTransaction.php index 4fde63e..ec8d55f 100644 --- a/src/Models/BankTransaction.php +++ b/src/Models/BankTransaction.php @@ -13,8 +13,10 @@ class BankTransaction $where = ['1=1']; $params = []; - $status = $filter['status'] ?? 'offen'; - if ($status !== '') { + $status = $filter['status'] ?? 'pending'; + if ($status === 'pending') { + $where[] = "bt.status IN ('offen','teilweise')"; + } elseif ($status !== '') { $where[] = 'bt.status = ?'; $params[] = $status; } @@ -51,11 +53,17 @@ class BankTransaction $rows = Database::fetchAll( "SELECT bt.*, bib.filename AS batch_filename, bif.name AS format_name, - b.id AS beleg_id, b.beleg_nr + btb_agg.beleg_id AS beleg_id, btb_agg.beleg_count, + b.beleg_nr FROM bank_transactions bt JOIN bank_import_batches bib ON bt.batch_id = bib.id JOIN bank_import_formats bif ON bib.format_id = bif.id - LEFT JOIN belege b ON b.id = bt.beleg_id + LEFT JOIN ( + SELECT bank_tx_id, MIN(beleg_id) AS beleg_id, COUNT(*) AS beleg_count + FROM bank_transaction_belege + GROUP BY bank_tx_id + ) btb_agg ON btb_agg.bank_tx_id = bt.id + LEFT JOIN belege b ON b.id = btb_agg.beleg_id WHERE $whereStr ORDER BY bt.wertstellung DESC, bt.id DESC LIMIT ? OFFSET ?", @@ -90,17 +98,105 @@ class BankTransaction ); } - public static function linkBeleg(int $id, int $belegId): void + /** Verknüpft einen Beleg mit zugeordnetem Betrag und aktualisiert den Status. */ + public static function linkBeleg(int $txId, int $belegId, float $betrag): void { Database::execute( - "UPDATE bank_transactions SET beleg_id = ?, status = 'gebucht' WHERE id = ?", - [$belegId, $id] + 'INSERT INTO bank_transaction_belege (bank_tx_id, beleg_id, betrag) + VALUES (?, ?, ?) + ON DUPLICATE KEY UPDATE betrag = VALUES(betrag)', + [$txId, $belegId, $betrag] ); + self::recalcStatus($txId); + } + + /** Entfernt eine Beleg-Verknüpfung und aktualisiert den Status. */ + public static function unlinkBeleg(int $txId, int $belegId): void + { + Database::execute( + 'DELETE FROM bank_transaction_belege WHERE bank_tx_id = ? AND beleg_id = ?', + [$txId, $belegId] + ); + self::recalcStatus($txId); + } + + /** Berechnet Status neu: 0 Links→offen, Restsaldo>0→teilweise, Restsaldo=0→gebucht. */ + public static function recalcStatus(int $txId): void + { + $row = Database::fetchOne( + 'SELECT ABS(bt.wert) AS brutto, COALESCE(SUM(btb.betrag), 0) AS allocated + FROM bank_transactions bt + LEFT JOIN bank_transaction_belege btb ON btb.bank_tx_id = bt.id + WHERE bt.id = ? + GROUP BY bt.id', + [$txId] + ); + if (!$row) return; + + $remaining = round((float)$row['brutto'] - (float)$row['allocated'], 2); + $allocated = (float)$row['allocated']; + + if ($allocated <= 0) { + $status = 'offen'; + } elseif ($remaining > 0.01) { + $status = 'teilweise'; + } else { + $status = 'gebucht'; + } + + Database::execute( + "UPDATE bank_transactions SET status = ? WHERE id = ?", + [$status, $txId] + ); + } + + /** Gibt alle verknüpften Belege mit ihren Beträgen zurück. */ + public static function getLinkedBelege(int $txId): array + { + return Database::fetchAll( + 'SELECT btb.betrag, b.id AS beleg_id, b.beleg_nr, b.beleg_datum, + b.belegtyp, b.betrag_brutto, s.name AS supplier_name + FROM bank_transaction_belege btb + JOIN belege b ON b.id = btb.beleg_id + LEFT JOIN suppliers s ON s.id = b.supplier_id + WHERE btb.bank_tx_id = ? + ORDER BY b.beleg_nr', + [$txId] + ); + } + + /** Gibt den noch nicht zugeordneten Restbetrag zurück. */ + public static function getRemainingBetrag(int $txId): float + { + $row = Database::fetchOne( + 'SELECT ABS(bt.wert) AS brutto, COALESCE(SUM(btb.betrag), 0) AS allocated + FROM bank_transactions bt + LEFT JOIN bank_transaction_belege btb ON btb.bank_tx_id = bt.id + WHERE bt.id = ? + GROUP BY bt.id', + [$txId] + ); + if (!$row) return 0.0; + return round(max(0.0, (float)$row['brutto'] - (float)$row['allocated']), 2); + } + + /** Sucht die Bankbuchung, die mit einem bestimmten Beleg verknüpft ist. */ + public static function findByBelegId(int $belegId): ?array + { + $row = Database::fetchOne( + 'SELECT bt.*, bib.filename AS batch_filename, btb.betrag AS alloc_betrag + FROM bank_transaction_belege btb + JOIN bank_transactions bt ON bt.id = btb.bank_tx_id + JOIN bank_import_batches bib ON bib.id = bt.batch_id + WHERE btb.beleg_id = ? + LIMIT 1', + [$belegId] + ); + return $row ?: null; } /** * Teilt $rows in ['new' => [...], 'dup' => [...]] auf. - * Eine Zeile gilt als Dublette, wenn buchungstag + wertstellung + wert + buchungstext(200) bereits existieren. */ public static function findDuplicates(array $rows): array { @@ -108,7 +204,6 @@ class BankTransaction return ['new' => [], 'dup' => []]; } - // Kandidaten-Abfrage: alle DB-Zeilen, deren (buchungstag, wertstellung, wert) in den Upload-Daten vorkommen $placeholders = implode(',', array_fill(0, count($rows), '(?,?,?)')); $params = []; foreach ($rows as $r) { @@ -124,7 +219,6 @@ class BankTransaction $params ); - // Lookup-Set für schnellen Vergleich $lookup = []; foreach ($existing as $e) { $lookup[$e['buchungstag'] . '|' . $e['wertstellung'] . '|' . $e['wert'] . '|' . $e['btext']] = true; @@ -147,19 +241,6 @@ class BankTransaction return ['new' => $new, 'dup' => $dup]; } - public static function findByBelegId(int $belegId): ?array - { - $row = Database::fetchOne( - 'SELECT bt.*, bib.filename AS batch_filename - FROM bank_transactions bt - JOIN bank_import_batches bib ON bib.id = bt.batch_id - WHERE bt.beleg_id = ? - LIMIT 1', - [$belegId] - ); - return $row ?: null; - } - public static function createBatch(int $formatId, string $filename, int $rowCount): int { Database::execute( diff --git a/src/Models/Booking.php b/src/Models/Booking.php index df95c97..522beb1 100644 --- a/src/Models/Booking.php +++ b/src/Models/Booking.php @@ -407,6 +407,18 @@ class Booking return sprintf('BU-%s-%06d', $year, $next); } + /** Summiert betrag_brutto aller aktiven Hauptbuchungen eines Belegs. */ + public static function sumBruttoForBeleg(int $belegId): float + { + $row = Database::fetchOne( + 'SELECT COALESCE(SUM(betrag_brutto), 0) AS total + FROM bookings + WHERE beleg_id = ? AND is_reversal = 0 AND parent_booking_id IS NULL', + [$belegId] + ); + return round((float)($row['total'] ?? 0), 2); + } + public static function sumByYear(int $year): array { return Database::fetchAll( diff --git a/src/Views/bank/index.php b/src/Views/bank/index.php index ce152a2..e1e5d06 100644 --- a/src/Views/bank/index.php +++ b/src/Views/bank/index.php @@ -36,11 +36,13 @@ $months = ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','D - + + + - + @@ -82,9 +84,10 @@ $months = ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','D $wert = (float)$row['wert']; $isPlus = $wert >= 0; $color = $isPlus ? 'var(--color-success)' : 'var(--color-danger)'; - $ziel = ($row['status'] === 'gebucht' && !empty($row['beleg_id'])) - ? '/belege/' . (int)$row['beleg_id'] - : '/bank/' . (int)$row['id']; + $ziel = '/bank/' . (int)$row['id']; + if ($row['status'] === 'gebucht' && !empty($row['beleg_id']) && ($row['beleg_count'] ?? 1) == 1) { + $ziel = '/belege/' . (int)$row['beleg_id']; + } ?> @@ -101,13 +104,20 @@ $months = ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','D 'badge-green', + 'teilweise' => 'badge-warning', 'ignoriert' => 'badge-gray', default => 'badge-blue', }; ?> - -
+ +
+ 1): ?> + Belege + + + +
diff --git a/src/Views/bank/show.php b/src/Views/bank/show.php index b9d18cb..21723de 100644 --- a/src/Views/bank/show.php +++ b/src/Views/bank/show.php @@ -11,6 +11,10 @@ $color = $isPlus ? 'var(--color-success)' : 'var(--color-danger)'; $settings = Setting::get(); $vorschauBreite = (int)($settings['beleg_vorschau_breite'] ?? 200); $vorschauHoehe = (int)($settings['beleg_vorschau_hoehe'] ?? 300); + +$remaining = (float)$remainingBetrag; +$totalBrutto = abs($wert); +$restFormatted = number_format($remaining, 2, ',', '.'); ?> @@ -33,16 +37,23 @@ $vorschauHoehe = (int)($settings['beleg_vorschau_hoehe'] ?? 300);
- Wert
+ Gesamt
€
+
+ Verbleibend
+ + € + +
Status
'badge-green', + 'teilweise' => 'badge-warning', 'ignoriert' => 'badge-gray', default => 'badge-blue', }; @@ -63,24 +74,133 @@ $vorschauHoehe = (int)($settings['beleg_vorschau_hoehe'] ?? 300);
+ + +
+
+
Verknüpfte Belege
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Belegnr.DatumTypLieferantBelegbetragZugeordnet
+ + –' ?> + –' ?> + + € + +
+ + +
+
+
+
+ + + 0.01): ?>
-
Beleg hochladen
-
-
-
-
- -
PDF, PNG, JPEG, TIFF, XML
+
Neuen Beleg hochladen
+
+ +
+ +
+
📄
+
Beleg hierher ziehen oder klicken
+
PDF · PNG · JPEG · TIFF · XML
+
- +
+
+
+ +
@@ -102,6 +222,7 @@ $vorschauHoehe = (int)($settings['beleg_vorschau_hoehe'] ?? 300); Typ Lieferant Brutto + Zuzuordnen (€) @@ -120,11 +241,19 @@ $vorschauHoehe = (int)($settings['beleg_vorschau_hoehe'] ?? 300); –' ?> - –' ?> + –' ?> - - Verknüpfen + +
+ + + +
@@ -168,12 +297,10 @@ $vorschauHoehe = (int)($settings['beleg_vorschau_hoehe'] ?? 300); const id = row.dataset.belegId; if (!id) return; - // Hervorhebung wechseln if (activeRow) activeRow.style.background = ''; activeRow = row; row.style.background = 'var(--color-primary-light, #eff6ff)'; - // Vorschau laden hint.style.display = 'none'; frame.style.display = 'block'; frame.src = '/belege/' + id + '/file'; @@ -181,3 +308,4 @@ $vorschauHoehe = (int)($settings['beleg_vorschau_hoehe'] ?? 300); }); })(); + diff --git a/src/Views/belege/detail.php b/src/Views/belege/detail.php index e96516b..68b7d87 100644 --- a/src/Views/belege/detail.php +++ b/src/Views/belege/detail.php @@ -298,23 +298,35 @@ $suppliers = $suppliers ?? []; - + @@ -375,8 +387,14 @@ $suppliers = $suppliers ?? [];
- - + + 0): ?> + +