dolibarr 24.0.0-beta
bank.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2006-2016 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2012 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2015 Alexandre Spangaro <alexandre@inovea-conseil.com>
5 * Copyright (C) 2016 Juanjo Menent <jmenent@2byte.es>
6 * Copyright (C) 2019 Nicolas ZABOURI <info@inovea-conseil.com>
7 * Copyright (C) 2021 Ferran Marcet <fmarcet@2byte.es>
8 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
9 * Copyright (C) 2024-2026 Frédéric France <frederic.france@free.fr>
10 * Copyright (C) 2026 Solution Libre SAS <contact@solution-libre.fr>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <https://www.gnu.org/licenses/>.
24 * or see https://www.gnu.org/
25 */
26
41{
42 global $db, $langs, $conf, $user;
43
44 $h = 0;
45 $head = array();
46
47 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/compta/bank/card.php', ['id' => $object->id]);
48 $head[$h][1] = $langs->trans("BankAccount");
49 $head[$h][2] = 'bankname';
50 $h++;
51
52 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/compta/bank/bankentries_list.php', ['id' => $object->id]);
53 $head[$h][1] = $langs->trans("BankTransactions");
54 $head[$h][2] = 'journal';
55 $h++;
56
57 if ($object->canBeConciliated() > 0) {
58 $allowautomaticconciliation = getDolGlobalBool('MAIN_ALLOW_AUTOMATIC_CONCILIATION'); // TODO
59 $titletoconciliatemanual = $langs->trans("Conciliate");
60 $titletoconciliateauto = $langs->trans("Conciliate");
61 if ($allowautomaticconciliation) {
62 $titletoconciliatemanual .= ' ('.$langs->trans("Manual").')';
63 $titletoconciliateauto .= ' ('.$langs->trans("Auto").')';
64 }
65
66 $param = '';
67
68 // If not cash account and can be reconciliate
69 if ($user->hasRight('banque', 'consolidate')) {
70 $query = [
71 'id' => $object->id,
72 'action' => 'reconcile',
73 'sortfield' => 'b.datev,b.dateo,b.rowid',
74 'sortorder' => 'asc,asc,asc',
75 'search_conciliated' => 0,
76 'search_account' => $object->id,
77 ];
78 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/compta/bank/bankentries_list.php', $query).$param;
79 $head[$h][1] = $titletoconciliatemanual;
80 $head[$h][2] = 'reconcile';
81 $h++;
82 }/* else {
83 $buttonreconcile = '<a class="butActionRefused classfortooltip" title="'.$langs->trans("NotEnoughPermissions").'" href="#">'.$titletoconciliatemanual.'</a>';
84 }*/
85
86 if ($allowautomaticconciliation) {
87 // If not cash account and can be reconciliate
88 if ($user->hasRight('banque', 'consolidate')) {
89 $newparam = $param;
90 $newparam = preg_replace('/search_conciliated=\d+/i', '', $newparam);
91
92 $head[$h][0] = DOL_URL_ROOT."/compta/bank/bankentries_list.php?id=".$object->id.'&action=reconcile&sortfield=b.datev,b.dateo,b.rowid&sortorder=asc,asc,asc&search_conciliated=0&search_account='.$object->id.$newparam;
93 $head[$h][1] = $titletoconciliateauto;
94 $head[$h][2] = 'reconcileauto';
95 $h++;
96
97 //$buttonreconcile .= ' <a class="butAction" style="margin-bottom: 5px !important; margin-top: 5px !important" href="'.DOL_URL_ROOT.'/compta/bank/bankentries_list.php?action=reconcile&sortfield=b.datev,b.dateo,b.rowid&sortorder=asc,asc,asc&search_conciliated=0'.$newparam.'">'.$titletoconciliateauto.'</a>';
98 }/* else {
99 $buttonreconcile .= ' <a class="butActionRefused" style="margin-bottom: 5px !important; margin-top: 5px !important" title="'.$langs->trans("NotEnoughPermissions").'" href="#">'.$titletoconciliateauto.'</a>';
100 }*/
101 }
102 }
103
104 if ($object->type != Account::TYPE_CASH || getDolGlobalString('BANK_CAN_RECONCILIATE_CASHACCOUNT')) {
105 $nbReceipts = 0;
106
107 // List of all standing receipts
108 $sql = "SELECT COUNT(DISTINCT(b.num_releve)) as nb";
109 $sql .= " FROM ".MAIN_DB_PREFIX."bank as b";
110 $sql .= " WHERE b.fk_account = ".((int) $object->id);
111
112 $resql = $db->query($sql);
113 if ($resql) {
114 $obj = $db->fetch_object($resql);
115 if ($obj) {
116 $nbReceipts = $obj->nb;
117 }
118 $db->free($resql);
119 }
120
121 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/compta/bank/releve.php', ['account' => $object->id]);
122 $head[$h][1] = $langs->trans("AccountStatements");
123 if (($nbReceipts) > 0) {
124 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.($nbReceipts).'</span>';
125 }
126 $head[$h][2] = 'statement';
127 $h++;
128 }
129
130 // Attached files
131 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
132 require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
133 $upload_dir = $conf->bank->dir_output."/".dol_sanitizeFileName($object->ref);
134 $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$'));
135 $nbLinks = Link::count($db, $object->element, $object->id);
136 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/compta/bank/document.php', ['account' => $object->id]);
137 $head[$h][1] = $langs->trans("Documents");
138 if (($nbFiles + $nbLinks) > 0) {
139 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.($nbFiles + $nbLinks).'</span>';
140 }
141 $head[$h][2] = 'document';
142 $h++;
143
144 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/compta/bank/annuel.php', ['account' => $object->id]);
145 $head[$h][1] = $langs->trans("Reports");
146 $head[$h][2] = 'annual';
147 $h++;
148
149 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/compta/bank/treso.php', ['account' => $object->id]);
150 $head[$h][1] = $langs->trans("PlannedTransactions");
151 $head[$h][2] = 'cash';
152 $h++;
153
154 // Show more tabs from modules
155 // Entries must be declared in modules descriptor with line
156 // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab
157 // $this->tabs = array('entity:-tabname); to remove a tab
158 complete_head_from_modules($conf, $langs, $object, $head, $h, 'bank');
159
160 /*$head[$h][0] = DOL_URL_ROOT . "/compta/bank/info.php?id=" . $object->id;
161 $head[$h][1] = $langs->trans("Info");
162 $head[$h][2] = 'info';
163 $h++;*/
164
165 complete_head_from_modules($conf, $langs, $object, $head, $h, 'bank', 'remove');
166
167 return $head;
168}
169
177{
178 global $db, $langs, $conf, $user;
179
180 $h = 0;
181 $head = array();
182
183 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/compta/bank/annuel.php', ['account' => $object->id]);
184 $head[$h][1] = $langs->trans("IOMonthlyReporting");
185 $head[$h][2] = 'annual';
186 $h++;
187
188 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/compta/bank/graph.php', ['account' => $object->id]);
189 $head[$h][1] = $langs->trans("Graph");
190 $head[$h][2] = 'graph';
191 $h++;
192
193 return $head;
194}
202{
203 global $langs, $conf, $extrafields;
204
205 $langs->loadLangs(array("compta"));
206
207 $extrafields->fetch_name_optionals_label('bank_account');
208 $extrafields->fetch_name_optionals_label('bank');
209 $extrafields->fetch_name_optionals_label('paiement');
210 $extrafields->fetch_name_optionals_label('payment_various');
211
212 $h = 0;
213 $head = array();
214
215 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/admin/bank.php');
216 $head[$h][1] = $langs->trans("Miscellaneous");
217 $head[$h][2] = 'general';
218 $h++;
219
220 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/admin/chequereceipts.php');
221 $head[$h][1] = $langs->trans("CheckReceiptShort");
222 $head[$h][2] = 'checkreceipts';
223 $h++;
224
225
226 // Show more tabs from modules
227 // Entries must be declared in modules descriptor with line
228 // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab
229 // $this->tabs = array('entity:-tabname); to remove a tab
230 complete_head_from_modules($conf, $langs, $object, $head, $h, 'bank_admin');
231
232 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/admin/bank_extrafields.php');
233 $head[$h][1] = $langs->trans("ExtraFields").' ('.$langs->trans("BankAccounts").')';
234 $nbExtrafields = $extrafields->attributes['bank_account']['count'];
235 if ($nbExtrafields > 0) {
236 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbExtrafields.'</span>';
237 }
238 $head[$h][2] = 'attributes';
239 $h++;
240
241 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/admin/bankline_extrafields.php');
242 $head[$h][1] = $langs->trans("ExtraFields").' ('.$langs->trans("BankTransactions").')';
243 $nbExtrafields = $extrafields->attributes['bank']['count'];
244 if ($nbExtrafields > 0) {
245 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbExtrafields.'</span>';
246 }
247 $head[$h][2] = 'bankline_extrafields';
248 $h++;
249
250 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/admin/bank_payments_extrafields.php');
251 $head[$h][1] = $langs->trans("ExtraFields").' ('.$langs->trans("Payments").')';
252 $nbExtrafields = $extrafields->attributes['paiement']['count'];
253 if ($nbExtrafields > 0) {
254 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbExtrafields.'</span>';
255 }
256 $head[$h][2] = 'bank_payments_extrafields';
257 $h++;
258
259 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/admin/bank_various_payment_extrafields.php');
260 $head[$h][1] = $langs->trans("ExtraFields").' ('.$langs->trans("VariousPayments").')';
261 $nbExtrafields = $extrafields->attributes['payment_various']['count'];
262 if ($nbExtrafields > 0) {
263 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbExtrafields.'</span>';
264 }
265 $head[$h][2] = 'bank_various_payment_extrafields';
266 $h++;
267
268 complete_head_from_modules($conf, $langs, $object, $head, $h, 'bank_admin', 'remove');
269
270 return $head;
271}
272
273
282{
283 global $langs, $conf, $db;
284 $h = 0;
285 $head = array();
286
287 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/compta/bank/releve.php', ['account' => $object->id, 'num' => $num]);
288 $head[$h][1] = $langs->trans("AccountStatement");
289 $head[$h][2] = 'statement';
290 $h++;
291
292 // Attached files
293 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
294 require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
295 $upload_dir = $conf->bank->dir_output."/".$object->id.'/statement/'.dol_sanitizeFileName($num);
296 $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$'));
297 $nbLinks = Link::count($db, $object->element, $object->id);
298
299 $head[$h][0] = dolBuildUrl(DOL_URL_ROOT.'/compta/bank/account_statement_document.php', ['account' => $object->id, 'num' => $num]);
300 $head[$h][1] = $langs->trans("Documents");
301 if (($nbFiles + $nbLinks) > 0) {
302 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.($nbFiles + $nbLinks).'</span>';
303 }
304 $head[$h][2] = 'document';
305 $h++;
306
307 complete_head_from_modules($conf, $langs, $object, $head, $h, 'account_statement');
308
309 complete_head_from_modules($conf, $langs, $object, $head, $h, 'account_statement', 'remove');
310
311 return $head;
312}
313
314
322{
323 global $db, $langs, $conf;
324
325 $h = 0;
326 $head = array();
327
328 $head[$h][0] = DOL_URL_ROOT.'/compta/bank/various_payment/card.php?id='.$object->id;
329 $head[$h][1] = $langs->trans("VariousPayment");
330 $head[$h][2] = 'card';
331 $h++;
332
333 // Show more tabs from modules
334 // Entries must be declared in modules descriptor with line
335 // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab
336 // $this->tabs = array('entity:-tabname); to remove a tab
337 complete_head_from_modules($conf, $langs, $object, $head, $h, 'various_payment');
338
339 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
340 require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
341 $upload_dir = $conf->bank->dir_output."/".dol_sanitizeFileName($object->ref);
342 $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$'));
343 $nbLinks = Link::count($db, $object->element, $object->id);
344 $head[$h][0] = DOL_URL_ROOT.'/compta/bank/various_payment/document.php?id='.$object->id;
345 $head[$h][1] = $langs->trans('Documents');
346 if (($nbFiles + $nbLinks) > 0) {
347 $head[$h][1] .= '<span class="badge marginleftonlyshort">'.($nbFiles + $nbLinks).'</span>';
348 }
349 $head[$h][2] = 'documents';
350 $h++;
351
352 $head[$h][0] = DOL_URL_ROOT.'/compta/bank/various_payment/info.php?id='.$object->id;
353 $head[$h][1] = $langs->trans("Info");
354 $head[$h][2] = 'info';
355 $h++;
356
357 complete_head_from_modules($conf, $langs, $object, $head, $h, 'various_payment', 'remove');
358
359 return $head;
360}
361
369function checkSwiftForAccount($account = null, $swift = null)
370{
371 if ($account == null && $swift == null) {
372 return false;
373 } elseif ($swift == null) {
374 $swift = $account->bic;
375 }
376 if (preg_match("/^([a-zA-Z]){4}([a-zA-Z]){2}([0-9a-zA-Z]){2}([0-9a-zA-Z]{3})?$/", $swift)) {
377 return true;
378 } else {
379 return false;
380 }
381}
382
390function checkIbanForAccount($account = null, $ibantocheck = null)
391{
392 if ($account == null && $ibantocheck == null) {
393 return false;
394 } elseif ($ibantocheck == null) {
395 $ibantocheck = ($account->iban ? $account->iban : $account->iban_prefix); // iban or iban_prefix for backward compatibility
396 }
397 require_once DOL_DOCUMENT_ROOT.'/includes/php-iban/oophp-iban.php';
398
399 $iban = new PHP_IBAN\IBAN($ibantocheck);
400 $check = $iban->Verify();
401
402 if ($check) {
403 return true;
404 } else {
405 return false;
406 }
407}
408
416{
417 if ($account->getCountryCode() == 'FR') {
418 require_once DOL_DOCUMENT_ROOT.'/includes/php-iban/oophp-iban.php';
419 $ibantoprint = preg_replace('/[^a-zA-Z0-9]/', '', empty($account->iban) ? '' : $account->iban);
420 $iban = new PHP_IBAN\IBAN($ibantoprint);
421 return $iban->HumanFormat();
422 }
423
424 return $account->iban;
425}
426
433function checkBanForAccount($account)
434{
435 $country_code = $account->getCountryCode();
436
437 // For compatibility between
438 // account of type CompanyBankAccount class (we use number, cle_rib)
439 // account of type Account class (we use num_compte, cle)
440 if (empty($account->number)) {
441 $account->number = $account->num_compte; // @phan-suppress-current-line PhanUndeclaredProperty
442 }
443 if (empty($account->cle)) {
444 $account->cle = $account->cle_rib;
445 }
446
447 dol_syslog("bank.lib::checkBanForAccount account->code_banque=".$account->code_banque." account->code_guichet=".$account->code_guichet." account->number=".$account->number." account->cle=".$account->cle." account->iban=".$account->iban." country_code=".$country_code, LOG_DEBUG);
448
449 if ($country_code == 'FR') { // France rules
450 $coef = array(62, 34, 3);
451 // Concatenate the code parts
452 $rib = strtolower(trim($account->code_banque).trim($account->code_guichet).trim($account->number).trim($account->cle));
453 // Replace any letters with numbers.
454 //$rib = strtr($rib, "abcdefghijklmnopqrstuvwxyz","12345678912345678912345678"); // don't work
455 $rib = strtr($rib, "abcdefghijklmnopqrstuvwxyz", "12345678912345678923456789");
456 // Separation du rib en 3 groups de 7 + 1 group de 2.
457 // Multiplication of each group by the coefficients in the array.
458
459 $s = 0;
460 for ($i = 0; $i < 3; $i++) {
461 $code = substr($rib, 7 * $i, 7);
462 $s += ((int) $code) * $coef[$i];
463 }
464 // Soustraction du modulo 97 de $s a 97 pour obtenir la cle
465 $cle_rib = 97 - ($s % 97);
466 if ($cle_rib == $account->cle) {
467 return true;
468 }
469 return false;
470 }
471
472 /*
473 if ($country_code == 'BE') { // Belgian rules
474 }
475 */
476
477 if ($country_code == 'ES') { // Spanish rules
478 $CCC = strtolower(trim($account->number));
479 $rib = strtolower(trim($account->code_banque).trim($account->code_guichet));
480 $cle_rib = strtolower(checkES($rib, $CCC));
481 if ($cle_rib == strtolower($account->cle)) {
482 return true;
483 }
484 return false;
485 }
486 if ($country_code == 'AU') { // Australian
487 if (strlen($account->code_banque) > 7) {
488 return false; // Should be 6 but can be 123-456
489 } elseif (strlen($account->code_banque) < 6) {
490 return false; // Should be 6
491 } else {
492 return true;
493 }
494 }
495
496 // No particular rule
497 // If account is CompanyBankAccount class, we use number
498 // If account is Account class, we use num_compte
499 if (empty($account->number)) {
500 return false;
501 }
502
503 return true;
504}
505
506
507
515function checkES($IentOfi, $InumCta)
516{
517 if (empty($IentOfi) || empty($InumCta) || strlen($IentOfi) != 8 || strlen($InumCta) != 10) {
518 $keycontrol = "";
519 return $keycontrol;
520 }
521
522 $ccc = $IentOfi.$InumCta;
523 $numbers = "1234567890";
524
525 $i = 0;
526
527 while ($i <= strlen($ccc) - 1) {
528 if (strpos($numbers, substr($ccc, $i, 1)) === false) {
529 $keycontrol = "";
530 return $keycontrol;
531 }
532 $i++;
533 }
534
535 $values = array(1, 2, 4, 8, 5, 10, 9, 7, 3, 6);
536 $sum = 0;
537
538 for ($i = 2; $i < 10; $i++) {
539 $sum += $values[$i] * (int) substr($IentOfi, $i - 2, 1);
540 }
541
542 $key = 11 - $sum % 11;
543
544 if ($key == 10) {
545 $key = 1;
546 }
547 if ($key == 11) {
548 $key = 0;
549 }
550
551 $keycontrol = $key;
552
553 $sum = 0;
554
555 for ($i = 0; $i < 11; $i++) {
556 $sum += $values[$i] * (int) substr($InumCta, $i, 1); //int to cast result of substr to a number
557 }
558
559 $key = 11 - $sum % 11;
560
561 if ($key == 10) {
562 $key = 1;
563 }
564 if ($key == 11) {
565 $key = 0;
566 }
567
568 $keycontrol .= $key;
569 return $keycontrol;
570}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
checkIbanForAccount($account=null, $ibantocheck=null)
Check IBAN number information for a bank account.
Definition bank.lib.php:390
checkES($IentOfi, $InumCta)
Returns the key for Spanish Banks Accounts.
Definition bank.lib.php:515
bank_report_prepare_head(Account $object)
Prepare array with list of tabs for bank report.
Definition bank.lib.php:176
account_statement_prepare_head($object, $num)
Prepare array with list of tabs.
Definition bank.lib.php:281
checkBanForAccount($account)
Check account number information for a bank account.
Definition bank.lib.php:433
getIbanHumanReadable(Account $account)
Returns the iban human readable.
Definition bank.lib.php:415
bank_prepare_head(Account $object)
Prepare array with list of tabs.
Definition bank.lib.php:40
various_payment_prepare_head($object)
Prepare array with list of tabs.
Definition bank.lib.php:321
checkSwiftForAccount($account=null, $swift=null)
Check SWIFT information for a bank account.
Definition bank.lib.php:369
bank_admin_prepare_head($object)
Prepare array with list of tabs.
Definition bank.lib.php:201
Class to manage bank accounts.
const TYPE_CASH
Cash account.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
dol_dir_list($utf8_path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:64
dolBuildUrl($url, $params=[], $addtoken=false, $anchor='')
Return path of url.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
getDolGlobalBool($key, $default=false)
Return a Dolibarr global constant boolean value.
complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode='add', $filterorigmodule='')
Complete or removed entries into a head array (used to build tabs).
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.