dolibarr 24.0.2
bonprelevement.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2004-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
5 * Copyright (C) 2010-2014 Laurent Destailleur <eldy@users.sourceforge.net>
6 * Copyright (C) 2014-2016 Ferran Marcet <fmarcet@2byte.es>
7 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
8 * Copyright (C) 2019 JC Prieto <jcprieto@virtual20.com><prietojc@gmail.com>
9 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
10 * Copyright (C) 2024-2026 Frédéric France <frederic.france@free.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 */
25
32require_once DOL_DOCUMENT_ROOT . '/core/class/commonobject.class.php';
33require_once DOL_DOCUMENT_ROOT . '/core/lib/bank.lib.php';
34require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
35require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
36require_once DOL_DOCUMENT_ROOT . '/compta/paiement/class/paiement.class.php';
37require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture.class.php';
38require_once DOL_DOCUMENT_ROOT . '/fourn/class/paiementfourn.class.php';
39require_once DOL_DOCUMENT_ROOT . '/salaries/class/salary.class.php';
40require_once DOL_DOCUMENT_ROOT . '/salaries/class/paymentsalary.class.php';
41require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
42require_once DOL_DOCUMENT_ROOT . '/user/class/userbankaccount.class.php';
43
44
49{
53 public $element = 'widthdraw';
54
58 public $table_element = 'prelevement_bons';
59
63 public $picto = 'payment';
64
68 public $date_echeance;
72 public $raison_sociale;
76 public $reference_remise;
80 public $emetteur_code_guichet;
84 public $emetteur_numero_compte;
88 public $emetteur_code_banque;
92 public $emetteur_number_key;
96 public $sepa_xml_pti_in_ctti;
97
101 public $emetteur_iban;
105 public $emetteur_bic;
109 public $emetteur_ics;
110
114 public $user_trans;
118 public $user_credit;
119
123 public $total;
124
128 public $fetched;
129
130 public $labelStatus = array();
131
135 public $factures = array();
136
140 public $methodes_trans = array();
141
145 public $invoice_in_error = array();
146
150 public $thirdparty_in_error = array();
151
155 public $file;
156
160 public $filename;
161
162 const STATUS_DRAFT = 0;
163 const STATUS_TRANSFERED = 1;
164 const STATUS_CREDITED = 2; // STATUS_CREDITED and STATUS_DEBITED is same. Difference is in ->type
165 const STATUS_DEBITED = 2; // STATUS_CREDITED and STATUS_DEBITED is same. Difference is in ->type
166 const STATUS_CANCELED = 9;
167
168
208 // BEGIN MODULEBUILDER PROPERTIES
212 public $fields = array(
213 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'position' => 10, 'notnull' => 1, 'visible' => 0,),
214 'ref' => array('type' => 'varchar(12)', 'label' => 'Ref', 'enabled' => 1, 'position' => 15, 'notnull' => 0, 'visible' => -1, 'csslist' => 'tdoverflowmax150', 'showoncombobox' => 1,),
215 'datec' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'position' => 25, 'notnull' => 0, 'visible' => -1,),
216 'amount' => array('type' => 'double(24,8)', 'label' => 'Amount', 'enabled' => 1, 'position' => 30, 'notnull' => 0, 'visible' => -1,),
217 'statut' => array('type' => 'smallint(6)', 'label' => 'Statut', 'enabled' => 1, 'position' => 500, 'notnull' => 0, 'visible' => -1, 'arrayofkeyval' => array(0 => 'Wait', 1 => 'Transfered', 2 => 'Credited')),
218 'credite' => array('type' => 'smallint(6)', 'label' => 'Credite', 'enabled' => 1, 'position' => 40, 'notnull' => 0, 'visible' => -1,),
219 'note' => array('type' => 'text', 'label' => 'Note', 'enabled' => 1, 'position' => 45, 'notnull' => 0, 'visible' => -1,),
220 'date_trans' => array('type' => 'datetime', 'label' => 'TransData', 'enabled' => 1, 'position' => 50, 'notnull' => 0, 'visible' => -1,),
221 'method_trans' => array('type' => 'smallint(6)', 'label' => 'Methodtrans', 'enabled' => 1, 'position' => 55, 'notnull' => 0, 'visible' => -1,),
222 'fk_user_trans' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'Fkusertrans', 'enabled' => 1, 'position' => 60, 'notnull' => 0, 'visible' => -1, 'css' => 'maxwidth500 widthcentpercentminusxx', 'csslist' => 'tdoverflowmax150',),
223 'date_credit' => array('type' => 'datetime', 'label' => 'CreditDate', 'enabled' => 1, 'position' => 65, 'notnull' => 0, 'visible' => -1,),
224 'fk_user_credit' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'Fkusercredit', 'enabled' => 1, 'position' => 70, 'notnull' => 0, 'visible' => -1, 'css' => 'maxwidth500 widthcentpercentminusxx', 'csslist' => 'tdoverflowmax150',),
225 'type' => array('type' => 'varchar(16)', 'label' => 'Type', 'enabled' => 1, 'position' => 75, 'notnull' => 0, 'visible' => -1,),
226 'fk_bank_account' => array('type' => 'integer', 'label' => 'Fkbankaccount', 'enabled' => 1, 'position' => 80, 'notnull' => 0, 'visible' => -1, 'css' => 'maxwidth500 widthcentpercentminusxx',),
227 );
231 public $rowid;
235 public $ref;
239 public $datec;
240
244 public $amount;
245
250 public $statut;
254 public $status;
255
259 public $credite;
260
265 public $note;
266
270 public $note_private;
271
275 public $date_trans;
279 public $method_trans;
283 public $fk_user_trans;
287 public $date_credit;
291 public $fk_user_credit;
295 public $type;
299 public $fk_bank_account;
300 // END MODULEBUILDER PROPERTIES
301
302
303
309 public function __construct($db)
310 {
311 $this->db = $db;
312
313 $this->filename = '';
314
315 $this->date_echeance = dol_now();
316 $this->raison_sociale = "";
317 $this->reference_remise = "";
318
319 $this->emetteur_code_guichet = "";
320 $this->emetteur_numero_compte = "";
321 $this->emetteur_code_banque = "";
322 $this->emetteur_number_key = "";
323 $this->sepa_xml_pti_in_ctti = false;
324
325 $this->emetteur_iban = "";
326 $this->emetteur_bic = "";
327 $this->emetteur_ics = "";
328
329 $this->factures = array();
330
331 $this->methodes_trans = array(0 => 'Internet', 2 => 'Email', 3 => 'Api');
332
333 $this->fetched = 0;
334 }
335
336 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
356 public function addWithdrawDetail($invoice_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key, $type = 'debit-order', $sourcetype = '', $bic = '', $iban = '', $rum = '', $id_prelevement_demande = 0)
357 {
358 // phpcs:enable
359 $result = 0;
360 $line_id = 0;
361
362 // TODO Save the $id_prelevement_demande
363
364 // Add lines into prelevement_lignes for tracking. The ID of line inserted is returned into $line_id.
365 $result = $this->addline($line_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key, $sourcetype, $bic, $iban, $rum, $id_prelevement_demande);
366
367
368 if ($result == 0) {
369 if ($line_id > 0) {
370 $sql = "INSERT INTO " . MAIN_DB_PREFIX . "prelevement (";
371 if ($type != 'bank-transfer') {
372 $sql .= "fk_facture";
373 } else {
374 if ($sourcetype == 'salary') {
375 $sql .= "fk_salary";
376 } else {
377 $sql .= "fk_facture_fourn";
378 }
379 }
380 $sql .= ",fk_prelevement_lignes";
381 $sql .= ") VALUES (";
382 $sql .= ((int) $invoice_id);
383 $sql .= ", " . ((int) $line_id);
384 $sql .= ")";
385
386 if ($this->db->query($sql)) {
387 $result = 0;
388 } else {
389 $result = -1;
390 $this->errors[] = get_class($this) . "::addWithdrawDetail " . $this->db->lasterror;
391 dol_syslog(get_class($this) . "::addWithdrawDetail Error $result");
392 }
393 } else {
394 $result = -2;
395 $this->errors[] = get_class($this) . "::addWithdrawDetail linedid Empty";
396 dol_syslog(get_class($this) . "::addWithdrawDetail Error $result");
397 }
398 } else {
399 $result = -3;
400 dol_syslog(get_class($this) . "::addWithdrawDetail Error $result");
401 }
402
403 return $result;
404 }
405
424 public function addline(&$line_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key, $sourcetype = '', $bic = '', $iban = '', $rum = '', $id_prelevement_demande = 0)
425 {
426 $result = -1;
427 $concat = getDolGlobalInt('MAIN_MODULE_PRELEVEMENT_CONCAT'); // ??? what is this for. Seems not used.
428
429 if ($concat == 1) {
434 $sql = "SELECT rowid";
435 $sql .= " FROM " . MAIN_DB_PREFIX . "prelevement_lignes";
436 $sql .= " WHERE fk_prelevement_bons = " . ((int) $this->id);
437 if ($sourcetype == 'salary') {
438 $sql .= " AND fk_soc = " . ((int) $client_id);
439 } else {
440 $sql .= " AND fk_user = " . ((int) $client_id);
441 }
442 $sql .= " AND code_banque = '" . $this->db->escape($code_banque) . "'";
443 $sql .= " AND code_guichet = '" . $this->db->escape($code_guichet) . "'";
444 $sql .= " AND number = '" . $this->db->escape($number) . "'";
445
446 $resql = $this->db->query($sql);
447 if ($resql) {
448 $num = $this->db->num_rows($resql);
449 } else {
450 $result = -1;
451 }
452 } else {
453 /*
454 * No aggregate, use 1 line per request of invoice/salary to pay
455 */
456 $sql = "INSERT INTO " . MAIN_DB_PREFIX . "prelevement_lignes (";
457 $sql .= "fk_prelevement_bons";
458 $sql .= ", fk_soc";
459 $sql .= ", client_nom";
460 $sql .= ", amount";
461 $sql .= ", fk_prelevement_demande";
462 $sql .= ($sourcetype == 'salary' ? ", fk_user" : "");
463 $sql .= ") VALUES (";
464 $sql .= ((int) $this->id);
465 $sql .= ", " . (($sourcetype != 'salary') ? ((int) $client_id) : "0"); // fk_soc can't be null
466 $sql .= ", '" . $this->db->escape($client_nom) . "'";
467 $sql .= ", " . ((float) price2num($amount));
468 $sql .= ", " . ((int) $id_prelevement_demande);
469 $sql .= (($sourcetype == 'salary') ? ", " . ((int) $client_id) : '');
470 $sql .= ")";
471 if ($this->db->query($sql)) {
472 $line_id = $this->db->last_insert_id(MAIN_DB_PREFIX . "prelevement_lignes");
473 $result = 0;
474 } else {
475 $this->errors[] = get_class($this) . "::addline Error -2 " . $this->db->lasterror;
476 dol_syslog(get_class($this) . "::addline Error -2");
477 $result = -2;
478 }
479 }
480
481 return $result;
482 }
483
490 public function getErrorString($error)
491 {
492 global $langs;
493
494 $errors = array();
495
496 $errors[1027] = $langs->trans("DateInvalid");
497
498 return $errors[abs($error)] ?? 'unknown error code';
499 }
500
508 public function fetch($rowid, $ref = '')
509 {
510 $sql = "SELECT p.rowid, p.ref, p.amount, p.note";
511 $sql .= ", p.datec as dc";
512 $sql .= ", p.date_trans as date_trans";
513 $sql .= ", p.method_trans, p.fk_user_trans";
514 $sql .= ", p.date_credit as date_credit";
515 $sql .= ", p.fk_user_credit";
516 $sql .= ", p.type";
517 $sql .= ", p.fk_bank_account";
518 $sql .= ", p.statut as status";
519 $sql .= " FROM " . MAIN_DB_PREFIX . "prelevement_bons as p";
520 $sql .= " WHERE p.entity IN (" . getEntity('invoice') . ")";
521 if ($rowid > 0) {
522 $sql .= " AND p.rowid = " . ((int) $rowid);
523 } else {
524 $sql .= " AND p.ref = '" . $this->db->escape($ref) . "'";
525 }
526
527 dol_syslog(get_class($this) . "::fetch", LOG_DEBUG);
528 $result = $this->db->query($sql);
529 if ($result) {
530 if ($this->db->num_rows($result)) {
531 $obj = $this->db->fetch_object($result);
532
533 $this->id = $obj->rowid;
534 $this->ref = $obj->ref;
535 $this->amount = $obj->amount;
536 $this->note = $obj->note;
537 $this->note_private = $obj->note;
538 $this->datec = $this->db->jdate($obj->dc);
539
540 $this->date_trans = $this->db->jdate($obj->date_trans);
541 $this->method_trans = $obj->method_trans;
542 $this->user_trans = $obj->fk_user_trans;
543
544 $this->date_credit = $this->db->jdate($obj->date_credit);
545 $this->user_credit = $obj->fk_user_credit;
546
547 $this->type = $obj->type;
548 $this->fk_bank_account = $obj->fk_bank_account;
549
550 $this->status = $obj->status;
551 if (empty($this->status)) { // Value is sometimes null in database
552 $this->status = 0;
553 }
554 $this->statut = $this->status; // For backward compatibility
555
556 $this->fetched = 1;
557
558 return 1;
559 } else {
560 dol_syslog(get_class($this) . "::Fetch no record found");
561 return 0;
562 }
563 } else {
564 return -1;
565 }
566 }
567
575 public function update(User $user, $notrigger = 0)
576 {
577 return $this->updateCommon($user, $notrigger);
578 }
579
580 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
590 public function set_infocredit($user, $date, $type = '')
591 {
592 // phpcs:enable
593 global $conf, $langs;
594
595 $error = 0;
596
597 if ($this->fetched == 1) {
598 if ($date < $this->date_trans) {
599 $langs->load("errors");
600 $this->error = $langs->trans('ErrorDateOfMovementLowerThanDateOfFileTransmission');
601 dol_syslog("bon-prelevment::set_infocredit 1027 " . $this->error);
602 return -1027;
603 }
604
605 $this->db->begin();
606
607 $sql = " UPDATE " . MAIN_DB_PREFIX . "prelevement_bons";
608 $sql .= " SET fk_user_credit = " . ((int) $user->id);
609 $sql .= ", statut = " . self::STATUS_CREDITED;
610 $sql .= ", date_credit = '" . $this->db->idate($date) . "'";
611 $sql .= " WHERE rowid = " . ((int) $this->id);
612 $sql .= " AND entity = " . ((int) $conf->entity);
613 $sql .= " AND statut = " . self::STATUS_TRANSFERED;
614
615 $resql = $this->db->query($sql);
616 if ($resql) {
617 $langs->load('withdrawals');
618 $subject = $langs->trans("InfoCreditSubject", $this->ref);
619 $message = $langs->trans("InfoCreditMessage", $this->ref, dol_print_date($date, 'dayhour'));
620
621 // Add payment of withdrawal into bank
622 $fk_bank_account = $this->fk_bank_account;
623 if (empty($fk_bank_account)) {
624 $fk_bank_account = ($this->type == 'bank-transfer' ? getDolGlobalInt('PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT') : getDolGlobalInt('PRELEVEMENT_ID_BANKACCOUNT'));
625 }
626
627 $amounts = array();
628 $amountsperthirdparty = array();
629
630 $facs = $this->getListInvoices(1, $type);
631 if ($this->error) {
632 $error++;
633 }
634
635 // Loop on each invoice or salary.
636 // $facs should be array(0=>id, 1=>amount requested)
637 $num = count($facs);
638 for ($i = 0; $i < $num; $i++) {
639 if ($this->type == 'bank-transfer') {
640 if ($type == 'salary') {
641 $fac = new Salary($this->db);
642 } else {
643 $fac = new FactureFournisseur($this->db);
644 }
645 } else {
646 $fac = new Facture($this->db);
647 }
648
649 $result = $fac->fetch($facs[$i][0]);
650
651 $amounts[$fac->id] = $facs[$i][1];
652 if ($this->type == 'bank-transfer') {
653 if ($type == 'salary') {
654 $amountsperthirdparty[$fac->fk_user][$fac->id] = $facs[$i][1];
655 } else {
656 $amountsperthirdparty[$fac->socid][$fac->id] = $facs[$i][1];
657 }
658 } else {
659 $amountsperthirdparty[$fac->socid][$fac->id] = $facs[$i][1];
660 }
661
662 $totalpaid = $fac->getSommePaiement();
663 $totalcreditnotes = 0;
664 if (method_exists($fac, 'getSumCreditNotesUsed')) {
665 $totalcreditnotes = $fac->getSumCreditNotesUsed();
666 }
667 $totaldeposits = 0;
668 if (method_exists($fac, 'getSumDepositsUsed')) {
669 $totaldeposits = $fac->getSumDepositsUsed();
670 }
671 $alreadypayed = $totalpaid + $totalcreditnotes + $totaldeposits;
672
673 // Set the main document to pay with status Paid.
674 // @TODO Move this after creation of payments done after
675 $amountofdocument = $fac->total_ttc;
676 if ($type == 'salary') {
677 $amountofdocument = $fac->amount;
678 }
679 if (price2num($alreadypayed + $facs[$i][1], 'MT') == price2num($amountofdocument, 'MT')) {
680 $result = $fac->setPaid($user);
681 if ($result < 0) {
682 $this->error = $fac->error;
683 $this->errors = $fac->errors;
684 }
685 }
686 }
687
688 // Make one payment per customer or employee
689 foreach ($amountsperthirdparty as $thirdpartyid => $cursoramounts) {
690 if ($this->type == 'bank-transfer') {
691 if ($type == 'salary') {
692 $paiement = new PaymentSalary($this->db);
693 } else {
694 $paiement = new PaiementFourn($this->db);
695 }
696 } else {
697 $paiement = new Paiement($this->db);
698 }
699 $paiement->datepaye = $date;
700 $paiement->amounts = $cursoramounts; // Array with detail of dispatching of payments for each invoice
701
702 if ($this->type == 'bank-transfer') {
703 if ($type == 'salary') {
704 $paiement->datep = $date;
705
706 $paiement->paiementid = 2;
707 $paiement->fk_typepayment = 2;
708 $paiement->paiementcode = 'VIR';
709 } else {
710 $paiement->paiementid = 2;
711 $paiement->paiementcode = 'VIR';
712 }
713 } else {
714 $paiement->paiementid = 3;
715 $paiement->paiementcode = 'PRE';
716 }
717
718 $paiement->num_payment = $this->ref; // Set ref of direct debit note
719 $paiement->id_prelevement = $this->id;
720
721 $result = $paiement->create($user, 1); // This use ->paiementid, that is ID of payment mode. closepaidinvoices=1 to convert deposit invoice to available credit
722
723 if ($result < 0) {
724 $error++;
725 $this->error = $paiement->error;
726 $this->errors = $paiement->errors;
727 dol_syslog(get_class($this) . "::set_infocredit AddPayment Error " . $this->error);
728 } else {
729 if ($this->type == 'bank-transfer') {
730 if ($type == 'salary') {
731 $modeforaddpayment = 'payment_salary';
732 $labelforaddpayment = '(SalaryPayment)';
733 $addbankurl = 'credit-transfer';
734 } else {
735 $modeforaddpayment = 'payment_supplier';
736 $labelforaddpayment = '(SupplierInvoicePayment)';
737 $addbankurl = 'credit-transfer';
738 }
739 } else {
740 $modeforaddpayment = 'payment';
741 $labelforaddpayment = '(CustomerInvoicePayment)';
742 $addbankurl = 'direct-debit'; // = 'directdebit'
743 }
744
745
746 if ($paiement instanceof PaymentSalary) {
747 // Only 6 arguments for PaymentSalary
748 $result = $paiement->addPaymentToBank($user, $modeforaddpayment, $labelforaddpayment, $fk_bank_account, '', '');
749 } else {
750 $result = $paiement->addPaymentToBank($user, $modeforaddpayment, $labelforaddpayment, $fk_bank_account, '', '', 0, '', $addbankurl);
751 }
752
753 if ($result < 0) {
754 $error++;
755 $this->error = $paiement->error;
756 $this->errors = $paiement->errors;
757 dol_syslog(get_class($this) . "::set_infocredit AddPaymentToBank Error " . $this->error);
758 }
759 }
760 }
761
762 // Update withdrawal line
763 // TODO: Translate to ligneprelevement.class.php
764 if (!$error) {
765 $sql = " UPDATE " . MAIN_DB_PREFIX . "prelevement_lignes";
766 $sql .= " SET statut = 2";
767 $sql .= " WHERE fk_prelevement_bons = " . ((int) $this->id);
768
769 if (!$this->db->query($sql)) {
770 dol_syslog(get_class($this) . "::set_infocredit Update lines Error");
771 $error++;
772 }
773 }
774 } else {
775 $this->error = $this->db->lasterror();
776 dol_syslog(get_class($this) . "::set_infocredit Update Bons Error");
777 $error++;
778 }
779
780 // End of procedure
781 if ($error == 0) {
782 $this->date_credit = $date; // date credit or debit
783 $this->statut = self::STATUS_CREDITED;
784 $this->status = self::STATUS_CREDITED;
785
786 $this->db->commit();
787 return 0;
788 } else {
789 $this->db->rollback();
790 return -1;
791 }
792 } else {
793 return -1026;
794 }
795 }
796
797 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
806 public function set_infotrans($user, $date, $method)
807 {
808 // phpcs:enable
809 global $conf, $langs;
810
811 $error = 0;
812
813 dol_syslog(get_class($this) . "::set_infotrans Start", LOG_INFO);
814
815 if ($this->db->begin()) {
816 $sql = "UPDATE " . MAIN_DB_PREFIX . "prelevement_bons ";
817 $sql .= " SET fk_user_trans = " . ((int) $user->id);
818 $sql .= " , date_trans = '" . $this->db->idate($date) . "'";
819 $sql .= " , method_trans = " . ((int) $method);
820 $sql .= " , statut = " . self::STATUS_TRANSFERED;
821 $sql .= " WHERE rowid = " . ((int) $this->id);
822 $sql .= " AND entity = " . ((int) $conf->entity);
823 $sql .= " AND statut = " . self::STATUS_DRAFT;
824
825 if ($this->db->query($sql)) {
826 $this->method_trans = $method;
827 $langs->load('withdrawals');
828 $subject = $langs->trans("InfoTransSubject", $this->ref);
829 $message = $langs->trans("InfoTransMessage", $this->ref, dolGetFirstLastname($user->firstname, $user->lastname));
830 $message .= $langs->trans("InfoTransData", price($this->amount), $this->methodes_trans[$this->method_trans], dol_print_date($date, 'day'));
831
832 // TODO Call trigger to create a notification using notification module
833 } else {
834 $error++;
835 }
836
837 if ($error == 0) {
838 $this->date_trans = $date;
839 $this->statut = self::STATUS_TRANSFERED;
840 $this->status = self::STATUS_TRANSFERED;
841 $this->user_trans = $user->id;
842
843 $this->db->commit();
844
845 return 0;
846 } else {
847 $this->db->rollback();
848 dol_syslog(get_class($this) . "::set_infotrans ROLLBACK", LOG_ERR);
849
850 return -1;
851 }
852 } else {
853 dol_syslog(get_class($this) . "::set_infotrans Ouverture transaction SQL impossible", LOG_CRIT);
854 return -2;
855 }
856 }
857
866 private function getListInvoices($amounts = 0, $type = '')
867 {
868 global $conf;
869
870 $arr = array();
871
872 dol_syslog(get_class($this) . "::getListInvoices");
873
874 // Returns all invoices presented within same order
875 $sql = "SELECT ";
876 if ($this->type == 'bank-transfer') {
877 if ($type == 'salary') {
878 $sql .= " p.fk_salary";
879 } else {
880 $sql .= " p.fk_facture_fourn";
881 }
882 } else {
883 $sql .= " p.fk_facture";
884 }
885 if ($amounts) {
886 $sql .= ", SUM(pl.amount)";
887 }
888 $sql .= " FROM " . MAIN_DB_PREFIX . "prelevement_bons as pb,";
889 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
890 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p";
891 $sql .= " WHERE p.fk_prelevement_lignes = pl.rowid";
892 $sql .= " AND pl.fk_prelevement_bons = pb.rowid";
893 $sql .= " AND pb.rowid = " . ((int) $this->id);
894 $sql .= " AND pb.entity = " . ((int) $conf->entity);
895 if ($amounts) {
896 if ($this->type == 'bank-transfer') {
897 if ($type == 'salary') {
898 $sql .= " GROUP BY p.fk_salary";
899 } else {
900 $sql .= " GROUP BY p.fk_facture_fourn";
901 }
902 } else {
903 $sql .= " GROUP BY p.fk_facture";
904 }
905 }
906
907 $resql = $this->db->query($sql);
908 if ($resql) {
909 $num = $this->db->num_rows($resql);
910
911 if ($num) {
912 $i = 0;
913 while ($i < $num) {
914 $row = $this->db->fetch_row($resql);
915 if (!$amounts) {
916 $arr[$i] = $row[0];
917 } else {
918 $arr[$i] = array(
919 $row[0],
920 $row[1]
921 );
922 }
923 $i++;
924 }
925 }
926 $this->db->free($resql);
927 } else {
928 $this->error = $this->db->lasterror();
929 }
930
931 return $arr;
932 }
933
934 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
942 public function SommeAPrelever($mode = 'direct-debit', $type = '')
943 {
944 // phpcs:enable
945 $sql = "SELECT sum(pd.amount) as nb";
946 if ($type !== 'salary') {
947 if ($mode != 'bank-transfer') {
948 $sql .= " FROM " . MAIN_DB_PREFIX . "facture as f,";
949 } else {
950 $sql .= " FROM " . MAIN_DB_PREFIX . "facture_fourn as f,";
951 }
952 } else {
953 $sql .= " FROM " . MAIN_DB_PREFIX . "salary as s,";
954 }
955 $sql .= " " . MAIN_DB_PREFIX . "prelevement_demande as pd";
956 $sql .= ($type !== 'salary' ? " WHERE f.entity IN (" . getEntity('invoice') . ")" : " WHERE s.entity IN (" . getEntity('salary') . ")");
957 if (!getDolGlobalString('WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS')) {
958 $sql .= ($type !== 'salary' ? " AND f.fk_statut = " . Facture::STATUS_VALIDATED : " AND s.paye = " . Salary::STATUS_UNPAID);
959 }
960 if ($type !== 'salary') {
961 if ($mode != 'bank-transfer') {
962 $sql .= " AND f.rowid = pd.fk_facture";
963 } else {
964 $sql .= " AND f.rowid = pd.fk_facture_fourn";
965 }
966 } else {
967 $sql .= " AND s.rowid = pd.fk_salary";
968 }
969 $sql .= ($type !== 'salary' ? " AND f.paye = 0" : "");
970 $sql .= " AND pd.traite = 0";
971 $sql .= " AND pd.ext_payment_id IS NULL";
972 $sql .= ($type !== 'salary' ? " AND f.total_ttc > 0" : "");
973
974 $resql = $this->db->query($sql);
975 if ($resql) {
976 $obj = $this->db->fetch_object($resql);
977
978 $this->db->free($resql);
979
980 return $obj->nb;
981 } else {
982 $error = 1;
983 dol_syslog(get_class($this) . "::SommeAPrelever Erreur -1");
984 dol_syslog($this->db->error());
985
986 return -1;
987 }
988 }
989
997 public function nbOfInvoiceToPay($mode = 'direct-debit', $type = '')
998 {
999 if ($type === 'salary') {
1000 return $this->NbFactureAPrelever($mode, 1);
1001 } else {
1002 return $this->NbFactureAPrelever($mode);
1003 }
1004 }
1005
1006 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1014 public function NbFactureAPrelever($type = 'direct-debit', $forsalary = 0)
1015 {
1016 // phpcs:enable
1017 if ($forsalary == 1) {
1018 $sql = "SELECT count(s.rowid) as nb";
1019 $sql .= " FROM " . MAIN_DB_PREFIX . "salary as s";
1020 } else {
1021 $sql = "SELECT count(f.rowid) as nb";
1022
1023 if ($type == 'bank-transfer') {
1024 $sql .= " FROM " . MAIN_DB_PREFIX . "facture_fourn as f";
1025 } else {
1026 $sql .= " FROM " . MAIN_DB_PREFIX . "facture as f";
1027 }
1028 }
1029 $sql .= ", " . MAIN_DB_PREFIX . "prelevement_demande as pd";
1030 if ($forsalary == 1) {
1031 $sql .= " WHERE s.entity IN (" . getEntity('invoice') . ")";
1032 if (!getDolGlobalString('WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS')) {
1033 $sql .= " AND s.paye = 0";
1034 }
1035 } else {
1036 $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
1037 if (!getDolGlobalString('WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS')) {
1038 $sql .= " AND f.fk_statut = " . Facture::STATUS_VALIDATED;
1039 }
1040 }
1041 if ($forsalary == 1) {
1042 $sql .= " AND s.rowid = pd.fk_salary";
1043 } else {
1044 if ($type == 'bank-transfer') {
1045 $sql .= " AND f.rowid = pd.fk_facture_fourn";
1046 } else {
1047 $sql .= " AND f.rowid = pd.fk_facture";
1048 }
1049 }
1050 $sql .= " AND pd.traite = 0";
1051 $sql .= " AND pd.ext_payment_id IS NULL";
1052 if (!$forsalary == 1) {
1053 $sql .= " AND f.total_ttc > 0";
1054 } else {
1055 $sql .= " AND s.paye = 0";
1056 }
1057
1058 dol_syslog(get_class($this) . "::NbFactureAPrelever");
1059 $resql = $this->db->query($sql);
1060
1061 if ($resql) {
1062 $obj = $this->db->fetch_object($resql);
1063 $this->db->free($resql);
1064
1065 return $obj->nb;
1066 } else {
1067 $this->error = get_class($this) . "::NbFactureAPrelever Erreur -1 sql=" . $this->db->error();
1068 return -1;
1069 }
1070 }
1071
1072
1073 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1097 public function create($banque = '', $agence = '', $mode = 'real', $format = 'FRST', $executiondate = 0, $notrigger = 0, $type = 'direct-debit', $dids = 0, $fk_bank_account = 0, $sourcetype = 'invoice')
1098 {
1099 // phpcs:enable
1100 global $conf, $langs, $user;
1101
1102 dol_syslog(__METHOD__ . " mode=".$mode." format=".$format." type=".$type." dids=".(is_array($dids) ? implode(',', $dids) : $dids)." fk_bank_account=".$fk_bank_account." sourcetype=".$sourcetype, LOG_DEBUG);
1103
1104 require_once DOL_DOCUMENT_ROOT . "/compta/facture/class/facture.class.php";
1105 require_once DOL_DOCUMENT_ROOT . "/societe/class/societe.class.php";
1106
1107 // Check params
1108 if ($type != 'bank-transfer') {
1109 $format = strtoupper($format);
1110 if (empty($format)) {
1111 $this->error = 'ErrorBadParametersForDirectDebitFileCreate';
1112 return -1;
1113 }
1114 if ($mode === 'real' && !in_array($format, array('FRST', 'RCUR', 'OOFF', 'FNAL'), true)) {
1115 $this->error = 'ErrorBadParametersForDirectDebitFileCreate';
1116 return -1;
1117 }
1118 }
1119
1120 if (!is_int($dids) && !is_array($dids)) {
1121 $this->error = 'ErrorBadParametersForDirectDebitFileCreateDids';
1122 return -1;
1123 }
1124
1125 // Clean params
1126 if (empty($fk_bank_account)) {
1127 $fk_bank_account = ($type == 'bank-transfer' ? getDolGlobalInt('PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT') : getDolGlobalInt('PRELEVEMENT_ID_BANKACCOUNT'));
1128 }
1129 if (is_int($dids)) {
1130 $dids = array($dids);
1131 }
1132
1133 $error = 0;
1134 // Pre-store some values into variables to simplify following sql requests
1135 if ($sourcetype != 'salary') {
1136 $entity = $type != 'bank-transfer' ? getEntity('invoice', 1) : getEntity('supplier_invoice', 1); // Return entity
1137 $sqlTable = $type != 'bank-transfer' ? "facture" : "facture_fourn";
1138 $socOrUser = 'fk_soc';
1139 $societeOrUser = 'societe';
1140 } else {
1141 $entity = getEntity('salary', 1); // Return entity
1142 $sqlTable = 'salary';
1143 $socOrUser = 'fk_user';
1144 $societeOrUser = 'user';
1145 }
1146
1147 /*
1148 $thirdpartyBANId = 0;
1149
1150 // Check if there is an iban associated to the bank transfer request or if we take the default
1151 if ($dids !== [0] && !empty($dids)) {
1152 $sql = "SELECT pd.fk_societe_rib";
1153 $sql .= " FROM " . $this->db->prefix() . "prelevement_demande as pd";
1154 $sql .= " WHERE pd.rowid IN (".$this->db->sanitize(implode(',', $dids)).")";
1155
1156 $resql = $this->db->query($sql);
1157
1158 if (!$resql) {
1159 $this->error = $this->db->lasterror();
1160 dol_syslog(__METHOD__ . " Read fk_societe_rib error " . $this->db->lasterror(), LOG_ERR);
1161 return -1;
1162 }
1163
1164 $obj = $this->db->fetch_object($resql);
1165 if ($obj) {
1166 $thirdpartyBANId = $obj->fk_societe_rib;
1167
1168 dol_syslog(__METHOD__ . " Found a BAN ID to use: ".$thirdpartyBANId);
1169 }
1170
1171 $this->db->free($resql);
1172 }
1173 */
1174
1175 $datetimeprev = dol_now('gmt');
1176 // Choice of the date of the execution direct debit
1177 if (!empty($executiondate)) {
1178 $datetimeprev = $executiondate;
1179 }
1180
1181 $month = dol_print_date($datetimeprev, "%m", 'gmt');
1182 $year = dol_print_date($datetimeprev, "%Y", 'gmt');
1183
1184 $this->invoice_in_error = array();
1185 $this->thirdparty_in_error = array();
1186
1187 // Get all invoices to process into $factures
1188 $factures = array(); // TODO Rename $factures... into $payment_requests...
1189 $factures_prev = array();
1190 $factures_prev_id = array();
1191
1192 dol_syslog(__METHOD__ . " Read invoices/salaries for dids=" . implode(', ', $dids), LOG_DEBUG);
1193
1194 $sql = "SELECT f.rowid, pd.rowid as pfdrowid";
1195 $sql .= ", f.".$this->db->sanitize($socOrUser); // fk_soc or fk_user
1196 $sql .= ", pd.code_banque, pd.code_guichet, pd.number, pd.cle_rib";
1197 $sql .= ", pd.amount";
1198 if ($sourcetype != 'salary') {
1199 $sql .= ", s.nom as name";
1200 $sql .= ", f.ref";
1201 $sql .= ", sr.bic, sr.iban_prefix, sr.frstrecur, sr.default_rib, sr.rum";
1202 } else {
1203 $sql .= ", CONCAT(s.firstname, ' ', s.lastname) as name";
1204 $sql .= ", f.ref";
1205 $sql .= ", sr.bic, sr.iban_prefix, 'FRST' as frstrecur, sr.default_rib, '' as rum";
1206 }
1207 $sql .= ", pd.fk_societe_rib as soc_rib_id"; // Forced payment IBAN to use in priority
1208 $sql .= " FROM " . $this->db->prefix() . $sqlTable . " as f"; // f is salary, facture or facture_fourn
1209 $sql .= " INNER JOIN " . $this->db->prefix() . "prelevement_demande as pd ON f.rowid = pd.fk_".$this->db->sanitize($sqlTable);
1210 $sql .= " LEFT JOIN " . $this->db->prefix() . $this->db->sanitize($societeOrUser)." as s ON s.rowid = f.".$this->db->sanitize($socOrUser);
1211 $sql .= " LEFT JOIN " . $this->db->prefix() . $this->db->sanitize($societeOrUser."_rib")." as sr ON s.rowid = sr.".$this->db->sanitize($socOrUser); // To get the default BAN of thirdparty
1212 if ($sourcetype != 'salary') {
1213 $sql .= " AND sr.default_rib = 1";
1214 $sql .= " AND sr.type = 'ban'";
1215 } else {
1216 //$sql .= " AND sr.type = 'ban'"; // TODO Add AND sr.type = 'ban' for users too
1217 // TODO Add 'AND sr.default_rib = 1' in sourcetype salary too
1218 // Note: the column has been created in v21 in llx_user_rib and default to 0
1219 // If we add a test on sr.default_rib = 1, we must also check we have a correct error management to stop if no default BAN is found.
1220 // Also it may be found for on thirdparty and not for the other.
1221 }
1222 $sql .= " WHERE f.entity IN (".((int) $entity).')';
1223 if ($sourcetype != 'salary') {
1224 $sql .= " AND f.fk_statut = ".Facture::STATUS_VALIDATED; // Invoice validated
1225 $sql .= " AND f.paye = 0";
1226 $sql .= " AND f.total_ttc > 0";
1227 /*if ($socid > 0) {
1228 $sql .= " AND f.fk_soc = ".((int) $socid);
1229 }*/
1230 } else {
1231 //$sql .= " AND f.fk_statut = 1"; // Invoice validated
1232 $sql .= " AND f.paye = 0";
1233 $sql .= " AND f.amount > 0";
1234 }
1235 $sql .= " AND pd.traite = 0";
1236 $sql .= " AND pd.ext_payment_id IS NULL";
1237 if ($dids !== [0] && !empty($dids)) {
1238 $sql .= " AND pd.rowid IN (".$this->db->sanitize(implode(',', $dids)).")";
1239 }
1240
1241 $resql = $this->db->query($sql);
1242 if ($resql) {
1243 $num = $this->db->num_rows($resql);
1244 $i = 0;
1245
1246 while ($i < $num) {
1247 $row = $this->db->fetch_row($resql); // TODO Replace with fetch_object()
1248 '@phan-var-force array<int<0,12>,string> $row';
1251 // All fields:
1252 // 0=invoice or salary id, 1=pfdrowid (id of payment request), 2=$socOrUser, 3=code_banque, 4=code_guichet, 5=number, 6=key,
1253 // 7=amount, 8=company name, 9=invoice ref,
1254 // 10=default bic, 11=default iban (=the BAN to use if no soc_rib_id set), 12=default frstrecur, 13=default_rib, 14=default rum, 15=soc_rib_id (=the BAN to use in priority)
1255 $factures[$i] = $row;
1256
1257 // Decode default BAN
1258 $factures[$i][11] = dolDecrypt($factures[$i][11]);
1259
1260 if ($row[7] == 0) {
1261 $error++;
1262 dol_syslog(__METHOD__ . " Read invoices/salaries error Found a null amount", LOG_WARNING);
1263 $this->invoice_in_error[$row[0]] = "Error for invoice or salary id " . $row[0] . ", found a null amount";
1264 break;
1265 }
1266 $i++;
1267 }
1268
1269 $this->db->free($resql);
1270 dol_syslog(__METHOD__ . " Read invoices/salaries, " . $i . " invoices/salaries to withdraw", LOG_DEBUG);
1271 } else {
1272 $this->error = $this->db->lasterror();
1273 dol_syslog(__METHOD__ . " Read invoices/salaries error " . $this->db->lasterror(), LOG_ERR);
1274 return -1;
1275 }
1276
1277 if (!$error) {
1278 // Make some checks
1279 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1280 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
1281 require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php';
1282 require_once DOL_DOCUMENT_ROOT . '/core/lib/bank.lib.php';
1283
1284 $tmpsoc = new Societe($this->db);
1285 $tmpuser = new User($this->db);
1286
1287 // Check BAN
1288 $i = 0;
1289 dol_syslog(__METHOD__ . " Check BAN for each invoices or salaries", LOG_DEBUG);
1290
1291 if (count($factures) > 0) {
1292 foreach ($factures as $key => $fac) {
1293 //var_dump($type, $format, $fac[8], $fac[12]);
1294
1295 // Check if $fac[8] s.nom is null
1296 if ($fac[8] != null) {
1297 if ($type != 'bank-transfer') {
1298 if ($format == 'FRST' && $fac[12] && $fac[12] != 'FRST') {
1299 continue;
1300 }
1301 if ($format == 'RCUR' && $fac[12] && $fac[12] != 'RCUR') {
1302 continue;
1303 }
1304 }
1305
1306 // If a bank account was forced on llx_prelevement_demande (the direct debit or credit transfer request),
1307 // we must use this one, so we reload values from soc_rib_id
1308 if (!empty($fac[15])) {
1309 $bankaccount = new CompanyBankAccount($this->db);
1310 $bankaccount->fetch((int) $fac[15]);
1311 if ($bankaccount->id > 0) {
1312 $fac[3] = $bankaccount->code_banque;
1313 $fac[4] = $bankaccount->code_guichet;
1314 $fac[5] = $bankaccount->number;
1315 $fac[6] = $bankaccount->cle_rib;
1316 $fac[10] = $bankaccount->bic;
1317 $fac[11] = $bankaccount->iban;
1318 $fac[14] = $bankaccount->rum;
1319 //var_dump('fetch id='.(int) $fac[14].' => '.$fac[3].'-'.$fac[4].'-'.$fac[5].'-'.$fac[6].'-'.$fac[10]."-".$fac[11]."-".$fac[14]);
1320 }
1321 }
1322
1323 $bicinloop = $fac[10];
1324 $baninloop = $fac[11];
1325
1326 $verif = checkSwiftForAccount(null, $bicinloop);
1327
1328 if ($verif || (empty($fac[10]) && getDolGlobalInt("WITHDRAWAL_WITHOUT_BIC"))) {
1329 dol_syslog(__METHOD__." now call checkIbanForAccount(null, ".$baninloop.")");
1330 $verif = checkIbanForAccount(null, $baninloop);
1331 }
1332
1333 if ($verif) {
1334 $factures_prev[$i] = $fac;
1335 /* second array necessary for BonPrelevement */
1336 $factures_prev_id[$i] = $fac[0];
1337 $i++;
1338 //dol_syslog(__METHOD__."::RIB is ok", LOG_DEBUG);
1339 } else {
1340 if ($type != 'bank-transfer') {
1341 $tmpsoc->id = (int) $fac[2];
1342 $tmpsoc->name = $fac[8];
1343 $invoice_url = "<a href='" . DOL_URL_ROOT . '/compta/facture/card.php?facid=' . $fac[0] . "'>" . $fac[9] . "</a>";
1344 $this->invoice_in_error[$fac[0]] = "Error incomplete properties of the default bank number ".$baninloop." IBAN/BIC for invoice " . $invoice_url . " for thirdparty " . $tmpsoc->getNomUrl(0);
1345 $this->thirdparty_in_error[$tmpsoc->id] = "Error on default bank number IBAN/BIC for invoice " . $invoice_url . " for thirdparty " . $tmpsoc->getNomUrl(0);
1346 $error++;
1347 }
1348 if ($type == 'bank-transfer' && $sourcetype != 'salary') {
1349 $tmpsoc->id = (int) $fac[2];
1350 $tmpsoc->name = $fac[8];
1351 $invoice_url = "<a href='" . DOL_URL_ROOT . '/fourn/facture/card.php?facid=' . $fac[0] . "'>" . $fac[9] . "</a>";
1352 $this->invoice_in_error[$fac[0]] = "Error incomplete properties of the default bank number ".$baninloop." IBAN/BIC for invoice " . $invoice_url . " for thirdparty " . $tmpsoc->getNomUrl(0);
1353 $this->thirdparty_in_error[$tmpsoc->id] = "Error on default bank number IBAN/BIC for invoice " . $invoice_url . " for thirdparty " . $tmpsoc->getNomUrl(0);
1354 $error++;
1355 }
1356 if ($type == 'bank-transfer' && $sourcetype == 'salary') {
1357 $tmpuser->id = (int) $fac[2];
1358 $tmpuser->firstname = $fac[8];
1359 $salary_url = "<a href='" . DOL_URL_ROOT . '/salaries/card.php?id=' . $fac[0] . "'>" . $fac[0] . "</a>";
1360 $this->invoice_in_error[$fac[0]] = "Error incomplete properties of the default bank number ".$baninloop." IBAN/BIC for salary " . $salary_url . " for employee " . $tmpuser->getNomUrl(0);
1361 $this->thirdparty_in_error[$tmpuser->id] = "Error on default bank number IBAN/BIC for salary " . $salary_url . " for employee " . $tmpuser->getNomUrl(0);
1362 $error++;
1363 }
1364 dol_syslog(__METHOD__ . " Check BAN Error on default bank number IBAN/BIC reported by verif(): " . implode(', ', $fac), LOG_WARNING);
1365 }
1366 } else {
1367 dol_syslog(__METHOD__ . " Check BAN Failed to read company", LOG_WARNING);
1368 }
1369 /*
1370 } else {
1371 dol_syslog(__METHOD__." Check BAN Failed to read invoice", LOG_WARNING);
1372 }
1373 */
1374 }
1375 } else {
1376 dol_syslog(__METHOD__ . " Check BAN No invoice to process", LOG_WARNING);
1377 }
1378 }
1379
1380 $ok = 0;
1381
1382 // Withdraw invoices in factures_prev array
1383 $out = count($factures_prev) . " invoices or salaries will be included.";
1384 dol_syslog($out);
1385
1386 //var_dump($factures_prev, $this->invoice_in_error, $this->thirdparty_in_error);exit;
1387
1388 if (count($factures_prev) > 0) {
1389 if ($mode == 'real') {
1390 $ok = 1;
1391 } else {
1392 print $langs->trans("ModeWarning"); // "Option for real mode was not set, we stop after this simulation\n";
1393 }
1394 }
1395 if ($ok) {
1396 /*
1397 * We are in real mode.
1398 * We create order and build file into disk
1399 */
1400 $this->db->begin();
1401
1402 $now = dol_now();
1403 $ref = '';
1404
1405 /*
1406 * Process order generation
1407 */
1408 if (!$error) {
1409 $ref = substr($year, -2) . $month;
1410
1411 $prefixt = "T";
1412
1413 // Get next free number for the ref of bon prelevement
1414 $sql = "SELECT SUBSTRING(ref, 6) AS refnumber"; // To suppress "TYYMM" from "TYYMMXXX"
1415 $sql .= " FROM " . MAIN_DB_PREFIX . "prelevement_bons";
1416 $sql .= " WHERE ref LIKE '" . $this->db->escape($prefixt . $ref) . "%'";
1417 $sql .= " AND entity = " . ((int) $conf->entity);
1418 $sql .= " ORDER BY LENGTH(ref) DESC, ref DESC";
1419 $sql .= " LIMIT 1";
1420
1421 dol_syslog(get_class($this) . " get next free number", LOG_DEBUG);
1422
1423 $resql = $this->db->query($sql);
1424
1425 if ($resql) {
1426 $row = $this->db->fetch_row($resql);
1427
1428 // Build the new ref
1429 $ref = $prefixt . $ref . sprintf("%03d", (intval($row[0] ?? 0) + 1));
1430
1431 // $conf->abc->dir_output may be:
1432 // /home/ldestailleur/git/dolibarr_15.0/documents/abc/
1433 // or
1434 // /home/ldestailleur/git/dolibarr_15.0/documents/X/abc with X >= 2 with multicompany.
1435 if ($type != 'bank-transfer') {
1436 $dir = $conf->prelevement->dir_output . '/receipts';
1437 } else {
1438 $dir = $conf->paymentbybanktransfer->dir_output . '/receipts';
1439 }
1440 if (!is_dir($dir)) {
1441 dol_mkdir($dir);
1442 }
1443
1444 if (isModEnabled('multicompany')) {
1445 $labelentity = $conf->entity;
1446 $this->filename = $dir . '/' . $ref . '-' . $labelentity . '.xml';
1447 } else {
1448 $this->filename = $dir . '/' . $ref . '.xml';
1449 }
1450
1451 // Create withdraw order in database
1452 $sql = "INSERT INTO " . MAIN_DB_PREFIX . "prelevement_bons (";
1453 $sql .= "ref, entity, datec, type, fk_bank_account";
1454 $sql .= ") VALUES (";
1455 $sql .= "'" . $this->db->escape($ref) . "'";
1456 $sql .= ", " . ((int) $conf->entity);
1457 $sql .= ", '" . $this->db->idate($now) . "'";
1458 $sql .= ", '" . ($type == 'bank-transfer' ? 'bank-transfer' : 'debit-order') . "'";
1459 $sql .= ", " . ((int) $fk_bank_account);
1460 $sql .= ")";
1461
1462 $resql = $this->db->query($sql);
1463
1464 if ($resql) {
1465 $prev_id = $this->db->last_insert_id(MAIN_DB_PREFIX . "prelevement_bons");
1466 $this->id = $prev_id;
1467 $this->ref = $ref;
1468 } else {
1469 $error++;
1470 $this->errors[] = $this->db->lasterror();
1471 dol_syslog(__METHOD__ . " Create withdraw receipt " . $this->db->lasterror(), LOG_ERR);
1472 }
1473 } else {
1474 $error++;
1475 $this->errors[] = $this->db->lasterror();
1476 dol_syslog(__METHOD__ . " Get last withdraw receipt " . $this->db->lasterror(), LOG_ERR);
1477 }
1478 }
1479
1480 if (!$error) {
1481 dol_syslog(__METHOD__ . " Now loop on each document to insert them in llx_prelevement_demande");
1482
1483 // Add lines for the direct debit or crdit transfer
1484 if (count($factures_prev) > 0) {
1485 foreach ($factures_prev as $fac) { // Add a link in database for each invoice or salary
1486 /*
1487 * Add standing order. This add record into llx_prelevement_lignes and llx_prelevement
1488 * The llx_prelevement_ligne will then be read to build the XML SEPA file.
1489 *
1490 * $fac[0] : invoice or salary id
1491 * $fac[1] : id of payment request (rowid in llx_prelevement_demande)
1492 * $fac[2] : third party id
1493 * $fac[3] : banque
1494 * $fac[4] : guichet
1495 * $fac[5] : number
1496 * $fac[6] : cle rib
1497 * $fac[7] : amount
1498 * $fac[8] : client nom
1499 * $fac[9] : Invoice ref
1500 * $fac[10] : BIC
1501 * $fac[11] : IBAN
1502 * $fac[12] : frstrcur
1503 * $fac[13] : default_rib (0 or 1)
1504 * $fac[14] : rum
1505 * $fac[15] : soc_rib_id (id bank account preselected for direct debit or credit transfer)
1506 */
1507 $ri = $this->addWithdrawDetail(
1508 $fac[0],
1509 $fac[2],
1510 $fac[8],
1511 $fac[7],
1512 $fac[3],
1513 $fac[4],
1514 $fac[5],
1515 $fac[6],
1516 $type,
1517 $sourcetype,
1518 $fac[10],
1519 $fac[11],
1520 $fac[14],
1521 $fac[1]
1522 );
1523
1524 if ($ri != 0) {
1525 $error++;
1526 }
1527
1528 // Update invoice requests as done
1529 $sql = "UPDATE " . MAIN_DB_PREFIX . "prelevement_demande";
1530 $sql .= " SET traite = 1";
1531 $sql .= ", date_traite = '" . $this->db->idate($now) . "'";
1532 $sql .= ", fk_prelevement_bons = " . ((int) $this->id);
1533 $sql .= " WHERE rowid = " . ((int) $fac[1]);
1534
1535 $resql = $this->db->query($sql);
1536 if (!$resql) {
1537 $error++;
1538 $this->errors[] = $this->db->lasterror();
1539 dol_syslog(__METHOD__ . " Update Error=" . $this->db->lasterror(), LOG_ERR);
1540 }
1541 }
1542 }
1543 }
1544
1545 if (!$error) {
1546 /*
1547 * Create file of type='direct-debit' for direct debit order or type='bank-transfer' for credit transfer into a XML file
1548 */
1549
1550 dol_syslog(__METHOD__ . " Init direct debit or credit transfer file for " . count($factures_prev) . " invoices", LOG_DEBUG);
1551
1552 if (count($factures_prev) > 0) {
1553 $this->date_echeance = $datetimeprev;
1554 $this->reference_remise = $ref;
1555
1556 $account = new Account($this->db);
1557 if ($account->fetch($fk_bank_account) > 0) {
1558 $this->emetteur_code_banque = $account->code_banque;
1559 $this->emetteur_code_guichet = $account->code_guichet;
1560 $this->emetteur_numero_compte = $account->number;
1561 $this->emetteur_number_key = $account->cle_rib;
1562 $this->sepa_xml_pti_in_ctti = (bool) $account->pti_in_ctti;
1563 $this->emetteur_iban = $account->iban;
1564 $this->emetteur_bic = $account->bic;
1565
1566 $this->emetteur_ics = (($type == 'bank-transfer' && getDolGlobalString("SEPA_USE_IDS")) ? $account->ics_transfer : $account->ics); // Example "FR78ZZZ123456"
1567
1568 $this->raison_sociale = $account->owner_name;
1569 }
1570 $this->factures = $factures_prev_id;
1571 $this->context['factures_prev'] = $factures_prev;
1572 // Generation of direct debit or credit transfer file $this->filename (May be a SEPA file for european countries)
1573 // This also set the property $this->total with amount that is included into file
1574 $userid = 0;
1575 if ($sourcetype == 'salary') {
1576 $userid = $this->context['factures_prev'][0][2];
1577 }
1578 $result = $this->generate($format, $executiondate, $type, $fk_bank_account, $userid, 0);
1579 if ($result < 0) {
1580 //var_dump($this->error);
1581 //var_dump($this->invoice_in_error);
1582 $error++;
1583 }
1584 }
1585 dol_syslog(__METHOD__ . " Bank order file has been generated under filename " . $this->filename, LOG_DEBUG);
1586 }
1587
1588
1589 /*
1590 * Update total defined after generation of file
1591 */
1592 if (!$error) {
1593 $sql = "UPDATE " . MAIN_DB_PREFIX . "prelevement_bons";
1594 $sql .= " SET amount = " . price2num($this->total);
1595 $sql .= " WHERE rowid = " . ((int) $this->id);
1596 $sql .= " AND entity = " . ((int) $conf->entity);
1597 $resql = $this->db->query($sql);
1598
1599 if (!$resql) {
1600 $error++;
1601 dol_syslog(__METHOD__ . " Error update total: " . $this->db->error(), LOG_ERR);
1602 }
1603 }
1604
1605 if (!$error && !$notrigger) {
1606 $triggerName = ($type == 'bank-transfer') ? 'CREDIT_TRANSFER_ORDER_CREATE' : 'DIRECT_DEBIT_ORDER_CREATE';
1607 $this->amount = $this->total;
1608
1609 // Call trigger
1610 $result = $this->call_trigger($triggerName, $user);
1611 if ($result < 0) {
1612 $error++;
1613 }
1614 // End call triggers
1615 }
1616
1617 if (!$error) {
1618 $this->db->commit();
1619 return count($factures_prev); // The error of failed lines are into $this->invoice_in_error and $this->thirdparty_in_error
1620 } else {
1621 $this->db->rollback();
1622 return -1;
1623 }
1624 } else {
1625 return 0;
1626 }
1627 }
1628
1629
1637 public function delete($user, $notrigger = 0)
1638 {
1639 $this->db->begin();
1640
1641 $error = 0;
1642 $resql1 = $resql2 = $resql3 = $resql4 = 0;
1643
1644 if (!$notrigger) {
1645 $triggername = 'DIRECT_DEBIT_ORDER_DELETE';
1646 if ($this->type == 'bank-transfer') {
1647 $triggername = 'PAYMENTBYBANKTRANFER_DELETE';
1648 }
1649 // Call trigger
1650 $result = $this->call_trigger($triggername, $user);
1651 if ($result < 0) {
1652 $error++;
1653 }
1654 // End call triggers
1655 }
1656
1657 if (!$error) {
1658 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "prelevement WHERE fk_prelevement_lignes IN (SELECT rowid FROM " . MAIN_DB_PREFIX . "prelevement_lignes WHERE fk_prelevement_bons = " . ((int) $this->id) . ")";
1659 $resql1 = $this->db->query($sql);
1660 if (!$resql1) {
1661 dol_print_error($this->db);
1662 }
1663 }
1664
1665 if (!$error) {
1666 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "prelevement_lignes WHERE fk_prelevement_bons = " . ((int) $this->id);
1667 $resql2 = $this->db->query($sql);
1668 if (!$resql2) {
1669 dol_print_error($this->db);
1670 }
1671 }
1672
1673 if (!$error) {
1674 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "prelevement_bons WHERE rowid = " . ((int) $this->id);
1675 $resql3 = $this->db->query($sql);
1676 if (!$resql3) {
1677 dol_print_error($this->db);
1678 }
1679 }
1680
1681 if (!$error) {
1682 $sql = "UPDATE " . MAIN_DB_PREFIX . "prelevement_demande SET fk_prelevement_bons = NULL, traite = 0 WHERE fk_prelevement_bons = " . ((int) $this->id);
1683 $resql4 = $this->db->query($sql);
1684 if (!$resql4) {
1685 dol_print_error($this->db);
1686 }
1687 }
1688
1689 if ($resql1 && $resql2 && $resql3 && $resql4 && !$error) {
1690 $this->db->commit();
1691 return 1;
1692 } else {
1693 $this->db->rollback();
1694 return -1;
1695 }
1696 }
1697
1698
1709 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1710 {
1711 global $conf, $langs, $hookmanager;
1712
1713 if (!empty($conf->dol_no_mouse_hover)) {
1714 $notooltip = 1; // Force disable tooltips
1715 }
1716
1717 $result = '';
1718
1719 $labeltoshow = 'PaymentByDirectDebit';
1720 $labelforclosedate = 'CreditDate';
1721 if (!empty($this->type) && $this->type == 'bank-transfer') {
1722 $labeltoshow = 'PaymentByBankTransfer';
1723 $labelforclosedate = 'ClosedOn';
1724 }
1725
1726 $label = img_picto('', $this->picto) . ' <u>' . $langs->trans($labeltoshow) . '</u> ' . $this->getLibStatut(5);
1727 $label .= '<br>';
1728 $label .= '<b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
1729 if (isset($this->amount)) {
1730 $label .= '<br><b>' . $langs->trans("Amount") . ':</b> <span class="amount">' . price($this->amount).'</span>';
1731 }
1732 if (isset($this->date_creation)) {
1733 $label .= '<br><b>'.$langs->trans("DateCreation").":</b> ".dol_print_date($this->date_creation, 'dayhour', 'tzuserrel');
1734 }
1735 if (isset($this->date_trans)) {
1736 $label .= '<br><b>' . $langs->trans("TransData") . ":</b> " . dol_print_date($this->date_trans, 'dayhour', 'tzuserrel');
1737 }
1738 if (isset($this->date_credit)) {
1739 $label .= '<br><b>'.$langs->trans($labelforclosedate).":</b> ".dol_print_date($this->date_credit, 'dayhour', 'tzuserrel');
1740 }
1741
1742 $url = DOL_URL_ROOT . '/compta/prelevement/card.php?id=' . $this->id;
1743 if (!empty($this->type) && $this->type == 'bank-transfer') {
1744 $url = DOL_URL_ROOT . '/compta/prelevement/card.php?id=' . $this->id;
1745 }
1746
1747 if ($option != 'nolink') {
1748 // Add param to save lastsearch_values or not
1749 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1750 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1751 $add_save_lastsearch_values = 1;
1752 }
1753 if ($add_save_lastsearch_values) {
1754 $url .= '&save_lastsearch_values=1';
1755 }
1756 }
1757
1758 $linkclose = '';
1759 if (empty($notooltip)) {
1760 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1761 $label = $langs->trans("ShowMyObject");
1762 $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
1763 }
1764 $linkclose .= ' title="' . dol_escape_htmltag($label, 1) . '"';
1765 $linkclose .= ' class="classfortooltip' . ($morecss ? ' ' . $morecss : '') . '"';
1766 } else {
1767 $linkclose = ($morecss ? ' class="' . $morecss . '"' : '');
1768 }
1769
1770 $linkstart = '<a href="' . $url . '"';
1771 $linkstart .= $linkclose . '>';
1772 $linkend = '</a>';
1773
1774 $result .= $linkstart;
1775 if ($withpicto) {
1776 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . 'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
1777 }
1778 if ($withpicto != 2) {
1779 $result .= $this->ref;
1780 }
1781 $result .= $linkend;
1782
1783 global $action, $hookmanager;
1784 $hookmanager->initHooks(array('banktransferdao'));
1785 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1786 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1787 if ($reshook > 0) {
1788 $result = $hookmanager->resPrint;
1789 } else {
1790 $result .= $hookmanager->resPrint;
1791 }
1792
1793 return $result;
1794 }
1795
1796
1803 public function deleteNotificationById($rowid)
1804 {
1805 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "notify_def";
1806 $sql .= " WHERE rowid = " . ((int) $rowid);
1807
1808 if ($this->db->query($sql)) {
1809 return 0;
1810 } else {
1811 return -1;
1812 }
1813 }
1814
1822 public function deleteNotification($user, $action)
1823 {
1824 if (is_object($user)) {
1825 $userid = $user->id;
1826 } else { // If user is an id
1827 $userid = $user;
1828 }
1829
1830 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "notify_def";
1831 $sql .= " WHERE fk_user = " . ((int) $userid) . " AND fk_action = " . ((int) $action);
1832
1833 if ($this->db->query($sql)) {
1834 return 0;
1835 } else {
1836 return -1;
1837 }
1838 }
1839
1840 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1849 public function addNotification($db, $user, $action)
1850 {
1851 // phpcs:enable
1852 $result = 0;
1853
1854 if (is_object($user)) {
1855 $userid = $user->id;
1856 } else { // If user is an id
1857 $userid = $user;
1858 }
1859
1860 if ($this->deleteNotification($user, $action) == 0) {
1861 $now = dol_now();
1862
1863 $sql = "INSERT INTO " . MAIN_DB_PREFIX . "notify_def (datec, fk_user, fk_soc, fk_contact, fk_action)";
1864 $sql .= " VALUES ('" . $this->db->idate($now) . "', " . ((int) $userid) . ", NULL, NULL, " . ((int) $action) . ")";
1865
1866 dol_syslog("adnotiff: " . $sql);
1867 if ($this->db->query($sql)) {
1868 $result = 0;
1869 } else {
1870 $result = -1;
1871 dol_syslog(get_class($this) . "::addNotification Error $result");
1872 }
1873 }
1874
1875 return $result;
1876 }
1877
1878
1894 public function generate(string $format = 'FRST', int $executiondate = 0, string $type = 'direct-debit', int $fk_bank_account = 0, int $forsalary = 0, int $thirdpartyBANId = 0)
1895 {
1896 global $conf, $langs, $mysoc;
1897
1898 if ($type !== 'bank-transfer') {
1899 $format = strtoupper($format);
1900 if (!in_array($format, array('FRST', 'RCUR', 'OOFF', 'FNAL'), true)) {
1901 $this->error = 'ErrorBadParametersForDirectDebitFileCreate';
1902 return -1;
1903 }
1904 }
1905
1906 //TODO: Optimize code to read lines in a single function
1907
1908 // Clean params
1909 if (empty($fk_bank_account)) {
1910 $fk_bank_account = ($type == 'bank-transfer' ? getDolGlobalInt('PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT') : getDolGlobalInt('PRELEVEMENT_ID_BANKACCOUNT'));
1911 }
1912
1913 $result = 0;
1914
1915 dol_syslog(get_class($this) . "::generate build file=" . $this->filename . " type=" . $type);
1916
1917 $this->file = fopen($this->filename, "w");
1918 if ($this->file == false) {
1919 $this->error = $langs->trans('ErrorFailedToOpenFile', $this->filename);
1920 return -1;
1921 }
1922
1923 $found = 0;
1924 $this->total = 0;
1925
1926 // Build file for European countries
1927 if ($mysoc->isInSEPA()) {
1928 $found++;
1929
1930 if ($type != 'bank-transfer') {
1934 // SEPA Initialisation
1935 $CrLf = "\n";
1936
1937 $now = dol_now();
1938
1939 $dateTime_ECMA = dol_print_date($now, '%Y-%m-%dT%H:%M:%S');
1940
1941 $date_actu = $now;
1942 if (!empty($executiondate)) {
1943 $date_actu = $executiondate;
1944 }
1945
1946 $dateTime_YMD = dol_print_date($date_actu, '%Y%m%d');
1947 $dateTime_YMDHMS = dol_print_date($date_actu, '%Y%m%d%H%M%S');
1948 $fileDebiteurSection = '';
1949 $fileEmetteurSection = '';
1950 $i = 0;
1951
1952 /*
1953 * Section Debitor (sepa Debiteurs block lines)
1954 */
1955
1956 $sql = "SELECT soc.rowid as socid, soc.code_client as code, soc.address, soc.zip, soc.town, c.code as country_code,";
1957 //$sql .= " pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, ";
1958 $sql .= " pl.client_nom as nom, pl.amount as somme, pl.fk_prelevement_demande,";
1959 $sql .= " f.ref as reffac,";
1960 $sql .= " p.fk_facture as idfac, p.rowid as pid,";
1961 $sql .= " rib.rowid, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum, rib.rum, rib.date_rum";
1962 $sql .= " FROM";
1963 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
1964 $sql .= " " . MAIN_DB_PREFIX . "facture as f,";
1965 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p,";
1966 $sql .= " " . MAIN_DB_PREFIX . "societe as soc,";
1967 $sql .= " " . MAIN_DB_PREFIX . "c_country as c,";
1968 $sql .= " " . MAIN_DB_PREFIX . "societe_rib as rib";
1969 $sql .= " WHERE pl.fk_prelevement_bons = " . ((int) $this->id);
1970 $sql .= " AND pl.rowid = p.fk_prelevement_lignes";
1971 $sql .= " AND p.fk_facture = f.rowid";
1972 $sql .= " AND f.fk_soc = soc.rowid";
1973 $sql .= " AND soc.fk_pays = c.rowid";
1974 $sql .= " AND rib.fk_soc = f.fk_soc";
1975 if (!empty($thirdpartyBANId)) {
1976 $sql .= " AND rib.rowid = " . ((int) $thirdpartyBANId);
1977 } else {
1978 $sql .= " AND rib.default_rib = 1";
1979 }
1980 $sql .= " AND rib.type = 'ban'";
1981
1982 // Define $fileDebiteurSection. One section DrctDbtTxInf per invoice.
1983 $resql = $this->db->query($sql);
1984 $nbtotalDrctDbtTxInf = -1;
1985 if ($resql) {
1986 $cachearraytotestduplicate = array();
1987
1988 $num = $this->db->num_rows($resql);
1989 while ($i < $num) {
1990 $obj = $this->db->fetch_object($resql);
1991
1992 if (!empty($cachearraytotestduplicate[$obj->idfac])) {
1993 $this->error = $langs->trans('ErrorCompanyHasDuplicateDefaultBAN', $obj->socid);
1994 $this->invoice_in_error[$obj->idfac] = $this->error;
1995 $result = -2;
1996 break;
1997 }
1998 $cachearraytotestduplicate[$obj->idfac] = $obj->rowid;
1999
2000 // Get the default value
2001 $daterum = (!empty($obj->date_rum)) ? $this->db->jdate($obj->date_rum) : $this->db->jdate($obj->datec);
2002 $iban = dolDecrypt($obj->iban);
2003 $bic = $obj->bic;
2004 $drum = $obj->drum;
2005 $rum = $obj->rum;
2006
2007 // But if a force bank account is defined, we use it instead
2008 if (!empty($obj->fk_prelevement_demande)) {
2009 $companybankaccountid = 0;
2010
2011 $sqltmp = "SELECT fk_societe_rib FROM ".MAIN_DB_PREFIX."prelevement_demande";
2012 $sqltmp .= " WHERE rowid = ".((int) $obj->fk_prelevement_demande);
2013
2014 $resqltmp = $this->db->query($sqltmp);
2015
2016 $objtmp = $this->db->fetch_object($resqltmp);
2017 if ($objtmp) {
2018 $companybankaccountid = (int) $objtmp->fk_societe_rib;
2019 }
2020
2021 $bankaccount = new CompanyBankAccount($this->db);
2022 $bankaccount->fetch($companybankaccountid);
2023 if ($bankaccount->id > 0) {
2024 $daterum = $bankaccount->date_rum;
2025 $iban = $bankaccount->iban;
2026 $bic = $bankaccount->bic;
2027 $drum = $bankaccount->id;
2028 $rum = $bankaccount->rum;
2029 }
2030 }
2031
2032 $fileDebiteurSection .= $this->EnregDestinataireSEPA($obj->code, $obj->nom, $obj->address, $obj->zip, $obj->town, $obj->country_code, '', '', '', $obj->somme, $obj->reffac, $obj->idfac, $iban, $bic, $daterum, (string) $drum, $rum, $type);
2033
2034 $this->total += $obj->somme;
2035 $i++;
2036 }
2037 $nbtotalDrctDbtTxInf = $i;
2038 } else {
2039 $this->error = $this->db->lasterror();
2040 fwrite($this->file, 'ERROR DEBITOR ' . $sql . $CrLf); // DEBITOR = Customers
2041 $result = -2;
2042 }
2043
2044 // Define $fileEmetteurSection. Start of block PmtInf. Will contains all $nbtotalDrctDbtTxInf
2045 if ($result != -2) {
2046 $fileEmetteurSection .= $this->EnregEmetteurSEPA($conf, $date_actu, $nbtotalDrctDbtTxInf, $this->total, $CrLf, $format, $type, $fk_bank_account);
2047 }
2048
2049 if (getDolGlobalString('SEPA_FORCE_TWO_DECIMAL')) {
2050 $this->total = number_format((float) price2num($this->total, 'MT'), 2, ".", "");
2051 }
2052
2056 // SEPA File Header
2057 fwrite($this->file, '<' . '?xml version="1.0" encoding="UTF-8" standalone="yes"?' . '>' . $CrLf);
2058 fwrite($this->file, '<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.001.02" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' . $CrLf);
2059 fwrite($this->file, ' <CstmrDrctDbtInitn>' . $CrLf);
2060 // SEPA Group header
2061 fwrite($this->file, ' <GrpHdr>' . $CrLf);
2062 fwrite($this->file, ' <MsgId>' . ('DOL/' . $dateTime_YMD . '/DD' . $this->id) . '</MsgId>' . $CrLf);
2063 fwrite($this->file, ' <CreDtTm>' . $dateTime_ECMA . '</CreDtTm>' . $CrLf);
2064 fwrite($this->file, ' <NbOfTxs>' . $i . '</NbOfTxs>' . $CrLf);
2065 fwrite($this->file, ' <CtrlSum>' . $this->total . '</CtrlSum>' . $CrLf);
2066 fwrite($this->file, ' <InitgPty>' . $CrLf);
2067 fwrite($this->file, ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))) . '</Nm>' . $CrLf);
2068 fwrite($this->file, ' <Id>' . $CrLf);
2069 fwrite($this->file, ' <PrvtId>' . $CrLf);
2070 fwrite($this->file, ' <Othr>' . $CrLf);
2071 fwrite($this->file, ' <Id>' . $this->emetteur_ics . '</Id>' . $CrLf);
2072 fwrite($this->file, ' </Othr>' . $CrLf);
2073 fwrite($this->file, ' </PrvtId>' . $CrLf);
2074 fwrite($this->file, ' </Id>' . $CrLf);
2075 fwrite($this->file, ' </InitgPty>' . $CrLf);
2076 fwrite($this->file, ' </GrpHdr>' . $CrLf);
2077 // SEPA File Emetteur
2078 if ($result != -2) {
2079 fwrite($this->file, $fileEmetteurSection);
2080 }
2081 // SEPA File Debiteurs
2082 if ($result != -2) {
2083 fwrite($this->file, $fileDebiteurSection);
2084 }
2085 // SEPA FILE FOOTER
2086 fwrite($this->file, ' </PmtInf>' . $CrLf);
2087 fwrite($this->file, ' </CstmrDrctDbtInitn>' . $CrLf);
2088 fwrite($this->file, '</Document>' . $CrLf);
2089 } else {
2093 // SEPA Initialisation
2094 $CrLf = "\n";
2095
2096 $now = dol_now();
2097
2098 $dateTime_ECMA = dol_print_date($now, '%Y-%m-%dT%H:%M:%S');
2099
2100 $date_actu = $now;
2101 if (!empty($executiondate)) {
2102 $date_actu = $executiondate;
2103 }
2104
2105 $dateTime_YMD = dol_print_date($date_actu, '%Y%m%d');
2106 $dateTime_YMDHMS = dol_print_date($date_actu, '%Y%m%d%H%M%S');
2107 $fileCrediteurSection = '';
2108 $fileEmetteurSection = '';
2109 $i = 0;
2110
2111 /*
2112 * Section Creditor (sepa Crediteurs block lines)
2113 */
2114 if (!empty($forsalary)) {
2115 $sql = "SELECT u.rowid as userId, u.address, u.zip, u.town, c.code as country_code, CONCAT(u.firstname,' ',u.lastname) as nom,";
2116 //$sql .= " pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, ";
2117 $sql .= " pl.client_nom as nom, pl.amount as somme, pl.fk_prelevement_demande,";
2118 $sql .= " s.ref as reffac,";
2119 $sql .= " p.fk_salary as idfac,";
2120 $sql .= " rib.rowid, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum, '' as rum, '' as date_rum";
2121 $sql .= " FROM";
2122 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
2123 $sql .= " " . MAIN_DB_PREFIX . "salary as s,";
2124 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p,";
2125 $sql .= " " . MAIN_DB_PREFIX . "user as u";
2126 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_country as c ON u.fk_country = c.rowid,";
2127 $sql .= " " . MAIN_DB_PREFIX . "user_rib as rib";
2128 $sql .= " WHERE pl.fk_prelevement_bons=" . ((int) $this->id);
2129 $sql .= " AND pl.rowid = p.fk_prelevement_lignes";
2130 $sql .= " AND p.fk_salary = s.rowid";
2131 $sql .= " AND s.fk_user = u.rowid";
2132 $sql .= " AND rib.fk_user = s.fk_user";
2133 } else {
2134 $sql = "SELECT soc.rowid as socid, soc.code_client as code, soc.address, soc.zip, soc.town, c.code as country_code,";
2135 //$sql .= " pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, ";
2136 $sql .= " pl.client_nom as nom, pl.amount as somme, pl.fk_prelevement_demande,";
2137 $sql .= " f.ref as reffac, f.ref_supplier as fac_ref_supplier,";
2138 $sql .= " p.fk_facture_fourn as idfac,";
2139 $sql .= " rib.rowid, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum, rib.rum, rib.date_rum";
2140 $sql .= " FROM";
2141 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
2142 $sql .= " " . MAIN_DB_PREFIX . "facture_fourn as f,";
2143 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p,";
2144 $sql .= " " . MAIN_DB_PREFIX . "societe as soc";
2145 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_country as c ON soc.fk_pays = c.rowid,";
2146 $sql .= " " . MAIN_DB_PREFIX . "societe_rib as rib";
2147 $sql .= " WHERE pl.fk_prelevement_bons = " . ((int) $this->id);
2148 $sql .= " AND pl.rowid = p.fk_prelevement_lignes";
2149 $sql .= " AND p.fk_facture_fourn = f.rowid";
2150 $sql .= " AND f.fk_soc = soc.rowid";
2151 $sql .= " AND rib.fk_soc = f.fk_soc";
2152 if (!empty($thirdpartyBANId)) {
2153 $sql .= " AND rib.rowid = " . ((int) $thirdpartyBANId);
2154 } else {
2155 $sql .= " AND rib.default_rib = 1";
2156 }
2157 $sql .= " AND rib.type = 'ban'";
2158 }
2159 // Define $fileCrediteurSection. One section DrctDbtTxInf per invoice.
2160 $nbtotalDrctDbtTxInf = -1;
2161
2162 require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php';
2163
2164 $resql = $this->db->query($sql);
2165 if ($resql) {
2166 $cachearraytotestduplicate = array();
2167
2168 $num = $this->db->num_rows($resql);
2169 while ($i < $num) {
2170 $obj = $this->db->fetch_object($resql);
2171
2172 // Test to avoid duplicate default IBAN, to ask user to clean its data
2173 if (!empty($cachearraytotestduplicate[$obj->idfac])) {
2174 $this->error = $langs->trans('ErrorCompanyHasDuplicateDefaultBAN', $obj->socid);
2175 $this->invoice_in_error[$obj->idfac] = $this->error;
2176 $result = -2;
2177 break;
2178 }
2179
2180 $cachearraytotestduplicate[$obj->idfac] = $obj->rowid;
2181
2182 // Get the default value
2183 $daterum = (!empty($obj->date_rum)) ? $this->db->jdate($obj->date_rum) : $this->db->jdate($obj->datec);
2184 $iban = dolDecrypt($obj->iban);
2185 $bic = $obj->bic;
2186 $drum = $obj->drum;
2187 $rum = $obj->rum;
2188
2189 // But if a force bank account is defined, we use it instead
2190 if (!empty($obj->fk_prelevement_demande)) {
2191 $companybankaccountid = 0;
2192
2193 $sqltmp = "SELECT fk_societe_rib FROM ".MAIN_DB_PREFIX."prelevement_demande";
2194 $sqltmp .= " WHERE rowid = ".((int) $obj->fk_prelevement_demande);
2195
2196 $resqltmp = $this->db->query($sqltmp);
2197
2198 $objtmp = $this->db->fetch_object($resqltmp);
2199 if ($objtmp) {
2200 $companybankaccountid = (int) $objtmp->fk_societe_rib;
2201 }
2202
2203 $bankaccount = new CompanyBankAccount($this->db);
2204 $bankaccount->fetch($companybankaccountid);
2205 if ($bankaccount->id > 0) {
2206 $daterum = $bankaccount->date_rum;
2207 $iban = $bankaccount->iban;
2208 $bic = $bankaccount->bic;
2209 $drum = $bankaccount->id;
2210 $rum = $bankaccount->rum;
2211 }
2212 }
2213
2214 $refobj = $obj->reffac;
2215 if (empty($refobj) && !empty($forsalary)) { // If ref of salary not defined, we force a value
2216 $refobj = "SAL" . $obj->idfac;
2217 }
2218
2219 $fileCrediteurSection .= $this->EnregDestinataireSEPA($obj->code, $obj->nom, $obj->address, $obj->zip, $obj->town, $obj->country_code, '', '', '', $obj->somme, $refobj, $obj->idfac, $iban, $bic, $daterum, (string) $drum, $rum, $type, $obj->fac_ref_supplier);
2220
2221 $this->total += $obj->somme;
2222 $i++;
2223 }
2224 $nbtotalDrctDbtTxInf = $i;
2225 } else {
2226 $this->error = $this->db->lasterror();
2227 fwrite($this->file, 'ERROR CREDITOR ' . $sql . $CrLf); // CREDITORS = Suppliers
2228 $result = -2;
2229 }
2230 // Define $fileEmetteurSection. Start of block PmtInf. Will contains all $nbtotalDrctDbtTxInf
2231 if ($result != -2) {
2232 $fileEmetteurSection .= $this->EnregEmetteurSEPA($conf, $date_actu, $nbtotalDrctDbtTxInf, $this->total, $CrLf, $format, $type);
2233 }
2234
2235 if (getDolGlobalString('SEPA_FORCE_TWO_DECIMAL')) {
2236 $this->total = number_format((float) price2num($this->total, 'MT'), 2, ".", "");
2237 }
2238
2242 // SEPA File Header
2243 fwrite($this->file, '<' . '?xml version="1.0" encoding="UTF-8" standalone="yes"?' . '>' . $CrLf);
2244 fwrite($this->file, '<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' . $CrLf);
2245 fwrite($this->file, ' <CstmrCdtTrfInitn>' . $CrLf);
2246 // SEPA Group header
2247 fwrite($this->file, ' <GrpHdr>' . $CrLf);
2248 fwrite($this->file, ' <MsgId>' . ('DOL/' . $dateTime_YMD . '/CT' . $this->id) . '</MsgId>' . $CrLf);
2249 fwrite($this->file, ' <CreDtTm>' . $dateTime_ECMA . '</CreDtTm>' . $CrLf);
2250 fwrite($this->file, ' <NbOfTxs>' . $i . '</NbOfTxs>' . $CrLf);
2251 fwrite($this->file, ' <CtrlSum>' . $this->total . '</CtrlSum>' . $CrLf);
2252 fwrite($this->file, ' <InitgPty>' . $CrLf);
2253 fwrite($this->file, ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))) . '</Nm>' . $CrLf);
2254 fwrite($this->file, ' <Id>' . $CrLf);
2255 fwrite($this->file, ' <PrvtId>' . $CrLf);
2256 fwrite($this->file, ' <Othr>' . $CrLf);
2257 fwrite($this->file, ' <Id>' . $this->emetteur_ics . '</Id>' . $CrLf);
2258 fwrite($this->file, ' </Othr>' . $CrLf);
2259 fwrite($this->file, ' </PrvtId>' . $CrLf);
2260 fwrite($this->file, ' </Id>' . $CrLf);
2261 fwrite($this->file, ' </InitgPty>' . $CrLf);
2262 fwrite($this->file, ' </GrpHdr>' . $CrLf);
2263 // SEPA File Emetteur (mycompany)
2264 if ($result != -2) {
2265 fwrite($this->file, $fileEmetteurSection);
2266 }
2267 // SEPA File Creditors
2268 if ($result != -2) {
2269 fwrite($this->file, $fileCrediteurSection);
2270 }
2271 // SEPA FILE FOOTER
2272 fwrite($this->file, ' </PmtInf>' . $CrLf);
2273 fwrite($this->file, ' </CstmrCdtTrfInitn>' . $CrLf);
2274 fwrite($this->file, '</Document>' . $CrLf);
2275 }
2276 }
2277
2278 // Build file for Other Countries with unknown format
2279 if (!$found) {
2280 if ($type != 'bank-transfer') {
2281 $sql = "SELECT pl.amount";
2282 $sql .= " FROM";
2283 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
2284 $sql .= " " . MAIN_DB_PREFIX . "facture as f,";
2285 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p";
2286 $sql .= " WHERE pl.fk_prelevement_bons = " . ((int) $this->id);
2287 $sql .= " AND pl.rowid = p.fk_prelevement_lignes";
2288 $sql .= " AND p.fk_facture = f.rowid";
2289
2290 // Lines
2291 $i = 0;
2292 $resql = $this->db->query($sql);
2293 if ($resql) {
2294 $num = $this->db->num_rows($resql);
2295
2296 while ($i < $num) {
2297 $obj = $this->db->fetch_object($resql);
2298 $this->total += $obj->amount;
2299
2300 // TODO Write record into file
2301 $i++;
2302 }
2303 } else {
2304 $result = -2;
2305 }
2306 } else {
2307 $sql = "SELECT pl.amount";
2308 $sql .= " FROM";
2309 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
2310 $sql .= " " . MAIN_DB_PREFIX . "facture_fourn as f,";
2311 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p";
2312 $sql .= " WHERE pl.fk_prelevement_bons = " . ((int) $this->id);
2313 $sql .= " AND pl.rowid = p.fk_prelevement_lignes";
2314 $sql .= " AND p.fk_facture_fourn = f.rowid";
2315 // Lines
2316 $i = 0;
2317 $resql = $this->db->query($sql);
2318 if ($resql) {
2319 $num = $this->db->num_rows($resql);
2320
2321 while ($i < $num) {
2322 $obj = $this->db->fetch_object($resql);
2323 $this->total += $obj->amount;
2324
2325 // TODO Write record into file
2326 $i++;
2327 }
2328 } else {
2329 $result = -2;
2330 }
2331 }
2332
2333 $langs->load('withdrawals');
2334
2335 // TODO Add here code to generate a generic file
2336 fwrite($this->file, $langs->transnoentitiesnoconv('WithdrawalFileNotCapable', $mysoc->country_code));
2337 }
2338
2339 fclose($this->file);
2340 dolChmod($this->filename);
2341
2342 return $result;
2343 }
2344
2345
2354 public static function buildRumNumber($row_code_client, $row_datec, $row_drum)
2355 {
2356 global $langs;
2357
2358 $pre = substr(dol_string_nospecial(dol_string_unaccent($langs->transnoentitiesnoconv('RUM'))), 0, 3); // Must always be on 3 char ('RUM' or 'UMR'. This is a protection against bad translation)
2359
2360 // 3 char + '-' + 10 (yymmddHHMM) + '-' + id + '-' + code. Must be under 32 (SEPA char limit for MndtId is however 35).
2361 return $pre . '-' . dol_print_date($row_datec, 'dayhourlogsmall') . '-' . dol_trunc((string) $row_drum . ($row_code_client ? '-' . $row_code_client : ''), 17, 'right', 'UTF-8', 1);
2362 }
2363
2364
2365 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2382 public function EnregDestinataire($rowid, $client_nom, $rib_banque, $rib_guichet, $rib_number, $amount, $ref, $facid, $rib_dom = '', $type = 'direct-debit')
2383 {
2384 // phpcs:enable
2385 fwrite($this->file, "06");
2386 fwrite($this->file, "08"); // Prelevement ordinaire
2387
2388 fwrite($this->file, " "); // Zone Reservee B2
2389
2390 fwrite($this->file, $this->emetteur_ics); // ICS
2391
2392 // Date d'echeance C1
2393
2394 fwrite($this->file, " ");
2395 fwrite($this->file, dol_print_date($this->date_echeance, "%d%m", 'gmt'));
2396 fwrite($this->file, substr(dol_print_date($this->date_echeance, "%y", 'gmt'), 1));
2397
2398 // Raison Sociale Destinataire C2
2399
2400 fwrite($this->file, substr(strtoupper($client_nom) . " ", 0, 24));
2401
2402 // Address optional D1
2403 $address = strtr($rib_dom, array(" " => "-", chr(13) => " ", chr(10) => ""));
2404 fwrite($this->file, substr($address . " ", 0, 24));
2405
2406 // Zone Reservee D2
2407
2408 fwrite($this->file, substr(" ", 0, 8));
2409
2410 // Code Guichet D3
2411
2412 fwrite($this->file, $rib_guichet);
2413
2414 // Numero de compte D4
2415
2416 fwrite($this->file, substr("000000000000000" . $rib_number, -11));
2417
2418 // Zone E Montant
2419
2420 $montant = (round($amount, 2) * 100);
2421
2422 fwrite($this->file, substr("000000000000000" . $montant, -16));
2423
2424 // Label F
2425
2426 fwrite($this->file, substr("*_" . $ref . "_RDVnet" . $rowid . " ", 0, 31));
2427
2428 // Code etablissement G1
2429
2430 fwrite($this->file, $rib_banque);
2431
2432 // Zone Reservee G2
2433
2434 fwrite($this->file, substr(" ", 0, 5));
2435
2436 fwrite($this->file, "\n");
2437 }
2438
2439
2440 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2466 public function EnregDestinataireSEPA($row_code_client, $row_nom, $row_address, $row_zip, $row_town, $row_country_code, $row_cb, $row_cg, $row_cc, $row_somme, $row_ref, $row_idfac, $row_iban, $row_bic, $row_datec, $row_drum, $row_rum, $type = 'direct-debit', $row_comment = '')
2467 {
2468 // phpcs:enable
2469 global $conf, $mysoc, $hookmanager;
2470
2471 if (getDolGlobalString('SEPA_FORCE_TWO_DECIMAL')) {
2472 $row_somme = number_format((float) price2num($row_somme, 'MT'), 2, ".", "");
2473 } else {
2474 $row_somme = round((float) $row_somme, 2);
2475 }
2476
2477 include_once DOL_DOCUMENT_ROOT . '/core/lib/functions2.lib.php';
2478
2479 $CrLf = "\n";
2480 $Rowing = sprintf("%010d", $row_idfac);
2481
2482 // Define value for RUM
2483 // Example: RUM-CustomerCode-CustomerBankAccountId-01424448606 (note: Date is the timestamp of the date of creation of CustomerBankAccountId)
2484 $Rum = (empty($row_rum) ? $this->buildRumNumber($row_code_client, $row_datec, $row_drum) : $row_rum);
2485
2486 // Define date of RUM signature
2487 $DtOfSgntr = dol_print_date($row_datec, '%Y-%m-%d');
2488 $XML_RESULT = '';
2489
2490 if (!is_object($hookmanager)) {
2491 include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
2492 $hookmanager = new HookManager($this->db);
2493 }
2494 $hookmanager->initHooks(array('bonprelevementdao'));
2495 $parameters = array(
2496 'row_code_client' => &$row_code_client, 'row_nom' => &$row_nom, 'row_address' => &$row_address, 'row_zip' => &$row_zip, 'row_town' => &$row_town,
2497 'row_country_code' => &$row_country_code, 'row_cb' => &$row_cb, 'row_cg' => &$row_cg, 'row_cc' => &$row_cc, 'row_somme' => &$row_somme,
2498 'row_ref' => &$row_ref, 'row_idfac' => &$row_idfac, 'row_iban' => &$row_iban, 'row_bic' => &$row_bic, 'row_datec' => &$row_datec,
2499 'row_drum' => &$row_drum, 'row_rum' => &$row_rum, 'type' => &$type, 'row_comment' => &$row_comment,
2500 'crlf' => &$CrLf, 'rowing' => &$Rowing, 'rum' => &$Rum, 'dtofsgntr' => &$DtOfSgntr,
2501 );
2502 $reshook = $hookmanager->executeHooks('enregDestinataireSEPA', $parameters, $this); // Note that $action and $object may have been modified by some hooks
2503 if (empty($reshook)) {
2504 if ($type != 'bank-transfer') {
2505 // SEPA Paiement Information of buyer for Direct Debit
2506 $XML_DEBITOR = '';
2507 $XML_DEBITOR .= ' <DrctDbtTxInf>' . $CrLf;
2508 $XML_DEBITOR .= ' <PmtId>' . $CrLf;
2509 // Add EndToEndId. Must be a unique ID for each payment (for example by including bank, buyer or seller, date, checksum)
2510 $XML_DEBITOR .= ' <EndToEndId>' . ((getDolGlobalString('PRELEVEMENT_END_TO_END') != "") ? $conf->global->PRELEVEMENT_END_TO_END : ('DD-' . dol_trunc($row_idfac . '-' . $row_ref, 20, 'right', 'UTF-8', 1)) . '-' . $Rowing) . '</EndToEndId>' . $CrLf; // ISO20022 states that EndToEndId has a MaxLength of 35 characters
2511 $XML_DEBITOR .= ' </PmtId>' . $CrLf;
2512 $XML_DEBITOR .= ' <InstdAmt Ccy="EUR">' . $row_somme . '</InstdAmt>' . $CrLf;
2513 $XML_DEBITOR .= ' <DrctDbtTx>' . $CrLf;
2514 $XML_DEBITOR .= ' <MndtRltdInf>' . $CrLf;
2515 $XML_DEBITOR .= ' <MndtId>' . $Rum . '</MndtId>' . $CrLf;
2516 $XML_DEBITOR .= ' <DtOfSgntr>' . $DtOfSgntr . '</DtOfSgntr>' . $CrLf;
2517 $XML_DEBITOR .= ' <AmdmntInd>false</AmdmntInd>' . $CrLf;
2518 $XML_DEBITOR .= ' </MndtRltdInf>' . $CrLf;
2519 $XML_DEBITOR .= ' </DrctDbtTx>' . $CrLf;
2520 $XML_DEBITOR .= ' <DbtrAgt>' . $CrLf;
2521 $XML_DEBITOR .= ' <FinInstnId>' . $CrLf;
2522 if (getDolGlobalInt('WITHDRAWAL_WITHOUT_BIC') == 0) {
2523 $XML_DEBITOR .= ' <BIC>' . $row_bic . '</BIC>' . $CrLf;
2524 }
2525 $XML_DEBITOR .= ' </FinInstnId>' . $CrLf;
2526 $XML_DEBITOR .= ' </DbtrAgt>' . $CrLf;
2527 $XML_DEBITOR .= ' <Dbtr>' . $CrLf;
2528 $XML_DEBITOR .= ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($row_nom), ' '))) . '</Nm>' . $CrLf;
2529 $XML_DEBITOR .= ' <PstlAdr>' . $CrLf;
2530 $XML_DEBITOR .= ' <Ctry>' . $row_country_code . '</Ctry>' . $CrLf;
2531 $addressline1 = strtr($row_address, array(chr(13) => ", ", chr(10) => ""));
2532 $addressline2 = strtr($row_zip . (($row_zip && $row_town) ? ' ' : '') . (string) $row_town, array(chr(13) => ", ", chr(10) => ""));
2533 if (trim($addressline1)) {
2534 $XML_DEBITOR .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2535 }
2536 if (trim($addressline2)) {
2537 $XML_DEBITOR .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2538 }
2539 $XML_DEBITOR .= ' </PstlAdr>' . $CrLf;
2540 $XML_DEBITOR .= ' </Dbtr>' . $CrLf;
2541 $XML_DEBITOR .= ' <DbtrAcct>' . $CrLf;
2542 $XML_DEBITOR .= ' <Id>' . $CrLf;
2543 $XML_DEBITOR .= ' <IBAN>' . preg_replace('/\s/', '', $row_iban) . '</IBAN>' . $CrLf;
2544 $XML_DEBITOR .= ' </Id>' . $CrLf;
2545 $XML_DEBITOR .= ' </DbtrAcct>' . $CrLf;
2546 $XML_DEBITOR .= ' <RmtInf>' . $CrLf;
2547
2548 // Structured data for Belgium
2549 if (getDolGlobalString('INVOICE_PAYMENT_ENABLE_STRUCTURED_COMMUNICATION') && $mysoc->country_code == 'BE') {
2550 include_once DOL_DOCUMENT_ROOT . '/core/lib/functions_be.lib.php';
2551
2552 $invoicestatic = new Facture($this->db);
2553 $invoicestatic->fetch($row_idfac);
2554
2555 $invoicePaymentKey = dolBECalculateStructuredCommunication($invoicestatic->ref, $invoicestatic->type);
2556 $XML_DEBITOR .= ' <strd>' . $invoicePaymentKey . '</strd>' . $CrLf;
2557 } else {
2558 // A string with some information on payment - 140 max
2559 $XML_DEBITOR .= ' <Ustrd>' . getDolGlobalString('PRELEVEMENT_USTRD', dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($row_ref . ($row_comment ? ' - ' . $row_comment : '')), '', '', '', 1), 135, 'right', 'UTF-8', 1))) . '</Ustrd>' . $CrLf; // Free unstuctured data - 140 max
2560 }
2561 $XML_DEBITOR .= ' </RmtInf>' . $CrLf;
2562 $XML_DEBITOR .= ' </DrctDbtTxInf>' . $CrLf;
2563
2564 $XML_RESULT = $XML_DEBITOR;
2565 } else {
2566 // SEPA Payment Information of seller for Credit Transfer
2567 $XML_CREDITOR = '';
2568 $XML_CREDITOR .= ' <CdtTrfTxInf>' . $CrLf;
2569 $XML_CREDITOR .= ' <PmtId>' . $CrLf;
2570 // Add EndToEndId. Must be a unique ID for each payment (for example by including bank, buyer or seller, date, checksum)
2571 $XML_CREDITOR .= ' <EndToEndId>' . ((getDolGlobalString('PRELEVEMENT_END_TO_END') != "") ? getDolGlobalString("PRELEVEMENT_END_TO_END") : ('CT-' . dol_trunc($row_idfac . '-' . $row_ref, 20, 'right', 'UTF-8', 1)) . '-' . $Rowing) . '</EndToEndId>' . $CrLf; // ISO20022 states that EndToEndId has a MaxLength of 35 characters
2572 $XML_CREDITOR .= ' </PmtId>' . $CrLf;
2573 if (!empty($this->sepa_xml_pti_in_ctti)) {
2574 $XML_CREDITOR .= ' <PmtTpInf>' . $CrLf;
2575
2576 // Can be 'NORM' for normal or 'HIGH' for high priority level
2577 if (getDolGlobalString('PAYMENTBYBANKTRANSFER_FORCE_HIGH_PRIORITY')) {
2578 $instrprty = 'HIGH';
2579 } else {
2580 $instrprty = 'NORM';
2581 }
2582
2583 // Set $categoryPurpose: CORE, TREA, SUPP, ...
2584 $categoryPurpose = getDolGlobalString('PAYMENTBYBANKTRANSFER_CUSTOM_CATEGORY_PURPOSE', 'CORE');
2585
2586 $XML_CREDITOR .= ' <InstrPrty>' . $instrprty . '</InstrPrty>' . $CrLf;
2587 $XML_CREDITOR .= ' <SvcLvl>' . $CrLf;
2588 $XML_CREDITOR .= ' <Cd>SEPA</Cd>' . $CrLf;
2589 $XML_CREDITOR .= ' </SvcLvl>' . $CrLf;
2590 $XML_CREDITOR .= ' <CtgyPurp>' . $CrLf;
2591 $XML_CREDITOR .= ' <Cd>' . $categoryPurpose . '</Cd>' . $CrLf;
2592 $XML_CREDITOR .= ' </CtgyPurp>' . $CrLf;
2593 $XML_CREDITOR .= ' </PmtTpInf>' . $CrLf;
2594 }
2595 $XML_CREDITOR .= ' <Amt>' . $CrLf;
2596 $XML_CREDITOR .= ' <InstdAmt Ccy="EUR">' . round((float) $row_somme, 2) . '</InstdAmt>' . $CrLf;
2597 $XML_CREDITOR .= ' </Amt>' . $CrLf;
2598 /*
2599 $XML_CREDITOR .= ' <DrctDbtTx>'.$CrLf;
2600 $XML_CREDITOR .= ' <MndtRltdInf>'.$CrLf;
2601 $XML_CREDITOR .= ' <MndtId>'.$Rum.'</MndtId>'.$CrLf;
2602 $XML_CREDITOR .= ' <DtOfSgntr>'.$DtOfSgntr.'</DtOfSgntr>'.$CrLf;
2603 $XML_CREDITOR .= ' <AmdmntInd>false</AmdmntInd>'.$CrLf;
2604 $XML_CREDITOR .= ' </MndtRltdInf>'.$CrLf;
2605 $XML_CREDITOR .= ' </DrctDbtTx>'.$CrLf;
2606 */
2607 //$XML_CREDITOR .= ' <ChrgBr>SLEV</ChrgBr>'.$CrLf;
2608 $XML_CREDITOR .= ' <CdtrAgt>' . $CrLf;
2609 $XML_CREDITOR .= ' <FinInstnId>' . $CrLf;
2610 $XML_CREDITOR .= ' <BIC>' . $row_bic . '</BIC>' . $CrLf;
2611 $XML_CREDITOR .= ' </FinInstnId>' . $CrLf;
2612 $XML_CREDITOR .= ' </CdtrAgt>' . $CrLf;
2613 $XML_CREDITOR .= ' <Cdtr>' . $CrLf;
2614 $XML_CREDITOR .= ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($row_nom), ' '))) . '</Nm>' . $CrLf;
2615 $XML_CREDITOR .= ' <PstlAdr>' . $CrLf;
2616 $XML_CREDITOR .= ' <Ctry>' . $row_country_code . '</Ctry>' . $CrLf;
2617 $addressline1 = strtr($row_address, array(chr(13) => ", ", chr(10) => ""));
2618 $addressline2 = strtr($row_zip . (($row_zip && $row_town) ? ' ' : '') . (string) $row_town, array(chr(13) => ", ", chr(10) => ""));
2619 if (trim($addressline1)) {
2620 $XML_CREDITOR .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2621 }
2622 if (trim($addressline2)) {
2623 $XML_CREDITOR .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2624 }
2625 $XML_CREDITOR .= ' </PstlAdr>' . $CrLf;
2626 $XML_CREDITOR .= ' </Cdtr>' . $CrLf;
2627 $XML_CREDITOR .= ' <CdtrAcct>' . $CrLf;
2628 $XML_CREDITOR .= ' <Id>' . $CrLf;
2629 $XML_CREDITOR .= ' <IBAN>' . preg_replace('/\s/', '', $row_iban) . '</IBAN>' . $CrLf;
2630 $XML_CREDITOR .= ' </Id>' . $CrLf;
2631 $XML_CREDITOR .= ' </CdtrAcct>' . $CrLf;
2632 $XML_CREDITOR .= ' <RmtInf>' . $CrLf;
2633 // A string with some information on payment - 140 max
2634 $XML_CREDITOR .= ' <Ustrd>' . getDolGlobalString('CREDITTRANSFER_USTRD', dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($row_ref . ($row_comment ? ' - ' . $row_comment : '')), '', '', '', 1), 135, 'right', 'UTF-8', 1))) . '</Ustrd>' . $CrLf; // Free unstructured data - 140 max
2635 $XML_CREDITOR .= ' </RmtInf>' . $CrLf;
2636 $XML_CREDITOR .= ' </CdtTrfTxInf>' . $CrLf;
2637
2638 $XML_RESULT = $XML_CREDITOR;
2639 }
2640 } elseif ($reshook > 0) {
2641 $XML_RESULT = $hookmanager->resPrint;
2642 }
2643 $XML_RESULT .= $hookmanager->resPrint;
2644
2645 return $XML_RESULT;
2646 }
2647
2648
2649 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2658 public function EnregEmetteur($type = 'direct-debit')
2659 {
2660 // phpcs:enable
2661 fwrite($this->file, "03");
2662 fwrite($this->file, "08"); // Prelevement ordinaire
2663
2664 fwrite($this->file, " "); // Zone Reservee B2
2665
2666 fwrite($this->file, $this->emetteur_ics); // ICS
2667
2668 // Date d'echeance C1
2669
2670 fwrite($this->file, " ");
2671 fwrite($this->file, dol_print_date($this->date_echeance, "%d%m", 'gmt'));
2672 fwrite($this->file, substr(dol_print_date($this->date_echeance, "%y", 'gmt'), 1));
2673
2674 // Raison Sociale C2
2675
2676 fwrite($this->file, substr($this->raison_sociale . " ", 0, 24));
2677
2678 // Ref of thirdparty on 7 characters
2679
2680 fwrite($this->file, substr($this->reference_remise . " ", 0, 7));
2681
2682 // Zone Reservee D1-2
2683
2684 fwrite($this->file, substr(" ", 0, 17));
2685
2686 // Zone Reservee D2
2687
2688 fwrite($this->file, substr(" ", 0, 2));
2689 fwrite($this->file, "E");
2690 fwrite($this->file, substr(" ", 0, 5));
2691
2692 // Code Guichet D3
2693
2694 fwrite($this->file, $this->emetteur_code_guichet);
2695
2696 // Numero de compte D4
2697
2698 fwrite($this->file, substr("000000000000000" . $this->emetteur_numero_compte, -11));
2699
2700 // Zone Reservee E
2701
2702 fwrite($this->file, substr(" ", 0, 16));
2703
2704 // Zone Reservee F
2705
2706 fwrite($this->file, substr(" ", 0, 31));
2707
2708 // Code etablissement
2709
2710 fwrite($this->file, $this->emetteur_code_banque);
2711
2712 // Zone Reservee G
2713
2714 fwrite($this->file, substr(" ", 0, 5));
2715
2716 fwrite($this->file, "\n");
2717 }
2718
2719
2720 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2735 public function EnregEmetteurSEPA($configuration, $ladate, $nombre, $total, $CrLf = '\n', $format = 'FRST', $type = 'direct-debit', $fk_bank_account = 0)
2736 {
2737 // phpcs:enable
2738
2739 // Clean parameters
2740 $dateTime_YMD = dol_print_date($ladate, '%Y%m%d');
2741 $dateTime_ETAD = dol_print_date($ladate, '%Y-%m-%d');
2742 $dateTime_YMDHMS = dol_print_date($ladate, '%Y-%m-%dT%H:%M:%S');
2743
2744 // Clean params
2745 if (empty($fk_bank_account)) {
2746 $fk_bank_account = ($type == 'bank-transfer' ? getDolGlobalInt('PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT') : getDolGlobalInt('PRELEVEMENT_ID_BANKACCOUNT'));
2747 }
2748
2749 // Get data of bank account
2750 $account = new Account($this->db);
2751 if ($account->fetch($fk_bank_account) > 0) {
2752 $this->emetteur_code_banque = $account->code_banque;
2753 $this->emetteur_code_guichet = $account->code_guichet;
2754 $this->emetteur_numero_compte = $account->number;
2755 $this->emetteur_number_key = $account->cle_rib;
2756 $this->sepa_xml_pti_in_ctti = (bool) $account->pti_in_ctti;
2757 $this->emetteur_iban = $account->iban;
2758 $this->emetteur_bic = $account->bic;
2759
2760 $this->emetteur_ics = (($type == 'bank-transfer' && getDolGlobalString("SEPA_USE_IDS")) ? $account->ics_transfer : $account->ics); // Ex: PRELEVEMENT_ICS = "FR78ZZZ123456";
2761
2762 $this->raison_sociale = $account->owner_name;
2763 }
2764
2765 // Get pending payments
2766 $sql = "SELECT rowid, ref";
2767 $sql .= " FROM " . MAIN_DB_PREFIX . "prelevement_bons as pb";
2768 $sql .= " WHERE pb.rowid = " . ((int) $this->id);
2769
2770 $resql = $this->db->query($sql);
2771 if ($resql) {
2772 $obj = $this->db->fetch_object($resql);
2773
2774 $country = explode(':', getDolGlobalString('MAIN_INFO_SOCIETE_COUNTRY'));
2775 $IdBon = sprintf("%05d", $obj->rowid);
2776 $RefBon = $obj->ref;
2777 $localInstrument = getDolGlobalString('PAYMENTBYBANKTRANSFER_CUSTOM_LOCAL_INSTRUMENT', 'CORE');
2778
2779 if (getDolGlobalString('SEPA_FORCE_TWO_DECIMAL')) {
2780 $total = number_format((float) price2num($total, 'MT'), 2, ".", "");
2781 }
2782
2783 if ($type != 'bank-transfer') {
2784 // SEPA Paiement Information of my company for Direct Debit
2785 $XML_SEPA_INFO = '';
2786 $XML_SEPA_INFO .= ' <PmtInf>' . $CrLf;
2787 $XML_SEPA_INFO .= ' <PmtInfId>' . ('DOL/' . $dateTime_YMD . '/DD' . $IdBon . '-' . $RefBon) . '</PmtInfId>' . $CrLf;
2788 $XML_SEPA_INFO .= ' <PmtMtd>DD</PmtMtd>' . $CrLf;
2789 $XML_SEPA_INFO .= ' <NbOfTxs>' . $nombre . '</NbOfTxs>' . $CrLf;
2790 $XML_SEPA_INFO .= ' <CtrlSum>' . $total . '</CtrlSum>' . $CrLf;
2791 $XML_SEPA_INFO .= ' <PmtTpInf>' . $CrLf;
2792 $XML_SEPA_INFO .= ' <SvcLvl>' . $CrLf;
2793 $XML_SEPA_INFO .= ' <Cd>SEPA</Cd>' . $CrLf;
2794 $XML_SEPA_INFO .= ' </SvcLvl>' . $CrLf;
2795 $XML_SEPA_INFO .= ' <LclInstrm>' . $CrLf;
2796 $XML_SEPA_INFO .= ' <Cd>' . $localInstrument . '</Cd>' . $CrLf;
2797 $XML_SEPA_INFO .= ' </LclInstrm>' . $CrLf;
2798 $XML_SEPA_INFO .= ' <SeqTp>' . $format . '</SeqTp>' . $CrLf;
2799 $XML_SEPA_INFO .= ' </PmtTpInf>' . $CrLf;
2800 $XML_SEPA_INFO .= ' <ReqdColltnDt>' . $dateTime_ETAD . '</ReqdColltnDt>' . $CrLf;
2801 $XML_SEPA_INFO .= ' <Cdtr>' . $CrLf;
2802 $XML_SEPA_INFO .= ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))) . '</Nm>' . $CrLf;
2803 $XML_SEPA_INFO .= ' <PstlAdr>' . $CrLf;
2804 $XML_SEPA_INFO .= ' <Ctry>' . $country[1] . '</Ctry>' . $CrLf;
2805 $addressline1 = strtr(getDolGlobalString('MAIN_INFO_SOCIETE_ADDRESS'), array(chr(13) => ", ", chr(10) => ""));
2806 $addressline2 = strtr(getDolGlobalString('MAIN_INFO_SOCIETE_ZIP') . ((getDolGlobalString('MAIN_INFO_SOCIETE_ZIP') || ' ' . getDolGlobalString('MAIN_INFO_SOCIETE_TOWN')) ? ' ' : '') . getDolGlobalString('MAIN_INFO_SOCIETE_TOWN'), array(chr(13) => ", ", chr(10) => ""));
2807 if ($addressline1) {
2808 $XML_SEPA_INFO .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2809 }
2810 if ($addressline2) {
2811 $XML_SEPA_INFO .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2812 }
2813 $XML_SEPA_INFO .= ' </PstlAdr>' . $CrLf;
2814 $XML_SEPA_INFO .= ' </Cdtr>' . $CrLf;
2815 $XML_SEPA_INFO .= ' <CdtrAcct>' . $CrLf;
2816 $XML_SEPA_INFO .= ' <Id>' . $CrLf;
2817 $XML_SEPA_INFO .= ' <IBAN>' . preg_replace('/\s/', '', $this->emetteur_iban) . '</IBAN>' . $CrLf;
2818 $XML_SEPA_INFO .= ' </Id>' . $CrLf;
2819 $XML_SEPA_INFO .= ' </CdtrAcct>' . $CrLf;
2820 $XML_SEPA_INFO .= ' <CdtrAgt>' . $CrLf;
2821 $XML_SEPA_INFO .= ' <FinInstnId>' . $CrLf;
2822 $XML_SEPA_INFO .= ' <BIC>' . $this->emetteur_bic . '</BIC>' . $CrLf;
2823 $XML_SEPA_INFO .= ' </FinInstnId>' . $CrLf;
2824 $XML_SEPA_INFO .= ' </CdtrAgt>' . $CrLf;
2825 /* $XML_SEPA_INFO .= ' <UltmtCdtr>'.$CrLf;
2826 $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
2827 $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
2828 $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
2829 $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent(getDolGlobalString('MAIN_INFO_SOCIETE_ADDRESS')), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
2830 $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent(getDolGlobalString('MAIN_INFO_SOCIETE_ZIP').' '.getDolGlobalString('MAIN_INFO_SOCIETE_TOWN')), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
2831 $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
2832 $XML_SEPA_INFO .= ' </UltmtCdtr>'.$CrLf;*/
2833 $XML_SEPA_INFO .= ' <ChrgBr>SLEV</ChrgBr>' . $CrLf; // Field "Responsible of fees". Must be SLEV
2834 $XML_SEPA_INFO .= ' <CdtrSchmeId>' . $CrLf;
2835 $XML_SEPA_INFO .= ' <Id>' . $CrLf;
2836 $XML_SEPA_INFO .= ' <PrvtId>' . $CrLf;
2837 $XML_SEPA_INFO .= ' <Othr>' . $CrLf;
2838 $XML_SEPA_INFO .= ' <Id>' . $this->emetteur_ics . '</Id>' . $CrLf;
2839 $XML_SEPA_INFO .= ' <SchmeNm>' . $CrLf;
2840 $XML_SEPA_INFO .= ' <Prtry>SEPA</Prtry>' . $CrLf;
2841 $XML_SEPA_INFO .= ' </SchmeNm>' . $CrLf;
2842 $XML_SEPA_INFO .= ' </Othr>' . $CrLf;
2843 $XML_SEPA_INFO .= ' </PrvtId>' . $CrLf;
2844 $XML_SEPA_INFO .= ' </Id>' . $CrLf;
2845 $XML_SEPA_INFO .= ' </CdtrSchmeId>' . $CrLf;
2846 } else {
2847 // SEPA Paiement Information of my company for Credit Transfer
2848 $XML_SEPA_INFO = '';
2849 $XML_SEPA_INFO .= ' <PmtInf>' . $CrLf;
2850 $XML_SEPA_INFO .= ' <PmtInfId>' . ('DOL/' . $dateTime_YMD . '/CT' . $IdBon . '-' . $RefBon) . '</PmtInfId>' . $CrLf;
2851 $XML_SEPA_INFO .= ' <PmtMtd>TRF</PmtMtd>' . $CrLf;
2852 //$XML_SEPA_INFO .= ' <BtchBookg>False</BtchBookg>'.$CrLf;
2853 $XML_SEPA_INFO .= ' <NbOfTxs>' . $nombre . '</NbOfTxs>' . $CrLf;
2854 $XML_SEPA_INFO .= ' <CtrlSum>' . $total . '</CtrlSum>' . $CrLf;
2855 if (!empty($this->sepa_xml_pti_in_ctti) && !empty($format)) { // @TODO Using $format (FRST ou RCUR) in a section for a Credit Transfer looks strange.
2856 $XML_SEPA_INFO .= ' <PmtTpInf>' . $CrLf;
2857 $XML_SEPA_INFO .= ' <SvcLvl>' . $CrLf;
2858 $XML_SEPA_INFO .= ' <Cd>SEPA</Cd>' . $CrLf;
2859 $XML_SEPA_INFO .= ' </SvcLvl>' . $CrLf;
2860 $XML_SEPA_INFO .= ' <LclInstrm>' . $CrLf;
2861 $XML_SEPA_INFO .= ' <Cd>' . $localInstrument . '</Cd>' . $CrLf;
2862 $XML_SEPA_INFO .= ' </LclInstrm>' . $CrLf;
2863 $XML_SEPA_INFO .= ' <SeqTp>' . $format . '</SeqTp>' . $CrLf;
2864 $XML_SEPA_INFO .= ' </PmtTpInf>' . $CrLf;
2865 }
2866 $XML_SEPA_INFO .= ' <ReqdExctnDt>' . dol_print_date($dateTime_ETAD, 'dayrfc') . '</ReqdExctnDt>' . $CrLf;
2867 $XML_SEPA_INFO .= ' <Dbtr>' . $CrLf;
2868 $XML_SEPA_INFO .= ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))) . '</Nm>' . $CrLf;
2869 $XML_SEPA_INFO .= ' <PstlAdr>' . $CrLf;
2870 $XML_SEPA_INFO .= ' <Ctry>' . $country[1] . '</Ctry>' . $CrLf;
2871 $addressline1 = strtr(getDolGlobalString('MAIN_INFO_SOCIETE_ADDRESS'), array(chr(13) => ", ", chr(10) => ""));
2872 $addressline2 = strtr(getDolGlobalString('MAIN_INFO_SOCIETE_ZIP') . ((getDolGlobalString('MAIN_INFO_SOCIETE_ZIP') || ' ' . getDolGlobalString('MAIN_INFO_SOCIETE_TOWN')) ? ' ' : '') . getDolGlobalString('MAIN_INFO_SOCIETE_TOWN'), array(chr(13) => ", ", chr(10) => ""));
2873 if ($addressline1) {
2874 $XML_SEPA_INFO .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2875 }
2876 if ($addressline2) {
2877 $XML_SEPA_INFO .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2878 }
2879 $XML_SEPA_INFO .= ' </PstlAdr>' . $CrLf;
2880 $XML_SEPA_INFO .= ' </Dbtr>' . $CrLf;
2881 $XML_SEPA_INFO .= ' <DbtrAcct>' . $CrLf;
2882 $XML_SEPA_INFO .= ' <Id>' . $CrLf;
2883 $XML_SEPA_INFO .= ' <IBAN>' . preg_replace('/\s/', '', $this->emetteur_iban) . '</IBAN>' . $CrLf;
2884 $XML_SEPA_INFO .= ' </Id>' . $CrLf;
2885 $XML_SEPA_INFO .= ' </DbtrAcct>' . $CrLf;
2886 $XML_SEPA_INFO .= ' <DbtrAgt>' . $CrLf;
2887 $XML_SEPA_INFO .= ' <FinInstnId>' . $CrLf;
2888 $XML_SEPA_INFO .= ' <BIC>' . $this->emetteur_bic . '</BIC>' . $CrLf;
2889 $XML_SEPA_INFO .= ' </FinInstnId>' . $CrLf;
2890 $XML_SEPA_INFO .= ' </DbtrAgt>' . $CrLf;
2891 /* $XML_SEPA_INFO .= ' <UltmtCdtr>'.$CrLf;
2892 $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
2893 $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
2894 $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
2895 $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent(getDolGlobalString('MAIN_INFO_SOCIETE_ADDRESS')), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
2896 $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent(getDolGlobalString('MAIN_INFO_SOCIETE_ZIP').' '.getDolGlobalString('MAIN_INFO_SOCIETE_TOWN')), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
2897 $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
2898 $XML_SEPA_INFO .= ' </UltmtCdtr>'.$CrLf;*/
2899 $XML_SEPA_INFO .= ' <ChrgBr>SLEV</ChrgBr>' . $CrLf; // Field "Responsible of fees". Must be SLEV
2900 /*$XML_SEPA_INFO .= ' <CdtrSchmeId>'.$CrLf;
2901 $XML_SEPA_INFO .= ' <Id>'.$CrLf;
2902 $XML_SEPA_INFO .= ' <PrvtId>'.$CrLf;
2903 $XML_SEPA_INFO .= ' <Othr>'.$CrLf;
2904 $XML_SEPA_INFO .= ' <Id>'.$this->emetteur_ics.'</Id>'.$CrLf;
2905 $XML_SEPA_INFO .= ' <SchmeNm>'.$CrLf;
2906 $XML_SEPA_INFO .= ' <Prtry>SEPA</Prtry>'.$CrLf;
2907 $XML_SEPA_INFO .= ' </SchmeNm>'.$CrLf;
2908 $XML_SEPA_INFO .= ' </Othr>'.$CrLf;
2909 $XML_SEPA_INFO .= ' </PrvtId>'.$CrLf;
2910 $XML_SEPA_INFO .= ' </Id>'.$CrLf;
2911 $XML_SEPA_INFO .= ' </CdtrSchmeId>'.$CrLf;*/
2912 }
2913 } else {
2914 fwrite($this->file, 'INCORRECT EMETTEUR ' . $this->raison_sociale . $CrLf);
2915 $XML_SEPA_INFO = '';
2916 }
2917 return $XML_SEPA_INFO;
2918 }
2919
2920 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2927 public function EnregTotal($total)
2928 {
2929 // phpcs:enable
2930 fwrite($this->file, "08");
2931 fwrite($this->file, "08"); // Prelevement ordinaire
2932
2933 fwrite($this->file, " "); // Zone Reservee B2
2934
2935 fwrite($this->file, $this->emetteur_ics); // ICS
2936
2937 // Reserve C1
2938
2939 fwrite($this->file, substr(" ", 0, 12));
2940
2941
2942 // Raison Sociale C2
2943
2944 fwrite($this->file, substr(" ", 0, 24));
2945
2946 // D1
2947
2948 fwrite($this->file, substr(" ", 0, 24));
2949
2950 // Zone Reservee D2
2951
2952 fwrite($this->file, substr(" ", 0, 8));
2953
2954 // Code Guichet D3
2955
2956 fwrite($this->file, substr(" ", 0, 5));
2957
2958 // Numero de compte D4
2959
2960 fwrite($this->file, substr(" ", 0, 11));
2961
2962 // Zone E Montant
2963
2964 $montant = ($total * 100);
2965
2966 fwrite($this->file, substr("000000000000000" . $montant, -16));
2967
2968 // Zone Reservee F
2969
2970 fwrite($this->file, substr(" ", 0, 31));
2971
2972 // Code etablissement
2973
2974 fwrite($this->file, substr(" ", 0, 5));
2975
2976 // Zone Reservee F
2977
2978 fwrite($this->file, substr(" ", 0, 5));
2979
2980 fwrite($this->file, "\n");
2981 }
2982
2989 public function getLibStatut($mode = 0)
2990 {
2991 return $this->LibStatut((isset($this->status) ? $this->status : $this->statut), $mode);
2992 }
2993
2994 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3002 public function LibStatut($status, $mode = 0)
3003 {
3004 // phpcs:enable
3005 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
3006 global $langs;
3007 //$langs->load("mymodule");
3008 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('StatusWaiting');
3009 $this->labelStatus[self::STATUS_TRANSFERED] = $langs->transnoentitiesnoconv('StatusTrans');
3010 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('StatusWaiting');
3011 $this->labelStatusShort[self::STATUS_TRANSFERED] = $langs->transnoentitiesnoconv('StatusTrans');
3012 if ($this->type == 'bank-transfer') {
3013 $this->labelStatus[self::STATUS_DEBITED] = $langs->transnoentitiesnoconv('StatusDebited');
3014 $this->labelStatusShort[self::STATUS_DEBITED] = $langs->transnoentitiesnoconv('StatusDebited');
3015 } else {
3016 $this->labelStatus[self::STATUS_CREDITED] = $langs->transnoentitiesnoconv('StatusCredited');
3017 $this->labelStatusShort[self::STATUS_CREDITED] = $langs->transnoentitiesnoconv('StatusCredited');
3018 }
3019 $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
3020 $this->labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
3021 }
3022
3023 $statusType = 'status1';
3024 if ($status == self::STATUS_TRANSFERED) {
3025 $statusType = 'status3';
3026 }
3027 if ($status == self::STATUS_CREDITED || $status == self::STATUS_DEBITED) {
3028 $statusType = 'status6';
3029 }
3030 if ($status == self::STATUS_CANCELED) {
3031 $statusType = 'status9';
3032 }
3033
3034 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
3035 }
3036
3037 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3045 public function load_board($user, $mode)
3046 {
3047 // phpcs:enable
3048 global $conf, $langs;
3049
3050 if ($user->socid) {
3051 return -1; // Protection to prevent calls by external users
3052 }
3053
3054 if ($mode == 'direct-debit') {
3055 $sql = "SELECT p.rowid, p.date_trans as date_trans, p.date_credit as date_credit";
3056 $sql .= " FROM " . MAIN_DB_PREFIX . "prelevement_bons as p";
3057 $sql .= " WHERE p.entity IN (" . getEntity('prelevement_bons') . ")";
3058 $sql .= " AND (p.type = 'debit-order' OR p.type = 'direct-debit')"; // direct debit
3059 $sql .= " AND p.statut < ".((int) BonPrelevement::STATUS_DEBITED);
3060 } else {
3061 $sql = "SELECT p.rowid, p.date_trans as date_trans, p.date_credit as date_credit";
3062 $sql .= " FROM " . MAIN_DB_PREFIX . "prelevement_bons as p";
3063 $sql .= " WHERE p.entity IN (" . getEntity('prelevement_bons') . ")";
3064 $sql .= " AND (p.type = 'bank-transfer' OR p.type = 'credit-transfer')"; // credit transfer
3065 $sql .= " AND p.statut < ".((int) BonPrelevement::STATUS_CREDITED);
3066 }
3067
3068 $resql = $this->db->query($sql);
3069 if ($resql) {
3070 $langs->load("banks");
3071 $now = dol_now();
3072
3073 $response = new WorkboardResponse();
3074 if ($mode == 'direct-debit') {
3075 $response->warning_delay = $conf->warning_delays['bank_direct_debit'] / 60 / 60 / 24;
3076 $response->label = $langs->trans("PendingDirectDebitToComplete");
3077 $response->labelShort = $langs->trans("PendingDirectDebitToCompleteShort");
3078 $response->url = DOL_URL_ROOT . '/compta/prelevement/orders_list.php?leftmenu=checks&mainmenu=bank&search_status=0,1';
3079 $response->url_late = DOL_URL_ROOT . '/compta/prelevement/orders_list.php?leftmenu=checks&mainmenu=bank&search_status=0,1';
3080 } else {
3081 $response->warning_delay = $conf->warning_delays['bank_credit_transfer'] / 60 / 60 / 24;
3082 $response->label = $langs->trans("PendingCreditTransferToComplete");
3083 $response->labelShort = $langs->trans("PendingCreditTransferToCompleteShort");
3084 $response->url = DOL_URL_ROOT . '/compta/prelevement/orders_list.php?leftmenu=checks&mainmenu=bank&type=bank-transfer&search_status=0,1';
3085 $response->url_late = DOL_URL_ROOT . '/compta/prelevement/orders_list.php?leftmenu=checks&mainmenu=bank&type=bank-transfer&search_status=0,1';
3086 }
3087 $response->img = img_object('', "payment");
3088
3089 $response->nbtodo = 0;
3090 $response->nbtodolate = 0;
3091
3092 while ($obj = $this->db->fetch_object($resql)) {
3093 $response->nbtodo++;
3094
3095 if ($this->db->jdate($obj->date_trans) < ($now - $response->warning_delay)) {
3096 $response->nbtodolate++;
3097 }
3098 }
3099
3100 // Return workboard only if quantity is not 0
3101 //if ($response->nbtodo) {
3102 return $response;
3103 //} else {
3104 // return 0;
3105 //}
3106 } else {
3107 dol_print_error($this->db);
3108 $this->error = $this->db->error();
3109 return -1;
3110 }
3111 }
3112
3120 public function getKanbanView($option = '', $arraydata = null)
3121 {
3122 global $langs;
3123
3124 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
3125
3126 $return = '<div class="box-flex-item box-flex-grow-zero">';
3127 $return .= '<div class="info-box info-box-sm">';
3128 $return .= '<span class="info-box-icon bg-infobox-action">';
3129 $return .= img_picto('', $this->picto);
3130 $return .= '</span>';
3131 $return .= '<div class="info-box-content">';
3132 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . $this->getNomUrl(1) . '</span>';
3133 if ($selected >= 0) {
3134 $return .= '<input id="cb' . $this->id . '" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="' . $this->id . '"' . ($selected ? ' checked="checked"' : '') . '>';
3135 }
3136 /*
3137 if (isset($this->date_trans)) {
3138 $return .= '<br><span class="opacitymedium">' . $langs->trans("TransData") . '</span> : <span class="info-box-label">' . dol_print_date($this->db->jdate($this->date_tans), 'day') . '</span>';
3139 }
3140 if (isset($this->date_credit)) {
3141 $return .= '<br><span class="opacitymedium">' . $langs->trans("CreditDate") . '</span> : <span class="info-box-label">' . dol_print_date($this->db->jdate($this->date_credit), 'day') . '</span>';
3142 }
3143 if (isset($this->date_echeance)) {
3144 $return .= '<br><span class="opacitymedium">' . $langs->trans("Date") . '</span> : <span class="info-box-label">' . dol_print_date($this->db->jdate($this->date_echeance), 'day') . '</span>';
3145 }
3146 */
3147 if (isset($this->amount)) {
3148 $return .= '<br><span class="opacitymedium">' . $langs->trans("Amount") . '</span> : <span class="amount">' . price($this->amount) . '</span>';
3149 }
3150 $return .= '<br><div class="info-box-status">' . $this->getLibStatut(3) . '</div>';
3151 $return .= '</div>';
3152 $return .= '</div>';
3153 $return .= '</div>';
3154 return $return;
3155 }
3156
3163 {
3164 if (!empty($this->id)) {
3165 $id = $this->id;
3166 } else {
3167 return 0;
3168 }
3169 $sql = "SELECT COUNT(*) AS nb FROM " . MAIN_DB_PREFIX . "prelevement_lignes";
3170 $sql .= " WHERE fk_prelevement_bons = " . ((int) $id);
3171 $sql .= " AND fk_soc = 0"; // fk_soc can't be NULL
3172 $sql .= " AND fk_user IS NOT NULL";
3173
3174 $num = 0;
3175 $resql = $this->db->query($sql);
3176 if ($resql) {
3177 $obj = $this->db->fetch_object($resql);
3178 $num = $obj->nb;
3179 } else {
3180 dol_print_error($this->db);
3181 }
3182 if ($num > 0) {
3183 return 1;
3184 }
3185
3186 return 0;
3187 }
3188}
checkIbanForAccount($account=null, $ibantocheck=null)
Check IBAN number information for a bank account.
Definition bank.lib.php:390
checkSwiftForAccount($account=null, $swift=null)
Check SWIFT information for a bank account.
Definition bank.lib.php:369
$object ref
Definition info.php:90
Class to manage bank accounts.
Class to manage withdrawal receipts.
addWithdrawDetail($invoice_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key, $type='debit-order', $sourcetype='', $bic='', $iban='', $rum='', $id_prelevement_demande=0)
Add invoice to withdrawal.
load_board($user, $mode)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
SommeAPrelever($mode='direct-debit', $type='')
Returns amount waiting for direct debit payment or credit transfer payment.
static buildRumNumber($row_code_client, $row_datec, $row_drum)
Generate dynamically a RUM number for a customer bank account.
EnregEmetteur($type='direct-debit')
Write sender of request (me).
checkIfSalaryBonPrelevement()
Check if is bon prelevement for salary invoice.
EnregTotal($total)
Write end.
NbFactureAPrelever($type='direct-debit', $forsalary=0)
Get number of invoices to pay.
fetch($rowid, $ref='')
Get object and lines from database.
addline(&$line_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key, $sourcetype='', $bic='', $iban='', $rum='', $id_prelevement_demande=0)
Add line to withdrawal.
getListInvoices($amounts=0, $type='')
Get invoice or salary list (with amount or not)
deleteNotificationById($rowid)
Delete a notification def by id.
__construct($db)
Constructor.
EnregDestinataire($rowid, $client_nom, $rib_banque, $rib_guichet, $rib_number, $amount, $ref, $facid, $rib_dom='', $type='direct-debit')
Write recipient of request (customer)
getKanbanView($option='', $arraydata=null)
Return clickable link of object (with eventually picto)
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Returns clickable name (with picto)
LibStatut($status, $mode=0)
Return status label for a status.
update(User $user, $notrigger=0)
Update object into database.
set_infotrans($user, $date, $method)
Set withdrawal to transmitted status.
generate(string $format='FRST', int $executiondate=0, string $type='direct-debit', int $fk_bank_account=0, int $forsalary=0, int $thirdpartyBANId=0)
Generate a direct debit or credit transfer file.
getErrorString($error)
Return error string.
EnregEmetteurSEPA($configuration, $ladate, $nombre, $total, $CrLf='\n', $format='FRST', $type='direct-debit', $fk_bank_account=0)
Write sender of request (me).
set_infocredit($user, $date, $type='')
Set direct debit or credit transfer order to "paid" status.
getLibStatut($mode=0)
Return status label of object.
EnregDestinataireSEPA($row_code_client, $row_nom, $row_address, $row_zip, $row_town, $row_country_code, $row_cb, $row_cg, $row_cc, $row_somme, $row_ref, $row_idfac, $row_iban, $row_bic, $row_datec, $row_drum, $row_rum, $type='direct-debit', $row_comment='')
Write recipient (thirdparty concerned by request)
addNotification($db, $user, $action)
Add a notification.
nbOfInvoiceToPay($mode='direct-debit', $type='')
Get number of invoices waiting for payment.
deleteNotification($user, $action)
Delete a notification.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
updateCommon(User $user, $notrigger=0)
Update object into database.
Class to manage bank accounts description of third parties.
Class to manage suppliers invoices.
Class to manage invoices.
const STATUS_VALIDATED
Validated (need to be paid)
Class to manage hooks.
Class to manage payments for supplier invoices.
Class to manage payments of customer invoices.
Class to manage payments of salaries.
Class to manage salary payments.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:169
global $mysoc
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
dol_now($mode='gmt')
Return date for now.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '...' if string larger than length.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
dolBECalculateStructuredCommunication($invoice_number, $invoice_type)
Calculate Structured Communication / BE Bank payment reference number.
print $langs trans('Date')." left Ref Label right Qty right Price right TotalHT right TotalTTC right right right right right right right right right centpercent right TotalHT right n right VAT right n right TotalVAT right n No sujeto a RE IRPF right TotalLT1 right n right TotalLT2 right n right TotalTTC right n takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency right TotalTTC takeposcustomercurrency right takeposcustomercurrency n right Paid right PaymentTypeShortLIQ right SELECT p pos_change as p datep as p p num_paiement as f pf amount as amount
Definition receipt.php:494
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition repair.php:137
dolDecrypt($chain, $key='', $patterntotest='')
Decode a string with a symmetric encryption.