From d26bbfc37b5325bf844cc591c0a0de5d42e9e2f5 Mon Sep 17 00:00:00 2001 From: fds2610-bot Date: Fri, 15 May 2026 16:51:38 +0200 Subject: [PATCH 1/6] =?UTF-8?q?Fix:=20Bank-Import-Duplikate=20durch=20Tran?= =?UTF-8?q?saktion,=20UNIQUE-Constraint=20und=20Dateiname-Pr=C3=BCfung=20v?= =?UTF-8?q?erhindern?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changes.md | 15 ++++++++++++++ migrations/051_bank_transactions_unique.sql | 22 +++++++++++++++++++++ src/Controllers/BankController.php | 18 ++++++++++++++--- src/Models/BankTransaction.php | 9 +++++++++ src/version.txt | 2 +- 5 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 migrations/051_bank_transactions_unique.sql diff --git a/Changes.md b/Changes.md index 1f8259d..876561a 100644 --- a/Changes.md +++ b/Changes.md @@ -2,6 +2,21 @@ --- +## 2026-05-15 – Fix: Bank-Import-Duplikate verhindern + +- Migration 051: UNIQUE-Constraint `(buchungstag, wertstellung, wert, buchungstext(200))` auf `bank_transactions`; bestehende Duplikate wurden dabei bereinigt +- `BankController::upload()`: Import läuft jetzt in einer DB-Transaktion – bei Fehler wird alles zurückgerollt statt einen unvollständigen Batch zu hinterlassen +- `BankController::upload()`: Dateiname-Prüfung vor dem Import – erneuter Upload derselben Datei wird mit Fehlermeldung abgelehnt +- `BankTransaction::filenameExists()`: neue Hilfsmethode zur Duplikat-Prüfung anhand Dateiname + +--- + +## 2026-05-15 – Fix: Netto-Neuberechnung bei Kategorie-Wechsel in Bank-Buchungsmaske + +- IIFE-Wrapper für `updateAutoUst` in einen `DOMContentLoaded`-Listener verschoben, damit er erst nach der Funktionsdefinition (späteres ` From aa0dd01e6654706e26eddff1ae9667025430a23f Mon Sep 17 00:00:00 2001 From: fds2610-bot Date: Fri, 15 May 2026 17:05:05 +0200 Subject: [PATCH 4/6] =?UTF-8?q?Fix:=20Dateiname-Check=20entfernt=20?= =?UTF-8?q?=E2=80=93=20Dublettenpr=C3=BCfung=20=C3=BCbernimmt=20die=20Schu?= =?UTF-8?q?tzfunktion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Controllers/BankController.php | 6 +----- src/Models/BankTransaction.php | 9 --------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/Controllers/BankController.php b/src/Controllers/BankController.php index 3f847e2..c28325c 100644 --- a/src/Controllers/BankController.php +++ b/src/Controllers/BankController.php @@ -4,9 +4,9 @@ declare(strict_types=1); namespace Steuerkram\Controllers; -use Steuerkram\Database; use Steuerkram\Models\BankImportFormat; use Steuerkram\Models\BankTransaction; +use Steuerkram\Database; use Steuerkram\Models\Beleg; use Steuerkram\Services\BankImportParser; use Steuerkram\View; @@ -84,10 +84,6 @@ class BankController View::redirect('/bank/upload', 'Keine Buchungszeilen in der Datei gefunden.', 'error'); } - if (BankTransaction::filenameExists($origName)) { - View::redirect('/bank/upload', 'Diese Datei wurde bereits importiert (' . $origName . ').', 'error'); - } - $split = BankTransaction::findDuplicates($rows); if (!empty($split['dup'])) { diff --git a/src/Models/BankTransaction.php b/src/Models/BankTransaction.php index 1b6b3b1..d4d9364 100644 --- a/src/Models/BankTransaction.php +++ b/src/Models/BankTransaction.php @@ -145,15 +145,6 @@ class BankTransaction return ['new' => $new, 'dup' => $dup]; } - public static function filenameExists(string $filename): bool - { - $row = Database::fetchOne( - 'SELECT id FROM bank_import_batches WHERE filename = ? LIMIT 1', - [$filename] - ); - return $row !== null; - } - public static function createBatch(int $formatId, string $filename, int $rowCount): int { Database::execute( From d7cc7c266125a815035d85473638d3bcf372ba74 Mon Sep 17 00:00:00 2001 From: fds2610-bot Date: Fri, 15 May 2026 17:09:35 +0200 Subject: [PATCH 5/6] Feature: Gebuchte Bankbuchungen verlinken auf Beleg; Belegnummer in Statuszeile --- src/Models/BankTransaction.php | 4 +++- src/Views/bank/index.php | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Models/BankTransaction.php b/src/Models/BankTransaction.php index d4d9364..0d0493f 100644 --- a/src/Models/BankTransaction.php +++ b/src/Models/BankTransaction.php @@ -50,10 +50,12 @@ class BankTransaction )['n'] ?? 0); $rows = Database::fetchAll( - "SELECT bt.*, bib.filename AS batch_filename, bif.name AS format_name + "SELECT bt.*, bib.filename AS batch_filename, bif.name AS format_name, + b.id AS beleg_id, 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 WHERE $whereStr ORDER BY bt.wertstellung DESC, bt.id DESC LIMIT ? OFFSET ?", diff --git a/src/Views/bank/index.php b/src/Views/bank/index.php index 60c6785..ce152a2 100644 --- a/src/Views/bank/index.php +++ b/src/Views/bank/index.php @@ -82,8 +82,11 @@ $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']; ?> - +
@@ -103,6 +106,9 @@ $months = ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','D }; ?> + +
+ From ce7a64534bdca8c482af04f3cd5ebc183d3c766c Mon Sep 17 00:00:00 2001 From: fds2610-bot Date: Fri, 15 May 2026 17:12:02 +0200 Subject: [PATCH 6/6] Feature: Bankbuchungs-Badge in Beleganzeige unterhalb der Buchungszeilen --- src/Controllers/BelegController.php | 3 +++ src/Models/BankTransaction.php | 13 +++++++++++++ src/Views/belege/detail.php | 22 ++++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/src/Controllers/BelegController.php b/src/Controllers/BelegController.php index 35f6180..1ddd7d1 100644 --- a/src/Controllers/BelegController.php +++ b/src/Controllers/BelegController.php @@ -243,6 +243,8 @@ class BelegController } } + $linkedBankTx = BankTransaction::findByBelegId((int)$beleg['id']); + $view = new View(); $view->render('layout/base.php', [ 'pageTitle' => 'Beleg ' . $beleg['beleg_nr'], @@ -260,6 +262,7 @@ class BelegController 'bankTxSupplier' => $bankTxSupplier, 'bankTxBrutto' => $bankTxBrutto, 'formData' => $bankFormData, + 'linkedBankTx' => $linkedBankTx, ]), ]); } diff --git a/src/Models/BankTransaction.php b/src/Models/BankTransaction.php index 0d0493f..4fde63e 100644 --- a/src/Models/BankTransaction.php +++ b/src/Models/BankTransaction.php @@ -147,6 +147,19 @@ 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/Views/belege/detail.php b/src/Views/belege/detail.php index 454bc73..e96516b 100644 --- a/src/Views/belege/detail.php +++ b/src/Views/belege/detail.php @@ -295,6 +295,28 @@ $suppliers = $suppliers ?? []; + + + + +
+
+ Bankbuchung + + + + + + + = 0 ? '+' : '' ?> € + +
+
+
+ +