Fix: Bank-Import-Duplikate durch Transaktion, UNIQUE-Constraint und Dateiname-Prüfung verhindern
This commit is contained in:
parent
d27911b707
commit
d26bbfc37b
5 changed files with 62 additions and 4 deletions
15
Changes.md
15
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 `<script>`-Tag) gesetzt wird und nicht sofort von ihr überschrieben wird.
|
||||
|
||||
---
|
||||
|
||||
## 2026-05-14 – Feature: Bank buchen
|
||||
|
||||
- Navigation: neuer Eintrag „Bank buchen" unter Belege & Buchungen
|
||||
|
|
|
|||
22
migrations/051_bank_transactions_unique.sql
Normal file
22
migrations/051_bank_transactions_unique.sql
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
-- Duplikate entfernen: pro Gruppe (buchungstag, wertstellung, wert, buchungstext) die niedrigste id behalten
|
||||
DELETE bt
|
||||
FROM bank_transactions bt
|
||||
INNER JOIN (
|
||||
SELECT MIN(id) AS keep_id, buchungstag, wertstellung, wert, buchungstext
|
||||
FROM bank_transactions
|
||||
GROUP BY buchungstag, wertstellung, wert, buchungstext
|
||||
HAVING COUNT(*) > 1
|
||||
) dup ON bt.buchungstag = dup.buchungstag
|
||||
AND bt.wertstellung = dup.wertstellung
|
||||
AND bt.wert = dup.wert
|
||||
AND bt.buchungstext = dup.buchungstext
|
||||
AND bt.id > dup.keep_id;
|
||||
|
||||
-- Unvollständige Batches entfernen (row_count stimmt nicht mit tatsächlichen Zeilen überein)
|
||||
DELETE FROM bank_import_batches
|
||||
WHERE id NOT IN (SELECT DISTINCT batch_id FROM bank_transactions)
|
||||
AND row_count > 0;
|
||||
|
||||
-- UNIQUE-Constraint gegen Doppel-Importe
|
||||
ALTER TABLE bank_transactions
|
||||
ADD CONSTRAINT uq_bank_tx UNIQUE (buchungstag, wertstellung, wert, buchungstext(200));
|
||||
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Steuerkram\Controllers;
|
||||
|
||||
use Steuerkram\Database;
|
||||
use Steuerkram\Models\BankImportFormat;
|
||||
use Steuerkram\Models\BankTransaction;
|
||||
use Steuerkram\Models\Beleg;
|
||||
|
|
@ -83,10 +84,21 @@ 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');
|
||||
}
|
||||
|
||||
Database::beginTransaction();
|
||||
try {
|
||||
$batchId = BankTransaction::createBatch($formatId, $origName, count($rows));
|
||||
foreach ($rows as $row) {
|
||||
BankTransaction::insertRow($batchId, $row);
|
||||
}
|
||||
Database::commit();
|
||||
} catch (\Throwable $e) {
|
||||
Database::rollBack();
|
||||
View::redirect('/bank/upload', 'Import fehlgeschlagen: ' . $e->getMessage(), 'error');
|
||||
}
|
||||
|
||||
View::redirect('/bank', count($rows) . ' Buchungen importiert.');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,15 @@ class BankTransaction
|
|||
);
|
||||
}
|
||||
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
1-260514
|
||||
1-260515
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue