* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. */ /** * \file bankimport/confirm.php * \ingroup bankimport * \brief Payment confirmation page - match bank transactions to invoices */ // Load Dolibarr environment $res = 0; if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) { $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; } $tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { $i--; $j--; } if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) { $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; } if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) { $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; } if (!$res && file_exists("../main.inc.php")) { $res = @include "../main.inc.php"; } if (!$res && file_exists("../../main.inc.php")) { $res = @include "../../main.inc.php"; } if (!$res) { die("Include of main fails"); } require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; dol_include_once('/bankimport/class/banktransaction.class.php'); dol_include_once('/bankimport/lib/bankimport.lib.php'); /** * @var Conf $conf * @var DoliDB $db * @var Translate $langs * @var User $user */ $langs->loadLangs(array("bankimport@bankimport", "banks", "bills")); $action = GETPOST('action', 'aZ09'); // Security check if (!$user->hasRight('bankimport', 'write')) { accessforbidden(); } $bankAccountId = getDolGlobalInt('BANKIMPORT_BANK_ACCOUNT_ID'); /* * Actions */ // Confirm single payment if ($action == 'confirmpayment' && !empty($bankAccountId)) { $transid = GETPOSTINT('transid'); $matchtype = GETPOST('matchtype', 'alpha'); $matchid = GETPOSTINT('matchid'); if ($transid > 0 && !empty($matchtype) && $matchid > 0) { $trans = new BankImportTransaction($db); if ($trans->fetch($transid) > 0) { if ($trans->status != BankImportTransaction::STATUS_NEW) { setEventMessages($langs->trans("TransactionAlreadyProcessed"), null, 'warnings'); } else { $result = $trans->confirmPayment($user, $matchtype, $matchid, $bankAccountId); if ($result > 0) { setEventMessages($langs->trans("PaymentCreatedSuccessfully", dol_escape_htmltag($trans->name), price(abs($trans->amount))), null, 'mesgs'); } else { setEventMessages($trans->error, $trans->errors, 'errors'); } } } } header("Location: ".$_SERVER["PHP_SELF"]."?token=".newToken()); exit; } // Confirm multiple invoices payment if ($action == 'confirmmulti' && !empty($bankAccountId)) { $transid = GETPOSTINT('transid'); $invoiceIds = GETPOST('invoices', 'array'); if ($transid > 0 && !empty($invoiceIds)) { $trans = new BankImportTransaction($db); if ($trans->fetch($transid) > 0) { if ($trans->status != BankImportTransaction::STATUS_NEW) { setEventMessages($langs->trans("TransactionAlreadyProcessed"), null, 'warnings'); } else { // Build invoices array with amounts require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php'; $invoices = array(); foreach ($invoiceIds as $invId) { $invId = (int) $invId; if ($invId > 0) { $invoice = new FactureFournisseur($db); if ($invoice->fetch($invId) > 0) { $alreadyPaid = $invoice->getSommePaiement(); $creditnotes = $invoice->getSumCreditNotesUsed(); $deposits = $invoice->getSumDepositsUsed(); $remainToPay = price2num($invoice->total_ttc - $alreadyPaid - $creditnotes - $deposits, 'MT'); if ($remainToPay > 0) { $invoices[] = array( 'type' => 'facture_fourn', 'id' => $invId, 'ref' => $invoice->ref, 'amount' => $remainToPay ); } } } } if (!empty($invoices)) { $result = $trans->confirmMultiplePayment($user, $invoices, $bankAccountId); if ($result > 0) { setEventMessages($langs->trans("PaymentCreatedSuccessfully", dol_escape_htmltag($trans->name), price(abs($trans->amount))).' ('.count($invoices).' '.$langs->trans("Invoices").')', null, 'mesgs'); } else { setEventMessages($trans->error, $trans->errors, 'errors'); } } else { setEventMessages($langs->trans("NoInvoicesSelected"), null, 'errors'); } } } } header("Location: ".$_SERVER["PHP_SELF"]."?token=".newToken()); exit; } // Confirm all high-score matches if ($action == 'confirmall' && !empty($bankAccountId)) { $transaction = new BankImportTransaction($db); $transactions = $transaction->fetchAll('date_trans', 'DESC', 0, 0, array('status' => BankImportTransaction::STATUS_NEW)); $created = 0; $failed = 0; if (is_array($transactions)) { foreach ($transactions as $trans) { $matches = $trans->findMatches(); if (!empty($matches) && $matches[0]['match_score'] >= 80) { $bestMatch = $matches[0]; // Handle multi-invoice matches if ($bestMatch['type'] == 'multi_facture_fourn' && !empty($bestMatch['invoices'])) { $invoices = array(); foreach ($bestMatch['invoices'] as $inv) { $invoices[] = array( 'type' => 'facture_fourn', 'id' => $inv['id'], 'ref' => $inv['ref'], 'amount' => $inv['amount'] ); } $result = $trans->confirmMultiplePayment($user, $invoices, $bankAccountId); } else { $result = $trans->confirmPayment($user, $bestMatch['type'], $bestMatch['id'], $bankAccountId); } if ($result > 0) { $created++; } else { $failed++; } } } } if ($created > 0 || $failed > 0) { setEventMessages($langs->trans("PaymentsCreatedSummary", $created, $failed), null, $failed > 0 ? 'warnings' : 'mesgs'); } else { setEventMessages($langs->trans("NoNewMatchesFound"), null, 'warnings'); } header("Location: ".$_SERVER["PHP_SELF"]."?token=".newToken()); exit; } // Ignore transaction if ($action == 'ignore') { $transid = GETPOSTINT('transid'); if ($transid > 0) { $trans = new BankImportTransaction($db); if ($trans->fetch($transid) > 0 && $trans->status == BankImportTransaction::STATUS_NEW) { $trans->setStatus(BankImportTransaction::STATUS_IGNORED, $user); setEventMessages($langs->trans("StatusUpdated"), null, 'mesgs'); } } header("Location: ".$_SERVER["PHP_SELF"]."?token=".newToken()); exit; } /* * View */ $form = new Form($db); $title = $langs->trans("PaymentConfirmation"); llxHeader('', $title, '', '', 0, 0, '', '', '', 'mod-bankimport page-confirm'); print load_fiche_titre($title, '', 'bank'); // Check if bank account is configured if (empty($bankAccountId)) { print '
| '.$langs->trans("Date").' | '; print ''.$langs->trans("Counterparty").' | '; print ''.$langs->trans("Amount").' ('.$langs->trans("Transaction").') | '; print ''; print ' | '.$langs->trans("Invoice").' | '; print ''.$langs->trans("ThirdParty").' | '; print ''.$langs->trans("Amount").' ('.$langs->trans("Invoice").') | '; print ''.$langs->trans("Score").' | '; print ''.$langs->trans("MatchReason").' | '; print ''.$langs->trans("Action").' | '; print '
|---|---|---|---|---|---|---|---|---|---|
| '.dol_print_date($trans->date_trans, 'day').' | '; // Counterparty name + description print '';
print ''.dol_escape_htmltag(dol_trunc($trans->name, 30)).'';
if ($trans->description) {
print ' '.dol_escape_htmltag(dol_trunc($trans->description, 50)).''; } print ' | ';
// Transaction amount
print ''; if ($trans->amount >= 0) { print '+'.price($trans->amount, 0, $langs, 1, -1, 2, $trans->currency).''; } else { print ''.price($trans->amount, 0, $langs, 1, -1, 2, $trans->currency).''; } print ' | '; // Arrow print '↔ | '; // Invoice reference(s) print '';
if ($isMultiInvoice && !empty($bestMatch['invoices'])) {
// Multi-invoice display
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
print ''.count($bestMatch['invoices']).' '.$langs->trans("Invoices").': '; foreach ($bestMatch['invoices'] as $invData) { $inv = new FactureFournisseur($db); $inv->fetch($invData['id']); print $inv->getNomUrl(1).' ('.price($invData['amount'], 0, $langs, 1, -1, 2, 'EUR').') '; } } elseif ($bestMatch['type'] == 'facture') { require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; $inv = new Facture($db); $inv->fetch($bestMatch['id']); print $inv->getNomUrl(1); } else { require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php'; $inv = new FactureFournisseur($db); $inv->fetch($bestMatch['id']); print $inv->getNomUrl(1); } print ' | ';
// Third party
print ''; if ($bestMatch['socid'] > 0) { require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php'; $soc = new Societe($db); $soc->fetch($bestMatch['socid']); print $soc->getNomUrl(1); } else { print dol_escape_htmltag($bestMatch['socname']); } print ' | '; // Invoice amount print '';
print price($bestMatch['amount'], 0, $langs, 1, -1, 2, 'EUR');
if ($isMultiInvoice && isset($bestMatch['difference']) && abs($bestMatch['difference']) > 0.01) {
$diffColor = $bestMatch['difference'] > 0 ? 'orange' : 'green';
print ' '.($bestMatch['difference'] > 0 ? '+' : '').price($bestMatch['difference'], 0, $langs, 1, -1, 2, 'EUR').''; } print ' | ';
// Score
print ''.$bestMatch['match_score'].'% | '; // Match reasons print ''; if (!empty($bestMatch['match_reasons'])) { foreach ($bestMatch['match_reasons'] as $reason) { $label = $reasonLabels[$reason] ?? $reason; print ''.$label.' '; } } print ' | '; // Actions print '';
if ($isMultiInvoice && !empty($bestMatch['invoices'])) {
// Multi-invoice: Form with checkboxes for selection
print '';
} else {
// Single invoice: Confirm payment button
print 'id.'&matchtype='.urlencode($bestMatch['type']).'&matchid='.$bestMatch['id'].'&token='.newToken().'">';
print $langs->trans("ConfirmPayment");
print '';
}
print ' '; // Ignore button print 'id.'&token='.newToken().'">'; print $langs->trans("SetAsIgnored"); print ''; // Show alternatives if multiple matches if (count($pm['matches']) > 1) { print ' '; print '+'.($count = count($pm['matches']) - 1).' '.$langs->trans("Alternatives"); print ''; } print ' | ';
print '