From 5bde9c7b56af375eaaa5eefc04fbb178f8b9a75d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 6 Feb 2026 20:22:21 +0100 Subject: [PATCH] Add tab on sepa direct debit --- htdocs/compta/prelevement/requests.php | 611 +++++++++++++++++++++++++ htdocs/core/lib/prelevement.lib.php | 8 +- 2 files changed, 618 insertions(+), 1 deletion(-) create mode 100644 htdocs/compta/prelevement/requests.php diff --git a/htdocs/compta/prelevement/requests.php b/htdocs/compta/prelevement/requests.php new file mode 100644 index 00000000000..a77505ac422 --- /dev/null +++ b/htdocs/compta/prelevement/requests.php @@ -0,0 +1,611 @@ + + * Copyright (C) 2005-2010 Laurent Destailleur + * Copyright (C) 2010-2016 Juanjo Menent + * Copyright (C) 2018-2024 Frédéric France + * Copyright (C) 2024-2025 MDW + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/compta/prelevement/requests.php + * \ingroup requests + * \brief Page with details of payment requests per invoice + */ + +// Load Dolibarr environment +require '../../main.inc.php'; +/** + * @var Conf $conf + * @var DoliDB $db + * @var HookManager $hookmanager + * @var Translate $langs + * @var User $user + */ +require_once DOL_DOCUMENT_ROOT.'/core/lib/prelevement.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/compta/prelevement/class/ligneprelevement.class.php'; +require_once DOL_DOCUMENT_ROOT.'/compta/prelevement/class/bonprelevement.class.php'; +require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array('banks', 'categories', 'bills', 'companies', 'withdrawals')); + +// Get supervariables +$action = GETPOST('action', 'aZ09'); + +$id = GETPOSTINT('id'); +$ref = GETPOST('ref', 'alpha'); +$socid = GETPOSTINT('socid'); +$type = GETPOST('type', 'aZ09'); +$date_trans = dol_mktime(GETPOSTINT('date_transhour'), GETPOSTINT('date_transmin'), GETPOSTINT('date_transsec'), GETPOSTINT('date_transmonth'), GETPOSTINT('date_transday'), GETPOSTINT('date_transyear')); + +// Load variable for pagination +$limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit; +$sortfield = GETPOST('sortfield', 'aZ09comma'); +$sortorder = GETPOST('sortorder', 'aZ09comma'); +$page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page"); +if (empty($page) || $page == -1) { + $page = 0; +} // If $page is not defined, or '' or -1 +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; + +if (!$sortfield) { + $sortfield = 'pd.rowid'; +} +if (!$sortorder) { + $sortorder = 'ASC'; +} + +$object = new BonPrelevement($db); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be 'include', not 'include_once'. Include fetch and fetch_thirdparty but not fetch_optionals + +$hookmanager->initHooks(array('directdebitprevcard', 'globalcard', 'directdebitprevlist')); + +$type = $object->type; + +// Check if salary or invoice +$salaryBonPl = $object->checkIfSalaryBonPrelevement(); + +// Security check +if ($type == 'bank-transfer') { + $result = restrictedArea($user, 'paymentbybanktransfer', '', '', ''); + + $permissiontoadd = $user->hasRight('paymentbybanktransfer', 'create'); + $permissiontosend = $user->hasRight('paymentbybanktransfer', 'send'); + $permissiontocreditdebit = $user->hasRight('paymentbybanktransfer', 'debit'); + $permissiontodelete = $user->hasRight('paymentbybanktransfer', 'read'); +} else { + $result = restrictedArea($user, 'prelevement', '', '', 'bons'); + + $permissiontoadd = $user->hasRight('prelevement', 'bons', 'creer'); + $permissiontosend = $user->hasRight('prelevement', 'bons', 'send'); + $permissiontocreditdebit = $user->hasRight('prelevement', 'bons', 'credit'); + $permissiontodelete = $user->hasRight('prelevement', 'bons', 'read'); +} + + +/* + * Actions + */ + +$parameters = array('socid' => $socid); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + if ($action == 'setbankaccount' && $permissiontoadd) { + $object->oldcopy = dol_clone($object, 2); // @phan-suppress-current-line PhanTypeMismatchProperty + $object->fk_bank_account = GETPOSTINT('fk_bank_account'); + + $object->update($user); + } + + // date of upload + if ($action == 'setdate_trans' && $permissiontosend) { + $result = $object->setValueFrom('date_trans', $date_trans, '', null, 'date'); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + } + } + + if ($action == 'infotrans' && $permissiontosend) { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $dt = dol_mktime(12, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear')); + + /* + if ($_FILES['userfile']['name'] && basename($_FILES['userfile']['name'],".ps") == $object->ref) + { + $dir = $conf->prelevement->dir_output.'/receipts'; + + if (dol_move_uploaded_file($_FILES['userfile']['tmp_name'], $dir . "/" . dol_unescapefile($_FILES['userfile']['name']),1) > 0) + { + $object->set_infotrans($user, $dt, GETPOST('methode','alpha')); + } + + header("Location: card.php?id=".$id); + exit; + } + else + { + dol_syslog("File invalid",LOG_WARNING); + $mesg='BadFile'; + }*/ + + $error = $object->set_infotrans($user, $dt, GETPOSTINT('methode')); + + if ($error) { + header("Location: card.php?id=".$id."&error=$error"); + exit; + } + } + + // Set direct debit order to credited, create payment and close invoices + if ($action == 'setinfocredit' && $permissiontocreditdebit) { + $dt = dol_mktime(12, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear')); + + if (($object->type != 'bank-transfer' && $object->statut == BonPrelevement::STATUS_CREDITED) || ($object->type == 'bank-transfer' && $object->statut == BonPrelevement::STATUS_DEBITED)) { + $error = 1; + setEventMessages('WithdrawalCantBeCreditedTwice', array(), 'errors'); + } else { + $error = $object->set_infocredit($user, $dt, ($salaryBonPl ? 'salary' : '')); + } + + if ($error) { + setEventMessages($object->error, $object->errors, 'errors'); + } + } + + if ($action == 'reopen' && $permissiontocreditdebit) { + $savtype = $object->type; + $res = $object->setStatut(BonPrelevement::STATUS_TRANSFERED); + if ($res <= 0) { + setEventMessages($object->error, $object->errors, 'errors'); + } + } + + if ($action == 'confirm_delete' && $permissiontodelete) { + $savtype = $object->type; + $res = $object->delete($user); + if ($res > 0) { + if ($savtype == 'bank-transfer') { + header("Location: ".DOL_URL_ROOT.'/compta/paymentbybanktransfer/index.php'); + } else { + header("Location: ".DOL_URL_ROOT.'/compta/prelevement/index.php'); + } + exit; + } + } +} + + +/* + * View + */ + +$form = new Form($db); + +llxHeader('', $langs->trans("WithdrawalsReceipts")); + +if ($id > 0 || $ref) { + $head = prelevement_prepare_head($object); + + print dol_get_fiche_head($head, 'requests', $langs->trans("WithdrawalsReceipts"), -1, 'payment'); + + if (GETPOST('error', 'alpha') != '') { + print '
'.$object->getErrorString(GETPOST('error', 'alpha')).'
'; + } + + $linkback = ''.$langs->trans("BackToList").''; + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref'); + + print '
'; + print '
'; + print ''; + + // Date for payment + print ''; + + print ''; + + // Upload file + if (!empty($object->date_trans)) { + $muser = new User($db); + $muser->fetch($object->user_trans); + + // Date upload + print ''; + } + print ''; + print ''; + + // Method upload + print ''; + } + + // Date real payment + if (!empty($object->date_credit)) { + print ''; + } + + print '
'.$langs->trans("Date").''.dol_print_date($object->datec, 'day').'
'.$langs->trans("Amount").''.price($object->amount).'
'; + print ''; + if ($action != 'editdate_trans' && $permissiontosend) { + print ''; + } + print '
'; + print $langs->trans('TransData'); + print 'id.'">'.img_edit($langs->trans('SetTransDate'), 1).'
'; + print '
'; + if ($action == 'editdate_trans' && $permissiontosend) { + print '
'; + print ''; + print ''; + print $form->selectDate($object->date_trans ? $object->date_trans : -1, 'date_trans', 0, 0, 0, "setdate_trans"); + print ''; + print '
'; + } else { + print $object->date_trans ? dol_print_date($object->date_trans, 'day') : ''; + print '   '.$langs->trans("By").' '.$muser->getNomUrl(-1).'
'.$langs->trans("TransMetod").''; + print $object->methodes_trans[$object->method_trans]; + print '
'.$langs->trans('CreditDate').''; + print dol_print_date($object->date_credit, 'day'); + print '
'; + + print '
'; + + print '
'; + print ''; + + // Get bank account for the payment + $acc = new Account($db); + $fk_bank_account = $object->fk_bank_account; + if (empty($fk_bank_account)) { + $fk_bank_account = ($object->type == 'bank-transfer' ? getDolGlobalInt('PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT') : getDolGlobalInt('PRELEVEMENT_ID_BANKACCOUNT')); + } + if ($fk_bank_account > 0) { + $result = $acc->fetch($fk_bank_account); + } + + // Bank account + $labelofbankfield = "BankToReceiveWithdraw"; + if ($object->type == 'bank-transfer') { + $labelofbankfield = 'BankToPayCreditTransfer'; + } + //print $langs->trans($labelofbankfield); + $caneditbank = $permissiontoadd; + if ($object->status != $object::STATUS_DRAFT) { + $caneditbank = 0; + } + /* + print ''; + print ''; + print ''; + */ + print '"; + print ''; + + // Download file + print ''; + + // Other attributes + $parameters = array(); + $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + + print '
'; + print $form->editfieldkey($langs->trans($labelofbankfield), 'fk_bank_account', $acc->id, $object, $caneditbank); + print ''; + print $form->editfieldval($langs->trans($labelofbankfield), 'fk_bank_account', $acc->id, $acc, $caneditbank, 'string', '', null, null, '', 1, 'getNomUrl'); + print '
'; + print ''; + } + print '
'; + print $form->textwithpicto($langs->trans("BankAccount"), $langs->trans($labelofbankfield)); + print ''; + if (($action != 'editbankaccount') && $caneditbank) { + print 'id.'">'.img_edit($langs->trans('SetBankAccount'), 1).'
'; + print '
'; + if ($action == 'editfkbankaccount') { + $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $fk_bank_account, 'fk_bank_account', 0); + } else { + $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $fk_bank_account, 'none'); + } + print "
'; + $labelfororderfield = 'WithdrawalFile'; + if ($object->type == 'bank-transfer') { + $labelfororderfield = 'CreditTransferFile'; + } + print $langs->trans($labelfororderfield).''; + + $modulepart = 'prelevement'; + if ($object->type == 'bank-transfer') { + $modulepart = 'paymentbybanktransfer'; + } + + if (isModEnabled('multicompany')) { + $labelentity = $conf->entity; + $relativepath = 'receipts/'.$object->ref.'-'.$labelentity.'.xml'; + + if ($type != 'bank-transfer') { + $dir = $conf->prelevement->dir_output; + } else { + $dir = $conf->paymentbybanktransfer->dir_output; + } + if (!dol_is_file($dir.'/'.$relativepath)) { // For backward compatibility + $relativepath = 'receipts/'.$object->ref.'.xml'; + } + } else { + $relativepath = 'receipts/'.$object->ref.'.xml'; + } + + print ''.$relativepath; + print img_picto('', 'download', 'class="paddingleft"'); + print ''; + print '
'; + + print '
'; + + print dol_get_fiche_end(); + + + $formconfirm = ''; + + // Confirmation to delete + if ($action == 'delete') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Delete'), $langs->trans('ConfirmDeleteObject'), 'confirm_delete', '', 0, 1); + } + + // Call Hook formConfirm + /*$parameters = array('formConfirm' => $formconfirm); + $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook)) $formconfirm.=$hookmanager->resPrint; + elseif ($reshook > 0) $formconfirm=$hookmanager->resPrint;*/ + + // Print form confirm + print $formconfirm; + + + if (empty($object->date_trans) && (($user->hasRight('prelevement', 'bons', 'send') && $object->type != 'bank-transfer') || ($user->hasRight('paymentbybanktransfer', 'send') && $object->type == 'bank-transfer')) && $action == 'settransmitted') { + print '
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print '
'.$langs->trans("NotifyTransmision").'
'.$langs->trans("TransData").''; + print $form->selectDate('', '', 0, 0, 0, "userfile", 1, 1); + print '
'.$langs->trans("TransMetod").''; + print $form->selectarray("methode", $object->methodes_trans); + print '
'; + print '
'; + print '
'; + print '
'; + } + + if ($object->status == BonPrelevement::STATUS_TRANSFERED && (($user->hasRight('prelevement', 'bons', 'credit') && $object->type != 'bank-transfer') || ($user->hasRight('paymentbybanktransfer', 'debit') && $object->type == 'bank-transfer')) && $action == 'setcredited') { + $btnLabel = ($object->type == 'bank-transfer') ? $langs->trans("ClassDebited") : $langs->trans("ClassCredited"); + print '
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print '
'.$langs->trans("NotifyCredit").'
'.$langs->trans('CreditDate').''; + print $form->selectDate(-1, '', 0, 0, 0, "infocredit", 1, 1, 0, '', '', array(array('adddateof' => $object->date_trans, 'labeladddateof' => $langs->transnoentitiesnoconv('TransData')))); + print '
'; + print '
'.$langs->trans("ThisWillAlsoAddPaymentOnInvoice").'
'; + print '
'; + print '
'; + print '
'; + } + + // Actions + if ($action != 'settransmitted' && $action != 'setcredited') { + print "\n".'
'."\n"; + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook)) { + if (empty($object->date_trans)) { + if ($object->type == 'bank-transfer') { + print dolGetButtonAction($langs->trans("SetToStatusSent"), '', 'default', 'card.php?action=settransmitted&token='.newToken().'&id='.$object->id, '', $user->hasRight('paymentbybanktransfer', 'send')); + } else { + print dolGetButtonAction($langs->trans("SetToStatusSent"), '', 'default', 'card.php?action=settransmitted&token='.newToken().'&id='.$object->id, '', $user->hasRight('prelevement', 'bons', 'send')); + } + } + + if ($object->status == BonPrelevement::STATUS_TRANSFERED) { + if ($object->type == 'bank-transfer') { + print dolGetButtonAction($langs->trans("ClassDebited"), '', 'default', 'card.php?action=setcredited&token='.newToken().'&id='.$object->id, '', $user->hasRight('paymentbybanktransfer', 'debit')); + } else { + print dolGetButtonAction($langs->trans("ClassCredited"), '', 'default', 'card.php?action=setcredited&token='.newToken().'&id='.$object->id, '', $user->hasRight('prelevement', 'bons', 'credit')); + } + } + + if (getDolGlobalString('BANK_CAN_REOPEN_DIRECT_DEBIT_OR_CREDIT_TRANSFER')) { + if ($object->status == BonPrelevement::STATUS_DEBITED || $object->status == BonPrelevement::STATUS_CREDITED) { + if ($object->type == 'bank-transfer') { + print dolGetButtonAction($langs->trans("ReOpen"), '', 'default', 'card.php?action=reopen&token='.newToken().'&id='.$object->id, '', $user->hasRight('paymentbybanktransfer', 'debit')); + } else { + print dolGetButtonAction($langs->trans("ReOpen"), '', 'default', 'card.php?action=reopen&token='.newToken().'&id='.$object->id, '', $user->hasRight('prelevement', 'bons', 'credit')); + } + } + } + + if ($object->type == 'bank-transfer') { + print dolGetButtonAction($langs->trans("Delete"), '', 'delete', 'card.php?action=delete&token='.newToken().'&id='.$object->id, '', $user->hasRight('paymentbybanktransfer', 'create')); + } else { + print dolGetButtonAction($langs->trans("Delete"), '', 'delete', 'card.php?action=delete&token='.newToken().'&id='.$object->id, '', $user->hasRight('prelevement', 'bons', 'creer')); + } + } + print '
'; + } + + + $ligne = new LignePrelevement($db); + + // Lines into withdraw request + $sql = "SELECT pd.rowid, pd.type, pd.ext_payment_id, pd.ext_payment_site, pd.amount, pd.fk_user_demande, pd.traite, pd.date_demande,"; + $sql .= " s.rowid as socid, s.nom as name"; + $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_demande as pd"; + $sql .= ", ".MAIN_DB_PREFIX."prelevement_bons as pb"; + $sql .= ", ".MAIN_DB_PREFIX."facture as f"; + $sql .= ", ".MAIN_DB_PREFIX."societe as s"; + $sql .= " WHERE pd.fk_prelevement_bons = ".((int) $id); + $sql .= " AND pd.fk_prelevement_bons = pb.rowid"; + $sql .= " AND pb.entity = ".((int) $conf->entity); // No sharing of entity here + $sql .= " AND pd.fk_facture = f.rowid AND f.fk_soc = s.rowid"; + if ($socid) { + $sql .= " AND s.rowid = ".((int) $socid); + } + $sql .= $db->order($sortfield, $sortorder); + + // Count total nb of records + $nbtotalofrecords = ''; + if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) { + $result = $db->query($sql); + $nbtotalofrecords = $db->num_rows($result); + if (($page * $limit) > (int) $nbtotalofrecords) { + // if total resultset is smaller then paging size (filtering), goto and load page 0 + $page = 0; + $offset = 0; + } + } + + $sql .= $db->plimit($limit + 1, $offset); + + $result = $db->query($sql); + + if ($result) { + $num = $db->num_rows($result); + $i = 0; + + $urladd = "&id=".urlencode((string) ($id)); + if ($limit > 0 && $limit != $conf->liste_limit) { + $urladd .= '&limit='.((int) $limit); + } + + print '
'."\n"; + print ''; + print ''; + print ''; + if (!empty($page)) { + print ''; + } + if (!empty($limit)) { + print ''; + } + if (!empty($sortfield)) { + print ''; + } + if (!empty($sortorder)) { + print ''; + } + // @phan-suppress-next-line PhanPluginSuspiciousParamOrder + print_barre_liste($langs->trans("Requests"), $page, $_SERVER["PHP_SELF"], $urladd, $sortfield, $sortorder, '', $num, $nbtotalofrecords, '', 0, '', '', $limit); + + print '
'; // You can use div-table-responsive-no-min if you don't need reserved height for your table + print ''; + print ''; + print_liste_field_titre("ID", $_SERVER["PHP_SELF"], "pd.rowid", '', $urladd, '', $sortfield, $sortorder); + print_liste_field_titre("Date", $_SERVER["PHP_SELF"], "pd.date_demande", '', $urladd, '', $sortfield, $sortorder); + print_liste_field_titre("User", $_SERVER["PHP_SELF"], "pd.fk_user_demande", "", $urladd, '', $sortfield, $sortorder); + print_liste_field_titre("Amount", $_SERVER["PHP_SELF"], "pd.amount", "", $urladd, 'class="right"', $sortfield, $sortorder); + print_liste_field_titre("Invoice", $_SERVER["PHP_SELF"], "pd.fk_facture", '', $urladd, '', $sortfield, $sortorder); + print_liste_field_titre(''); + print "\n"; + + $total = 0; + + while ($i < min($num, $limit)) { + $obj = $db->fetch_object($result); + + print ''; + + // Status of line + print "'; + + print '\n"; + + print ''; + + print '\n"; + + print ''; + + print ''; + + print ''; + + $total += $obj->amount; + + $i++; + } + + if ($num > 0) { + $total = price2num($total, 'MT'); + + print ''; + print ''; + print ''; + print ''; + print '\n"; + print ''; + print ''; + print "\n"; + } + + print "
"; + print $obj->rowid; + print ''; + print dol_print_date($obj->date_demande, 'dayhour', 'tzuserrel'); + print "'; + print $obj->fk_user_demande; + print ''.price($obj->amount)."'; + print $obj->fk_facture; + print ''; + print $obj->ext_payment_id; + print '
'.$langs->trans("Total").'  '; + if (empty($offset) && $num <= $limit) { + // If we have all record on same page, then the following test/warning can be done + if ($total != $object->amount) { + print img_warning($langs->trans("TotalAmountOfdirectDebitOrderDiffersFromSumOfLines")); + } + } + print price($total); + print "  
"; + print '
'; + print '
'; + + $db->free($result); + } else { + dol_print_error($db); + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/core/lib/prelevement.lib.php b/htdocs/core/lib/prelevement.lib.php index 67e7dbf68d2..a683fdddb57 100644 --- a/htdocs/core/lib/prelevement.lib.php +++ b/htdocs/core/lib/prelevement.lib.php @@ -48,12 +48,18 @@ function prelevement_prepare_head(BonPrelevement $object) if ($object->type == 'bank-transfer') { $titleoftab = "BankTransferReceipts"; } - $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/compta/prelevement/card.php', ['id' => $object->id]); $head[$h][1] = $langs->trans($titleoftab); $head[$h][2] = 'prelevement'; $h++; + if (getDolGlobalString('PRELEVEMENT_SEPA_SHOW_REQUESTS') && $object->type != 'bank-transfer' && $object->type != 'salary') { + $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/compta/prelevement/requests.php', ['id' => $object->id]); + $head[$h][1] = $langs->trans('Requests'); + $head[$h][2] = 'requests'; + $h++; + } + $titleoftab = $langs->trans("Bills"); if ($object->type == 'bank-transfer') { $titleoftab = $langs->trans("SupplierBills");