dolibarr 23.0.3
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-2025 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
167
207 // BEGIN MODULEBUILDER PROPERTIES
211 public $fields = array(
212 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'position' => 10, 'notnull' => 1, 'visible' => 0,),
213 'ref' => array('type' => 'varchar(12)', 'label' => 'Ref', 'enabled' => 1, 'position' => 15, 'notnull' => 0, 'visible' => -1, 'csslist' => 'tdoverflowmax150', 'showoncombobox' => 1,),
214 'datec' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'position' => 25, 'notnull' => 0, 'visible' => -1,),
215 'amount' => array('type' => 'double(24,8)', 'label' => 'Amount', 'enabled' => 1, 'position' => 30, 'notnull' => 0, 'visible' => -1,),
216 'statut' => array('type' => 'smallint(6)', 'label' => 'Statut', 'enabled' => 1, 'position' => 500, 'notnull' => 0, 'visible' => -1, 'arrayofkeyval' => array(0 => 'Wait', 1 => 'Transfered', 2 => 'Credited')),
217 'credite' => array('type' => 'smallint(6)', 'label' => 'Credite', 'enabled' => 1, 'position' => 40, 'notnull' => 0, 'visible' => -1,),
218 'note' => array('type' => 'text', 'label' => 'Note', 'enabled' => 1, 'position' => 45, 'notnull' => 0, 'visible' => -1,),
219 'date_trans' => array('type' => 'datetime', 'label' => 'Datetrans', 'enabled' => 1, 'position' => 50, 'notnull' => 0, 'visible' => -1,),
220 'method_trans' => array('type' => 'smallint(6)', 'label' => 'Methodtrans', 'enabled' => 1, 'position' => 55, 'notnull' => 0, 'visible' => -1,),
221 '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',),
222 'date_credit' => array('type' => 'datetime', 'label' => 'Datecredit', 'enabled' => 1, 'position' => 65, 'notnull' => 0, 'visible' => -1,),
223 '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',),
224 'type' => array('type' => 'varchar(16)', 'label' => 'Type', 'enabled' => 1, 'position' => 75, 'notnull' => 0, 'visible' => -1,),
225 'fk_bank_account' => array('type' => 'integer', 'label' => 'Fkbankaccount', 'enabled' => 1, 'position' => 80, 'notnull' => 0, 'visible' => -1, 'css' => 'maxwidth500 widthcentpercentminusxx',),
226 );
230 public $rowid;
234 public $ref;
238 public $datec;
239
243 public $amount;
244
249 public $statut;
253 public $status;
254
258 public $credite;
262 public $note;
263
267 public $date_trans;
271 public $method_trans;
275 public $fk_user_trans;
279 public $date_credit;
283 public $fk_user_credit;
287 public $type;
291 public $fk_bank_account;
292 // END MODULEBUILDER PROPERTIES
293
294
295
301 public function __construct($db)
302 {
303 $this->db = $db;
304
305 $this->filename = '';
306
307 $this->date_echeance = dol_now();
308 $this->raison_sociale = "";
309 $this->reference_remise = "";
310
311 $this->emetteur_code_guichet = "";
312 $this->emetteur_numero_compte = "";
313 $this->emetteur_code_banque = "";
314 $this->emetteur_number_key = "";
315 $this->sepa_xml_pti_in_ctti = false;
316
317 $this->emetteur_iban = "";
318 $this->emetteur_bic = "";
319 $this->emetteur_ics = "";
320
321 $this->factures = array();
322
323 $this->methodes_trans = array(0 => 'Internet', 2 => 'Email', 3 => 'Api');
324
325 $this->fetched = 0;
326 }
327
328 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
347 public function AddFacture($invoice_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key, $type = 'debit-order', $sourcetype = '', $bic = '', $iban = '', $rum = '')
348 {
349 // phpcs:enable
350 $result = 0;
351 $line_id = 0;
352
353 // Add lines into prelevement_lignes for tracking. The ID of line inserted is returned into $line_id.
354 $result = $this->addline($line_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key, $sourcetype, $bic, $iban, $rum);
355
356
357 if ($result == 0) {
358 if ($line_id > 0) {
359 $sql = "INSERT INTO " . MAIN_DB_PREFIX . "prelevement (";
360 if ($type != 'bank-transfer') {
361 $sql .= "fk_facture";
362 } else {
363 if ($sourcetype == 'salary') {
364 $sql .= "fk_salary";
365 } else {
366 $sql .= "fk_facture_fourn";
367 }
368 }
369 $sql .= ",fk_prelevement_lignes";
370 $sql .= ") VALUES (";
371 $sql .= ((int) $invoice_id);
372 $sql .= ", " . ((int) $line_id);
373 $sql .= ")";
374
375 if ($this->db->query($sql)) {
376 $result = 0;
377 } else {
378 $result = -1;
379 $this->errors[] = get_class($this) . "::AddFacture " . $this->db->lasterror;
380 dol_syslog(get_class($this) . "::AddFacture Error $result");
381 }
382 } else {
383 $result = -2;
384 $this->errors[] = get_class($this) . "::AddFacture linedid Empty";
385 dol_syslog(get_class($this) . "::AddFacture Error $result");
386 }
387 } else {
388 $result = -3;
389 dol_syslog(get_class($this) . "::AddFacture Error $result");
390 }
391
392 return $result;
393 }
394
412 public function addline(&$line_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key, $sourcetype = '', $bic = '', $iban = '', $rum = '')
413 {
414 $result = -1;
415 $concat = getDolGlobalInt('MAIN_MODULE_PRELEVEMENT_CONCAT'); // ??? what is this for. Seems not used.
416
417 if ($concat == 1) {
418 /*
419 * We aggregate the lines
420 */
421 $sql = "SELECT rowid";
422 $sql .= " FROM " . MAIN_DB_PREFIX . "prelevement_lignes";
423 $sql .= " WHERE fk_prelevement_bons = " . ((int) $this->id);
424 if ($sourcetype == 'salary') {
425 $sql .= " AND fk_soc = " . ((int) $client_id);
426 } else {
427 $sql .= " AND fk_user = " . ((int) $client_id);
428 }
429 $sql .= " AND code_banque = '" . $this->db->escape($code_banque) . "'";
430 $sql .= " AND code_guichet = '" . $this->db->escape($code_guichet) . "'";
431 $sql .= " AND number = '" . $this->db->escape($number) . "'";
432
433 $resql = $this->db->query($sql);
434 if ($resql) {
435 $num = $this->db->num_rows($resql);
436 } else {
437 $result = -1;
438 }
439 } else {
440 /*
441 * No aggregate, use 1 line per invoice/salary to pay
442 */
443 $sql = "INSERT INTO " . MAIN_DB_PREFIX . "prelevement_lignes (";
444 $sql .= "fk_prelevement_bons";
445 $sql .= ", fk_soc";
446 $sql .= ", client_nom";
447 $sql .= ", amount";
448 $sql .= ", bic";
449 $sql .= ", iban";
450 $sql .= ", rum";
451 $sql .= ($sourcetype == 'salary' ? ", fk_user" : "");
452 $sql .= ") VALUES (";
453 $sql .= $this->id;
454 $sql .= ", " . (($sourcetype != 'salary') ? ((int) $client_id) : "0"); // fk_soc can't be null
455 $sql .= ", '" . $this->db->escape($client_nom) . "'";
456 $sql .= ", " . ((float) price2num($amount));
457 $sql .= ", '" . $this->db->escape($bic) . "'";
458 $sql .= ", '" . $this->db->escape($iban) . "'";
459 $sql .= ", '" . $this->db->escape($rum) . "'";
460 $sql .= (($sourcetype == 'salary') ? ", " . ((int) $client_id) : '');
461 $sql .= ")";
462 if ($this->db->query($sql)) {
463 $line_id = $this->db->last_insert_id(MAIN_DB_PREFIX . "prelevement_lignes");
464 $result = 0;
465 } else {
466 $this->errors[] = get_class($this) . "::addline Error -2 " . $this->db->lasterror;
467 dol_syslog(get_class($this) . "::addline Error -2");
468 $result = -2;
469 }
470 }
471
472 return $result;
473 }
474
481 public function getErrorString($error)
482 {
483 global $langs;
484
485 $errors = array();
486
487 $errors[1027] = $langs->trans("DateInvalid");
488
489 return $errors[abs($error)];
490 }
491
499 public function fetch($rowid, $ref = '')
500 {
501 $sql = "SELECT p.rowid, p.ref, p.amount, p.note";
502 $sql .= ", p.datec as dc";
503 $sql .= ", p.date_trans as date_trans";
504 $sql .= ", p.method_trans, p.fk_user_trans";
505 $sql .= ", p.date_credit as date_credit";
506 $sql .= ", p.fk_user_credit";
507 $sql .= ", p.type";
508 $sql .= ", p.fk_bank_account";
509 $sql .= ", p.statut as status";
510 $sql .= " FROM " . MAIN_DB_PREFIX . "prelevement_bons as p";
511 $sql .= " WHERE p.entity IN (" . getEntity('invoice') . ")";
512 if ($rowid > 0) {
513 $sql .= " AND p.rowid = " . ((int) $rowid);
514 } else {
515 $sql .= " AND p.ref = '" . $this->db->escape($ref) . "'";
516 }
517
518 dol_syslog(get_class($this) . "::fetch", LOG_DEBUG);
519 $result = $this->db->query($sql);
520 if ($result) {
521 if ($this->db->num_rows($result)) {
522 $obj = $this->db->fetch_object($result);
523
524 $this->id = $obj->rowid;
525 $this->ref = $obj->ref;
526 $this->amount = $obj->amount;
527 $this->note = $obj->note;
528 $this->datec = $this->db->jdate($obj->dc);
529
530 $this->date_trans = $this->db->jdate($obj->date_trans);
531 $this->method_trans = $obj->method_trans;
532 $this->user_trans = $obj->fk_user_trans;
533
534 $this->date_credit = $this->db->jdate($obj->date_credit);
535 $this->user_credit = $obj->fk_user_credit;
536
537 $this->type = $obj->type;
538 $this->fk_bank_account = $obj->fk_bank_account;
539
540 $this->status = $obj->status;
541 if (empty($this->status)) { // Value is sometimes null in database
542 $this->status = 0;
543 }
544 $this->statut = $this->status; // For backward compatibility
545
546 $this->fetched = 1;
547
548 return 1;
549 } else {
550 dol_syslog(get_class($this) . "::Fetch no record found");
551 return 0;
552 }
553 } else {
554 return -1;
555 }
556 }
557
565 public function update(User $user, $notrigger = 0)
566 {
567 return $this->updateCommon($user, $notrigger);
568 }
569
570 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
580 public function set_infocredit($user, $date, $type = '')
581 {
582 // phpcs:enable
583 global $conf, $langs;
584
585 $error = 0;
586
587 if ($this->fetched == 1) {
588 if ($date < $this->date_trans) {
589 $langs->load("errors");
590 $this->error = $langs->trans('ErrorDateOfMovementLowerThanDateOfFileTransmission');
591 dol_syslog("bon-prelevment::set_infocredit 1027 " . $this->error);
592 return -1027;
593 }
594
595 $this->db->begin();
596
597 $sql = " UPDATE " . MAIN_DB_PREFIX . "prelevement_bons";
598 $sql .= " SET fk_user_credit = " . ((int) $user->id);
599 $sql .= ", statut = " . self::STATUS_CREDITED;
600 $sql .= ", date_credit = '" . $this->db->idate($date) . "'";
601 $sql .= " WHERE rowid = " . ((int) $this->id);
602 $sql .= " AND entity = " . ((int) $conf->entity);
603 $sql .= " AND statut = " . self::STATUS_TRANSFERED;
604
605 $resql = $this->db->query($sql);
606 if ($resql) {
607 $langs->load('withdrawals');
608 $subject = $langs->trans("InfoCreditSubject", $this->ref);
609 $message = $langs->trans("InfoCreditMessage", $this->ref, dol_print_date($date, 'dayhour'));
610
611 // Add payment of withdrawal into bank
612 $fk_bank_account = $this->fk_bank_account;
613 if (empty($fk_bank_account)) {
614 $fk_bank_account = ($this->type == 'bank-transfer' ? getDolGlobalInt('PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT') : getDolGlobalInt('PRELEVEMENT_ID_BANKACCOUNT'));
615 }
616
617 $amounts = array();
618 $amountsperthirdparty = array();
619
620 $facs = $this->getListInvoices(1, $type);
621 if ($this->error) {
622 $error++;
623 }
624
625 // Loop on each invoice or salary.
626 // $facs should be array(0=>id, 1=>amount requested)
627 $num = count($facs);
628 for ($i = 0; $i < $num; $i++) {
629 if ($this->type == 'bank-transfer') {
630 if ($type == 'salary') {
631 $fac = new Salary($this->db);
632 } else {
633 $fac = new FactureFournisseur($this->db);
634 }
635 } else {
636 $fac = new Facture($this->db);
637 }
638
639 $result = $fac->fetch($facs[$i][0]);
640
641 $amounts[$fac->id] = $facs[$i][1];
642 if ($this->type == 'bank-transfer') {
643 if ($type == 'salary') {
644 $amountsperthirdparty[$fac->fk_user][$fac->id] = $facs[$i][1];
645 } else {
646 $amountsperthirdparty[$fac->socid][$fac->id] = $facs[$i][1];
647 }
648 } else {
649 $amountsperthirdparty[$fac->socid][$fac->id] = $facs[$i][1];
650 }
651
652 $totalpaid = $fac->getSommePaiement();
653 $totalcreditnotes = 0;
654 if (method_exists($fac, 'getSumCreditNotesUsed')) {
655 $totalcreditnotes = $fac->getSumCreditNotesUsed();
656 }
657 $totaldeposits = 0;
658 if (method_exists($fac, 'getSumDepositsUsed')) {
659 $totaldeposits = $fac->getSumDepositsUsed();
660 }
661 $alreadypayed = $totalpaid + $totalcreditnotes + $totaldeposits;
662
663 // Set the main document to pay with status Paid.
664 // @TODO Move this after creation of payments done after
665 $amountofdocument = $fac->total_ttc;
666 if ($type == 'salary') {
667 $amountofdocument = $fac->amount;
668 }
669 if (price2num($alreadypayed + $facs[$i][1], 'MT') == price2num($amountofdocument, 'MT')) {
670 $result = $fac->setPaid($user);
671 if ($result < 0) {
672 $this->error = $fac->error;
673 $this->errors = $fac->errors;
674 }
675 }
676 }
677
678 // Make one payment per customer or employee
679 foreach ($amountsperthirdparty as $thirdpartyid => $cursoramounts) {
680 if ($this->type == 'bank-transfer') {
681 if ($type == 'salary') {
682 $paiement = new PaymentSalary($this->db);
683 } else {
684 $paiement = new PaiementFourn($this->db);
685 }
686 } else {
687 $paiement = new Paiement($this->db);
688 }
689 $paiement->datepaye = $date;
690 $paiement->amounts = $cursoramounts; // Array with detail of dispatching of payments for each invoice
691
692 if ($this->type == 'bank-transfer') {
693 if ($type == 'salary') {
694 $paiement->datep = $date;
695
696 $paiement->paiementid = 2;
697 $paiement->fk_typepayment = 2;
698 $paiement->paiementcode = 'VIR';
699 } else {
700 $paiement->paiementid = 2;
701 $paiement->paiementcode = 'VIR';
702 }
703 } else {
704 $paiement->paiementid = 3;
705 $paiement->paiementcode = 'PRE';
706 }
707
708 $paiement->num_payment = $this->ref; // Set ref of direct debit note
709 $paiement->id_prelevement = $this->id;
710
711 $result = $paiement->create($user, 1); // This use ->paiementid, that is ID of payment mode. closepaidinvoices=1 to convert deposit invoice to available credit
712
713 if ($result < 0) {
714 $error++;
715 $this->error = $paiement->error;
716 $this->errors = $paiement->errors;
717 dol_syslog(get_class($this) . "::set_infocredit AddPayment Error " . $this->error);
718 } else {
719 if ($this->type == 'bank-transfer') {
720 if ($type == 'salary') {
721 $modeforaddpayment = 'payment_salary';
722 $labelforaddpayment = '(SalaryPayment)';
723 $addbankurl = 'credit-transfer';
724 } else {
725 $modeforaddpayment = 'payment_supplier';
726 $labelforaddpayment = '(SupplierInvoicePayment)';
727 $addbankurl = 'credit-transfer';
728 }
729 } else {
730 $modeforaddpayment = 'payment';
731 $labelforaddpayment = '(CustomerInvoicePayment)';
732 $addbankurl = 'direct-debit'; // = 'directdebit'
733 }
734
735
736 if ($paiement instanceof PaymentSalary) {
737 // Only 6 arguments for PaymentSalary
738 $result = $paiement->addPaymentToBank($user, $modeforaddpayment, $labelforaddpayment, $fk_bank_account, '', '');
739 } else {
740 $result = $paiement->addPaymentToBank($user, $modeforaddpayment, $labelforaddpayment, $fk_bank_account, '', '', 0, '', $addbankurl);
741 }
742
743 if ($result < 0) {
744 $error++;
745 $this->error = $paiement->error;
746 $this->errors = $paiement->errors;
747 dol_syslog(get_class($this) . "::set_infocredit AddPaymentToBank Error " . $this->error);
748 }
749 }
750 }
751
752 // Update withdrawal line
753 // TODO: Translate to ligneprelevement.class.php
754 if (!$error) {
755 $sql = " UPDATE " . MAIN_DB_PREFIX . "prelevement_lignes";
756 $sql .= " SET statut = 2";
757 $sql .= " WHERE fk_prelevement_bons = " . ((int) $this->id);
758
759 if (!$this->db->query($sql)) {
760 dol_syslog(get_class($this) . "::set_infocredit Update lines Error");
761 $error++;
762 }
763 }
764 } else {
765 $this->error = $this->db->lasterror();
766 dol_syslog(get_class($this) . "::set_infocredit Update Bons Error");
767 $error++;
768 }
769
770 // End of procedure
771 if ($error == 0) {
772 $this->date_credit = $date; // date credit or debit
773 $this->statut = self::STATUS_CREDITED;
774 $this->status = self::STATUS_CREDITED;
775
776 $this->db->commit();
777 return 0;
778 } else {
779 $this->db->rollback();
780 return -1;
781 }
782 } else {
783 return -1026;
784 }
785 }
786
787 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
796 public function set_infotrans($user, $date, $method)
797 {
798 // phpcs:enable
799 global $conf, $langs;
800
801 $error = 0;
802
803 dol_syslog(get_class($this) . "::set_infotrans Start", LOG_INFO);
804
805 if ($this->db->begin()) {
806 $sql = "UPDATE " . MAIN_DB_PREFIX . "prelevement_bons ";
807 $sql .= " SET fk_user_trans = " . $user->id;
808 $sql .= " , date_trans = '" . $this->db->idate($date) . "'";
809 $sql .= " , method_trans = " . ((int) $method);
810 $sql .= " , statut = " . self::STATUS_TRANSFERED;
811 $sql .= " WHERE rowid = " . ((int) $this->id);
812 $sql .= " AND entity = " . ((int) $conf->entity);
813 $sql .= " AND statut = " . self::STATUS_DRAFT;
814
815 if ($this->db->query($sql)) {
816 $this->method_trans = $method;
817 $langs->load('withdrawals');
818 $subject = $langs->trans("InfoTransSubject", $this->ref);
819 $message = $langs->trans("InfoTransMessage", $this->ref, dolGetFirstLastname($user->firstname, $user->lastname));
820 $message .= $langs->trans("InfoTransData", price($this->amount), $this->methodes_trans[$this->method_trans], dol_print_date($date, 'day'));
821
822 // TODO Call trigger to create a notification using notification module
823 } else {
824 $error++;
825 }
826
827 if ($error == 0) {
828 $this->date_trans = $date;
829 $this->statut = self::STATUS_TRANSFERED;
830 $this->status = self::STATUS_TRANSFERED;
831 $this->user_trans = $user->id;
832
833 $this->db->commit();
834
835 return 0;
836 } else {
837 $this->db->rollback();
838 dol_syslog(get_class($this) . "::set_infotrans ROLLBACK", LOG_ERR);
839
840 return -1;
841 }
842 } else {
843 dol_syslog(get_class($this) . "::set_infotrans Ouverture transaction SQL impossible", LOG_CRIT);
844 return -2;
845 }
846 }
847
856 private function getListInvoices($amounts = 0, $type = '')
857 {
858 global $conf;
859
860 $arr = array();
861
862 dol_syslog(get_class($this) . "::getListInvoices");
863
864 // Returns all invoices presented within same order
865 $sql = "SELECT ";
866 if ($this->type == 'bank-transfer') {
867 if ($type == 'salary') {
868 $sql .= " p.fk_salary";
869 } else {
870 $sql .= " p.fk_facture_fourn";
871 }
872 } else {
873 $sql .= " p.fk_facture";
874 }
875 if ($amounts) {
876 $sql .= ", SUM(pl.amount)";
877 }
878 $sql .= " FROM " . MAIN_DB_PREFIX . "prelevement_bons as pb,";
879 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
880 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p";
881 $sql .= " WHERE p.fk_prelevement_lignes = pl.rowid";
882 $sql .= " AND pl.fk_prelevement_bons = pb.rowid";
883 $sql .= " AND pb.rowid = " . ((int) $this->id);
884 $sql .= " AND pb.entity = " . ((int) $conf->entity);
885 if ($amounts) {
886 if ($this->type == 'bank-transfer') {
887 if ($type == 'salary') {
888 $sql .= " GROUP BY p.fk_salary";
889 } else {
890 $sql .= " GROUP BY p.fk_facture_fourn";
891 }
892 } else {
893 $sql .= " GROUP BY p.fk_facture";
894 }
895 }
896
897 $resql = $this->db->query($sql);
898 if ($resql) {
899 $num = $this->db->num_rows($resql);
900
901 if ($num) {
902 $i = 0;
903 while ($i < $num) {
904 $row = $this->db->fetch_row($resql);
905 if (!$amounts) {
906 $arr[$i] = $row[0];
907 } else {
908 $arr[$i] = array(
909 $row[0],
910 $row[1]
911 );
912 }
913 $i++;
914 }
915 }
916 $this->db->free($resql);
917 } else {
918 $this->error = $this->db->lasterror();
919 }
920
921 return $arr;
922 }
923
924 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
932 public function SommeAPrelever($mode = 'direct-debit', $type = '')
933 {
934 // phpcs:enable
935 $sql = "SELECT sum(pd.amount) as nb";
936 if ($type !== 'salary') {
937 if ($mode != 'bank-transfer') {
938 $sql .= " FROM " . MAIN_DB_PREFIX . "facture as f,";
939 } else {
940 $sql .= " FROM " . MAIN_DB_PREFIX . "facture_fourn as f,";
941 }
942 } else {
943 $sql .= " FROM " . MAIN_DB_PREFIX . "salary as s,";
944 }
945 $sql .= " " . MAIN_DB_PREFIX . "prelevement_demande as pd";
946 $sql .= ($type !== 'salary' ? " WHERE f.entity IN (" . getEntity('invoice') . ")" : " WHERE s.entity IN (" . getEntity('salary') . ")");
947 if (!getDolGlobalString('WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS')) {
948 $sql .= ($type !== 'salary' ? " AND f.fk_statut = " . Facture::STATUS_VALIDATED : " AND s.paye = " . Salary::STATUS_UNPAID);
949 }
950 if ($type !== 'salary') {
951 if ($mode != 'bank-transfer') {
952 $sql .= " AND f.rowid = pd.fk_facture";
953 } else {
954 $sql .= " AND f.rowid = pd.fk_facture_fourn";
955 }
956 } else {
957 $sql .= " AND s.rowid = pd.fk_salary";
958 }
959 $sql .= ($type !== 'salary' ? " AND f.paye = 0" : "");
960 $sql .= " AND pd.traite = 0";
961 $sql .= " AND pd.ext_payment_id IS NULL";
962 $sql .= ($type !== 'salary' ? " AND f.total_ttc > 0" : "");
963
964 $resql = $this->db->query($sql);
965 if ($resql) {
966 $obj = $this->db->fetch_object($resql);
967
968 $this->db->free($resql);
969
970 return $obj->nb;
971 } else {
972 $error = 1;
973 dol_syslog(get_class($this) . "::SommeAPrelever Erreur -1");
974 dol_syslog($this->db->error());
975
976 return -1;
977 }
978 }
979
987 public function nbOfInvoiceToPay($mode = 'direct-debit', $type = '')
988 {
989 if ($type === 'salary') {
990 return $this->NbFactureAPrelever($mode, 1);
991 } else {
992 return $this->NbFactureAPrelever($mode);
993 }
994 }
995
996 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1004 public function NbFactureAPrelever($type = 'direct-debit', $forsalary = 0)
1005 {
1006 // phpcs:enable
1007 if ($forsalary == 1) {
1008 $sql = "SELECT count(s.rowid) as nb";
1009 $sql .= " FROM " . MAIN_DB_PREFIX . "salary as s";
1010 } else {
1011 $sql = "SELECT count(f.rowid) as nb";
1012
1013 if ($type == 'bank-transfer') {
1014 $sql .= " FROM " . MAIN_DB_PREFIX . "facture_fourn as f";
1015 } else {
1016 $sql .= " FROM " . MAIN_DB_PREFIX . "facture as f";
1017 }
1018 }
1019 $sql .= ", " . MAIN_DB_PREFIX . "prelevement_demande as pd";
1020 if ($forsalary == 1) {
1021 $sql .= " WHERE s.entity IN (" . getEntity('invoice') . ")";
1022 if (!getDolGlobalString('WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS')) {
1023 $sql .= " AND s.paye = 0";
1024 }
1025 } else {
1026 $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
1027 if (!getDolGlobalString('WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS')) {
1028 $sql .= " AND f.fk_statut = " . Facture::STATUS_VALIDATED;
1029 }
1030 }
1031 if ($forsalary == 1) {
1032 $sql .= " AND s.rowid = pd.fk_salary";
1033 } else {
1034 if ($type == 'bank-transfer') {
1035 $sql .= " AND f.rowid = pd.fk_facture_fourn";
1036 } else {
1037 $sql .= " AND f.rowid = pd.fk_facture";
1038 }
1039 }
1040 $sql .= " AND pd.traite = 0";
1041 $sql .= " AND pd.ext_payment_id IS NULL";
1042 if (!$forsalary == 1) {
1043 $sql .= " AND f.total_ttc > 0";
1044 } else {
1045 $sql .= " AND s.paye = 0";
1046 }
1047
1048 dol_syslog(get_class($this) . "::NbFactureAPrelever");
1049 $resql = $this->db->query($sql);
1050
1051 if ($resql) {
1052 $obj = $this->db->fetch_object($resql);
1053 $this->db->free($resql);
1054
1055 return $obj->nb;
1056 } else {
1057 $this->error = get_class($this) . "::NbFactureAPrelever Erreur -1 sql=" . $this->db->error();
1058 return -1;
1059 }
1060 }
1061
1062
1063 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1084 public function create($banque = '', $agence = '', $mode = 'real', $format = 'ALL', $executiondate = 0, $notrigger = 0, $type = 'direct-debit', $did = 0, $fk_bank_account = 0, $sourcetype = 'invoice')
1085 {
1086 // phpcs:enable
1087 global $conf, $langs, $user;
1088
1089 dol_syslog(__METHOD__ . " Bank=".$banque." Office=".$agence." mode=".$mode." format=".$format." type=".$type." did=".$did." fk_bank_account=".$fk_bank_account." sourcetype=".$sourcetype, LOG_DEBUG);
1090
1091 require_once DOL_DOCUMENT_ROOT . "/compta/facture/class/facture.class.php";
1092 require_once DOL_DOCUMENT_ROOT . "/societe/class/societe.class.php";
1093
1094 // Check params
1095 if ($type != 'bank-transfer') {
1096 if (empty($format)) {
1097 $this->error = 'ErrorBadParametersForDirectDebitFileCreate';
1098 return -1;
1099 }
1100 }
1101
1102 // Clean params
1103 if (empty($fk_bank_account)) {
1104 $fk_bank_account = ($type == 'bank-transfer' ? getDolGlobalInt('PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT') : getDolGlobalInt('PRELEVEMENT_ID_BANKACCOUNT'));
1105 }
1106
1107 $error = 0;
1108 // Pre-store some values into variables to simplify following sql requests
1109 if ($sourcetype != 'salary') {
1110 $entities = $type != 'bank-transfer' ? getEntity('invoice', 1) : getEntity('supplier_invoice', 1); // Return alist of entities
1111 $sqlTable = $type != 'bank-transfer' ? "facture" : "facture_fourn";
1112 $socOrUser = 'fk_soc';
1113 $societeOrUser = 'societe';
1114 } else {
1115 $entities = getEntity('salary', 1); // Return a list of entities
1116 $sqlTable = 'salary';
1117 $socOrUser = 'fk_user';
1118 $societeOrUser = 'user';
1119 }
1120
1121 $thirdpartyBANId = 0;
1122
1123 // Check if there is an iban associated to the bank transfer request or if we take the default
1124 if ($did > 0) {
1125 $sql = "SELECT pd.fk_societe_rib";
1126 $sql .= " FROM " . $this->db->prefix() . "prelevement_demande as pd";
1127 $sql .= " WHERE pd.rowid = ".((int) $did);
1128
1129 $resql = $this->db->query($sql);
1130
1131 if (!$resql) {
1132 $this->error = $this->db->lasterror();
1133 dol_syslog(__METHOD__ . " Read fk_societe_rib error " . $this->db->lasterror(), LOG_ERR);
1134 return -1;
1135 }
1136
1137 $obj = $this->db->fetch_object($resql);
1138 if ($obj) {
1139 $thirdpartyBANId = $obj->fk_societe_rib;
1140
1141 dol_syslog(__METHOD__ . " Found an BAN ID to use: ".$thirdpartyBANId);
1142 }
1143
1144 $this->db->free($resql);
1145 }
1146
1147 $datetimeprev = dol_now('gmt');
1148 // Choice of the date of the execution direct debit
1149 if (!empty($executiondate)) {
1150 $datetimeprev = $executiondate;
1151 }
1152
1153 $month = dol_print_date($datetimeprev, "%m", 'gmt');
1154 $year = dol_print_date($datetimeprev, "%Y", 'gmt');
1155
1156 $this->invoice_in_error = array();
1157 $this->thirdparty_in_error = array();
1158
1159 // Read invoices
1160 $factures = array();
1161 $factures_prev = array();
1162 $factures_prev_id = array();
1163
1164 dol_syslog(__METHOD__ . " Read invoices/salaries for did=" . ((int) $did), LOG_DEBUG);
1165
1166 $sql = "SELECT f.rowid, pd.rowid as pfdrowid";
1167 $sql .= ", f.".$this->db->sanitize($socOrUser); // fk_soc or fk_user
1168 $sql .= ", pd.code_banque, pd.code_guichet, pd.number, pd.cle_rib";
1169 $sql .= ", pd.amount";
1170 if ($sourcetype != 'salary') {
1171 $sql .= ", s.nom as name";
1172 $sql .= ", f.ref";
1173 $sql .= ", sr.bic, sr.iban_prefix, sr.frstrecur, sr.default_rib, sr.rum";
1174 } else {
1175 $sql .= ", CONCAT(s.firstname, ' ', s.lastname) as name";
1176 $sql .= ", f.ref";
1177 $sql .= ", sr.bic, sr.iban_prefix, 'FRST' as frstrecur, sr.default_rib, '' as rum";
1178 }
1179 $sql .= ", pd.fk_societe_rib as soc_rib_id";
1180 $sql .= " FROM " . $this->db->prefix() . $sqlTable . " as f"; // f is salary, facture or facture_fourn
1181 $sql .= " LEFT JOIN " . $this->db->prefix() . "prelevement_demande as pd ON f.rowid = pd.fk_".$this->db->sanitize($sqlTable);
1182 $sql .= " LEFT JOIN " . $this->db->prefix() . $this->db->sanitize($societeOrUser)." as s ON s.rowid = f.".$this->db->sanitize($socOrUser);
1183 $sql .= " LEFT JOIN " . $this->db->prefix() . $this->db->sanitize($societeOrUser."_rib")." as sr ON s.rowid = sr.".$this->db->sanitize($socOrUser);
1184 if ($sourcetype != 'salary') {
1185 if (!empty($thirdpartyBANId)) {
1186 $sql .= " AND sr.rowid = " . ((int) $thirdpartyBANId);
1187 } else {
1188 $sql .= " AND sr.default_rib = 1";
1189 }
1190 $sql .= " AND sr.type = 'ban'";
1191 } else {
1192 //$sql .= " AND sr.type = 'ban'"; // TODO Add AND sr.type = 'ban' for users too
1193 // TODO Add 'AND sr.default_rib = 1' in sourcetype salary too
1194 // Note: the column has been created in v21 in llx_user_rib and default to 0
1195 // 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.
1196 // Also it may be found for on thirdparty and not for the other.
1197 }
1198 $sql .= " WHERE f.entity IN (".$this->db->escape($entities).')';
1199 if ($sourcetype != 'salary') {
1200 $sql .= " AND f.fk_statut = ".Facture::STATUS_VALIDATED; // Invoice validated
1201 $sql .= " AND f.paye = 0";
1202 $sql .= " AND f.total_ttc > 0";
1203 /*if ($socid > 0) {
1204 $sql .= " AND f.fk_soc = ".((int) $socid);
1205 }*/
1206 } else {
1207 //$sql .= " AND f.fk_statut = 1"; // Invoice validated
1208 $sql .= " AND f.paye = 0";
1209 $sql .= " AND f.amount > 0";
1210 }
1211 $sql .= " AND pd.traite = 0";
1212 $sql .= " AND pd.ext_payment_id IS NULL";
1213 if ($did > 0) {
1214 $sql .= " AND pd.rowid = " . ((int) $did);
1215 }
1216
1217 $resql = $this->db->query($sql);
1218 if ($resql) {
1219 $num = $this->db->num_rows($resql);
1220 $i = 0;
1221
1222 while ($i < $num) {
1223 $row = $this->db->fetch_row($resql); // TODO Replace with fetch_object()
1224 '@phan-var-force array<int<0,12>,string> $row';
1227 // All fields:
1228 // 0=rowid, 1=pfdrowid, 2=$socOrUser, 3=code_banque, 4=code_guichet, 5=number, 6=key,
1229 // 7=amount, 8=name, 9=ref, 10=bic, 11=iban, 12=frstrecur, 13=default_rib, 14=rum, 15=soc_rib_id
1230 $factures[$i] = $row;
1231
1232 // Decode BAN
1233 $factures[$i][11] = dolDecrypt($factures[$i][11]);
1234
1235 if ($row[7] == 0) {
1236 $error++;
1237 dol_syslog(__METHOD__ . " Read invoices/salaries error Found a null amount", LOG_WARNING);
1238 $this->invoice_in_error[$row[0]] = "Error for invoice or salary id " . $row[0] . ", found a null amount";
1239 break;
1240 }
1241 $i++;
1242 }
1243
1244 $this->db->free($resql);
1245 dol_syslog(__METHOD__ . " Read invoices/salaries, " . $i . " invoices/salaries to withdraw", LOG_DEBUG);
1246 } else {
1247 $this->error = $this->db->lasterror();
1248 dol_syslog(__METHOD__ . " Read invoices/salaries error " . $this->db->lasterror(), LOG_ERR);
1249 return -1;
1250 }
1251
1252 if (!$error) {
1253 // Make some checks
1254 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1255 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
1256 require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php';
1257 require_once DOL_DOCUMENT_ROOT . '/core/lib/bank.lib.php';
1258
1259 $tmpsoc = new Societe($this->db);
1260 $tmpuser = new User($this->db);
1261
1262 // Check BAN
1263 $i = 0;
1264 dol_syslog(__METHOD__ . " Check BAN for each invoices or salaries", LOG_DEBUG);
1265
1266 if (count($factures) > 0) {
1267 foreach ($factures as $key => $fac) {
1268 // Check if $fac[8] s.nom is null
1269 if ($fac[8] != null) {
1270 if ($type != 'bank-transfer') {
1271 if ($format == 'FRST' && $fac[12] != 'FRST') {
1272 continue;
1273 }
1274 if ($format == 'RCUR' && $fac[12] != 'RCUR') {
1275 continue;
1276 }
1277 }
1278
1279 // If a bank account was forced on llx_prelevement_demande (the direct debit or credit transfer request),
1280 // we must use this oney,so we reload values from soc_rib_id
1281 if (!empty($fac[14])) {
1282 $bankaccount = new CompanyBankAccount($this->db);
1283 $bankaccount->fetch((int) $fac[15]);
1284 if ($bankaccount->id > 0) {
1285 $fac[3] = $bankaccount->code_banque;
1286 $fac[4] = $bankaccount->code_guichet;
1287 $fac[5] = $bankaccount->number;
1288 $fac[6] = $bankaccount->cle_rib;
1289 $fac[10] = $bankaccount->bic;
1290 $fac[11] = $bankaccount->iban;
1291 $fac[14] = $bankaccount->rum;
1292 //var_dump('fetch id='.(int) $fac[14].' => '.$fac[3].'-'.$fac[4].'-'.$fac[5].'-'.$fac[6].'-'.$fac[10]."-".$fac[11]."-".$fac[14]);
1293 }
1294 }
1295
1296 $bicinloop = $fac[10];
1297 $baninloop = $fac[11];
1298
1299 $verif = checkSwiftForAccount(null, $bicinloop);
1300 if ($verif || (empty($fac[10]) && getDolGlobalInt("WITHDRAWAL_WITHOUT_BIC"))) {
1301 dol_syslog(__METHOD__." now call checkIbanForAccount(null, ".$baninloop.")");
1302 $verif = checkIbanForAccount(null, $baninloop);
1303 }
1304
1305 if ($verif) {
1306 $factures_prev[$i] = $fac;
1307 /* second array necessary for BonPrelevement */
1308 $factures_prev_id[$i] = $fac[0];
1309 $i++;
1310 //dol_syslog(__METHOD__."::RIB is ok", LOG_DEBUG);
1311 } else {
1312 if ($type != 'bank-transfer') {
1313 $tmpsoc->id = (int) $fac[2];
1314 $tmpsoc->name = $fac[8];
1315 $invoice_url = "<a href='" . DOL_URL_ROOT . '/compta/facture/card.php?facid=' . $fac[0] . "'>" . $fac[9] . "</a>";
1316 $this->invoice_in_error[$fac[0]] = "Error on default bank number IBAN/BIC for invoice " . $invoice_url . " for thirdparty " . $tmpsoc->getNomUrl(0);
1317 $this->thirdparty_in_error[$tmpsoc->id] = "Error on default bank number IBAN/BIC for invoice " . $invoice_url . " for thirdparty " . $tmpsoc->getNomUrl(0);
1318 $error++;
1319 }
1320 if ($type == 'bank-transfer' && $sourcetype != 'salary') {
1321 $tmpsoc->id = (int) $fac[2];
1322 $tmpsoc->name = $fac[8];
1323 $invoice_url = "<a href='" . DOL_URL_ROOT . '/fourn/facture/card.php?facid=' . $fac[0] . "'>" . $fac[9] . "</a>";
1324 $this->invoice_in_error[$fac[0]] = "Error on default bank number IBAN/BIC for invoice " . $invoice_url . " for thirdparty " . $tmpsoc->getNomUrl(0);
1325 $this->thirdparty_in_error[$tmpsoc->id] = "Error on default bank number IBAN/BIC for invoice " . $invoice_url . " for thirdparty " . $tmpsoc->getNomUrl(0);
1326 $error++;
1327 }
1328 if ($type == 'bank-transfer' && $sourcetype == 'salary') {
1329 $tmpuser->id = (int) $fac[2];
1330 $tmpuser->firstname = $fac[8];
1331 $salary_url = "<a href='" . DOL_URL_ROOT . '/salaries/card.php?id=' . $fac[0] . "'>" . $fac[0] . "</a>";
1332 $this->invoice_in_error[$fac[0]] = "Error on default bank number IBAN/BIC for salary " . $salary_url . " for employee " . $tmpuser->getNomUrl(0);
1333 $this->thirdparty_in_error[$tmpuser->id] = "Error on default bank number IBAN/BIC for salary " . $salary_url . " for employee " . $tmpuser->getNomUrl(0);
1334 $error++;
1335 }
1336 dol_syslog(__METHOD__ . " Check BAN Error on default bank number IBAN/BIC reported by verif(): " . implode(', ', $fac), LOG_WARNING);
1337 }
1338 } else {
1339 dol_syslog(__METHOD__ . " Check BAN Failed to read company", LOG_WARNING);
1340 }
1341 /*
1342 } else {
1343 dol_syslog(__METHOD__." Check BAN Failed to read invoice", LOG_WARNING);
1344 }
1345 */
1346 }
1347 } else {
1348 dol_syslog(__METHOD__ . " Check BAN No invoice to process", LOG_WARNING);
1349 }
1350 }
1351
1352 $ok = 0;
1353
1354 // Withdraw invoices in factures_prev array
1355 $out = count($factures_prev) . " invoices or salaries will be included.";
1356 //print $out."\n";
1357 dol_syslog($out);
1358
1359 // Return warning
1360 /*$i=0;
1361 foreach ($this->thirdparty_in_error as $key => $val)
1362 {
1363 if ($i < 10) setEventMessages($val, null, 'warnings');
1364 else setEventMessages('More error were discarded...', null, 'warnings');
1365 $i++;
1366 }*/
1367
1368 if (count($factures_prev) > 0) {
1369 if ($mode == 'real') {
1370 $ok = 1;
1371 } else {
1372 print $langs->trans("ModeWarning"); // "Option for real mode was not set, we stop after this simulation\n";
1373 }
1374 }
1375 if ($ok) {
1376 /*
1377 * We are in real mode.
1378 * We create order and build file into disk
1379 */
1380 $this->db->begin();
1381
1382 $now = dol_now();
1383 $ref = '';
1384
1385 /*
1386 * Process order generation
1387 */
1388 if (!$error) {
1389 $ref = substr($year, -2) . $month;
1390
1391 $prefixt = "T";
1392
1393 // Get next free number for the ref of bon prelevement
1394 $sql = "SELECT SUBSTRING(ref, 6) AS refnumber"; // To suppress "TYYMM" from "TYYMMXXX"
1395 $sql .= " FROM " . MAIN_DB_PREFIX . "prelevement_bons";
1396 $sql .= " WHERE ref LIKE '" . $this->db->escape($prefixt . $ref) . "%'";
1397 $sql .= " AND entity = " . ((int) $conf->entity);
1398 $sql .= " ORDER BY LENGTH(ref) DESC, ref DESC";
1399 $sql .= " LIMIT 1";
1400
1401 dol_syslog(get_class($this) . " get next free number", LOG_DEBUG);
1402
1403 $resql = $this->db->query($sql);
1404
1405 if ($resql) {
1406 $row = $this->db->fetch_row($resql);
1407
1408 // Build the new ref
1409 $ref = $prefixt . $ref . sprintf("%03d", (intval($row[0]) + 1));
1410
1411 // $conf->abc->dir_output may be:
1412 // /home/ldestailleur/git/dolibarr_15.0/documents/abc/
1413 // or
1414 // /home/ldestailleur/git/dolibarr_15.0/documents/X/abc with X >= 2 with multicompany.
1415 if ($type != 'bank-transfer') {
1416 $dir = $conf->prelevement->dir_output . '/receipts';
1417 } else {
1418 $dir = $conf->paymentbybanktransfer->dir_output . '/receipts';
1419 }
1420 if (!is_dir($dir)) {
1421 dol_mkdir($dir);
1422 }
1423
1424 if (isModEnabled('multicompany')) {
1425 $labelentity = $conf->entity;
1426 $this->filename = $dir . '/' . $ref . '-' . $labelentity . '.xml';
1427 } else {
1428 $this->filename = $dir . '/' . $ref . '.xml';
1429 }
1430
1431 // Create withdraw order in database
1432 $sql = "INSERT INTO " . MAIN_DB_PREFIX . "prelevement_bons (";
1433 $sql .= "ref, entity, datec, type, fk_bank_account";
1434 $sql .= ") VALUES (";
1435 $sql .= "'" . $this->db->escape($ref) . "'";
1436 $sql .= ", " . ((int) $conf->entity);
1437 $sql .= ", '" . $this->db->idate($now) . "'";
1438 $sql .= ", '" . ($type == 'bank-transfer' ? 'bank-transfer' : 'debit-order') . "'";
1439 $sql .= ", " . ((int) $fk_bank_account);
1440 $sql .= ")";
1441
1442 $resql = $this->db->query($sql);
1443
1444 if ($resql) {
1445 $prev_id = $this->db->last_insert_id(MAIN_DB_PREFIX . "prelevement_bons");
1446 $this->id = $prev_id;
1447 $this->ref = $ref;
1448 } else {
1449 $error++;
1450 $this->errors[] = $this->db->lasterror();
1451 dol_syslog(__METHOD__ . " Create withdraw receipt " . $this->db->lasterror(), LOG_ERR);
1452 }
1453 } else {
1454 $error++;
1455 $this->errors[] = $this->db->lasterror();
1456 dol_syslog(__METHOD__ . " Get last withdraw receipt " . $this->db->lasterror(), LOG_ERR);
1457 }
1458 }
1459
1460 if (!$error) {
1461 dol_syslog(__METHOD__ . " Now loop on each document to insert them in llx_prelevement_demande");
1462
1463 // Add lines for the direct debit or crdit transfer
1464 if (count($factures_prev) > 0) {
1465 foreach ($factures_prev as $fac) { // Add a link in database for each invoice ro salary
1466 /*
1467 * Add standing order. This add record into llx_prelevement_lignes and llx_prelevement
1468 *
1469 * $fac[0] : invoice_id
1470 * $fac[1] : ???
1471 * $fac[2] : third party id
1472 * $fac[3] : banque
1473 * $fac[4] : guichet
1474 * $fac[5] : number
1475 * $fac[6] : cle rib
1476 * $fac[7] : amount
1477 * $fac[8] : client nom
1478 * $fac[9] : Invoice ref
1479 * $fac[10] : BIC
1480 * $fac[11] : IBAN
1481 * $fac[12] : frstrcur
1482 * $fac[13] : default_rib (0 or 1)
1483 * $fac[14] : rum
1484 * $fac[15] : soc_rib_id (id bank account preselected for direct debit or credit transfer)
1485 */
1486 $ri = $this->AddFacture(
1487 $fac[0],
1488 $fac[2],
1489 $fac[8],
1490 $fac[7],
1491 $fac[3],
1492 $fac[4],
1493 $fac[5],
1494 $fac[6],
1495 $type,
1496 $sourcetype,
1497 $fac[10],
1498 $fac[11],
1499 $fac[14]
1500 );
1501
1502 if ($ri != 0) {
1503 $error++;
1504 }
1505
1506 // Update invoice requests as done
1507 $sql = "UPDATE " . MAIN_DB_PREFIX . "prelevement_demande";
1508 $sql .= " SET traite = 1";
1509 $sql .= ", date_traite = '" . $this->db->idate($now) . "'";
1510 $sql .= ", fk_prelevement_bons = " . ((int) $this->id);
1511 $sql .= " WHERE rowid = " . ((int) $fac[1]);
1512
1513 $resql = $this->db->query($sql);
1514 if (!$resql) {
1515 $error++;
1516 $this->errors[] = $this->db->lasterror();
1517 dol_syslog(__METHOD__ . " Update Error=" . $this->db->lasterror(), LOG_ERR);
1518 }
1519 }
1520 }
1521 }
1522
1523 if (!$error) {
1524 /*
1525 * Create file of type='direct-debit' for direct debit order or type='bank-transfer' for credit transfer into a XML file
1526 */
1527
1528 dol_syslog(__METHOD__ . " Init direct debit or credit transfer file for " . count($factures_prev) . " invoices", LOG_DEBUG);
1529
1530 if (count($factures_prev) > 0) {
1531 $this->date_echeance = $datetimeprev;
1532 $this->reference_remise = $ref;
1533
1534 $account = new Account($this->db);
1535 if ($account->fetch($fk_bank_account) > 0) {
1536 $this->emetteur_code_banque = $account->code_banque;
1537 $this->emetteur_code_guichet = $account->code_guichet;
1538 $this->emetteur_numero_compte = $account->number;
1539 $this->emetteur_number_key = $account->cle_rib;
1540 $this->sepa_xml_pti_in_ctti = (bool) $account->pti_in_ctti;
1541 $this->emetteur_iban = $account->iban;
1542 $this->emetteur_bic = $account->bic;
1543
1544 $this->emetteur_ics = (($type == 'bank-transfer' && getDolGlobalString("SEPA_USE_IDS")) ? $account->ics_transfer : $account->ics); // Example "FR78ZZZ123456"
1545
1546 $this->raison_sociale = $account->owner_name;
1547 }
1548 $this->factures = $factures_prev_id;
1549 $this->context['factures_prev'] = $factures_prev;
1550 // Generation of direct debit or credit transfer file $this->filename (May be a SEPA file for european countries)
1551 // This also set the property $this->total with amount that is included into file
1552 $userid = 0;
1553 if ($sourcetype == 'salary') {
1554 $userid = $this->context['factures_prev'][0][2];
1555 }
1556 $result = $this->generate($format, $executiondate, $type, $fk_bank_account, $userid, (int) $thirdpartyBANId);
1557 if ($result < 0) {
1558 //var_dump($this->error);
1559 //var_dump($this->invoice_in_error);
1560 $error++;
1561 }
1562 }
1563 dol_syslog(__METHOD__ . " Bank order file has been generated under filename " . $this->filename, LOG_DEBUG);
1564 }
1565
1566
1567 /*
1568 * Update total defined after generation of file
1569 */
1570 if (!$error) {
1571 $sql = "UPDATE " . MAIN_DB_PREFIX . "prelevement_bons";
1572 $sql .= " SET amount = " . price2num($this->total);
1573 $sql .= " WHERE rowid = " . ((int) $this->id);
1574 $sql .= " AND entity = " . ((int) $conf->entity);
1575 $resql = $this->db->query($sql);
1576
1577 if (!$resql) {
1578 $error++;
1579 dol_syslog(__METHOD__ . " Error update total: " . $this->db->error(), LOG_ERR);
1580 }
1581 }
1582
1583 if (!$error && !$notrigger) {
1584 $triggerName = 'DIRECT_DEBIT_ORDER_CREATE';
1585 if ($type != 'bank-transfer') {
1586 $triggerName = 'CREDIT_TRANSFER_ORDER_CREATE';
1587 }
1588
1589 // Call trigger
1590 $result = $this->call_trigger($triggerName, $user);
1591 if ($result < 0) {
1592 $error++;
1593 }
1594 // End call triggers
1595 }
1596
1597 if (!$error) {
1598 $this->db->commit();
1599 return count($factures_prev); // The error of failed lines are into $this->invoice_in_error and $this->thirdparty_in_error
1600 } else {
1601 $this->db->rollback();
1602 return -1;
1603 }
1604 } else {
1605 return 0;
1606 }
1607 }
1608
1609
1617 public function delete($user, $notrigger = 0)
1618 {
1619 $this->db->begin();
1620
1621 $error = 0;
1622 $resql1 = $resql2 = $resql3 = $resql4 = 0;
1623
1624 if (!$notrigger) {
1625 $triggername = 'DIRECT_DEBIT_ORDER_DELETE';
1626 if ($this->type == 'bank-transfer') {
1627 $triggername = 'PAYMENTBYBANKTRANFER_DELETE';
1628 }
1629 // Call trigger
1630 $result = $this->call_trigger($triggername, $user);
1631 if ($result < 0) {
1632 $error++;
1633 }
1634 // End call triggers
1635 }
1636
1637 if (!$error) {
1638 $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) . ")";
1639 $resql1 = $this->db->query($sql);
1640 if (!$resql1) {
1641 dol_print_error($this->db);
1642 }
1643 }
1644
1645 if (!$error) {
1646 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "prelevement_lignes WHERE fk_prelevement_bons = " . ((int) $this->id);
1647 $resql2 = $this->db->query($sql);
1648 if (!$resql2) {
1649 dol_print_error($this->db);
1650 }
1651 }
1652
1653 if (!$error) {
1654 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "prelevement_bons WHERE rowid = " . ((int) $this->id);
1655 $resql3 = $this->db->query($sql);
1656 if (!$resql3) {
1657 dol_print_error($this->db);
1658 }
1659 }
1660
1661 if (!$error) {
1662 $sql = "UPDATE " . MAIN_DB_PREFIX . "prelevement_demande SET fk_prelevement_bons = NULL, traite = 0 WHERE fk_prelevement_bons = " . ((int) $this->id);
1663 $resql4 = $this->db->query($sql);
1664 if (!$resql4) {
1665 dol_print_error($this->db);
1666 }
1667 }
1668
1669 if ($resql1 && $resql2 && $resql3 && $resql4 && !$error) {
1670 $this->db->commit();
1671 return 1;
1672 } else {
1673 $this->db->rollback();
1674 return -1;
1675 }
1676 }
1677
1678
1689 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1690 {
1691 global $conf, $langs, $hookmanager;
1692
1693 if (!empty($conf->dol_no_mouse_hover)) {
1694 $notooltip = 1; // Force disable tooltips
1695 }
1696
1697 $result = '';
1698
1699 $labeltoshow = 'PaymentByDirectDebit';
1700 if (!empty($this->type) && $this->type == 'bank-transfer') {
1701 $labeltoshow = 'PaymentByBankTransfer';
1702 }
1703
1704 $label = img_picto('', $this->picto) . ' <u>' . $langs->trans($labeltoshow) . '</u> ' . $this->getLibStatut(5);
1705 $label .= '<br>';
1706 $label .= '<b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
1707 if (isset($this->amount)) {
1708 $label .= '<br><b>' . $langs->trans("Amount") . ":</b> " . price($this->amount);
1709 }
1710 if (isset($this->date_trans)) {
1711 $label .= '<br><b>' . $langs->trans("TransData") . ":</b> " . dol_print_date($this->date_trans, 'dayhour', 'tzuserrel');
1712 }
1713 /*if (isset($this->date_credit)) {
1714 $label .= '<br><b>'.$langs->trans("TransData").":</b> ".dol_print_date($this->date_credit, 'dayhour', 'tzuserrel');
1715 }*/
1716
1717 $url = DOL_URL_ROOT . '/compta/prelevement/card.php?id=' . $this->id;
1718 if (!empty($this->type) && $this->type == 'bank-transfer') {
1719 $url = DOL_URL_ROOT . '/compta/prelevement/card.php?id=' . $this->id;
1720 }
1721
1722 if ($option != 'nolink') {
1723 // Add param to save lastsearch_values or not
1724 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1725 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1726 $add_save_lastsearch_values = 1;
1727 }
1728 if ($add_save_lastsearch_values) {
1729 $url .= '&save_lastsearch_values=1';
1730 }
1731 }
1732
1733 $linkclose = '';
1734 if (empty($notooltip)) {
1735 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1736 $label = $langs->trans("ShowMyObject");
1737 $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
1738 }
1739 $linkclose .= ' title="' . dol_escape_htmltag($label, 1) . '"';
1740 $linkclose .= ' class="classfortooltip' . ($morecss ? ' ' . $morecss : '') . '"';
1741 } else {
1742 $linkclose = ($morecss ? ' class="' . $morecss . '"' : '');
1743 }
1744
1745 $linkstart = '<a href="' . $url . '"';
1746 $linkstart .= $linkclose . '>';
1747 $linkend = '</a>';
1748
1749 $result .= $linkstart;
1750 if ($withpicto) {
1751 $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);
1752 }
1753 if ($withpicto != 2) {
1754 $result .= $this->ref;
1755 }
1756 $result .= $linkend;
1757
1758 global $action, $hookmanager;
1759 $hookmanager->initHooks(array('banktransferdao'));
1760 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1761 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1762 if ($reshook > 0) {
1763 $result = $hookmanager->resPrint;
1764 } else {
1765 $result .= $hookmanager->resPrint;
1766 }
1767
1768 return $result;
1769 }
1770
1771
1778 public function deleteNotificationById($rowid)
1779 {
1780 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "notify_def";
1781 $sql .= " WHERE rowid = " . ((int) $rowid);
1782
1783 if ($this->db->query($sql)) {
1784 return 0;
1785 } else {
1786 return -1;
1787 }
1788 }
1789
1797 public function deleteNotification($user, $action)
1798 {
1799 if (is_object($user)) {
1800 $userid = $user->id;
1801 } else { // If user is an id
1802 $userid = $user;
1803 }
1804
1805 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "notify_def";
1806 $sql .= " WHERE fk_user=" . ((int) $userid) . " AND fk_action='" . $this->db->escape($action) . "'";
1807
1808 if ($this->db->query($sql)) {
1809 return 0;
1810 } else {
1811 return -1;
1812 }
1813 }
1814
1815 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1824 public function addNotification($db, $user, $action)
1825 {
1826 // phpcs:enable
1827 $result = 0;
1828
1829 if (is_object($user)) {
1830 $userid = $user->id;
1831 } else { // If user is an id
1832 $userid = $user;
1833 }
1834
1835 if ($this->deleteNotification($user, $action) == 0) {
1836 $now = dol_now();
1837
1838 $sql = "INSERT INTO " . MAIN_DB_PREFIX . "notify_def (datec,fk_user, fk_soc, fk_contact, fk_action)";
1839 $sql .= " VALUES ('" . $this->db->idate($now) . "', " . ((int) $userid) . ", 'NULL', 'NULL', '" . $this->db->escape($action) . "')";
1840
1841 dol_syslog("adnotiff: " . $sql);
1842 if ($this->db->query($sql)) {
1843 $result = 0;
1844 } else {
1845 $result = -1;
1846 dol_syslog(get_class($this) . "::addNotification Error $result");
1847 }
1848 }
1849
1850 return $result;
1851 }
1852
1853
1869 public function generate(string $format = 'ALL', int $executiondate = 0, string $type = 'direct-debit', int $fk_bank_account = 0, int $forsalary = 0, int $thirdpartyBANId = 0)
1870 {
1871 global $conf, $langs, $mysoc;
1872
1873 //TODO: Optimize code to read lines in a single function
1874
1875 // Clean params
1876 if (empty($fk_bank_account)) {
1877 $fk_bank_account = ($type == 'bank-transfer' ? getDolGlobalInt('PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT') : getDolGlobalInt('PRELEVEMENT_ID_BANKACCOUNT'));
1878 }
1879
1880 $result = 0;
1881
1882 dol_syslog(get_class($this) . "::generate build file=" . $this->filename . " type=" . $type);
1883
1884 $this->file = fopen($this->filename, "w");
1885 if ($this->file == false) {
1886 $this->error = $langs->trans('ErrorFailedToOpenFile', $this->filename);
1887 return -1;
1888 }
1889
1890 $found = 0;
1891 $this->total = 0;
1892
1893 // Build file for European countries
1894 if ($mysoc->isInSEPA()) {
1895 $found++;
1896
1897 if ($type != 'bank-transfer') {
1901 // SEPA Initialisation
1902 $CrLf = "\n";
1903
1904 $now = dol_now();
1905
1906 $dateTime_ECMA = dol_print_date($now, '%Y-%m-%dT%H:%M:%S');
1907
1908 $date_actu = $now;
1909 if (!empty($executiondate)) {
1910 $date_actu = $executiondate;
1911 }
1912
1913 $dateTime_YMD = dol_print_date($date_actu, '%Y%m%d');
1914 $dateTime_YMDHMS = dol_print_date($date_actu, '%Y%m%d%H%M%S');
1915 $fileDebiteurSection = '';
1916 $fileEmetteurSection = '';
1917 $i = 0;
1918
1919 /*
1920 * Section Debitor (sepa Debiteurs block lines)
1921 */
1922
1923 $sql = "SELECT soc.rowid as socid, soc.code_client as code, soc.address, soc.zip, soc.town, c.code as country_code,";
1924 $sql .= " pl.client_nom as nom, pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, pl.amount as somme,";
1925 $sql .= " f.ref as reffac, p.fk_facture as idfac,";
1926 $sql .= " rib.rowid, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum, rib.rum, rib.date_rum";
1927 $sql .= " FROM";
1928 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
1929 $sql .= " " . MAIN_DB_PREFIX . "facture as f,";
1930 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p,";
1931 $sql .= " " . MAIN_DB_PREFIX . "societe as soc,";
1932 $sql .= " " . MAIN_DB_PREFIX . "c_country as c,";
1933 $sql .= " " . MAIN_DB_PREFIX . "societe_rib as rib";
1934 $sql .= " WHERE pl.fk_prelevement_bons = " . ((int) $this->id);
1935 $sql .= " AND pl.rowid = p.fk_prelevement_lignes";
1936 $sql .= " AND p.fk_facture = f.rowid";
1937 $sql .= " AND f.fk_soc = soc.rowid";
1938 $sql .= " AND soc.fk_pays = c.rowid";
1939 $sql .= " AND rib.fk_soc = f.fk_soc";
1940 if (!empty($thirdpartyBANId)) {
1941 $sql .= " AND rib.rowid = " . ((int) $thirdpartyBANId);
1942 } else {
1943 $sql .= " AND rib.default_rib = 1";
1944 }
1945 $sql .= " AND rib.type = 'ban'";
1946
1947 // Define $fileDebiteurSection. One section DrctDbtTxInf per invoice.
1948 $resql = $this->db->query($sql);
1949 $nbtotalDrctDbtTxInf = -1;
1950 if ($resql) {
1951 $cachearraytotestduplicate = array();
1952
1953 $num = $this->db->num_rows($resql);
1954 while ($i < $num) {
1955 $obj = $this->db->fetch_object($resql);
1956
1957 if (!empty($cachearraytotestduplicate[$obj->idfac])) {
1958 $this->error = $langs->trans('ErrorCompanyHasDuplicateDefaultBAN', $obj->socid);
1959 $this->invoice_in_error[$obj->idfac] = $this->error;
1960 $result = -2;
1961 break;
1962 }
1963 $cachearraytotestduplicate[$obj->idfac] = $obj->rowid;
1964
1965 $daterum = (!empty($obj->date_rum)) ? $this->db->jdate($obj->date_rum) : $this->db->jdate($obj->datec);
1966 $iban = dolDecrypt($obj->iban);
1967
1968 $fileDebiteurSection .= $this->EnregDestinataireSEPA($obj->code, $obj->nom, $obj->address, $obj->zip, $obj->town, $obj->country_code, $obj->cb, $obj->cg, $obj->cc, $obj->somme, $obj->reffac, $obj->idfac, $iban, $obj->bic, $daterum, $obj->drum, $obj->rum, $type);
1969
1970 $this->total += $obj->somme;
1971 $i++;
1972 }
1973 $nbtotalDrctDbtTxInf = $i;
1974 } else {
1975 $this->error = $this->db->lasterror();
1976 fwrite($this->file, 'ERROR DEBITOR ' . $sql . $CrLf); // DEBITOR = Customers
1977 $result = -2;
1978 }
1979
1980 // Define $fileEmetteurSection. Start of block PmtInf. Will contains all $nbtotalDrctDbtTxInf
1981 if ($result != -2) {
1982 $fileEmetteurSection .= $this->EnregEmetteurSEPA($conf, $date_actu, $nbtotalDrctDbtTxInf, $this->total, $CrLf, $format, $type, $fk_bank_account);
1983 }
1984
1985 if (getDolGlobalString('SEPA_FORCE_TWO_DECIMAL')) {
1986 $this->total = number_format((float) price2num($this->total, 'MT'), 2, ".", "");
1987 }
1988
1992 // SEPA File Header
1993 fwrite($this->file, '<' . '?xml version="1.0" encoding="UTF-8" standalone="yes"?' . '>' . $CrLf);
1994 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);
1995 fwrite($this->file, ' <CstmrDrctDbtInitn>' . $CrLf);
1996 // SEPA Group header
1997 fwrite($this->file, ' <GrpHdr>' . $CrLf);
1998 fwrite($this->file, ' <MsgId>' . ('DOL/' . $dateTime_YMD . '/DD' . $this->id) . '</MsgId>' . $CrLf);
1999 fwrite($this->file, ' <CreDtTm>' . $dateTime_ECMA . '</CreDtTm>' . $CrLf);
2000 fwrite($this->file, ' <NbOfTxs>' . $i . '</NbOfTxs>' . $CrLf);
2001 fwrite($this->file, ' <CtrlSum>' . $this->total . '</CtrlSum>' . $CrLf);
2002 fwrite($this->file, ' <InitgPty>' . $CrLf);
2003 fwrite($this->file, ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))) . '</Nm>' . $CrLf);
2004 fwrite($this->file, ' <Id>' . $CrLf);
2005 fwrite($this->file, ' <PrvtId>' . $CrLf);
2006 fwrite($this->file, ' <Othr>' . $CrLf);
2007 fwrite($this->file, ' <Id>' . $this->emetteur_ics . '</Id>' . $CrLf);
2008 fwrite($this->file, ' </Othr>' . $CrLf);
2009 fwrite($this->file, ' </PrvtId>' . $CrLf);
2010 fwrite($this->file, ' </Id>' . $CrLf);
2011 fwrite($this->file, ' </InitgPty>' . $CrLf);
2012 fwrite($this->file, ' </GrpHdr>' . $CrLf);
2013 // SEPA File Emetteur
2014 if ($result != -2) {
2015 fwrite($this->file, $fileEmetteurSection);
2016 }
2017 // SEPA File Debiteurs
2018 if ($result != -2) {
2019 fwrite($this->file, $fileDebiteurSection);
2020 }
2021 // SEPA FILE FOOTER
2022 fwrite($this->file, ' </PmtInf>' . $CrLf);
2023 fwrite($this->file, ' </CstmrDrctDbtInitn>' . $CrLf);
2024 fwrite($this->file, '</Document>' . $CrLf);
2025 } else {
2029 // SEPA Initialisation
2030 $CrLf = "\n";
2031
2032 $now = dol_now();
2033
2034 $dateTime_ECMA = dol_print_date($now, '%Y-%m-%dT%H:%M:%S');
2035
2036 $date_actu = $now;
2037 if (!empty($executiondate)) {
2038 $date_actu = $executiondate;
2039 }
2040
2041 $dateTime_YMD = dol_print_date($date_actu, '%Y%m%d');
2042 $dateTime_YMDHMS = dol_print_date($date_actu, '%Y%m%d%H%M%S');
2043 $fileCrediteurSection = '';
2044 $fileEmetteurSection = '';
2045 $i = 0;
2046
2047 /*
2048 * Section Creditor (sepa Crediteurs block lines)
2049 */
2050 if (!empty($forsalary)) {
2051 $sql = "SELECT u.rowid as userId, u.address, u.zip, u.town, c.code as country_code, CONCAT(u.firstname,' ',u.lastname) as nom,";
2052 $sql .= " pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, pl.amount as somme,";
2053 $sql .= " s.ref as reffac, p.fk_salary as idfac,";
2054 $sql .= " rib.rowid, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum, '' as rum, '' as date_rum";
2055 $sql .= " FROM";
2056 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
2057 $sql .= " " . MAIN_DB_PREFIX . "salary as s,";
2058 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p,";
2059 $sql .= " " . MAIN_DB_PREFIX . "user as u";
2060 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_country as c ON u.fk_country = c.rowid,";
2061 $sql .= " " . MAIN_DB_PREFIX . "user_rib as rib";
2062 $sql .= " WHERE pl.fk_prelevement_bons=" . ((int) $this->id);
2063 $sql .= " AND pl.rowid = p.fk_prelevement_lignes";
2064 $sql .= " AND p.fk_salary = s.rowid";
2065 $sql .= " AND s.fk_user = u.rowid";
2066 $sql .= " AND rib.fk_user = s.fk_user";
2067 } else {
2068 $sql = "SELECT soc.rowid as socid, soc.code_client as code, soc.address, soc.zip, soc.town, c.code as country_code,";
2069 $sql .= " pl.client_nom as nom, pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, pl.amount as somme,";
2070 $sql .= " f.ref as reffac, f.ref_supplier as fac_ref_supplier, p.fk_facture_fourn as idfac,";
2071 $sql .= " rib.rowid, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum, rib.rum, rib.date_rum";
2072 $sql .= " FROM";
2073 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
2074 $sql .= " " . MAIN_DB_PREFIX . "facture_fourn as f,";
2075 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p,";
2076 $sql .= " " . MAIN_DB_PREFIX . "societe as soc";
2077 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_country as c ON soc.fk_pays = c.rowid,";
2078 $sql .= " " . MAIN_DB_PREFIX . "societe_rib as rib";
2079 $sql .= " WHERE pl.fk_prelevement_bons = " . ((int) $this->id);
2080 $sql .= " AND pl.rowid = p.fk_prelevement_lignes";
2081 $sql .= " AND p.fk_facture_fourn = f.rowid";
2082 $sql .= " AND f.fk_soc = soc.rowid";
2083 $sql .= " AND rib.fk_soc = f.fk_soc";
2084 if (!empty($thirdpartyBANId)) {
2085 $sql .= " AND rib.rowid = " . ((int) $thirdpartyBANId);
2086 } else {
2087 $sql .= " AND rib.default_rib = 1";
2088 }
2089 $sql .= " AND rib.type = 'ban'";
2090 }
2091 // Define $fileCrediteurSection. One section DrctDbtTxInf per invoice.
2092 $nbtotalDrctDbtTxInf = -1;
2093
2094 $resql = $this->db->query($sql);
2095 if ($resql) {
2096 $cachearraytotestduplicate = array();
2097
2098 $num = $this->db->num_rows($resql);
2099 while ($i < $num) {
2100 $obj = $this->db->fetch_object($resql);
2101 if (!empty($cachearraytotestduplicate[$obj->idfac])) {
2102 $this->error = $langs->trans('ErrorCompanyHasDuplicateDefaultBAN', $obj->socid);
2103 $this->invoice_in_error[$obj->idfac] = $this->error;
2104 $result = -2;
2105 break;
2106 }
2107 $cachearraytotestduplicate[$obj->idfac] = $obj->rowid;
2108
2109 $daterum = (!empty($obj->date_rum)) ? $this->db->jdate($obj->date_rum) : $this->db->jdate($obj->datec);
2110 $iban = dolDecrypt($obj->iban);
2111 $refobj = $obj->reffac;
2112 if (empty($refobj) && !empty($forsalary)) { // If ref of salary not defined, we force a value
2113 $refobj = "SAL" . $obj->idfac;
2114 }
2115
2116 $fileCrediteurSection .= $this->EnregDestinataireSEPA($obj->code, $obj->nom, $obj->address, $obj->zip, $obj->town, $obj->country_code, $obj->cb, $obj->cg, $obj->cc, $obj->somme, $refobj, $obj->idfac, $iban, $obj->bic, $daterum, $obj->drum, $obj->rum, $type, $obj->fac_ref_supplier);
2117
2118 $this->total += $obj->somme;
2119 $i++;
2120 }
2121 $nbtotalDrctDbtTxInf = $i;
2122 } else {
2123 $this->error = $this->db->lasterror();
2124 fwrite($this->file, 'ERROR CREDITOR ' . $sql . $CrLf); // CREDITORS = Suppliers
2125 $result = -2;
2126 }
2127 // Define $fileEmetteurSection. Start of block PmtInf. Will contains all $nbtotalDrctDbtTxInf
2128 if ($result != -2) {
2129 $fileEmetteurSection .= $this->EnregEmetteurSEPA($conf, $date_actu, $nbtotalDrctDbtTxInf, $this->total, $CrLf, $format, $type);
2130 }
2131
2132 if (getDolGlobalString('SEPA_FORCE_TWO_DECIMAL')) {
2133 $this->total = number_format((float) price2num($this->total, 'MT'), 2, ".", "");
2134 }
2135
2139 // SEPA File Header
2140 fwrite($this->file, '<' . '?xml version="1.0" encoding="UTF-8" standalone="yes"?' . '>' . $CrLf);
2141 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);
2142 fwrite($this->file, ' <CstmrCdtTrfInitn>' . $CrLf);
2143 // SEPA Group header
2144 fwrite($this->file, ' <GrpHdr>' . $CrLf);
2145 fwrite($this->file, ' <MsgId>' . ('DOL/' . $dateTime_YMD . '/CT' . $this->id) . '</MsgId>' . $CrLf);
2146 fwrite($this->file, ' <CreDtTm>' . $dateTime_ECMA . '</CreDtTm>' . $CrLf);
2147 fwrite($this->file, ' <NbOfTxs>' . $i . '</NbOfTxs>' . $CrLf);
2148 fwrite($this->file, ' <CtrlSum>' . $this->total . '</CtrlSum>' . $CrLf);
2149 fwrite($this->file, ' <InitgPty>' . $CrLf);
2150 fwrite($this->file, ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))) . '</Nm>' . $CrLf);
2151 fwrite($this->file, ' <Id>' . $CrLf);
2152 fwrite($this->file, ' <PrvtId>' . $CrLf);
2153 fwrite($this->file, ' <Othr>' . $CrLf);
2154 fwrite($this->file, ' <Id>' . $this->emetteur_ics . '</Id>' . $CrLf);
2155 fwrite($this->file, ' </Othr>' . $CrLf);
2156 fwrite($this->file, ' </PrvtId>' . $CrLf);
2157 fwrite($this->file, ' </Id>' . $CrLf);
2158 fwrite($this->file, ' </InitgPty>' . $CrLf);
2159 fwrite($this->file, ' </GrpHdr>' . $CrLf);
2160 // SEPA File Emetteur (mycompany)
2161 if ($result != -2) {
2162 fwrite($this->file, $fileEmetteurSection);
2163 }
2164 // SEPA File Creditors
2165 if ($result != -2) {
2166 fwrite($this->file, $fileCrediteurSection);
2167 }
2168 // SEPA FILE FOOTER
2169 fwrite($this->file, ' </PmtInf>' . $CrLf);
2170 fwrite($this->file, ' </CstmrCdtTrfInitn>' . $CrLf);
2171 fwrite($this->file, '</Document>' . $CrLf);
2172 }
2173 }
2174
2175 // Build file for Other Countries with unknown format
2176 if (!$found) {
2177 if ($type != 'bank-transfer') {
2178 $sql = "SELECT pl.amount";
2179 $sql .= " FROM";
2180 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
2181 $sql .= " " . MAIN_DB_PREFIX . "facture as f,";
2182 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p";
2183 $sql .= " WHERE pl.fk_prelevement_bons = " . ((int) $this->id);
2184 $sql .= " AND pl.rowid = p.fk_prelevement_lignes";
2185 $sql .= " AND p.fk_facture = f.rowid";
2186
2187 // Lines
2188 $i = 0;
2189 $resql = $this->db->query($sql);
2190 if ($resql) {
2191 $num = $this->db->num_rows($resql);
2192
2193 while ($i < $num) {
2194 $obj = $this->db->fetch_object($resql);
2195 $this->total += $obj->amount;
2196
2197 // TODO Write record into file
2198 $i++;
2199 }
2200 } else {
2201 $result = -2;
2202 }
2203 } else {
2204 $sql = "SELECT pl.amount";
2205 $sql .= " FROM";
2206 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
2207 $sql .= " " . MAIN_DB_PREFIX . "facture_fourn as f,";
2208 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p";
2209 $sql .= " WHERE pl.fk_prelevement_bons = " . ((int) $this->id);
2210 $sql .= " AND pl.rowid = p.fk_prelevement_lignes";
2211 $sql .= " AND p.fk_facture_fourn = f.rowid";
2212 // Lines
2213 $i = 0;
2214 $resql = $this->db->query($sql);
2215 if ($resql) {
2216 $num = $this->db->num_rows($resql);
2217
2218 while ($i < $num) {
2219 $obj = $this->db->fetch_object($resql);
2220 $this->total += $obj->amount;
2221
2222 // TODO Write record into file
2223 $i++;
2224 }
2225 } else {
2226 $result = -2;
2227 }
2228 }
2229
2230 $langs->load('withdrawals');
2231
2232 // TODO Add here code to generate a generic file
2233 fwrite($this->file, $langs->transnoentitiesnoconv('WithdrawalFileNotCapable', $mysoc->country_code));
2234 }
2235
2236 fclose($this->file);
2237 dolChmod($this->filename);
2238
2239 return $result;
2240 }
2241
2242
2251 public static function buildRumNumber($row_code_client, $row_datec, $row_drum)
2252 {
2253 global $langs;
2254
2255 $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)
2256
2257 // 3 char + '-' + 10 (yymmddHHMM) + '-' + id + '-' + code. Must be under 32 (SEPA char limit for MndtId is however 35).
2258 return $pre . '-' . dol_print_date($row_datec, 'dayhourlogsmall') . '-' . dol_trunc($row_drum . ($row_code_client ? '-' . $row_code_client : ''), 17, 'right', 'UTF-8', 1);
2259 }
2260
2261
2262 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2279 public function EnregDestinataire($rowid, $client_nom, $rib_banque, $rib_guichet, $rib_number, $amount, $ref, $facid, $rib_dom = '', $type = 'direct-debit')
2280 {
2281 // phpcs:enable
2282 fwrite($this->file, "06");
2283 fwrite($this->file, "08"); // Prelevement ordinaire
2284
2285 fwrite($this->file, " "); // Zone Reservee B2
2286
2287 fwrite($this->file, $this->emetteur_ics); // ICS
2288
2289 // Date d'echeance C1
2290
2291 fwrite($this->file, " ");
2292 fwrite($this->file, dol_print_date($this->date_echeance, "%d%m", 'gmt'));
2293 fwrite($this->file, substr(dol_print_date($this->date_echeance, "%y", 'gmt'), 1));
2294
2295 // Raison Sociale Destinataire C2
2296
2297 fwrite($this->file, substr(strtoupper($client_nom) . " ", 0, 24));
2298
2299 // Address optional D1
2300 $address = strtr($rib_dom, array(" " => "-", chr(13) => " ", chr(10) => ""));
2301 fwrite($this->file, substr($address . " ", 0, 24));
2302
2303 // Zone Reservee D2
2304
2305 fwrite($this->file, substr(" ", 0, 8));
2306
2307 // Code Guichet D3
2308
2309 fwrite($this->file, $rib_guichet);
2310
2311 // Numero de compte D4
2312
2313 fwrite($this->file, substr("000000000000000" . $rib_number, -11));
2314
2315 // Zone E Montant
2316
2317 $montant = (round($amount, 2) * 100);
2318
2319 fwrite($this->file, substr("000000000000000" . $montant, -16));
2320
2321 // Label F
2322
2323 fwrite($this->file, substr("*_" . $ref . "_RDVnet" . $rowid . " ", 0, 31));
2324
2325 // Code etablissement G1
2326
2327 fwrite($this->file, $rib_banque);
2328
2329 // Zone Reservee G2
2330
2331 fwrite($this->file, substr(" ", 0, 5));
2332
2333 fwrite($this->file, "\n");
2334 }
2335
2336
2337 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2363 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 = '')
2364 {
2365 // phpcs:enable
2366 global $conf, $mysoc;
2367
2368 if (getDolGlobalString('SEPA_FORCE_TWO_DECIMAL')) {
2369 $row_somme = number_format((float) price2num($row_somme, 'MT'), 2, ".", "");
2370 } else {
2371 $row_somme = round((float) $row_somme, 2);
2372 }
2373
2374 include_once DOL_DOCUMENT_ROOT . '/core/lib/functions2.lib.php';
2375
2376 $CrLf = "\n";
2377 $Rowing = sprintf("%010d", $row_idfac);
2378
2379 // Define value for RUM
2380 // Example: RUM-CustomerCode-CustomerBankAccountId-01424448606 (note: Date is the timestamp of the date of creation of CustomerBankAccountId)
2381 $Rum = (empty($row_rum) ? $this->buildRumNumber($row_code_client, $row_datec, $row_drum) : $row_rum);
2382
2383 // Define date of RUM signature
2384 $DtOfSgntr = dol_print_date($row_datec, '%Y-%m-%d');
2385
2386 if ($type != 'bank-transfer') {
2387 // SEPA Paiement Information of buyer for Direct Debit
2388 $XML_DEBITOR = '';
2389 $XML_DEBITOR .= ' <DrctDbtTxInf>' . $CrLf;
2390 $XML_DEBITOR .= ' <PmtId>' . $CrLf;
2391 // Add EndToEndId. Must be a unique ID for each payment (for example by including bank, buyer or seller, date, checksum)
2392 $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
2393 $XML_DEBITOR .= ' </PmtId>' . $CrLf;
2394 $XML_DEBITOR .= ' <InstdAmt Ccy="EUR">' . $row_somme . '</InstdAmt>' . $CrLf;
2395 $XML_DEBITOR .= ' <DrctDbtTx>' . $CrLf;
2396 $XML_DEBITOR .= ' <MndtRltdInf>' . $CrLf;
2397 $XML_DEBITOR .= ' <MndtId>' . $Rum . '</MndtId>' . $CrLf;
2398 $XML_DEBITOR .= ' <DtOfSgntr>' . $DtOfSgntr . '</DtOfSgntr>' . $CrLf;
2399 $XML_DEBITOR .= ' <AmdmntInd>false</AmdmntInd>' . $CrLf;
2400 $XML_DEBITOR .= ' </MndtRltdInf>' . $CrLf;
2401 $XML_DEBITOR .= ' </DrctDbtTx>' . $CrLf;
2402 $XML_DEBITOR .= ' <DbtrAgt>' . $CrLf;
2403 $XML_DEBITOR .= ' <FinInstnId>' . $CrLf;
2404 if (getDolGlobalInt('WITHDRAWAL_WITHOUT_BIC') == 0) {
2405 $XML_DEBITOR .= ' <BIC>' . $row_bic . '</BIC>' . $CrLf;
2406 }
2407 $XML_DEBITOR .= ' </FinInstnId>' . $CrLf;
2408 $XML_DEBITOR .= ' </DbtrAgt>' . $CrLf;
2409 $XML_DEBITOR .= ' <Dbtr>' . $CrLf;
2410 $XML_DEBITOR .= ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($row_nom), ' '))) . '</Nm>' . $CrLf;
2411 $XML_DEBITOR .= ' <PstlAdr>' . $CrLf;
2412 $XML_DEBITOR .= ' <Ctry>' . $row_country_code . '</Ctry>' . $CrLf;
2413 $addressline1 = strtr($row_address, array(chr(13) => ", ", chr(10) => ""));
2414 $addressline2 = strtr($row_zip . (($row_zip && $row_town) ? ' ' : '') . (string) $row_town, array(chr(13) => ", ", chr(10) => ""));
2415 if (trim($addressline1)) {
2416 $XML_DEBITOR .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2417 }
2418 if (trim($addressline2)) {
2419 $XML_DEBITOR .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2420 }
2421 $XML_DEBITOR .= ' </PstlAdr>' . $CrLf;
2422 $XML_DEBITOR .= ' </Dbtr>' . $CrLf;
2423 $XML_DEBITOR .= ' <DbtrAcct>' . $CrLf;
2424 $XML_DEBITOR .= ' <Id>' . $CrLf;
2425 $XML_DEBITOR .= ' <IBAN>' . preg_replace('/\s/', '', $row_iban) . '</IBAN>' . $CrLf;
2426 $XML_DEBITOR .= ' </Id>' . $CrLf;
2427 $XML_DEBITOR .= ' </DbtrAcct>' . $CrLf;
2428 $XML_DEBITOR .= ' <RmtInf>' . $CrLf;
2429
2430 // Structured data for Belgium
2431 if (getDolGlobalString('INVOICE_PAYMENT_ENABLE_STRUCTURED_COMMUNICATION') && $mysoc->country_code == 'BE') {
2432 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions_be.lib.php';
2433
2434 $invoicestatic = new Facture($this->db);
2435 $invoicestatic->fetch($row_idfac);
2436
2437 $invoicePaymentKey = dolBECalculateStructuredCommunication($invoicestatic->ref, $invoicestatic->type);
2438 $XML_DEBITOR .= ' <strd>' . $invoicePaymentKey . '</strd>' . $CrLf;
2439 } else {
2440 // A string with some information on payment - 140 max
2441 $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
2442 }
2443 $XML_DEBITOR .= ' </RmtInf>' . $CrLf;
2444 $XML_DEBITOR .= ' </DrctDbtTxInf>' . $CrLf;
2445 return $XML_DEBITOR;
2446 } else {
2447 // SEPA Payment Information of seller for Credit Transfer
2448 $XML_CREDITOR = '';
2449 $XML_CREDITOR .= ' <CdtTrfTxInf>' . $CrLf;
2450 $XML_CREDITOR .= ' <PmtId>' . $CrLf;
2451 // Add EndToEndId. Must be a unique ID for each payment (for example by including bank, buyer or seller, date, checksum)
2452 $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
2453 $XML_CREDITOR .= ' </PmtId>' . $CrLf;
2454 if (!empty($this->sepa_xml_pti_in_ctti)) {
2455 $XML_CREDITOR .= ' <PmtTpInf>' . $CrLf;
2456
2457 // Can be 'NORM' for normal or 'HIGH' for high priority level
2458 if (getDolGlobalString('PAYMENTBYBANKTRANSFER_FORCE_HIGH_PRIORITY')) {
2459 $instrprty = 'HIGH';
2460 } else {
2461 $instrprty = 'NORM';
2462 }
2463
2464 // Set $categoryPurpose: CORE, TREA, SUPP, ...
2465 $categoryPurpose = getDolGlobalString('PAYMENTBYBANKTRANSFER_CUSTOM_CATEGORY_PURPOSE', 'CORE');
2466
2467 $XML_CREDITOR .= ' <InstrPrty>' . $instrprty . '</InstrPrty>' . $CrLf;
2468 $XML_CREDITOR .= ' <SvcLvl>' . $CrLf;
2469 $XML_CREDITOR .= ' <Cd>SEPA</Cd>' . $CrLf;
2470 $XML_CREDITOR .= ' </SvcLvl>' . $CrLf;
2471 $XML_CREDITOR .= ' <CtgyPurp>' . $CrLf;
2472 $XML_CREDITOR .= ' <Cd>' . $categoryPurpose . '</Cd>' . $CrLf;
2473 $XML_CREDITOR .= ' </CtgyPurp>' . $CrLf;
2474 $XML_CREDITOR .= ' </PmtTpInf>' . $CrLf;
2475 }
2476 $XML_CREDITOR .= ' <Amt>' . $CrLf;
2477 $XML_CREDITOR .= ' <InstdAmt Ccy="EUR">'.round((float) $row_somme, 2).'</InstdAmt>'.$CrLf;
2478 $XML_CREDITOR .= ' </Amt>' . $CrLf;
2479 /*
2480 $XML_CREDITOR .= ' <DrctDbtTx>'.$CrLf;
2481 $XML_CREDITOR .= ' <MndtRltdInf>'.$CrLf;
2482 $XML_CREDITOR .= ' <MndtId>'.$Rum.'</MndtId>'.$CrLf;
2483 $XML_CREDITOR .= ' <DtOfSgntr>'.$DtOfSgntr.'</DtOfSgntr>'.$CrLf;
2484 $XML_CREDITOR .= ' <AmdmntInd>false</AmdmntInd>'.$CrLf;
2485 $XML_CREDITOR .= ' </MndtRltdInf>'.$CrLf;
2486 $XML_CREDITOR .= ' </DrctDbtTx>'.$CrLf;
2487 */
2488 //$XML_CREDITOR .= ' <ChrgBr>SLEV</ChrgBr>'.$CrLf;
2489 $XML_CREDITOR .= ' <CdtrAgt>' . $CrLf;
2490 $XML_CREDITOR .= ' <FinInstnId>' . $CrLf;
2491 $XML_CREDITOR .= ' <BIC>' . $row_bic . '</BIC>' . $CrLf;
2492 $XML_CREDITOR .= ' </FinInstnId>' . $CrLf;
2493 $XML_CREDITOR .= ' </CdtrAgt>' . $CrLf;
2494 $XML_CREDITOR .= ' <Cdtr>' . $CrLf;
2495 $XML_CREDITOR .= ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($row_nom), ' '))) . '</Nm>' . $CrLf;
2496 $XML_CREDITOR .= ' <PstlAdr>' . $CrLf;
2497 $XML_CREDITOR .= ' <Ctry>' . $row_country_code . '</Ctry>' . $CrLf;
2498 $addressline1 = strtr($row_address, array(chr(13) => ", ", chr(10) => ""));
2499 $addressline2 = strtr($row_zip . (($row_zip && $row_town) ? ' ' : '') . (string) $row_town, array(chr(13) => ", ", chr(10) => ""));
2500 if (trim($addressline1)) {
2501 $XML_CREDITOR .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2502 }
2503 if (trim($addressline2)) {
2504 $XML_CREDITOR .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2505 }
2506 $XML_CREDITOR .= ' </PstlAdr>' . $CrLf;
2507 $XML_CREDITOR .= ' </Cdtr>' . $CrLf;
2508 $XML_CREDITOR .= ' <CdtrAcct>' . $CrLf;
2509 $XML_CREDITOR .= ' <Id>' . $CrLf;
2510 $XML_CREDITOR .= ' <IBAN>' . preg_replace('/\s/', '', $row_iban) . '</IBAN>' . $CrLf;
2511 $XML_CREDITOR .= ' </Id>' . $CrLf;
2512 $XML_CREDITOR .= ' </CdtrAcct>' . $CrLf;
2513 $XML_CREDITOR .= ' <RmtInf>' . $CrLf;
2514 // A string with some information on payment - 140 max
2515 $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
2516 $XML_CREDITOR .= ' </RmtInf>' . $CrLf;
2517 $XML_CREDITOR .= ' </CdtTrfTxInf>' . $CrLf;
2518 return $XML_CREDITOR;
2519 }
2520 }
2521
2522
2523 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2532 public function EnregEmetteur($type = 'direct-debit')
2533 {
2534 // phpcs:enable
2535 fwrite($this->file, "03");
2536 fwrite($this->file, "08"); // Prelevement ordinaire
2537
2538 fwrite($this->file, " "); // Zone Reservee B2
2539
2540 fwrite($this->file, $this->emetteur_ics); // ICS
2541
2542 // Date d'echeance C1
2543
2544 fwrite($this->file, " ");
2545 fwrite($this->file, dol_print_date($this->date_echeance, "%d%m", 'gmt'));
2546 fwrite($this->file, substr(dol_print_date($this->date_echeance, "%y", 'gmt'), 1));
2547
2548 // Raison Sociale C2
2549
2550 fwrite($this->file, substr($this->raison_sociale . " ", 0, 24));
2551
2552 // Ref of thirdparty on 7 characters
2553
2554 fwrite($this->file, substr($this->reference_remise . " ", 0, 7));
2555
2556 // Zone Reservee D1-2
2557
2558 fwrite($this->file, substr(" ", 0, 17));
2559
2560 // Zone Reservee D2
2561
2562 fwrite($this->file, substr(" ", 0, 2));
2563 fwrite($this->file, "E");
2564 fwrite($this->file, substr(" ", 0, 5));
2565
2566 // Code Guichet D3
2567
2568 fwrite($this->file, $this->emetteur_code_guichet);
2569
2570 // Numero de compte D4
2571
2572 fwrite($this->file, substr("000000000000000" . $this->emetteur_numero_compte, -11));
2573
2574 // Zone Reservee E
2575
2576 fwrite($this->file, substr(" ", 0, 16));
2577
2578 // Zone Reservee F
2579
2580 fwrite($this->file, substr(" ", 0, 31));
2581
2582 // Code etablissement
2583
2584 fwrite($this->file, $this->emetteur_code_banque);
2585
2586 // Zone Reservee G
2587
2588 fwrite($this->file, substr(" ", 0, 5));
2589
2590 fwrite($this->file, "\n");
2591 }
2592
2593
2594 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2609 public function EnregEmetteurSEPA($configuration, $ladate, $nombre, $total, $CrLf = '\n', $format = 'FRST', $type = 'direct-debit', $fk_bank_account = 0)
2610 {
2611 // phpcs:enable
2612
2613 // Clean parameters
2614 $dateTime_YMD = dol_print_date($ladate, '%Y%m%d');
2615 $dateTime_ETAD = dol_print_date($ladate, '%Y-%m-%d');
2616 $dateTime_YMDHMS = dol_print_date($ladate, '%Y-%m-%dT%H:%M:%S');
2617
2618 // Clean params
2619 if (empty($fk_bank_account)) {
2620 $fk_bank_account = ($type == 'bank-transfer' ? getDolGlobalInt('PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT') : getDolGlobalInt('PRELEVEMENT_ID_BANKACCOUNT'));
2621 }
2622
2623 // Get data of bank account
2624 $account = new Account($this->db);
2625 if ($account->fetch($fk_bank_account) > 0) {
2626 $this->emetteur_code_banque = $account->code_banque;
2627 $this->emetteur_code_guichet = $account->code_guichet;
2628 $this->emetteur_numero_compte = $account->number;
2629 $this->emetteur_number_key = $account->cle_rib;
2630 $this->sepa_xml_pti_in_ctti = (bool) $account->pti_in_ctti;
2631 $this->emetteur_iban = $account->iban;
2632 $this->emetteur_bic = $account->bic;
2633
2634 $this->emetteur_ics = (($type == 'bank-transfer' && getDolGlobalString("SEPA_USE_IDS")) ? $account->ics_transfer : $account->ics); // Ex: PRELEVEMENT_ICS = "FR78ZZZ123456";
2635
2636 $this->raison_sociale = $account->owner_name;
2637 }
2638
2639 // Get pending payments
2640 $sql = "SELECT rowid, ref";
2641 $sql .= " FROM " . MAIN_DB_PREFIX . "prelevement_bons as pb";
2642 $sql .= " WHERE pb.rowid = " . ((int) $this->id);
2643
2644 $resql = $this->db->query($sql);
2645 if ($resql) {
2646 $obj = $this->db->fetch_object($resql);
2647
2648 $country = explode(':', getDolGlobalString('MAIN_INFO_SOCIETE_COUNTRY'));
2649 $IdBon = sprintf("%05d", $obj->rowid);
2650 $RefBon = $obj->ref;
2651 $localInstrument = getDolGlobalString('PAYMENTBYBANKTRANSFER_CUSTOM_LOCAL_INSTRUMENT', 'CORE');
2652
2653 if (getDolGlobalString('SEPA_FORCE_TWO_DECIMAL')) {
2654 $total = number_format((float) price2num($total, 'MT'), 2, ".", "");
2655 }
2656
2657 if ($type != 'bank-transfer') {
2658 // SEPA Paiement Information of my company for Direct Debit
2659 $XML_SEPA_INFO = '';
2660 $XML_SEPA_INFO .= ' <PmtInf>' . $CrLf;
2661 $XML_SEPA_INFO .= ' <PmtInfId>' . ('DOL/' . $dateTime_YMD . '/DD' . $IdBon . '-' . $RefBon) . '</PmtInfId>' . $CrLf;
2662 $XML_SEPA_INFO .= ' <PmtMtd>DD</PmtMtd>' . $CrLf;
2663 $XML_SEPA_INFO .= ' <NbOfTxs>' . $nombre . '</NbOfTxs>' . $CrLf;
2664 $XML_SEPA_INFO .= ' <CtrlSum>' . $total . '</CtrlSum>' . $CrLf;
2665 $XML_SEPA_INFO .= ' <PmtTpInf>' . $CrLf;
2666 $XML_SEPA_INFO .= ' <SvcLvl>' . $CrLf;
2667 $XML_SEPA_INFO .= ' <Cd>SEPA</Cd>' . $CrLf;
2668 $XML_SEPA_INFO .= ' </SvcLvl>' . $CrLf;
2669 $XML_SEPA_INFO .= ' <LclInstrm>' . $CrLf;
2670 $XML_SEPA_INFO .= ' <Cd>' . $localInstrument . '</Cd>' . $CrLf;
2671 $XML_SEPA_INFO .= ' </LclInstrm>' . $CrLf;
2672 $XML_SEPA_INFO .= ' <SeqTp>' . $format . '</SeqTp>' . $CrLf;
2673 $XML_SEPA_INFO .= ' </PmtTpInf>' . $CrLf;
2674 $XML_SEPA_INFO .= ' <ReqdColltnDt>' . $dateTime_ETAD . '</ReqdColltnDt>' . $CrLf;
2675 $XML_SEPA_INFO .= ' <Cdtr>' . $CrLf;
2676 $XML_SEPA_INFO .= ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))) . '</Nm>' . $CrLf;
2677 $XML_SEPA_INFO .= ' <PstlAdr>' . $CrLf;
2678 $XML_SEPA_INFO .= ' <Ctry>' . $country[1] . '</Ctry>' . $CrLf;
2679 $addressline1 = strtr(getDolGlobalString('MAIN_INFO_SOCIETE_ADDRESS'), array(chr(13) => ", ", chr(10) => ""));
2680 $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) => ""));
2681 if ($addressline1) {
2682 $XML_SEPA_INFO .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2683 }
2684 if ($addressline2) {
2685 $XML_SEPA_INFO .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2686 }
2687 $XML_SEPA_INFO .= ' </PstlAdr>' . $CrLf;
2688 $XML_SEPA_INFO .= ' </Cdtr>' . $CrLf;
2689 $XML_SEPA_INFO .= ' <CdtrAcct>' . $CrLf;
2690 $XML_SEPA_INFO .= ' <Id>' . $CrLf;
2691 $XML_SEPA_INFO .= ' <IBAN>' . preg_replace('/\s/', '', $this->emetteur_iban) . '</IBAN>' . $CrLf;
2692 $XML_SEPA_INFO .= ' </Id>' . $CrLf;
2693 $XML_SEPA_INFO .= ' </CdtrAcct>' . $CrLf;
2694 $XML_SEPA_INFO .= ' <CdtrAgt>' . $CrLf;
2695 $XML_SEPA_INFO .= ' <FinInstnId>' . $CrLf;
2696 $XML_SEPA_INFO .= ' <BIC>' . $this->emetteur_bic . '</BIC>' . $CrLf;
2697 $XML_SEPA_INFO .= ' </FinInstnId>' . $CrLf;
2698 $XML_SEPA_INFO .= ' </CdtrAgt>' . $CrLf;
2699 /* $XML_SEPA_INFO .= ' <UltmtCdtr>'.$CrLf;
2700 $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
2701 $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
2702 $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
2703 $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;
2704 $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;
2705 $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
2706 $XML_SEPA_INFO .= ' </UltmtCdtr>'.$CrLf;*/
2707 $XML_SEPA_INFO .= ' <ChrgBr>SLEV</ChrgBr>' . $CrLf; // Field "Responsible of fees". Must be SLEV
2708 $XML_SEPA_INFO .= ' <CdtrSchmeId>' . $CrLf;
2709 $XML_SEPA_INFO .= ' <Id>' . $CrLf;
2710 $XML_SEPA_INFO .= ' <PrvtId>' . $CrLf;
2711 $XML_SEPA_INFO .= ' <Othr>' . $CrLf;
2712 $XML_SEPA_INFO .= ' <Id>' . $this->emetteur_ics . '</Id>' . $CrLf;
2713 $XML_SEPA_INFO .= ' <SchmeNm>' . $CrLf;
2714 $XML_SEPA_INFO .= ' <Prtry>SEPA</Prtry>' . $CrLf;
2715 $XML_SEPA_INFO .= ' </SchmeNm>' . $CrLf;
2716 $XML_SEPA_INFO .= ' </Othr>' . $CrLf;
2717 $XML_SEPA_INFO .= ' </PrvtId>' . $CrLf;
2718 $XML_SEPA_INFO .= ' </Id>' . $CrLf;
2719 $XML_SEPA_INFO .= ' </CdtrSchmeId>' . $CrLf;
2720 } else {
2721 // SEPA Paiement Information of my company for Credit Transfer
2722 $XML_SEPA_INFO = '';
2723 $XML_SEPA_INFO .= ' <PmtInf>' . $CrLf;
2724 $XML_SEPA_INFO .= ' <PmtInfId>' . ('DOL/' . $dateTime_YMD . '/CT' . $IdBon . '-' . $RefBon) . '</PmtInfId>' . $CrLf;
2725 $XML_SEPA_INFO .= ' <PmtMtd>TRF</PmtMtd>' . $CrLf;
2726 //$XML_SEPA_INFO .= ' <BtchBookg>False</BtchBookg>'.$CrLf;
2727 $XML_SEPA_INFO .= ' <NbOfTxs>' . $nombre . '</NbOfTxs>' . $CrLf;
2728 $XML_SEPA_INFO .= ' <CtrlSum>' . $total . '</CtrlSum>' . $CrLf;
2729 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.
2730 $XML_SEPA_INFO .= ' <PmtTpInf>' . $CrLf;
2731 $XML_SEPA_INFO .= ' <SvcLvl>' . $CrLf;
2732 $XML_SEPA_INFO .= ' <Cd>SEPA</Cd>' . $CrLf;
2733 $XML_SEPA_INFO .= ' </SvcLvl>' . $CrLf;
2734 $XML_SEPA_INFO .= ' <LclInstrm>' . $CrLf;
2735 $XML_SEPA_INFO .= ' <Cd>' . $localInstrument . '</Cd>' . $CrLf;
2736 $XML_SEPA_INFO .= ' </LclInstrm>' . $CrLf;
2737 $XML_SEPA_INFO .= ' <SeqTp>' . $format . '</SeqTp>' . $CrLf;
2738 $XML_SEPA_INFO .= ' </PmtTpInf>' . $CrLf;
2739 }
2740 $XML_SEPA_INFO .= ' <ReqdExctnDt>' . dol_print_date($dateTime_ETAD, 'dayrfc') . '</ReqdExctnDt>' . $CrLf;
2741 $XML_SEPA_INFO .= ' <Dbtr>' . $CrLf;
2742 $XML_SEPA_INFO .= ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))) . '</Nm>' . $CrLf;
2743 $XML_SEPA_INFO .= ' <PstlAdr>' . $CrLf;
2744 $XML_SEPA_INFO .= ' <Ctry>' . $country[1] . '</Ctry>' . $CrLf;
2745 $addressline1 = strtr(getDolGlobalString('MAIN_INFO_SOCIETE_ADDRESS'), array(chr(13) => ", ", chr(10) => ""));
2746 $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) => ""));
2747 if ($addressline1) {
2748 $XML_SEPA_INFO .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2749 }
2750 if ($addressline2) {
2751 $XML_SEPA_INFO .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2752 }
2753 $XML_SEPA_INFO .= ' </PstlAdr>' . $CrLf;
2754 $XML_SEPA_INFO .= ' </Dbtr>' . $CrLf;
2755 $XML_SEPA_INFO .= ' <DbtrAcct>' . $CrLf;
2756 $XML_SEPA_INFO .= ' <Id>' . $CrLf;
2757 $XML_SEPA_INFO .= ' <IBAN>' . preg_replace('/\s/', '', $this->emetteur_iban) . '</IBAN>' . $CrLf;
2758 $XML_SEPA_INFO .= ' </Id>' . $CrLf;
2759 $XML_SEPA_INFO .= ' </DbtrAcct>' . $CrLf;
2760 $XML_SEPA_INFO .= ' <DbtrAgt>' . $CrLf;
2761 $XML_SEPA_INFO .= ' <FinInstnId>' . $CrLf;
2762 $XML_SEPA_INFO .= ' <BIC>' . $this->emetteur_bic . '</BIC>' . $CrLf;
2763 $XML_SEPA_INFO .= ' </FinInstnId>' . $CrLf;
2764 $XML_SEPA_INFO .= ' </DbtrAgt>' . $CrLf;
2765 /* $XML_SEPA_INFO .= ' <UltmtCdtr>'.$CrLf;
2766 $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
2767 $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
2768 $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
2769 $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;
2770 $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;
2771 $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
2772 $XML_SEPA_INFO .= ' </UltmtCdtr>'.$CrLf;*/
2773 $XML_SEPA_INFO .= ' <ChrgBr>SLEV</ChrgBr>' . $CrLf; // Field "Responsible of fees". Must be SLEV
2774 /*$XML_SEPA_INFO .= ' <CdtrSchmeId>'.$CrLf;
2775 $XML_SEPA_INFO .= ' <Id>'.$CrLf;
2776 $XML_SEPA_INFO .= ' <PrvtId>'.$CrLf;
2777 $XML_SEPA_INFO .= ' <Othr>'.$CrLf;
2778 $XML_SEPA_INFO .= ' <Id>'.$this->emetteur_ics.'</Id>'.$CrLf;
2779 $XML_SEPA_INFO .= ' <SchmeNm>'.$CrLf;
2780 $XML_SEPA_INFO .= ' <Prtry>SEPA</Prtry>'.$CrLf;
2781 $XML_SEPA_INFO .= ' </SchmeNm>'.$CrLf;
2782 $XML_SEPA_INFO .= ' </Othr>'.$CrLf;
2783 $XML_SEPA_INFO .= ' </PrvtId>'.$CrLf;
2784 $XML_SEPA_INFO .= ' </Id>'.$CrLf;
2785 $XML_SEPA_INFO .= ' </CdtrSchmeId>'.$CrLf;*/
2786 }
2787 } else {
2788 fwrite($this->file, 'INCORRECT EMETTEUR ' . $this->raison_sociale . $CrLf);
2789 $XML_SEPA_INFO = '';
2790 }
2791 return $XML_SEPA_INFO;
2792 }
2793
2794 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2801 public function EnregTotal($total)
2802 {
2803 // phpcs:enable
2804 fwrite($this->file, "08");
2805 fwrite($this->file, "08"); // Prelevement ordinaire
2806
2807 fwrite($this->file, " "); // Zone Reservee B2
2808
2809 fwrite($this->file, $this->emetteur_ics); // ICS
2810
2811 // Reserve C1
2812
2813 fwrite($this->file, substr(" ", 0, 12));
2814
2815
2816 // Raison Sociale C2
2817
2818 fwrite($this->file, substr(" ", 0, 24));
2819
2820 // D1
2821
2822 fwrite($this->file, substr(" ", 0, 24));
2823
2824 // Zone Reservee D2
2825
2826 fwrite($this->file, substr(" ", 0, 8));
2827
2828 // Code Guichet D3
2829
2830 fwrite($this->file, substr(" ", 0, 5));
2831
2832 // Numero de compte D4
2833
2834 fwrite($this->file, substr(" ", 0, 11));
2835
2836 // Zone E Montant
2837
2838 $montant = ($total * 100);
2839
2840 fwrite($this->file, substr("000000000000000" . $montant, -16));
2841
2842 // Zone Reservee F
2843
2844 fwrite($this->file, substr(" ", 0, 31));
2845
2846 // Code etablissement
2847
2848 fwrite($this->file, substr(" ", 0, 5));
2849
2850 // Zone Reservee F
2851
2852 fwrite($this->file, substr(" ", 0, 5));
2853
2854 fwrite($this->file, "\n");
2855 }
2856
2863 public function getLibStatut($mode = 0)
2864 {
2865 return $this->LibStatut((isset($this->status) ? $this->status : $this->statut), $mode);
2866 }
2867
2868 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2876 public function LibStatut($status, $mode = 0)
2877 {
2878 // phpcs:enable
2879 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
2880 global $langs;
2881 //$langs->load("mymodule");
2882 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('StatusWaiting');
2883 $this->labelStatus[self::STATUS_TRANSFERED] = $langs->transnoentitiesnoconv('StatusTrans');
2884 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('StatusWaiting');
2885 $this->labelStatusShort[self::STATUS_TRANSFERED] = $langs->transnoentitiesnoconv('StatusTrans');
2886 if ($this->type == 'bank-transfer') {
2887 $this->labelStatus[self::STATUS_DEBITED] = $langs->transnoentitiesnoconv('StatusDebited');
2888 $this->labelStatusShort[self::STATUS_DEBITED] = $langs->transnoentitiesnoconv('StatusDebited');
2889 } else {
2890 $this->labelStatus[self::STATUS_CREDITED] = $langs->transnoentitiesnoconv('StatusCredited');
2891 $this->labelStatusShort[self::STATUS_CREDITED] = $langs->transnoentitiesnoconv('StatusCredited');
2892 }
2893 }
2894
2895 $statusType = 'status1';
2896 if ($status == self::STATUS_TRANSFERED) {
2897 $statusType = 'status3';
2898 }
2899 if ($status == self::STATUS_CREDITED || $status == self::STATUS_DEBITED) {
2900 $statusType = 'status6';
2901 }
2902
2903 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
2904 }
2905
2906 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2914 public function load_board($user, $mode)
2915 {
2916 // phpcs:enable
2917 if ($user->socid) {
2918 return -1; // protection pour eviter appel par utilisateur externe
2919 }
2920
2921 /*
2922 if ($mode == 'direct_debit') {
2923 $sql = "SELECT b.rowid, f.datedue as datefin";
2924 $sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
2925 $sql .= " WHERE f.entity IN (".getEntity('facture').")";
2926 $sql .= " AND f.total_ttc > 0";
2927 } else {
2928 $sql = "SELECT b.rowid, f.datedue as datefin";
2929 $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2930 $sql .= " WHERE f.entity IN (".getEntity('facture_fourn').")";
2931 $sql .= " AND f.total_ttc > 0";
2932 }
2933
2934 $resql = $this->db->query($sql);
2935 if ($resql) {
2936 $langs->load("banks");
2937 $now = dol_now();
2938
2939 $response = new WorkboardResponse();
2940 if ($mode == 'direct_debit') {
2941 $response->warning_delay = $conf->prelevement->warning_delay / 60 / 60 / 24;
2942 $response->label = $langs->trans("PendingDirectDebitToComplete");
2943 $response->labelShort = $langs->trans("PendingDirectDebitToCompleteShort");
2944 $response->url = DOL_URL_ROOT.'/compta/prelevement/index.php?leftmenu=checks&mainmenu=bank';
2945 } else {
2946 $response->warning_delay = $conf->paymentbybanktransfer->warning_delay / 60 / 60 / 24;
2947 $response->label = $langs->trans("PendingCreditTransferToComplete");
2948 $response->labelShort = $langs->trans("PendingCreditTransferToCompleteShort");
2949 $response->url = DOL_URL_ROOT.'/compta/paymentbybanktransfer/index.php?leftmenu=checks&mainmenu=bank';
2950 }
2951 $response->img = img_object('', "payment");
2952
2953 while ($obj = $this->db->fetch_object($resql)) {
2954 $response->nbtodo++;
2955
2956 if ($this->db->jdate($obj->datefin) < ($now - $conf->withdraw->warning_delay)) {
2957 $response->nbtodolate++;
2958 }
2959 }
2960
2961 $response->nbtodo = 0;
2962 $response->nbtodolate = 0;
2963 // Return workboard only if quantity is not 0
2964 if ($response->nbtodo) {
2965 return $response;
2966 } else {
2967 return 0;
2968 }
2969 } else {
2970 dol_print_error($this->db);
2971 $this->error = $this->db->error();
2972 return -1;
2973 }
2974 */
2975 return 0;
2976 }
2977
2985 public function getKanbanView($option = '', $arraydata = null)
2986 {
2987 global $langs;
2988
2989 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
2990
2991 $return = '<div class="box-flex-item box-flex-grow-zero">';
2992 $return .= '<div class="info-box info-box-sm">';
2993 $return .= '<span class="info-box-icon bg-infobox-action">';
2994 $return .= img_picto('', $this->picto);
2995 $return .= '</span>';
2996 $return .= '<div class="info-box-content">';
2997 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . $this->getNomUrl(1) . '</span>';
2998 if ($selected >= 0) {
2999 $return .= '<input id="cb' . $this->id . '" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="' . $this->id . '"' . ($selected ? ' checked="checked"' : '') . '>';
3000 }
3001 if (isset($this->date_echeance)) {
3002 $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>';
3003 }
3004 if (isset($this->total)) {
3005 $return .= '<br><span class="opacitymedium">' . $langs->trans("Amount") . '</span> : <span class="amount">' . price($this->total) . '</span>';
3006 }
3007 $return .= '<br><div class="info-box-status">' . $this->getLibStatut(3) . '</div>';
3008 $return .= '</div>';
3009 $return .= '</div>';
3010 $return .= '</div>';
3011 return $return;
3012 }
3013
3020 {
3021 if (!empty($this->id)) {
3022 $id = $this->id;
3023 } else {
3024 return 0;
3025 }
3026 $sql = "SELECT COUNT(*) AS nb FROM " . MAIN_DB_PREFIX . "prelevement_lignes";
3027 $sql .= " WHERE fk_prelevement_bons = " . ((int) $id);
3028 $sql .= " AND fk_soc = 0"; // fk_soc can't be NULL
3029 $sql .= " AND fk_user IS NOT NULL";
3030
3031 $num = 0;
3032 $resql = $this->db->query($sql);
3033 if ($resql) {
3034 $obj = $this->db->fetch_object($resql);
3035 $num = $obj->nb;
3036 } else {
3037 dol_print_error($this->db);
3038 }
3039 if ($num > 0) {
3040 return 1;
3041 }
3042
3043 return 0;
3044 }
3045}
checkIbanForAccount($account=null, $ibantocheck=null)
Check IBAN number information for a bank account.
Definition bank.lib.php:380
checkSwiftForAccount($account=null, $swift=null)
Check SWIFT information for a bank account.
Definition bank.lib.php:359
$object ref
Definition info.php:90
Class to manage bank accounts.
Class to manage withdrawal receipts.
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.
getListInvoices($amounts=0, $type='')
Get invoice or salary list (with amount or not)
AddFacture($invoice_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key, $type='debit-order', $sourcetype='', $bic='', $iban='', $rum='')
Add invoice to withdrawal.
deleteNotificationById($rowid)
Delete a notification def by id.
addline(&$line_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key, $sourcetype='', $bic='', $iban='', $rum='')
Add line to withdrawal.
__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.
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.
generate(string $format='ALL', 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.
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 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:171
global $mysoc
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.
if(getDolGlobalString( 'TAKEPOS_SHOW_CUSTOMER')) print $langs trans('Date')." left 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 PaymentTypeShortLIQ right SELECT p pos_change as p datep as p p num_paiement as f pf amount as amount
Definition receipt.php:466
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:125
dolDecrypt($chain, $key='')
Decode a string with a symmetric encryption.