From dbcad6a88427c3879f0a8437444824c3cb19865d Mon Sep 17 00:00:00 2001 From: data Date: Thu, 5 Mar 2026 10:46:23 +0100 Subject: [PATCH] feat: Multi-Invoice Skonto-Erkennung und automatische Skonto-Verarbeitung MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Toleranz für Multi-Invoice-Matching auf 3% des Betrags erhöht (statt 5€ fix) - Automatische proportionale Verteilung der Zahlung bei Skonto-Abzug - Rechnungen werden mit close_code='discount_vat' als bezahlt markiert - Skonto-Betrag wird in der Notiz dokumentiert - Version 3.1 Co-Authored-By: Claude Opus 4.5 --- admin/cronmonitor.php | 0 class/banktransaction.class.php | 60 ++++++++++++++++++++++++++-- core/modules/modBankImport.class.php | 2 +- langs/de_DE/bankimport.lang | 5 +++ langs/en_US/bankimport.lang | 5 +++ 5 files changed, 68 insertions(+), 4 deletions(-) mode change 100644 => 100755 admin/cronmonitor.php diff --git a/admin/cronmonitor.php b/admin/cronmonitor.php old mode 100644 new mode 100755 diff --git a/class/banktransaction.class.php b/class/banktransaction.class.php index bfe2dde..d9f57c2 100755 --- a/class/banktransaction.class.php +++ b/class/banktransaction.class.php @@ -829,7 +829,9 @@ class BankImportTransaction extends CommonObject $socid = $this->findSupplierForMultiMatch($searchText); if ($socid > 0) { - $multiMatch = $this->findMultipleSupplierInvoiceMatches($searchText, $socid, $absAmount, 5.00); + // Tolerance: 3% of amount (for cash discounts/skonto) or minimum 5 EUR + $tolerance = max($absAmount * 0.03, 5.00); + $multiMatch = $this->findMultipleSupplierInvoiceMatches($searchText, $socid, $absAmount, $tolerance); if ($multiMatch && count($multiMatch['invoices']) > 1) { // Add as a special "multi" match @@ -1603,6 +1605,26 @@ class BankImportTransaction extends CommonObject return -2; } + // Check for cash discount (Skonto): If paid amount is less than invoice sum + $actualAmount = abs($this->amount); + $hasDiscount = false; + $discountAmount = 0; + $discountFactor = 1.0; + + if ($actualAmount < $totalPayment && $actualAmount > 0) { + $discountAmount = $totalPayment - $actualAmount; + // Only apply discount logic if within 5% (typical cash discount range) + if ($discountAmount <= ($totalPayment * 0.05)) { + $hasDiscount = true; + $discountFactor = $actualAmount / $totalPayment; + // Adjust amounts proportionally + foreach ($amounts as $invoiceId => $amount) { + $amounts[$invoiceId] = price2num($amount * $discountFactor, 'MT'); + $multicurrency_amounts[$invoiceId] = $amounts[$invoiceId]; + } + } + } + if ($isSupplier) { // Supplier invoice payment require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php'; @@ -1635,6 +1657,21 @@ class BankImportTransaction extends CommonObject ); if ($bankLineId > 0) { + // If we had a cash discount, close the invoices with discount code + if ($hasDiscount) { + foreach ($invoices as $inv) { + $invObj = new FactureFournisseur($this->db); + if ($invObj->fetch($inv['id']) > 0) { + // Check if invoice still has remaining amount + $remaining = $invObj->getRemainToPay(); + if ($remaining > 0 && $remaining <= $discountAmount) { + // Close with discount code + $invObj->setPaid($user, 'discount_vat', $langs->trans("CashDiscount").' ('.price($remaining).' '.$this->currency.')'); + } + } + } + } + $this->fk_paiementfourn = $paymentId; $this->fk_bank = $bankLineId; $this->fk_societe = $socid; @@ -1643,7 +1680,8 @@ class BankImportTransaction extends CommonObject $this->date_match = dol_now(); // Store first invoice as reference (or could store all in note) $this->fk_facture_fourn = $invoices[0]['id']; - $this->note_private = ($this->note_private ? $this->note_private."\n" : '').'Multi-invoice payment: '.implode(', ', array_column($invoices, 'ref')); + $discountNote = $hasDiscount ? ' (Skonto: '.price($discountAmount).' '.$this->currency.')' : ''; + $this->note_private = ($this->note_private ? $this->note_private."\n" : '').'Multi-invoice payment: '.implode(', ', array_column($invoices, 'ref')).$discountNote; $this->update($user); } else { $this->error = 'Failed to add payment to bank'; @@ -1682,6 +1720,21 @@ class BankImportTransaction extends CommonObject ); if ($bankLineId > 0) { + // If we had a cash discount, close the invoices with discount code + if ($hasDiscount) { + foreach ($invoices as $inv) { + $invObj = new Facture($this->db); + if ($invObj->fetch($inv['id']) > 0) { + // Check if invoice still has remaining amount + $remaining = $invObj->getRemainToPay(); + if ($remaining > 0 && $remaining <= $discountAmount) { + // Close with discount code + $invObj->setPaid($user, 'discount_vat', $langs->trans("CashDiscount").' ('.price($remaining).' '.$this->currency.')'); + } + } + } + } + $this->fk_paiement = $paymentId; $this->fk_bank = $bankLineId; $this->fk_societe = $socid; @@ -1689,7 +1742,8 @@ class BankImportTransaction extends CommonObject $this->fk_user_match = $user->id; $this->date_match = dol_now(); $this->fk_facture = $invoices[0]['id']; - $this->note_private = ($this->note_private ? $this->note_private."\n" : '').'Multi-invoice payment: '.implode(', ', array_column($invoices, 'ref')); + $discountNote = $hasDiscount ? ' (Skonto: '.price($discountAmount).' '.$this->currency.')' : ''; + $this->note_private = ($this->note_private ? $this->note_private."\n" : '').'Multi-invoice payment: '.implode(', ', array_column($invoices, 'ref')).$discountNote; $this->update($user); } else { $this->error = 'Failed to add payment to bank'; diff --git a/core/modules/modBankImport.class.php b/core/modules/modBankImport.class.php index a0da9e4..c2bd408 100755 --- a/core/modules/modBankImport.class.php +++ b/core/modules/modBankImport.class.php @@ -76,7 +76,7 @@ class modBankImport extends DolibarrModules $this->editor_squarred_logo = ''; // Must be image filename into the module/img directory followed with @modulename. Example: 'myimage.png@bankimport' // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z' - $this->version = '2.9'; + $this->version = '3.2'; // Url to the file with your last numberversion of this module //$this->url_last_version = 'http://www.example.com/versionmodule.txt'; diff --git a/langs/de_DE/bankimport.lang b/langs/de_DE/bankimport.lang index e0461bb..abe2fbf 100755 --- a/langs/de_DE/bankimport.lang +++ b/langs/de_DE/bankimport.lang @@ -370,3 +370,8 @@ Repair = Reparieren # AdminTools = Admin-Werkzeuge Open = Öffnen + +# +# Cash Discount / Skonto +# +CashDiscount = Skonto diff --git a/langs/en_US/bankimport.lang b/langs/en_US/bankimport.lang index 4b7613b..e4c5c3d 100755 --- a/langs/en_US/bankimport.lang +++ b/langs/en_US/bankimport.lang @@ -266,3 +266,8 @@ Repair = Repair # AdminTools = Admin Tools Open = Open + +# +# Cash Discount / Skonto +# +CashDiscount = Cash Discount