dolibarr 23.0.4
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 = ($type == 'bank-transfer') ? 'CREDIT_TRANSFER_ORDER_CREATE' : 'DIRECT_DEBIT_ORDER_CREATE';
1585 $this->amount = $this->total;
1586
1587 // Call trigger
1588 $result = $this->call_trigger($triggerName, $user);
1589 if ($result < 0) {
1590 $error++;
1591 }
1592 // End call triggers
1593 }
1594
1595 if (!$error) {
1596 $this->db->commit();
1597 return count($factures_prev); // The error of failed lines are into $this->invoice_in_error and $this->thirdparty_in_error
1598 } else {
1599 $this->db->rollback();
1600 return -1;
1601 }
1602 } else {
1603 return 0;
1604 }
1605 }
1606
1607
1615 public function delete($user, $notrigger = 0)
1616 {
1617 $this->db->begin();
1618
1619 $error = 0;
1620 $resql1 = $resql2 = $resql3 = $resql4 = 0;
1621
1622 if (!$notrigger) {
1623 $triggername = 'DIRECT_DEBIT_ORDER_DELETE';
1624 if ($this->type == 'bank-transfer') {
1625 $triggername = 'PAYMENTBYBANKTRANFER_DELETE';
1626 }
1627 // Call trigger
1628 $result = $this->call_trigger($triggername, $user);
1629 if ($result < 0) {
1630 $error++;
1631 }
1632 // End call triggers
1633 }
1634
1635 if (!$error) {
1636 $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) . ")";
1637 $resql1 = $this->db->query($sql);
1638 if (!$resql1) {
1639 dol_print_error($this->db);
1640 }
1641 }
1642
1643 if (!$error) {
1644 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "prelevement_lignes WHERE fk_prelevement_bons = " . ((int) $this->id);
1645 $resql2 = $this->db->query($sql);
1646 if (!$resql2) {
1647 dol_print_error($this->db);
1648 }
1649 }
1650
1651 if (!$error) {
1652 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "prelevement_bons WHERE rowid = " . ((int) $this->id);
1653 $resql3 = $this->db->query($sql);
1654 if (!$resql3) {
1655 dol_print_error($this->db);
1656 }
1657 }
1658
1659 if (!$error) {
1660 $sql = "UPDATE " . MAIN_DB_PREFIX . "prelevement_demande SET fk_prelevement_bons = NULL, traite = 0 WHERE fk_prelevement_bons = " . ((int) $this->id);
1661 $resql4 = $this->db->query($sql);
1662 if (!$resql4) {
1663 dol_print_error($this->db);
1664 }
1665 }
1666
1667 if ($resql1 && $resql2 && $resql3 && $resql4 && !$error) {
1668 $this->db->commit();
1669 return 1;
1670 } else {
1671 $this->db->rollback();
1672 return -1;
1673 }
1674 }
1675
1676
1687 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1688 {
1689 global $conf, $langs, $hookmanager;
1690
1691 if (!empty($conf->dol_no_mouse_hover)) {
1692 $notooltip = 1; // Force disable tooltips
1693 }
1694
1695 $result = '';
1696
1697 $labeltoshow = 'PaymentByDirectDebit';
1698 if (!empty($this->type) && $this->type == 'bank-transfer') {
1699 $labeltoshow = 'PaymentByBankTransfer';
1700 }
1701
1702 $label = img_picto('', $this->picto) . ' <u>' . $langs->trans($labeltoshow) . '</u> ' . $this->getLibStatut(5);
1703 $label .= '<br>';
1704 $label .= '<b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
1705 if (isset($this->amount)) {
1706 $label .= '<br><b>' . $langs->trans("Amount") . ":</b> " . price($this->amount);
1707 }
1708 if (isset($this->date_trans)) {
1709 $label .= '<br><b>' . $langs->trans("TransData") . ":</b> " . dol_print_date($this->date_trans, 'dayhour', 'tzuserrel');
1710 }
1711 /*if (isset($this->date_credit)) {
1712 $label .= '<br><b>'.$langs->trans("TransData").":</b> ".dol_print_date($this->date_credit, 'dayhour', 'tzuserrel');
1713 }*/
1714
1715 $url = DOL_URL_ROOT . '/compta/prelevement/card.php?id=' . $this->id;
1716 if (!empty($this->type) && $this->type == 'bank-transfer') {
1717 $url = DOL_URL_ROOT . '/compta/prelevement/card.php?id=' . $this->id;
1718 }
1719
1720 if ($option != 'nolink') {
1721 // Add param to save lastsearch_values or not
1722 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1723 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1724 $add_save_lastsearch_values = 1;
1725 }
1726 if ($add_save_lastsearch_values) {
1727 $url .= '&save_lastsearch_values=1';
1728 }
1729 }
1730
1731 $linkclose = '';
1732 if (empty($notooltip)) {
1733 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1734 $label = $langs->trans("ShowMyObject");
1735 $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
1736 }
1737 $linkclose .= ' title="' . dol_escape_htmltag($label, 1) . '"';
1738 $linkclose .= ' class="classfortooltip' . ($morecss ? ' ' . $morecss : '') . '"';
1739 } else {
1740 $linkclose = ($morecss ? ' class="' . $morecss . '"' : '');
1741 }
1742
1743 $linkstart = '<a href="' . $url . '"';
1744 $linkstart .= $linkclose . '>';
1745 $linkend = '</a>';
1746
1747 $result .= $linkstart;
1748 if ($withpicto) {
1749 $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);
1750 }
1751 if ($withpicto != 2) {
1752 $result .= $this->ref;
1753 }
1754 $result .= $linkend;
1755
1756 global $action, $hookmanager;
1757 $hookmanager->initHooks(array('banktransferdao'));
1758 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1759 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1760 if ($reshook > 0) {
1761 $result = $hookmanager->resPrint;
1762 } else {
1763 $result .= $hookmanager->resPrint;
1764 }
1765
1766 return $result;
1767 }
1768
1769
1776 public function deleteNotificationById($rowid)
1777 {
1778 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "notify_def";
1779 $sql .= " WHERE rowid = " . ((int) $rowid);
1780
1781 if ($this->db->query($sql)) {
1782 return 0;
1783 } else {
1784 return -1;
1785 }
1786 }
1787
1795 public function deleteNotification($user, $action)
1796 {
1797 if (is_object($user)) {
1798 $userid = $user->id;
1799 } else { // If user is an id
1800 $userid = $user;
1801 }
1802
1803 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "notify_def";
1804 $sql .= " WHERE fk_user = " . ((int) $userid) . " AND fk_action = " . ((int) $action);
1805
1806 if ($this->db->query($sql)) {
1807 return 0;
1808 } else {
1809 return -1;
1810 }
1811 }
1812
1813 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1822 public function addNotification($db, $user, $action)
1823 {
1824 // phpcs:enable
1825 $result = 0;
1826
1827 if (is_object($user)) {
1828 $userid = $user->id;
1829 } else { // If user is an id
1830 $userid = $user;
1831 }
1832
1833 if ($this->deleteNotification($user, $action) == 0) {
1834 $now = dol_now();
1835
1836 $sql = "INSERT INTO " . MAIN_DB_PREFIX . "notify_def (datec, fk_user, fk_soc, fk_contact, fk_action)";
1837 $sql .= " VALUES ('" . $this->db->idate($now) . "', " . ((int) $userid) . ", NULL, NULL, " . ((int) $action) . ")";
1838
1839 dol_syslog("adnotiff: " . $sql);
1840 if ($this->db->query($sql)) {
1841 $result = 0;
1842 } else {
1843 $result = -1;
1844 dol_syslog(get_class($this) . "::addNotification Error $result");
1845 }
1846 }
1847
1848 return $result;
1849 }
1850
1851
1867 public function generate(string $format = 'ALL', int $executiondate = 0, string $type = 'direct-debit', int $fk_bank_account = 0, int $forsalary = 0, int $thirdpartyBANId = 0)
1868 {
1869 global $conf, $langs, $mysoc;
1870
1871 //TODO: Optimize code to read lines in a single function
1872
1873 // Clean params
1874 if (empty($fk_bank_account)) {
1875 $fk_bank_account = ($type == 'bank-transfer' ? getDolGlobalInt('PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT') : getDolGlobalInt('PRELEVEMENT_ID_BANKACCOUNT'));
1876 }
1877
1878 $result = 0;
1879
1880 dol_syslog(get_class($this) . "::generate build file=" . $this->filename . " type=" . $type);
1881
1882 $this->file = fopen($this->filename, "w");
1883 if ($this->file == false) {
1884 $this->error = $langs->trans('ErrorFailedToOpenFile', $this->filename);
1885 return -1;
1886 }
1887
1888 $found = 0;
1889 $this->total = 0;
1890
1891 // Build file for European countries
1892 if ($mysoc->isInSEPA()) {
1893 $found++;
1894
1895 if ($type != 'bank-transfer') {
1899 // SEPA Initialisation
1900 $CrLf = "\n";
1901
1902 $now = dol_now();
1903
1904 $dateTime_ECMA = dol_print_date($now, '%Y-%m-%dT%H:%M:%S');
1905
1906 $date_actu = $now;
1907 if (!empty($executiondate)) {
1908 $date_actu = $executiondate;
1909 }
1910
1911 $dateTime_YMD = dol_print_date($date_actu, '%Y%m%d');
1912 $dateTime_YMDHMS = dol_print_date($date_actu, '%Y%m%d%H%M%S');
1913 $fileDebiteurSection = '';
1914 $fileEmetteurSection = '';
1915 $i = 0;
1916
1917 /*
1918 * Section Debitor (sepa Debiteurs block lines)
1919 */
1920
1921 $sql = "SELECT soc.rowid as socid, soc.code_client as code, soc.address, soc.zip, soc.town, c.code as country_code,";
1922 $sql .= " pl.client_nom as nom, pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, pl.amount as somme,";
1923 $sql .= " f.ref as reffac, p.fk_facture as idfac,";
1924 $sql .= " rib.rowid, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum, rib.rum, rib.date_rum";
1925 $sql .= " FROM";
1926 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
1927 $sql .= " " . MAIN_DB_PREFIX . "facture as f,";
1928 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p,";
1929 $sql .= " " . MAIN_DB_PREFIX . "societe as soc,";
1930 $sql .= " " . MAIN_DB_PREFIX . "c_country as c,";
1931 $sql .= " " . MAIN_DB_PREFIX . "societe_rib as rib";
1932 $sql .= " WHERE pl.fk_prelevement_bons = " . ((int) $this->id);
1933 $sql .= " AND pl.rowid = p.fk_prelevement_lignes";
1934 $sql .= " AND p.fk_facture = f.rowid";
1935 $sql .= " AND f.fk_soc = soc.rowid";
1936 $sql .= " AND soc.fk_pays = c.rowid";
1937 $sql .= " AND rib.fk_soc = f.fk_soc";
1938 if (!empty($thirdpartyBANId)) {
1939 $sql .= " AND rib.rowid = " . ((int) $thirdpartyBANId);
1940 } else {
1941 $sql .= " AND rib.default_rib = 1";
1942 }
1943 $sql .= " AND rib.type = 'ban'";
1944
1945 // Define $fileDebiteurSection. One section DrctDbtTxInf per invoice.
1946 $resql = $this->db->query($sql);
1947 $nbtotalDrctDbtTxInf = -1;
1948 if ($resql) {
1949 $cachearraytotestduplicate = array();
1950
1951 $num = $this->db->num_rows($resql);
1952 while ($i < $num) {
1953 $obj = $this->db->fetch_object($resql);
1954
1955 if (!empty($cachearraytotestduplicate[$obj->idfac])) {
1956 $this->error = $langs->trans('ErrorCompanyHasDuplicateDefaultBAN', $obj->socid);
1957 $this->invoice_in_error[$obj->idfac] = $this->error;
1958 $result = -2;
1959 break;
1960 }
1961 $cachearraytotestduplicate[$obj->idfac] = $obj->rowid;
1962
1963 $daterum = (!empty($obj->date_rum)) ? $this->db->jdate($obj->date_rum) : $this->db->jdate($obj->datec);
1964 $iban = dolDecrypt($obj->iban);
1965
1966 $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);
1967
1968 $this->total += $obj->somme;
1969 $i++;
1970 }
1971 $nbtotalDrctDbtTxInf = $i;
1972 } else {
1973 $this->error = $this->db->lasterror();
1974 fwrite($this->file, 'ERROR DEBITOR ' . $sql . $CrLf); // DEBITOR = Customers
1975 $result = -2;
1976 }
1977
1978 // Define $fileEmetteurSection. Start of block PmtInf. Will contains all $nbtotalDrctDbtTxInf
1979 if ($result != -2) {
1980 $fileEmetteurSection .= $this->EnregEmetteurSEPA($conf, $date_actu, $nbtotalDrctDbtTxInf, $this->total, $CrLf, $format, $type, $fk_bank_account);
1981 }
1982
1983 if (getDolGlobalString('SEPA_FORCE_TWO_DECIMAL')) {
1984 $this->total = number_format((float) price2num($this->total, 'MT'), 2, ".", "");
1985 }
1986
1990 // SEPA File Header
1991 fwrite($this->file, '<' . '?xml version="1.0" encoding="UTF-8" standalone="yes"?' . '>' . $CrLf);
1992 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);
1993 fwrite($this->file, ' <CstmrDrctDbtInitn>' . $CrLf);
1994 // SEPA Group header
1995 fwrite($this->file, ' <GrpHdr>' . $CrLf);
1996 fwrite($this->file, ' <MsgId>' . ('DOL/' . $dateTime_YMD . '/DD' . $this->id) . '</MsgId>' . $CrLf);
1997 fwrite($this->file, ' <CreDtTm>' . $dateTime_ECMA . '</CreDtTm>' . $CrLf);
1998 fwrite($this->file, ' <NbOfTxs>' . $i . '</NbOfTxs>' . $CrLf);
1999 fwrite($this->file, ' <CtrlSum>' . $this->total . '</CtrlSum>' . $CrLf);
2000 fwrite($this->file, ' <InitgPty>' . $CrLf);
2001 fwrite($this->file, ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))) . '</Nm>' . $CrLf);
2002 fwrite($this->file, ' <Id>' . $CrLf);
2003 fwrite($this->file, ' <PrvtId>' . $CrLf);
2004 fwrite($this->file, ' <Othr>' . $CrLf);
2005 fwrite($this->file, ' <Id>' . $this->emetteur_ics . '</Id>' . $CrLf);
2006 fwrite($this->file, ' </Othr>' . $CrLf);
2007 fwrite($this->file, ' </PrvtId>' . $CrLf);
2008 fwrite($this->file, ' </Id>' . $CrLf);
2009 fwrite($this->file, ' </InitgPty>' . $CrLf);
2010 fwrite($this->file, ' </GrpHdr>' . $CrLf);
2011 // SEPA File Emetteur
2012 if ($result != -2) {
2013 fwrite($this->file, $fileEmetteurSection);
2014 }
2015 // SEPA File Debiteurs
2016 if ($result != -2) {
2017 fwrite($this->file, $fileDebiteurSection);
2018 }
2019 // SEPA FILE FOOTER
2020 fwrite($this->file, ' </PmtInf>' . $CrLf);
2021 fwrite($this->file, ' </CstmrDrctDbtInitn>' . $CrLf);
2022 fwrite($this->file, '</Document>' . $CrLf);
2023 } else {
2027 // SEPA Initialisation
2028 $CrLf = "\n";
2029
2030 $now = dol_now();
2031
2032 $dateTime_ECMA = dol_print_date($now, '%Y-%m-%dT%H:%M:%S');
2033
2034 $date_actu = $now;
2035 if (!empty($executiondate)) {
2036 $date_actu = $executiondate;
2037 }
2038
2039 $dateTime_YMD = dol_print_date($date_actu, '%Y%m%d');
2040 $dateTime_YMDHMS = dol_print_date($date_actu, '%Y%m%d%H%M%S');
2041 $fileCrediteurSection = '';
2042 $fileEmetteurSection = '';
2043 $i = 0;
2044
2045 /*
2046 * Section Creditor (sepa Crediteurs block lines)
2047 */
2048 if (!empty($forsalary)) {
2049 $sql = "SELECT u.rowid as userId, u.address, u.zip, u.town, c.code as country_code, CONCAT(u.firstname,' ',u.lastname) as nom,";
2050 $sql .= " pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, pl.amount as somme,";
2051 $sql .= " s.ref as reffac, p.fk_salary as idfac,";
2052 $sql .= " rib.rowid, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum, '' as rum, '' as date_rum";
2053 $sql .= " FROM";
2054 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
2055 $sql .= " " . MAIN_DB_PREFIX . "salary as s,";
2056 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p,";
2057 $sql .= " " . MAIN_DB_PREFIX . "user as u";
2058 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_country as c ON u.fk_country = c.rowid,";
2059 $sql .= " " . MAIN_DB_PREFIX . "user_rib as rib";
2060 $sql .= " WHERE pl.fk_prelevement_bons=" . ((int) $this->id);
2061 $sql .= " AND pl.rowid = p.fk_prelevement_lignes";
2062 $sql .= " AND p.fk_salary = s.rowid";
2063 $sql .= " AND s.fk_user = u.rowid";
2064 $sql .= " AND rib.fk_user = s.fk_user";
2065 } else {
2066 $sql = "SELECT soc.rowid as socid, soc.code_client as code, soc.address, soc.zip, soc.town, c.code as country_code,";
2067 $sql .= " pl.client_nom as nom, pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, pl.amount as somme,";
2068 $sql .= " f.ref as reffac, f.ref_supplier as fac_ref_supplier, p.fk_facture_fourn as idfac,";
2069 $sql .= " rib.rowid, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum, rib.rum, rib.date_rum";
2070 $sql .= " FROM";
2071 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
2072 $sql .= " " . MAIN_DB_PREFIX . "facture_fourn as f,";
2073 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p,";
2074 $sql .= " " . MAIN_DB_PREFIX . "societe as soc";
2075 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_country as c ON soc.fk_pays = c.rowid,";
2076 $sql .= " " . MAIN_DB_PREFIX . "societe_rib as rib";
2077 $sql .= " WHERE pl.fk_prelevement_bons = " . ((int) $this->id);
2078 $sql .= " AND pl.rowid = p.fk_prelevement_lignes";
2079 $sql .= " AND p.fk_facture_fourn = f.rowid";
2080 $sql .= " AND f.fk_soc = soc.rowid";
2081 $sql .= " AND rib.fk_soc = f.fk_soc";
2082 if (!empty($thirdpartyBANId)) {
2083 $sql .= " AND rib.rowid = " . ((int) $thirdpartyBANId);
2084 } else {
2085 $sql .= " AND rib.default_rib = 1";
2086 }
2087 $sql .= " AND rib.type = 'ban'";
2088 }
2089 // Define $fileCrediteurSection. One section DrctDbtTxInf per invoice.
2090 $nbtotalDrctDbtTxInf = -1;
2091
2092 $resql = $this->db->query($sql);
2093 if ($resql) {
2094 $cachearraytotestduplicate = array();
2095
2096 $num = $this->db->num_rows($resql);
2097 while ($i < $num) {
2098 $obj = $this->db->fetch_object($resql);
2099 if (!empty($cachearraytotestduplicate[$obj->idfac])) {
2100 $this->error = $langs->trans('ErrorCompanyHasDuplicateDefaultBAN', $obj->socid);
2101 $this->invoice_in_error[$obj->idfac] = $this->error;
2102 $result = -2;
2103 break;
2104 }
2105 $cachearraytotestduplicate[$obj->idfac] = $obj->rowid;
2106
2107 $daterum = (!empty($obj->date_rum)) ? $this->db->jdate($obj->date_rum) : $this->db->jdate($obj->datec);
2108 $iban = dolDecrypt($obj->iban);
2109 $refobj = $obj->reffac;
2110 if (empty($refobj) && !empty($forsalary)) { // If ref of salary not defined, we force a value
2111 $refobj = "SAL" . $obj->idfac;
2112 }
2113
2114 $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);
2115
2116 $this->total += $obj->somme;
2117 $i++;
2118 }
2119 $nbtotalDrctDbtTxInf = $i;
2120 } else {
2121 $this->error = $this->db->lasterror();
2122 fwrite($this->file, 'ERROR CREDITOR ' . $sql . $CrLf); // CREDITORS = Suppliers
2123 $result = -2;
2124 }
2125 // Define $fileEmetteurSection. Start of block PmtInf. Will contains all $nbtotalDrctDbtTxInf
2126 if ($result != -2) {
2127 $fileEmetteurSection .= $this->EnregEmetteurSEPA($conf, $date_actu, $nbtotalDrctDbtTxInf, $this->total, $CrLf, $format, $type);
2128 }
2129
2130 if (getDolGlobalString('SEPA_FORCE_TWO_DECIMAL')) {
2131 $this->total = number_format((float) price2num($this->total, 'MT'), 2, ".", "");
2132 }
2133
2137 // SEPA File Header
2138 fwrite($this->file, '<' . '?xml version="1.0" encoding="UTF-8" standalone="yes"?' . '>' . $CrLf);
2139 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);
2140 fwrite($this->file, ' <CstmrCdtTrfInitn>' . $CrLf);
2141 // SEPA Group header
2142 fwrite($this->file, ' <GrpHdr>' . $CrLf);
2143 fwrite($this->file, ' <MsgId>' . ('DOL/' . $dateTime_YMD . '/CT' . $this->id) . '</MsgId>' . $CrLf);
2144 fwrite($this->file, ' <CreDtTm>' . $dateTime_ECMA . '</CreDtTm>' . $CrLf);
2145 fwrite($this->file, ' <NbOfTxs>' . $i . '</NbOfTxs>' . $CrLf);
2146 fwrite($this->file, ' <CtrlSum>' . $this->total . '</CtrlSum>' . $CrLf);
2147 fwrite($this->file, ' <InitgPty>' . $CrLf);
2148 fwrite($this->file, ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))) . '</Nm>' . $CrLf);
2149 fwrite($this->file, ' <Id>' . $CrLf);
2150 fwrite($this->file, ' <PrvtId>' . $CrLf);
2151 fwrite($this->file, ' <Othr>' . $CrLf);
2152 fwrite($this->file, ' <Id>' . $this->emetteur_ics . '</Id>' . $CrLf);
2153 fwrite($this->file, ' </Othr>' . $CrLf);
2154 fwrite($this->file, ' </PrvtId>' . $CrLf);
2155 fwrite($this->file, ' </Id>' . $CrLf);
2156 fwrite($this->file, ' </InitgPty>' . $CrLf);
2157 fwrite($this->file, ' </GrpHdr>' . $CrLf);
2158 // SEPA File Emetteur (mycompany)
2159 if ($result != -2) {
2160 fwrite($this->file, $fileEmetteurSection);
2161 }
2162 // SEPA File Creditors
2163 if ($result != -2) {
2164 fwrite($this->file, $fileCrediteurSection);
2165 }
2166 // SEPA FILE FOOTER
2167 fwrite($this->file, ' </PmtInf>' . $CrLf);
2168 fwrite($this->file, ' </CstmrCdtTrfInitn>' . $CrLf);
2169 fwrite($this->file, '</Document>' . $CrLf);
2170 }
2171 }
2172
2173 // Build file for Other Countries with unknown format
2174 if (!$found) {
2175 if ($type != 'bank-transfer') {
2176 $sql = "SELECT pl.amount";
2177 $sql .= " FROM";
2178 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
2179 $sql .= " " . MAIN_DB_PREFIX . "facture as f,";
2180 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p";
2181 $sql .= " WHERE pl.fk_prelevement_bons = " . ((int) $this->id);
2182 $sql .= " AND pl.rowid = p.fk_prelevement_lignes";
2183 $sql .= " AND p.fk_facture = f.rowid";
2184
2185 // Lines
2186 $i = 0;
2187 $resql = $this->db->query($sql);
2188 if ($resql) {
2189 $num = $this->db->num_rows($resql);
2190
2191 while ($i < $num) {
2192 $obj = $this->db->fetch_object($resql);
2193 $this->total += $obj->amount;
2194
2195 // TODO Write record into file
2196 $i++;
2197 }
2198 } else {
2199 $result = -2;
2200 }
2201 } else {
2202 $sql = "SELECT pl.amount";
2203 $sql .= " FROM";
2204 $sql .= " " . MAIN_DB_PREFIX . "prelevement_lignes as pl,";
2205 $sql .= " " . MAIN_DB_PREFIX . "facture_fourn as f,";
2206 $sql .= " " . MAIN_DB_PREFIX . "prelevement as p";
2207 $sql .= " WHERE pl.fk_prelevement_bons = " . ((int) $this->id);
2208 $sql .= " AND pl.rowid = p.fk_prelevement_lignes";
2209 $sql .= " AND p.fk_facture_fourn = f.rowid";
2210 // Lines
2211 $i = 0;
2212 $resql = $this->db->query($sql);
2213 if ($resql) {
2214 $num = $this->db->num_rows($resql);
2215
2216 while ($i < $num) {
2217 $obj = $this->db->fetch_object($resql);
2218 $this->total += $obj->amount;
2219
2220 // TODO Write record into file
2221 $i++;
2222 }
2223 } else {
2224 $result = -2;
2225 }
2226 }
2227
2228 $langs->load('withdrawals');
2229
2230 // TODO Add here code to generate a generic file
2231 fwrite($this->file, $langs->transnoentitiesnoconv('WithdrawalFileNotCapable', $mysoc->country_code));
2232 }
2233
2234 fclose($this->file);
2235 dolChmod($this->filename);
2236
2237 return $result;
2238 }
2239
2240
2249 public static function buildRumNumber($row_code_client, $row_datec, $row_drum)
2250 {
2251 global $langs;
2252
2253 $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)
2254
2255 // 3 char + '-' + 10 (yymmddHHMM) + '-' + id + '-' + code. Must be under 32 (SEPA char limit for MndtId is however 35).
2256 return $pre . '-' . dol_print_date($row_datec, 'dayhourlogsmall') . '-' . dol_trunc($row_drum . ($row_code_client ? '-' . $row_code_client : ''), 17, 'right', 'UTF-8', 1);
2257 }
2258
2259
2260 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2277 public function EnregDestinataire($rowid, $client_nom, $rib_banque, $rib_guichet, $rib_number, $amount, $ref, $facid, $rib_dom = '', $type = 'direct-debit')
2278 {
2279 // phpcs:enable
2280 fwrite($this->file, "06");
2281 fwrite($this->file, "08"); // Prelevement ordinaire
2282
2283 fwrite($this->file, " "); // Zone Reservee B2
2284
2285 fwrite($this->file, $this->emetteur_ics); // ICS
2286
2287 // Date d'echeance C1
2288
2289 fwrite($this->file, " ");
2290 fwrite($this->file, dol_print_date($this->date_echeance, "%d%m", 'gmt'));
2291 fwrite($this->file, substr(dol_print_date($this->date_echeance, "%y", 'gmt'), 1));
2292
2293 // Raison Sociale Destinataire C2
2294
2295 fwrite($this->file, substr(strtoupper($client_nom) . " ", 0, 24));
2296
2297 // Address optional D1
2298 $address = strtr($rib_dom, array(" " => "-", chr(13) => " ", chr(10) => ""));
2299 fwrite($this->file, substr($address . " ", 0, 24));
2300
2301 // Zone Reservee D2
2302
2303 fwrite($this->file, substr(" ", 0, 8));
2304
2305 // Code Guichet D3
2306
2307 fwrite($this->file, $rib_guichet);
2308
2309 // Numero de compte D4
2310
2311 fwrite($this->file, substr("000000000000000" . $rib_number, -11));
2312
2313 // Zone E Montant
2314
2315 $montant = (round($amount, 2) * 100);
2316
2317 fwrite($this->file, substr("000000000000000" . $montant, -16));
2318
2319 // Label F
2320
2321 fwrite($this->file, substr("*_" . $ref . "_RDVnet" . $rowid . " ", 0, 31));
2322
2323 // Code etablissement G1
2324
2325 fwrite($this->file, $rib_banque);
2326
2327 // Zone Reservee G2
2328
2329 fwrite($this->file, substr(" ", 0, 5));
2330
2331 fwrite($this->file, "\n");
2332 }
2333
2334
2335 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2361 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 = '')
2362 {
2363 // phpcs:enable
2364 global $conf, $mysoc;
2365
2366 if (getDolGlobalString('SEPA_FORCE_TWO_DECIMAL')) {
2367 $row_somme = number_format((float) price2num($row_somme, 'MT'), 2, ".", "");
2368 } else {
2369 $row_somme = round((float) $row_somme, 2);
2370 }
2371
2372 include_once DOL_DOCUMENT_ROOT . '/core/lib/functions2.lib.php';
2373
2374 $CrLf = "\n";
2375 $Rowing = sprintf("%010d", $row_idfac);
2376
2377 // Define value for RUM
2378 // Example: RUM-CustomerCode-CustomerBankAccountId-01424448606 (note: Date is the timestamp of the date of creation of CustomerBankAccountId)
2379 $Rum = (empty($row_rum) ? $this->buildRumNumber($row_code_client, $row_datec, $row_drum) : $row_rum);
2380
2381 // Define date of RUM signature
2382 $DtOfSgntr = dol_print_date($row_datec, '%Y-%m-%d');
2383
2384 if ($type != 'bank-transfer') {
2385 // SEPA Paiement Information of buyer for Direct Debit
2386 $XML_DEBITOR = '';
2387 $XML_DEBITOR .= ' <DrctDbtTxInf>' . $CrLf;
2388 $XML_DEBITOR .= ' <PmtId>' . $CrLf;
2389 // Add EndToEndId. Must be a unique ID for each payment (for example by including bank, buyer or seller, date, checksum)
2390 $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
2391 $XML_DEBITOR .= ' </PmtId>' . $CrLf;
2392 $XML_DEBITOR .= ' <InstdAmt Ccy="EUR">' . $row_somme . '</InstdAmt>' . $CrLf;
2393 $XML_DEBITOR .= ' <DrctDbtTx>' . $CrLf;
2394 $XML_DEBITOR .= ' <MndtRltdInf>' . $CrLf;
2395 $XML_DEBITOR .= ' <MndtId>' . $Rum . '</MndtId>' . $CrLf;
2396 $XML_DEBITOR .= ' <DtOfSgntr>' . $DtOfSgntr . '</DtOfSgntr>' . $CrLf;
2397 $XML_DEBITOR .= ' <AmdmntInd>false</AmdmntInd>' . $CrLf;
2398 $XML_DEBITOR .= ' </MndtRltdInf>' . $CrLf;
2399 $XML_DEBITOR .= ' </DrctDbtTx>' . $CrLf;
2400 $XML_DEBITOR .= ' <DbtrAgt>' . $CrLf;
2401 $XML_DEBITOR .= ' <FinInstnId>' . $CrLf;
2402 if (getDolGlobalInt('WITHDRAWAL_WITHOUT_BIC') == 0) {
2403 $XML_DEBITOR .= ' <BIC>' . $row_bic . '</BIC>' . $CrLf;
2404 }
2405 $XML_DEBITOR .= ' </FinInstnId>' . $CrLf;
2406 $XML_DEBITOR .= ' </DbtrAgt>' . $CrLf;
2407 $XML_DEBITOR .= ' <Dbtr>' . $CrLf;
2408 $XML_DEBITOR .= ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($row_nom), ' '))) . '</Nm>' . $CrLf;
2409 $XML_DEBITOR .= ' <PstlAdr>' . $CrLf;
2410 $XML_DEBITOR .= ' <Ctry>' . $row_country_code . '</Ctry>' . $CrLf;
2411 $addressline1 = strtr($row_address, array(chr(13) => ", ", chr(10) => ""));
2412 $addressline2 = strtr($row_zip . (($row_zip && $row_town) ? ' ' : '') . (string) $row_town, array(chr(13) => ", ", chr(10) => ""));
2413 if (trim($addressline1)) {
2414 $XML_DEBITOR .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2415 }
2416 if (trim($addressline2)) {
2417 $XML_DEBITOR .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2418 }
2419 $XML_DEBITOR .= ' </PstlAdr>' . $CrLf;
2420 $XML_DEBITOR .= ' </Dbtr>' . $CrLf;
2421 $XML_DEBITOR .= ' <DbtrAcct>' . $CrLf;
2422 $XML_DEBITOR .= ' <Id>' . $CrLf;
2423 $XML_DEBITOR .= ' <IBAN>' . preg_replace('/\s/', '', $row_iban) . '</IBAN>' . $CrLf;
2424 $XML_DEBITOR .= ' </Id>' . $CrLf;
2425 $XML_DEBITOR .= ' </DbtrAcct>' . $CrLf;
2426 $XML_DEBITOR .= ' <RmtInf>' . $CrLf;
2427
2428 // Structured data for Belgium
2429 if (getDolGlobalString('INVOICE_PAYMENT_ENABLE_STRUCTURED_COMMUNICATION') && $mysoc->country_code == 'BE') {
2430 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions_be.lib.php';
2431
2432 $invoicestatic = new Facture($this->db);
2433 $invoicestatic->fetch($row_idfac);
2434
2435 $invoicePaymentKey = dolBECalculateStructuredCommunication($invoicestatic->ref, $invoicestatic->type);
2436 $XML_DEBITOR .= ' <strd>' . $invoicePaymentKey . '</strd>' . $CrLf;
2437 } else {
2438 // A string with some information on payment - 140 max
2439 $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
2440 }
2441 $XML_DEBITOR .= ' </RmtInf>' . $CrLf;
2442 $XML_DEBITOR .= ' </DrctDbtTxInf>' . $CrLf;
2443 return $XML_DEBITOR;
2444 } else {
2445 // SEPA Payment Information of seller for Credit Transfer
2446 $XML_CREDITOR = '';
2447 $XML_CREDITOR .= ' <CdtTrfTxInf>' . $CrLf;
2448 $XML_CREDITOR .= ' <PmtId>' . $CrLf;
2449 // Add EndToEndId. Must be a unique ID for each payment (for example by including bank, buyer or seller, date, checksum)
2450 $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
2451 $XML_CREDITOR .= ' </PmtId>' . $CrLf;
2452 if (!empty($this->sepa_xml_pti_in_ctti)) {
2453 $XML_CREDITOR .= ' <PmtTpInf>' . $CrLf;
2454
2455 // Can be 'NORM' for normal or 'HIGH' for high priority level
2456 if (getDolGlobalString('PAYMENTBYBANKTRANSFER_FORCE_HIGH_PRIORITY')) {
2457 $instrprty = 'HIGH';
2458 } else {
2459 $instrprty = 'NORM';
2460 }
2461
2462 // Set $categoryPurpose: CORE, TREA, SUPP, ...
2463 $categoryPurpose = getDolGlobalString('PAYMENTBYBANKTRANSFER_CUSTOM_CATEGORY_PURPOSE', 'CORE');
2464
2465 $XML_CREDITOR .= ' <InstrPrty>' . $instrprty . '</InstrPrty>' . $CrLf;
2466 $XML_CREDITOR .= ' <SvcLvl>' . $CrLf;
2467 $XML_CREDITOR .= ' <Cd>SEPA</Cd>' . $CrLf;
2468 $XML_CREDITOR .= ' </SvcLvl>' . $CrLf;
2469 $XML_CREDITOR .= ' <CtgyPurp>' . $CrLf;
2470 $XML_CREDITOR .= ' <Cd>' . $categoryPurpose . '</Cd>' . $CrLf;
2471 $XML_CREDITOR .= ' </CtgyPurp>' . $CrLf;
2472 $XML_CREDITOR .= ' </PmtTpInf>' . $CrLf;
2473 }
2474 $XML_CREDITOR .= ' <Amt>' . $CrLf;
2475 $XML_CREDITOR .= ' <InstdAmt Ccy="EUR">'.round((float) $row_somme, 2).'</InstdAmt>'.$CrLf;
2476 $XML_CREDITOR .= ' </Amt>' . $CrLf;
2477 /*
2478 $XML_CREDITOR .= ' <DrctDbtTx>'.$CrLf;
2479 $XML_CREDITOR .= ' <MndtRltdInf>'.$CrLf;
2480 $XML_CREDITOR .= ' <MndtId>'.$Rum.'</MndtId>'.$CrLf;
2481 $XML_CREDITOR .= ' <DtOfSgntr>'.$DtOfSgntr.'</DtOfSgntr>'.$CrLf;
2482 $XML_CREDITOR .= ' <AmdmntInd>false</AmdmntInd>'.$CrLf;
2483 $XML_CREDITOR .= ' </MndtRltdInf>'.$CrLf;
2484 $XML_CREDITOR .= ' </DrctDbtTx>'.$CrLf;
2485 */
2486 //$XML_CREDITOR .= ' <ChrgBr>SLEV</ChrgBr>'.$CrLf;
2487 $XML_CREDITOR .= ' <CdtrAgt>' . $CrLf;
2488 $XML_CREDITOR .= ' <FinInstnId>' . $CrLf;
2489 $XML_CREDITOR .= ' <BIC>' . $row_bic . '</BIC>' . $CrLf;
2490 $XML_CREDITOR .= ' </FinInstnId>' . $CrLf;
2491 $XML_CREDITOR .= ' </CdtrAgt>' . $CrLf;
2492 $XML_CREDITOR .= ' <Cdtr>' . $CrLf;
2493 $XML_CREDITOR .= ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($row_nom), ' '))) . '</Nm>' . $CrLf;
2494 $XML_CREDITOR .= ' <PstlAdr>' . $CrLf;
2495 $XML_CREDITOR .= ' <Ctry>' . $row_country_code . '</Ctry>' . $CrLf;
2496 $addressline1 = strtr($row_address, array(chr(13) => ", ", chr(10) => ""));
2497 $addressline2 = strtr($row_zip . (($row_zip && $row_town) ? ' ' : '') . (string) $row_town, array(chr(13) => ", ", chr(10) => ""));
2498 if (trim($addressline1)) {
2499 $XML_CREDITOR .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2500 }
2501 if (trim($addressline2)) {
2502 $XML_CREDITOR .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2503 }
2504 $XML_CREDITOR .= ' </PstlAdr>' . $CrLf;
2505 $XML_CREDITOR .= ' </Cdtr>' . $CrLf;
2506 $XML_CREDITOR .= ' <CdtrAcct>' . $CrLf;
2507 $XML_CREDITOR .= ' <Id>' . $CrLf;
2508 $XML_CREDITOR .= ' <IBAN>' . preg_replace('/\s/', '', $row_iban) . '</IBAN>' . $CrLf;
2509 $XML_CREDITOR .= ' </Id>' . $CrLf;
2510 $XML_CREDITOR .= ' </CdtrAcct>' . $CrLf;
2511 $XML_CREDITOR .= ' <RmtInf>' . $CrLf;
2512 // A string with some information on payment - 140 max
2513 $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
2514 $XML_CREDITOR .= ' </RmtInf>' . $CrLf;
2515 $XML_CREDITOR .= ' </CdtTrfTxInf>' . $CrLf;
2516 return $XML_CREDITOR;
2517 }
2518 }
2519
2520
2521 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2530 public function EnregEmetteur($type = 'direct-debit')
2531 {
2532 // phpcs:enable
2533 fwrite($this->file, "03");
2534 fwrite($this->file, "08"); // Prelevement ordinaire
2535
2536 fwrite($this->file, " "); // Zone Reservee B2
2537
2538 fwrite($this->file, $this->emetteur_ics); // ICS
2539
2540 // Date d'echeance C1
2541
2542 fwrite($this->file, " ");
2543 fwrite($this->file, dol_print_date($this->date_echeance, "%d%m", 'gmt'));
2544 fwrite($this->file, substr(dol_print_date($this->date_echeance, "%y", 'gmt'), 1));
2545
2546 // Raison Sociale C2
2547
2548 fwrite($this->file, substr($this->raison_sociale . " ", 0, 24));
2549
2550 // Ref of thirdparty on 7 characters
2551
2552 fwrite($this->file, substr($this->reference_remise . " ", 0, 7));
2553
2554 // Zone Reservee D1-2
2555
2556 fwrite($this->file, substr(" ", 0, 17));
2557
2558 // Zone Reservee D2
2559
2560 fwrite($this->file, substr(" ", 0, 2));
2561 fwrite($this->file, "E");
2562 fwrite($this->file, substr(" ", 0, 5));
2563
2564 // Code Guichet D3
2565
2566 fwrite($this->file, $this->emetteur_code_guichet);
2567
2568 // Numero de compte D4
2569
2570 fwrite($this->file, substr("000000000000000" . $this->emetteur_numero_compte, -11));
2571
2572 // Zone Reservee E
2573
2574 fwrite($this->file, substr(" ", 0, 16));
2575
2576 // Zone Reservee F
2577
2578 fwrite($this->file, substr(" ", 0, 31));
2579
2580 // Code etablissement
2581
2582 fwrite($this->file, $this->emetteur_code_banque);
2583
2584 // Zone Reservee G
2585
2586 fwrite($this->file, substr(" ", 0, 5));
2587
2588 fwrite($this->file, "\n");
2589 }
2590
2591
2592 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2607 public function EnregEmetteurSEPA($configuration, $ladate, $nombre, $total, $CrLf = '\n', $format = 'FRST', $type = 'direct-debit', $fk_bank_account = 0)
2608 {
2609 // phpcs:enable
2610
2611 // Clean parameters
2612 $dateTime_YMD = dol_print_date($ladate, '%Y%m%d');
2613 $dateTime_ETAD = dol_print_date($ladate, '%Y-%m-%d');
2614 $dateTime_YMDHMS = dol_print_date($ladate, '%Y-%m-%dT%H:%M:%S');
2615
2616 // Clean params
2617 if (empty($fk_bank_account)) {
2618 $fk_bank_account = ($type == 'bank-transfer' ? getDolGlobalInt('PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT') : getDolGlobalInt('PRELEVEMENT_ID_BANKACCOUNT'));
2619 }
2620
2621 // Get data of bank account
2622 $account = new Account($this->db);
2623 if ($account->fetch($fk_bank_account) > 0) {
2624 $this->emetteur_code_banque = $account->code_banque;
2625 $this->emetteur_code_guichet = $account->code_guichet;
2626 $this->emetteur_numero_compte = $account->number;
2627 $this->emetteur_number_key = $account->cle_rib;
2628 $this->sepa_xml_pti_in_ctti = (bool) $account->pti_in_ctti;
2629 $this->emetteur_iban = $account->iban;
2630 $this->emetteur_bic = $account->bic;
2631
2632 $this->emetteur_ics = (($type == 'bank-transfer' && getDolGlobalString("SEPA_USE_IDS")) ? $account->ics_transfer : $account->ics); // Ex: PRELEVEMENT_ICS = "FR78ZZZ123456";
2633
2634 $this->raison_sociale = $account->owner_name;
2635 }
2636
2637 // Get pending payments
2638 $sql = "SELECT rowid, ref";
2639 $sql .= " FROM " . MAIN_DB_PREFIX . "prelevement_bons as pb";
2640 $sql .= " WHERE pb.rowid = " . ((int) $this->id);
2641
2642 $resql = $this->db->query($sql);
2643 if ($resql) {
2644 $obj = $this->db->fetch_object($resql);
2645
2646 $country = explode(':', getDolGlobalString('MAIN_INFO_SOCIETE_COUNTRY'));
2647 $IdBon = sprintf("%05d", $obj->rowid);
2648 $RefBon = $obj->ref;
2649 $localInstrument = getDolGlobalString('PAYMENTBYBANKTRANSFER_CUSTOM_LOCAL_INSTRUMENT', 'CORE');
2650
2651 if (getDolGlobalString('SEPA_FORCE_TWO_DECIMAL')) {
2652 $total = number_format((float) price2num($total, 'MT'), 2, ".", "");
2653 }
2654
2655 if ($type != 'bank-transfer') {
2656 // SEPA Paiement Information of my company for Direct Debit
2657 $XML_SEPA_INFO = '';
2658 $XML_SEPA_INFO .= ' <PmtInf>' . $CrLf;
2659 $XML_SEPA_INFO .= ' <PmtInfId>' . ('DOL/' . $dateTime_YMD . '/DD' . $IdBon . '-' . $RefBon) . '</PmtInfId>' . $CrLf;
2660 $XML_SEPA_INFO .= ' <PmtMtd>DD</PmtMtd>' . $CrLf;
2661 $XML_SEPA_INFO .= ' <NbOfTxs>' . $nombre . '</NbOfTxs>' . $CrLf;
2662 $XML_SEPA_INFO .= ' <CtrlSum>' . $total . '</CtrlSum>' . $CrLf;
2663 $XML_SEPA_INFO .= ' <PmtTpInf>' . $CrLf;
2664 $XML_SEPA_INFO .= ' <SvcLvl>' . $CrLf;
2665 $XML_SEPA_INFO .= ' <Cd>SEPA</Cd>' . $CrLf;
2666 $XML_SEPA_INFO .= ' </SvcLvl>' . $CrLf;
2667 $XML_SEPA_INFO .= ' <LclInstrm>' . $CrLf;
2668 $XML_SEPA_INFO .= ' <Cd>' . $localInstrument . '</Cd>' . $CrLf;
2669 $XML_SEPA_INFO .= ' </LclInstrm>' . $CrLf;
2670 $XML_SEPA_INFO .= ' <SeqTp>' . $format . '</SeqTp>' . $CrLf;
2671 $XML_SEPA_INFO .= ' </PmtTpInf>' . $CrLf;
2672 $XML_SEPA_INFO .= ' <ReqdColltnDt>' . $dateTime_ETAD . '</ReqdColltnDt>' . $CrLf;
2673 $XML_SEPA_INFO .= ' <Cdtr>' . $CrLf;
2674 $XML_SEPA_INFO .= ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))) . '</Nm>' . $CrLf;
2675 $XML_SEPA_INFO .= ' <PstlAdr>' . $CrLf;
2676 $XML_SEPA_INFO .= ' <Ctry>' . $country[1] . '</Ctry>' . $CrLf;
2677 $addressline1 = strtr(getDolGlobalString('MAIN_INFO_SOCIETE_ADDRESS'), array(chr(13) => ", ", chr(10) => ""));
2678 $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) => ""));
2679 if ($addressline1) {
2680 $XML_SEPA_INFO .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2681 }
2682 if ($addressline2) {
2683 $XML_SEPA_INFO .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2684 }
2685 $XML_SEPA_INFO .= ' </PstlAdr>' . $CrLf;
2686 $XML_SEPA_INFO .= ' </Cdtr>' . $CrLf;
2687 $XML_SEPA_INFO .= ' <CdtrAcct>' . $CrLf;
2688 $XML_SEPA_INFO .= ' <Id>' . $CrLf;
2689 $XML_SEPA_INFO .= ' <IBAN>' . preg_replace('/\s/', '', $this->emetteur_iban) . '</IBAN>' . $CrLf;
2690 $XML_SEPA_INFO .= ' </Id>' . $CrLf;
2691 $XML_SEPA_INFO .= ' </CdtrAcct>' . $CrLf;
2692 $XML_SEPA_INFO .= ' <CdtrAgt>' . $CrLf;
2693 $XML_SEPA_INFO .= ' <FinInstnId>' . $CrLf;
2694 $XML_SEPA_INFO .= ' <BIC>' . $this->emetteur_bic . '</BIC>' . $CrLf;
2695 $XML_SEPA_INFO .= ' </FinInstnId>' . $CrLf;
2696 $XML_SEPA_INFO .= ' </CdtrAgt>' . $CrLf;
2697 /* $XML_SEPA_INFO .= ' <UltmtCdtr>'.$CrLf;
2698 $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
2699 $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
2700 $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
2701 $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;
2702 $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;
2703 $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
2704 $XML_SEPA_INFO .= ' </UltmtCdtr>'.$CrLf;*/
2705 $XML_SEPA_INFO .= ' <ChrgBr>SLEV</ChrgBr>' . $CrLf; // Field "Responsible of fees". Must be SLEV
2706 $XML_SEPA_INFO .= ' <CdtrSchmeId>' . $CrLf;
2707 $XML_SEPA_INFO .= ' <Id>' . $CrLf;
2708 $XML_SEPA_INFO .= ' <PrvtId>' . $CrLf;
2709 $XML_SEPA_INFO .= ' <Othr>' . $CrLf;
2710 $XML_SEPA_INFO .= ' <Id>' . $this->emetteur_ics . '</Id>' . $CrLf;
2711 $XML_SEPA_INFO .= ' <SchmeNm>' . $CrLf;
2712 $XML_SEPA_INFO .= ' <Prtry>SEPA</Prtry>' . $CrLf;
2713 $XML_SEPA_INFO .= ' </SchmeNm>' . $CrLf;
2714 $XML_SEPA_INFO .= ' </Othr>' . $CrLf;
2715 $XML_SEPA_INFO .= ' </PrvtId>' . $CrLf;
2716 $XML_SEPA_INFO .= ' </Id>' . $CrLf;
2717 $XML_SEPA_INFO .= ' </CdtrSchmeId>' . $CrLf;
2718 } else {
2719 // SEPA Paiement Information of my company for Credit Transfer
2720 $XML_SEPA_INFO = '';
2721 $XML_SEPA_INFO .= ' <PmtInf>' . $CrLf;
2722 $XML_SEPA_INFO .= ' <PmtInfId>' . ('DOL/' . $dateTime_YMD . '/CT' . $IdBon . '-' . $RefBon) . '</PmtInfId>' . $CrLf;
2723 $XML_SEPA_INFO .= ' <PmtMtd>TRF</PmtMtd>' . $CrLf;
2724 //$XML_SEPA_INFO .= ' <BtchBookg>False</BtchBookg>'.$CrLf;
2725 $XML_SEPA_INFO .= ' <NbOfTxs>' . $nombre . '</NbOfTxs>' . $CrLf;
2726 $XML_SEPA_INFO .= ' <CtrlSum>' . $total . '</CtrlSum>' . $CrLf;
2727 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.
2728 $XML_SEPA_INFO .= ' <PmtTpInf>' . $CrLf;
2729 $XML_SEPA_INFO .= ' <SvcLvl>' . $CrLf;
2730 $XML_SEPA_INFO .= ' <Cd>SEPA</Cd>' . $CrLf;
2731 $XML_SEPA_INFO .= ' </SvcLvl>' . $CrLf;
2732 $XML_SEPA_INFO .= ' <LclInstrm>' . $CrLf;
2733 $XML_SEPA_INFO .= ' <Cd>' . $localInstrument . '</Cd>' . $CrLf;
2734 $XML_SEPA_INFO .= ' </LclInstrm>' . $CrLf;
2735 $XML_SEPA_INFO .= ' <SeqTp>' . $format . '</SeqTp>' . $CrLf;
2736 $XML_SEPA_INFO .= ' </PmtTpInf>' . $CrLf;
2737 }
2738 $XML_SEPA_INFO .= ' <ReqdExctnDt>' . dol_print_date($dateTime_ETAD, 'dayrfc') . '</ReqdExctnDt>' . $CrLf;
2739 $XML_SEPA_INFO .= ' <Dbtr>' . $CrLf;
2740 $XML_SEPA_INFO .= ' <Nm>' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))) . '</Nm>' . $CrLf;
2741 $XML_SEPA_INFO .= ' <PstlAdr>' . $CrLf;
2742 $XML_SEPA_INFO .= ' <Ctry>' . $country[1] . '</Ctry>' . $CrLf;
2743 $addressline1 = strtr(getDolGlobalString('MAIN_INFO_SOCIETE_ADDRESS'), array(chr(13) => ", ", chr(10) => ""));
2744 $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) => ""));
2745 if ($addressline1) {
2746 $XML_SEPA_INFO .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2747 }
2748 if ($addressline2) {
2749 $XML_SEPA_INFO .= ' <AdrLine>' . dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)) . '</AdrLine>' . $CrLf;
2750 }
2751 $XML_SEPA_INFO .= ' </PstlAdr>' . $CrLf;
2752 $XML_SEPA_INFO .= ' </Dbtr>' . $CrLf;
2753 $XML_SEPA_INFO .= ' <DbtrAcct>' . $CrLf;
2754 $XML_SEPA_INFO .= ' <Id>' . $CrLf;
2755 $XML_SEPA_INFO .= ' <IBAN>' . preg_replace('/\s/', '', $this->emetteur_iban) . '</IBAN>' . $CrLf;
2756 $XML_SEPA_INFO .= ' </Id>' . $CrLf;
2757 $XML_SEPA_INFO .= ' </DbtrAcct>' . $CrLf;
2758 $XML_SEPA_INFO .= ' <DbtrAgt>' . $CrLf;
2759 $XML_SEPA_INFO .= ' <FinInstnId>' . $CrLf;
2760 $XML_SEPA_INFO .= ' <BIC>' . $this->emetteur_bic . '</BIC>' . $CrLf;
2761 $XML_SEPA_INFO .= ' </FinInstnId>' . $CrLf;
2762 $XML_SEPA_INFO .= ' </DbtrAgt>' . $CrLf;
2763 /* $XML_SEPA_INFO .= ' <UltmtCdtr>'.$CrLf;
2764 $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
2765 $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
2766 $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
2767 $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;
2768 $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;
2769 $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
2770 $XML_SEPA_INFO .= ' </UltmtCdtr>'.$CrLf;*/
2771 $XML_SEPA_INFO .= ' <ChrgBr>SLEV</ChrgBr>' . $CrLf; // Field "Responsible of fees". Must be SLEV
2772 /*$XML_SEPA_INFO .= ' <CdtrSchmeId>'.$CrLf;
2773 $XML_SEPA_INFO .= ' <Id>'.$CrLf;
2774 $XML_SEPA_INFO .= ' <PrvtId>'.$CrLf;
2775 $XML_SEPA_INFO .= ' <Othr>'.$CrLf;
2776 $XML_SEPA_INFO .= ' <Id>'.$this->emetteur_ics.'</Id>'.$CrLf;
2777 $XML_SEPA_INFO .= ' <SchmeNm>'.$CrLf;
2778 $XML_SEPA_INFO .= ' <Prtry>SEPA</Prtry>'.$CrLf;
2779 $XML_SEPA_INFO .= ' </SchmeNm>'.$CrLf;
2780 $XML_SEPA_INFO .= ' </Othr>'.$CrLf;
2781 $XML_SEPA_INFO .= ' </PrvtId>'.$CrLf;
2782 $XML_SEPA_INFO .= ' </Id>'.$CrLf;
2783 $XML_SEPA_INFO .= ' </CdtrSchmeId>'.$CrLf;*/
2784 }
2785 } else {
2786 fwrite($this->file, 'INCORRECT EMETTEUR ' . $this->raison_sociale . $CrLf);
2787 $XML_SEPA_INFO = '';
2788 }
2789 return $XML_SEPA_INFO;
2790 }
2791
2792 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2799 public function EnregTotal($total)
2800 {
2801 // phpcs:enable
2802 fwrite($this->file, "08");
2803 fwrite($this->file, "08"); // Prelevement ordinaire
2804
2805 fwrite($this->file, " "); // Zone Reservee B2
2806
2807 fwrite($this->file, $this->emetteur_ics); // ICS
2808
2809 // Reserve C1
2810
2811 fwrite($this->file, substr(" ", 0, 12));
2812
2813
2814 // Raison Sociale C2
2815
2816 fwrite($this->file, substr(" ", 0, 24));
2817
2818 // D1
2819
2820 fwrite($this->file, substr(" ", 0, 24));
2821
2822 // Zone Reservee D2
2823
2824 fwrite($this->file, substr(" ", 0, 8));
2825
2826 // Code Guichet D3
2827
2828 fwrite($this->file, substr(" ", 0, 5));
2829
2830 // Numero de compte D4
2831
2832 fwrite($this->file, substr(" ", 0, 11));
2833
2834 // Zone E Montant
2835
2836 $montant = ($total * 100);
2837
2838 fwrite($this->file, substr("000000000000000" . $montant, -16));
2839
2840 // Zone Reservee F
2841
2842 fwrite($this->file, substr(" ", 0, 31));
2843
2844 // Code etablissement
2845
2846 fwrite($this->file, substr(" ", 0, 5));
2847
2848 // Zone Reservee F
2849
2850 fwrite($this->file, substr(" ", 0, 5));
2851
2852 fwrite($this->file, "\n");
2853 }
2854
2861 public function getLibStatut($mode = 0)
2862 {
2863 return $this->LibStatut((isset($this->status) ? $this->status : $this->statut), $mode);
2864 }
2865
2866 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2874 public function LibStatut($status, $mode = 0)
2875 {
2876 // phpcs:enable
2877 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
2878 global $langs;
2879 //$langs->load("mymodule");
2880 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('StatusWaiting');
2881 $this->labelStatus[self::STATUS_TRANSFERED] = $langs->transnoentitiesnoconv('StatusTrans');
2882 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('StatusWaiting');
2883 $this->labelStatusShort[self::STATUS_TRANSFERED] = $langs->transnoentitiesnoconv('StatusTrans');
2884 if ($this->type == 'bank-transfer') {
2885 $this->labelStatus[self::STATUS_DEBITED] = $langs->transnoentitiesnoconv('StatusDebited');
2886 $this->labelStatusShort[self::STATUS_DEBITED] = $langs->transnoentitiesnoconv('StatusDebited');
2887 } else {
2888 $this->labelStatus[self::STATUS_CREDITED] = $langs->transnoentitiesnoconv('StatusCredited');
2889 $this->labelStatusShort[self::STATUS_CREDITED] = $langs->transnoentitiesnoconv('StatusCredited');
2890 }
2891 }
2892
2893 $statusType = 'status1';
2894 if ($status == self::STATUS_TRANSFERED) {
2895 $statusType = 'status3';
2896 }
2897 if ($status == self::STATUS_CREDITED || $status == self::STATUS_DEBITED) {
2898 $statusType = 'status6';
2899 }
2900
2901 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
2902 }
2903
2904 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2912 public function load_board($user, $mode)
2913 {
2914 // phpcs:enable
2915 if ($user->socid) {
2916 return -1; // protection pour eviter appel par utilisateur externe
2917 }
2918
2919 /*
2920 if ($mode == 'direct_debit') {
2921 $sql = "SELECT b.rowid, f.datedue as datefin";
2922 $sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
2923 $sql .= " WHERE f.entity IN (".getEntity('facture').")";
2924 $sql .= " AND f.total_ttc > 0";
2925 } else {
2926 $sql = "SELECT b.rowid, f.datedue as datefin";
2927 $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2928 $sql .= " WHERE f.entity IN (".getEntity('facture_fourn').")";
2929 $sql .= " AND f.total_ttc > 0";
2930 }
2931
2932 $resql = $this->db->query($sql);
2933 if ($resql) {
2934 $langs->load("banks");
2935 $now = dol_now();
2936
2937 $response = new WorkboardResponse();
2938 if ($mode == 'direct_debit') {
2939 $response->warning_delay = $conf->prelevement->warning_delay / 60 / 60 / 24;
2940 $response->label = $langs->trans("PendingDirectDebitToComplete");
2941 $response->labelShort = $langs->trans("PendingDirectDebitToCompleteShort");
2942 $response->url = DOL_URL_ROOT.'/compta/prelevement/index.php?leftmenu=checks&mainmenu=bank';
2943 } else {
2944 $response->warning_delay = $conf->paymentbybanktransfer->warning_delay / 60 / 60 / 24;
2945 $response->label = $langs->trans("PendingCreditTransferToComplete");
2946 $response->labelShort = $langs->trans("PendingCreditTransferToCompleteShort");
2947 $response->url = DOL_URL_ROOT.'/compta/paymentbybanktransfer/index.php?leftmenu=checks&mainmenu=bank';
2948 }
2949 $response->img = img_object('', "payment");
2950
2951 while ($obj = $this->db->fetch_object($resql)) {
2952 $response->nbtodo++;
2953
2954 if ($this->db->jdate($obj->datefin) < ($now - $conf->withdraw->warning_delay)) {
2955 $response->nbtodolate++;
2956 }
2957 }
2958
2959 $response->nbtodo = 0;
2960 $response->nbtodolate = 0;
2961 // Return workboard only if quantity is not 0
2962 if ($response->nbtodo) {
2963 return $response;
2964 } else {
2965 return 0;
2966 }
2967 } else {
2968 dol_print_error($this->db);
2969 $this->error = $this->db->error();
2970 return -1;
2971 }
2972 */
2973 return 0;
2974 }
2975
2983 public function getKanbanView($option = '', $arraydata = null)
2984 {
2985 global $langs;
2986
2987 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
2988
2989 $return = '<div class="box-flex-item box-flex-grow-zero">';
2990 $return .= '<div class="info-box info-box-sm">';
2991 $return .= '<span class="info-box-icon bg-infobox-action">';
2992 $return .= img_picto('', $this->picto);
2993 $return .= '</span>';
2994 $return .= '<div class="info-box-content">';
2995 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . $this->getNomUrl(1) . '</span>';
2996 if ($selected >= 0) {
2997 $return .= '<input id="cb' . $this->id . '" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="' . $this->id . '"' . ($selected ? ' checked="checked"' : '') . '>';
2998 }
2999 if (isset($this->date_echeance)) {
3000 $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>';
3001 }
3002 if (isset($this->total)) {
3003 $return .= '<br><span class="opacitymedium">' . $langs->trans("Amount") . '</span> : <span class="amount">' . price($this->total) . '</span>';
3004 }
3005 $return .= '<br><div class="info-box-status">' . $this->getLibStatut(3) . '</div>';
3006 $return .= '</div>';
3007 $return .= '</div>';
3008 $return .= '</div>';
3009 return $return;
3010 }
3011
3018 {
3019 if (!empty($this->id)) {
3020 $id = $this->id;
3021 } else {
3022 return 0;
3023 }
3024 $sql = "SELECT COUNT(*) AS nb FROM " . MAIN_DB_PREFIX . "prelevement_lignes";
3025 $sql .= " WHERE fk_prelevement_bons = " . ((int) $id);
3026 $sql .= " AND fk_soc = 0"; // fk_soc can't be NULL
3027 $sql .= " AND fk_user IS NOT NULL";
3028
3029 $num = 0;
3030 $resql = $this->db->query($sql);
3031 if ($resql) {
3032 $obj = $this->db->fetch_object($resql);
3033 $num = $obj->nb;
3034 } else {
3035 dol_print_error($this->db);
3036 }
3037 if ($num > 0) {
3038 return 1;
3039 }
3040
3041 return 0;
3042 }
3043}
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:471
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:132
dolDecrypt($chain, $key='')
Decode a string with a symmetric encryption.