feat: Multi-Invoice Skonto-Erkennung und automatische Skonto-Verarbeitung
- 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 <noreply@anthropic.com>
This commit is contained in:
parent
6e4b5b0de2
commit
dbcad6a884
5 changed files with 68 additions and 4 deletions
0
admin/cronmonitor.php
Normal file → Executable file
0
admin/cronmonitor.php
Normal file → Executable file
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -370,3 +370,8 @@ Repair = Reparieren
|
|||
#
|
||||
AdminTools = Admin-Werkzeuge
|
||||
Open = Öffnen
|
||||
|
||||
#
|
||||
# Cash Discount / Skonto
|
||||
#
|
||||
CashDiscount = Skonto
|
||||
|
|
|
|||
|
|
@ -266,3 +266,8 @@ Repair = Repair
|
|||
#
|
||||
AdminTools = Admin Tools
|
||||
Open = Open
|
||||
|
||||
#
|
||||
# Cash Discount / Skonto
|
||||
#
|
||||
CashDiscount = Cash Discount
|
||||
|
|
|
|||
Loading…
Reference in a new issue