dolibarr  18.0.0-alpha
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  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <https://www.gnu.org/licenses/>.
22  */
23 
30 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
31 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
32 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
33 require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
34 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
35 require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
36 require_once DOL_DOCUMENT_ROOT.'/fourn/class/paiementfourn.class.php';
37 
38 
39 
44 {
48  public $element = 'widthdraw';
49 
53  public $table_element = 'prelevement_bons';
54 
58  public $picto = 'payment';
59 
60  public $date_echeance;
61  public $raison_sociale;
62  public $reference_remise;
63  public $emetteur_code_guichet;
64  public $emetteur_numero_compte;
65  public $emetteur_code_banque;
66  public $emetteur_number_key;
67  public $sepa_xml_pti_in_ctti;
68 
69  public $emetteur_iban;
70  public $emetteur_bic;
71  public $emetteur_ics;
72 
73  public $user_trans;
74  public $user_credit;
75 
76  public $total;
77  public $fetched;
78  public $labelStatus = array();
79 
80  public $factures = array();
81 
82  public $invoice_in_error = array();
83  public $thirdparty_in_error = array();
84 
85 
86  const STATUS_DRAFT = 0;
87  const STATUS_TRANSFERED = 1;
88  const STATUS_CREDITED = 2; // STATUS_CREDITED and STATUS_DEBITED is same. Difference is in ->type
89  const STATUS_DEBITED = 2; // STATUS_CREDITED and STATUS_DEBITED is same. Difference is in ->type
90 
91 
131  // BEGIN MODULEBUILDER PROPERTIES
135  public $fields=array(
136  'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>'1', 'position'=>10, 'notnull'=>1, 'visible'=>0,),
137  'ref' => array('type'=>'varchar(12)', 'label'=>'Ref', 'enabled'=>'1', 'position'=>15, 'notnull'=>0, 'visible'=>-1, 'csslist'=>'tdoverflowmax150', 'showoncombobox'=>'1',),
138  'datec' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>'1', 'position'=>25, 'notnull'=>0, 'visible'=>-1,),
139  'amount' => array('type'=>'double(24,8)', 'label'=>'Amount', 'enabled'=>'1', 'position'=>30, 'notnull'=>0, 'visible'=>-1,),
140  'statut' => array('type'=>'smallint(6)', 'label'=>'Statut', 'enabled'=>'1', 'position'=>500, 'notnull'=>0, 'visible'=>-1, 'arrayofkeyval'=>array(0=>'Wait', 1=>'Transfered', 2=>'Credited')),
141  'credite' => array('type'=>'smallint(6)', 'label'=>'Credite', 'enabled'=>'1', 'position'=>40, 'notnull'=>0, 'visible'=>-1,),
142  'note' => array('type'=>'text', 'label'=>'Note', 'enabled'=>'1', 'position'=>45, 'notnull'=>0, 'visible'=>-1,),
143  'date_trans' => array('type'=>'datetime', 'label'=>'Datetrans', 'enabled'=>'1', 'position'=>50, 'notnull'=>0, 'visible'=>-1,),
144  'method_trans' => array('type'=>'smallint(6)', 'label'=>'Methodtrans', 'enabled'=>'1', 'position'=>55, 'notnull'=>0, 'visible'=>-1,),
145  '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',),
146  'date_credit' => array('type'=>'datetime', 'label'=>'Datecredit', 'enabled'=>'1', 'position'=>65, 'notnull'=>0, 'visible'=>-1,),
147  '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',),
148  'type' => array('type'=>'varchar(16)', 'label'=>'Type', 'enabled'=>'1', 'position'=>75, 'notnull'=>0, 'visible'=>-1,),
149  'fk_bank_account' => array('type'=>'integer', 'label'=>'Fkbankaccount', 'enabled'=>'1', 'position'=>80, 'notnull'=>0, 'visible'=>-1, 'css'=>'maxwidth500 widthcentpercentminusxx',),
150  );
151  public $rowid;
152  public $ref;
153  public $datec;
154  public $amount;
155  public $statut;
156  public $credite;
157  public $note;
158  public $date_trans;
159  public $method_trans;
160  public $fk_user_trans;
161  public $date_credit;
162  public $fk_user_credit;
163  public $type;
164  public $fk_bank_account;
165  // END MODULEBUILDER PROPERTIES
166 
167 
168 
174  public function __construct($db)
175  {
176  global $conf, $langs;
177 
178  $this->db = $db;
179 
180  $this->filename = '';
181 
182  $this->date_echeance = dol_now();
183  $this->raison_sociale = "";
184  $this->reference_remise = "";
185 
186  $this->emetteur_code_guichet = "";
187  $this->emetteur_numero_compte = "";
188  $this->emetteur_code_banque = "";
189  $this->emetteur_number_key = "";
190  $this->sepa_xml_pti_in_ctti = false;
191 
192  $this->emetteur_iban = "";
193  $this->emetteur_bic = "";
194  $this->emetteur_ics = "";
195 
196  $this->factures = array();
197 
198  $this->methodes_trans = array(0 => 'Internet', 2 => 'Email', 3 => 'Api');
199 
200  $this->fetched = 0;
201  }
202 
203  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
218  public function AddFacture($invoice_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key, $type = 'debit-order')
219  {
220  // phpcs:enable
221  $result = 0;
222  $line_id = 0;
223 
224  // Add lines
225  $result = $this->addline($line_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key);
226 
227  if ($result == 0) {
228  if ($line_id > 0) {
229  $sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevement (";
230  if ($type != 'bank-transfer') {
231  $sql .= "fk_facture";
232  } else {
233  $sql .= "fk_facture_fourn";
234  }
235  $sql .= ",fk_prelevement_lignes";
236  $sql .= ") VALUES (";
237  $sql .= ((int) $invoice_id);
238  $sql .= ", ".((int) $line_id);
239  $sql .= ")";
240 
241  if ($this->db->query($sql)) {
242  $result = 0;
243  } else {
244  $result = -1;
245  $this->errors[] = get_class($this)."::AddFacture ".$this->db->lasterror;
246  dol_syslog(get_class($this)."::AddFacture Error $result");
247  }
248  } else {
249  $result = -2;
250  $this->errors[] = get_class($this)."::AddFacture linedid Empty";
251  dol_syslog(get_class($this)."::AddFacture Error $result");
252  }
253  } else {
254  $result = -3;
255  dol_syslog(get_class($this)."::AddFacture Error $result");
256  }
257 
258  return $result;
259  }
260 
274  public function addline(&$line_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key)
275  {
276  $result = -1;
277  $concat = 0;
278 
279  if ($concat == 1) {
280  /*
281  * We aggregate the lines
282  */
283  $sql = "SELECT rowid";
284  $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_lignes";
285  $sql .= " WHERE fk_prelevement_bons = ".((int) $this->id);
286  $sql .= " AND fk_soc =".((int) $client_id);
287  $sql .= " AND code_banque = '".$this->db->escape($code_banque)."'";
288  $sql .= " AND code_guichet = '".$this->db->escape($code_guichet)."'";
289  $sql .= " AND number = '".$this->db->escape($number)."'";
290 
291  $resql = $this->db->query($sql);
292  if ($resql) {
293  $num = $this->db->num_rows($resql);
294  } else {
295  $result = -1;
296  }
297  } else {
298  /*
299  * No aggregate
300  */
301  $sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevement_lignes (";
302  $sql .= "fk_prelevement_bons";
303  $sql .= ", fk_soc";
304  $sql .= ", client_nom";
305  $sql .= ", amount";
306  $sql .= ", code_banque";
307  $sql .= ", code_guichet";
308  $sql .= ", number";
309  $sql .= ", cle_rib";
310  $sql .= ") VALUES (";
311  $sql .= $this->id;
312  $sql .= ", ".((int) $client_id);
313  $sql .= ", '".$this->db->escape($client_nom)."'";
314  $sql .= ", ".((float) price2num($amount));
315  $sql .= ", '".$this->db->escape($code_banque)."'";
316  $sql .= ", '".$this->db->escape($code_guichet)."'";
317  $sql .= ", '".$this->db->escape($number)."'";
318  $sql .= ", '".$this->db->escape($number_key)."'";
319  $sql .= ")";
320 
321  if ($this->db->query($sql)) {
322  $line_id = $this->db->last_insert_id(MAIN_DB_PREFIX."prelevement_lignes");
323  $result = 0;
324  } else {
325  $this->errors[] = get_class($this)."::addline Error -2 ".$this->db->lasterror;
326  dol_syslog(get_class($this)."::addline Error -2");
327  $result = -2;
328  }
329  }
330 
331  return $result;
332  }
333 
340  public function getErrorString($error)
341  {
342  global $langs;
343 
344  $errors = array();
345 
346  $errors[1027] = $langs->trans("DateInvalid");
347 
348  return $errors[abs($error)];
349  }
350 
358  public function fetch($rowid, $ref = '')
359  {
360  $sql = "SELECT p.rowid, p.ref, p.amount, p.note";
361  $sql .= ", p.datec as dc";
362  $sql .= ", p.date_trans as date_trans";
363  $sql .= ", p.method_trans, p.fk_user_trans";
364  $sql .= ", p.date_credit as date_credit";
365  $sql .= ", p.fk_user_credit";
366  $sql .= ", p.type";
367  $sql .= ", p.fk_bank_account";
368  $sql .= ", p.statut as status";
369  $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_bons as p";
370  $sql .= " WHERE p.entity IN (".getEntity('invoice').")";
371  if ($rowid > 0) {
372  $sql .= " AND p.rowid = ".((int) $rowid);
373  } else {
374  $sql .= " AND p.ref = '".$this->db->escape($ref)."'";
375  }
376 
377  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
378  $result = $this->db->query($sql);
379  if ($result) {
380  if ($this->db->num_rows($result)) {
381  $obj = $this->db->fetch_object($result);
382 
383  $this->id = $obj->rowid;
384  $this->ref = $obj->ref;
385  $this->amount = $obj->amount;
386  $this->note = $obj->note;
387  $this->datec = $this->db->jdate($obj->dc);
388 
389  $this->date_trans = $this->db->jdate($obj->date_trans);
390  $this->method_trans = $obj->method_trans;
391  $this->user_trans = $obj->fk_user_trans;
392 
393  $this->date_credit = $this->db->jdate($obj->date_credit);
394  $this->user_credit = $obj->fk_user_credit;
395 
396  $this->type = $obj->type;
397  $this->fk_bank_account = $obj->fk_bank_account;
398 
399  $this->status = $obj->status;
400  $this->statut = $obj->status; // For backward compatibility
401 
402  $this->fetched = 1;
403 
404  return 1;
405  } else {
406  dol_syslog(get_class($this)."::Fetch Erreur aucune ligne retournee");
407  return -1;
408  }
409  } else {
410  return -2;
411  }
412  }
413 
421  public function update(User $user, $notrigger = false)
422  {
423  return $this->updateCommon($user, $notrigger);
424  }
425 
426  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
435  public function set_infocredit($user, $date)
436  {
437  // phpcs:enable
438  global $conf, $langs;
439 
440  $error = 0;
441 
442  if ($this->fetched == 1) {
443  if ($date < $this->date_trans) {
444  $langs->load("errors");
445  $this->error = $langs->trans('ErrorDateOfMovementLowerThanDateOfFileTransmission');
446  dol_syslog("bon-prelevment::set_infocredit 1027 ".$this->error);
447  return -1027;
448  }
449 
450  $this->db->begin();
451 
452  $sql = " UPDATE ".MAIN_DB_PREFIX."prelevement_bons";
453  $sql .= " SET fk_user_credit = ".$user->id;
454  $sql .= ", statut = ".self::STATUS_CREDITED;
455  $sql .= ", date_credit = '".$this->db->idate($date)."'";
456  $sql .= " WHERE rowid=".((int) $this->id);
457  $sql .= " AND entity = ".((int) $conf->entity);
458  $sql .= " AND statut = ".self::STATUS_TRANSFERED;
459 
460  $resql = $this->db->query($sql);
461  if ($resql) {
462  $langs->load('withdrawals');
463  $subject = $langs->trans("InfoCreditSubject", $this->ref);
464  $message = $langs->trans("InfoCreditMessage", $this->ref, dol_print_date($date, 'dayhour'));
465 
466  // Add payment of withdrawal into bank
467  $fk_bank_account = $this->fk_bank_account;
468  if (empty($fk_bank_account)) {
469  $fk_bank_account = ($this->type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
470  }
471 
472  $facs = array();
473  $amounts = array();
474  $amountsperthirdparty = array();
475 
476  $facs = $this->getListInvoices(1);
477 
478  // Loop on each invoice. $facs=array(0=>id, 1=>amount requested)
479  $num = count($facs);
480  for ($i = 0; $i < $num; $i++) {
481  if ($this->type == 'bank-transfer') {
482  $fac = new FactureFournisseur($this->db);
483  } else {
484  $fac = new Facture($this->db);
485  }
486 
487  $result = $fac->fetch($facs[$i][0]);
488 
489  $amounts[$fac->id] = $facs[$i][1];
490  $amountsperthirdparty[$fac->socid][$fac->id] = $facs[$i][1];
491 
492  $totalpaid = $fac->getSommePaiement();
493  $totalcreditnotes = $fac->getSumCreditNotesUsed();
494  $totaldeposits = $fac->getSumDepositsUsed();
495  $alreadypayed = $totalpaid + $totalcreditnotes + $totaldeposits;
496 
497  // @TODO Move this after creation of payment
498  if (price2num($alreadypayed + $facs[$i][1], 'MT') == $fac->total_ttc) {
499  $result = $fac->setPaid($user);
500  if ($result < 0) {
501  $this->error = $fac->error;
502  $this->errors = $fac->errors;
503  }
504  }
505  }
506  //var_dump($amountsperthirdparty);exit;
507 
508  // Make one payment per customer
509  foreach ($amountsperthirdparty as $thirdpartyid => $cursoramounts) {
510  if ($this->type == 'bank-transfer') {
511  $paiement = new PaiementFourn($this->db);
512  } else {
513  $paiement = new Paiement($this->db);
514  }
515  $paiement->datepaye = $date;
516  $paiement->amounts = $cursoramounts; // Array with detail of dispatching of payments for each invoice
517 
518  if ($this->type == 'bank-transfer') {
519  $paiement->paiementid = 2;
520  $paiement->paiementcode = 'VIR';
521  } else {
522  $paiement->paiementid = 3;
523  $paiement->paiementcode = 'PRE';
524  }
525 
526  $paiement->num_payment = $this->ref; // Set ref of direct debit note
527  $paiement->id_prelevement = $this->id;
528 
529  $paiement_id = $paiement->create($user); // This use ->paiementid, that is ID of payment mode
530  if ($paiement_id < 0) {
531  $error++;
532  $this->error = $paiement->error;
533  $this->errors = $paiement->errors;
534  dol_syslog(get_class($this)."::set_infocredit AddPayment Error ".$this->error);
535  } else {
536  if ($this->type == 'bank-transfer') {
537  $modeforaddpayment = 'payment_supplier';
538  } else {
539  $modeforaddpayment = 'payment';
540  }
541 
542  $result = $paiement->addPaymentToBank($user, $modeforaddpayment, '(WithdrawalPayment)', $fk_bank_account, '', '');
543  if ($result < 0) {
544  $error++;
545  $this->error = $paiement->error;
546  $this->errors = $paiement->errors;
547  dol_syslog(get_class($this)."::set_infocredit AddPaymentToBank Error ".$this->error);
548  }
549  }
550  }
551 
552  // Update withdrawal line
553  // TODO: Translate to ligneprelevement.class.php
554  if (!$error) {
555  $sql = " UPDATE ".MAIN_DB_PREFIX."prelevement_lignes";
556  $sql .= " SET statut = 2";
557  $sql .= " WHERE fk_prelevement_bons = ".((int) $this->id);
558 
559  if (!$this->db->query($sql)) {
560  dol_syslog(get_class($this)."::set_infocredit Update lines Error");
561  $error++;
562  }
563  }
564  } else {
565  $this->error = $this->db->lasterror();
566  dol_syslog(get_class($this)."::set_infocredit Update Bons Error");
567  $error++;
568  }
569 
570  /*
571  * End of procedure
572  */
573  if ($error == 0) {
574  $this->date_credit = $date;
575  $this->statut = self::STATUS_CREDITED;
576 
577  $this->db->commit();
578  return 0;
579  } else {
580  $this->db->rollback();
581  return -1;
582  }
583  } else {
584  return -1026;
585  }
586  }
587 
588  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
597  public function set_infotrans($user, $date, $method)
598  {
599  // phpcs:enable
600  global $conf, $langs;
601 
602  $error = 0;
603 
604  dol_syslog(get_class($this)."::set_infotrans Start", LOG_INFO);
605  if ($this->db->begin()) {
606  $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_bons ";
607  $sql .= " SET fk_user_trans = ".$user->id;
608  $sql .= " , date_trans = '".$this->db->idate($date)."'";
609  $sql .= " , method_trans = ".((int) $method);
610  $sql .= " , statut = ".self::STATUS_TRANSFERED;
611  $sql .= " WHERE rowid = ".((int) $this->id);
612  $sql .= " AND entity = ".((int) $conf->entity);
613  $sql .= " AND statut = 0";
614 
615  if ($this->db->query($sql)) {
616  $this->method_trans = $method;
617  $langs->load('withdrawals');
618  $subject = $langs->trans("InfoTransSubject", $this->ref);
619  $message = $langs->trans("InfoTransMessage", $this->ref, dolGetFirstLastname($user->firstname, $user->lastname));
620  $message .= $langs->trans("InfoTransData", price($this->amount), $this->methodes_trans[$this->method_trans], dol_print_date($date, 'day'));
621 
622  // TODO Call trigger to create a notification using notification module
623  } else {
624  $error++;
625  }
626 
627  if ($error == 0) {
628  $this->date_trans = $date;
629  $this->statut = 1;
630  $this->user_trans = $user->id;
631  $this->db->commit();
632 
633  return 0;
634  } else {
635  $this->db->rollback();
636  dol_syslog(get_class($this)."::set_infotrans ROLLBACK", LOG_ERR);
637 
638  return -1;
639  }
640  } else {
641  dol_syslog(get_class($this)."::set_infotrans Ouverture transaction SQL impossible", LOG_CRIT);
642  return -2;
643  }
644  }
645 
652  private function getListInvoices($amounts = 0)
653  {
654  global $conf;
655 
656  $arr = array();
657 
658  /*
659  * Returns all invoices presented within same order
660  */
661  $sql = "SELECT ";
662  if ($this->type == 'bank-transfer') {
663  $sql .= " pf.fk_facture_fourn";
664  } else {
665  $sql .= " pf.fk_facture";
666  }
667  if ($amounts) {
668  $sql .= ", SUM(pl.amount)";
669  }
670  $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_bons as p";
671  $sql .= " , ".MAIN_DB_PREFIX."prelevement_lignes as pl";
672  $sql .= " , ".MAIN_DB_PREFIX."prelevement as pf";
673  $sql .= " WHERE pf.fk_prelevement_lignes = pl.rowid";
674  $sql .= " AND pl.fk_prelevement_bons = p.rowid";
675  $sql .= " AND p.rowid = ".((int) $this->id);
676  $sql .= " AND p.entity = ".((int) $conf->entity);
677  if ($amounts) {
678  if ($this->type == 'bank-transfer') {
679  $sql .= " GROUP BY fk_facture_fourn";
680  } else {
681  $sql .= " GROUP BY fk_facture";
682  }
683  }
684 
685  $resql = $this->db->query($sql);
686  if ($resql) {
687  $num = $this->db->num_rows($resql);
688 
689  if ($num) {
690  $i = 0;
691  while ($i < $num) {
692  $row = $this->db->fetch_row($resql);
693  if (!$amounts) {
694  $arr[$i] = $row[0];
695  } else {
696  $arr[$i] = array(
697  $row[0],
698  $row[1]
699  );
700  }
701  $i++;
702  }
703  }
704  $this->db->free($resql);
705  } else {
706  dol_syslog(get_class($this)."::getListInvoices Erreur");
707  }
708 
709  return $arr;
710  }
711 
712  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
719  public function SommeAPrelever($mode = 'direct-debit')
720  {
721  // phpcs:enable
722  global $conf;
723 
724  $sql = "SELECT sum(pfd.amount) as nb";
725  if ($mode != 'bank-transfer') {
726  $sql .= " FROM ".MAIN_DB_PREFIX."facture as f,";
727  } else {
728  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f,";
729  }
730  $sql .= " ".MAIN_DB_PREFIX."prelevement_demande as pfd";
731  $sql .= " WHERE f.entity IN (".getEntity('invoice').")";
732  if (empty($conf->global->WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS)) {
733  $sql .= " AND f.fk_statut = ".Facture::STATUS_VALIDATED;
734  }
735  if ($mode != 'bank-transfer') {
736  $sql .= " AND f.rowid = pfd.fk_facture";
737  } else {
738  $sql .= " AND f.rowid = pfd.fk_facture_fourn";
739  }
740  $sql .= " AND f.paye = 0";
741  $sql .= " AND pfd.traite = 0";
742  $sql .= " AND pfd.ext_payment_id IS NULL";
743  $sql .= " AND f.total_ttc > 0";
744 
745  $resql = $this->db->query($sql);
746  if ($resql) {
747  $obj = $this->db->fetch_object($resql);
748 
749  $this->db->free($resql);
750 
751  return $obj->nb;
752  } else {
753  $error = 1;
754  dol_syslog(get_class($this)."::SommeAPrelever Erreur -1");
755  dol_syslog($this->db->error());
756 
757  return -1;
758  }
759  }
760 
767  public function nbOfInvoiceToPay($mode = 'direct-debit')
768  {
769  return $this->NbFactureAPrelever($mode);
770  }
771 
772  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
779  public function NbFactureAPrelever($type = 'direct-debit')
780  {
781  // phpcs:enable
782  global $conf;
783 
784  $sql = "SELECT count(f.rowid) as nb";
785  if ($type == 'bank-transfer') {
786  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
787  } else {
788  $sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
789  }
790  $sql .= ", ".MAIN_DB_PREFIX."prelevement_demande as pfd";
791  $sql .= " WHERE f.entity IN (".getEntity('invoice').")";
792  if (empty($conf->global->WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS)) {
793  $sql .= " AND f.fk_statut = ".Facture::STATUS_VALIDATED;
794  }
795  if ($type == 'bank-transfer') {
796  $sql .= " AND f.rowid = pfd.fk_facture_fourn";
797  } else {
798  $sql .= " AND f.rowid = pfd.fk_facture";
799  }
800  $sql .= " AND pfd.traite = 0";
801  $sql .= " AND pfd.ext_payment_id IS NULL";
802  $sql .= " AND f.total_ttc > 0";
803 
804  dol_syslog(get_class($this)."::NbFactureAPrelever");
805  $resql = $this->db->query($sql);
806 
807  if ($resql) {
808  $obj = $this->db->fetch_object($resql);
809 
810  $this->db->free($resql);
811 
812  return $obj->nb;
813  } else {
814  $this->error = get_class($this)."::NbFactureAPrelever Erreur -1 sql=".$this->db->error();
815  return -1;
816  }
817  }
818 
819 
820  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
840  public function create($banque = 0, $agence = 0, $mode = 'real', $format = 'ALL', $executiondate = '', $notrigger = 0, $type = 'direct-debit', $did = 0, $fk_bank_account = 0)
841  {
842  // phpcs:enable
843  global $conf, $langs, $user;
844 
845  dol_syslog(__METHOD__." Bank=".$banque." Office=".$agence." mode=".$mode." format=".$format, LOG_DEBUG);
846 
847  require_once DOL_DOCUMENT_ROOT."/compta/facture/class/facture.class.php";
848  require_once DOL_DOCUMENT_ROOT."/societe/class/societe.class.php";
849 
850  // Check params
851  if ($type != 'bank-transfer') {
852  if (empty($format)) {
853  $this->error = 'ErrorBadParametersForDirectDebitFileCreate';
854  return -1;
855  }
856  }
857 
858  // Clean params
859  if (empty($fk_bank_account)) {
860  $fk_bank_account = ($type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
861  }
862 
863  $error = 0;
864 
865  $datetimeprev = dol_now('gmt');
866  //Choice the date of the execution direct debit
867  if (!empty($executiondate)) {
868  $datetimeprev = $executiondate;
869  }
870 
871  $month = dol_print_date($datetimeprev, "%m", 'gmt');
872  $year = dol_print_date($datetimeprev, "%Y", 'gmt');
873 
874  $this->invoice_in_error = array();
875  $this->thirdparty_in_error = array();
876 
877  // Read invoices
878  $factures = array();
879  $factures_prev = array();
880  $factures_result = array();
881  $factures_prev_id = array();
882  $factures_errors = array();
883 
884  if (!$error) {
885  $sql = "SELECT f.rowid, pfd.rowid as pfdrowid, f.fk_soc";
886  $sql .= ", pfd.code_banque, pfd.code_guichet, pfd.number, pfd.cle_rib";
887  $sql .= ", pfd.amount";
888  $sql .= ", s.nom as name";
889  if ($type != 'bank-transfer') {
890  $sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
891  } else {
892  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
893  }
894  $sql .= ", ".MAIN_DB_PREFIX."societe as s";
895  $sql .= ", ".MAIN_DB_PREFIX."prelevement_demande as pfd";
896  $sql .= " WHERE f.entity IN (".getEntity('invoice').')';
897  if ($type != 'bank-transfer') {
898  $sql .= " AND f.rowid = pfd.fk_facture";
899  } else {
900  $sql .= " AND f.rowid = pfd.fk_facture_fourn";
901  }
902  $sql .= " AND s.rowid = f.fk_soc";
903  $sql .= " AND f.fk_statut = 1"; // Invoice validated
904  $sql .= " AND f.paye = 0";
905  $sql .= " AND pfd.traite = 0";
906  $sql .= " AND f.total_ttc > 0";
907  $sql .= " AND pfd.ext_payment_id IS NULL";
908  if ($did > 0) {
909  $sql .= " AND pfd.rowid = ".((int) $did);
910  }
911  dol_syslog(__METHOD__." Read invoices,", LOG_DEBUG);
912 
913  $resql = $this->db->query($sql);
914  if ($resql) {
915  $num = $this->db->num_rows($resql);
916  $i = 0;
917 
918  while ($i < $num) {
919  $row = $this->db->fetch_row($resql);
920  $factures[$i] = $row; // All fields
921  if ($row[7] == 0) {
922  $error++;
923  dol_syslog(__METHOD__." Read invoices error Found a null invoice", LOG_ERR);
924  $this->invoice_in_error[$row[0]] = "Error for invoice id ".$row[0].", found a null amount";
925  break;
926  }
927  $i++;
928  }
929  $this->db->free($resql);
930  dol_syslog(__METHOD__." Read invoices, ".$i." invoices to withdraw", LOG_DEBUG);
931  } else {
932  $error++;
933  dol_syslog(__METHOD__." Read invoices error ".$this->db->error(), LOG_ERR);
934  }
935  }
936 
937  if (!$error) {
938  require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php';
939  $soc = new Societe($this->db);
940 
941  // Check BAN
942  $i = 0;
943  dol_syslog(__METHOD__." Check BAN", LOG_DEBUG);
944 
945  if (count($factures) > 0) {
946  foreach ($factures as $key => $fac) {
947  if ($type != 'bank-transfer') {
948  $tmpinvoice = new Facture($this->db);
949  } else {
950  $tmpinvoice = new FactureFournisseur($this->db);
951  }
952  $resfetch = $tmpinvoice->fetch($fac[0]);
953  if ($resfetch >= 0) { // Field 0 of $fac is rowid of invoice
954  if ($soc->fetch($tmpinvoice->socid) >= 0) {
955  $bac = new CompanyBankAccount($this->db);
956  $bac->fetch(0, $soc->id);
957 
958  if ($type != 'bank-transfer') {
959  if ($format == 'FRST' && $bac->frstrecur != 'FRST') {
960  continue;
961  }
962  if ($format == 'RCUR' && ($bac->frstrecur != 'RCUR' && $bac->frstrecur != 'RECUR')) {
963  continue;
964  }
965  }
966 
967  if ($bac->verif() >= 1) {
968  $factures_prev[$i] = $fac;
969  /* second array necessary for BonPrelevement */
970  $factures_prev_id[$i] = $fac[0];
971  $i++;
972  //dol_syslog(__METHOD__."::RIB is ok", LOG_DEBUG);
973  } else {
974  dol_syslog(__METHOD__." Check BAN Error on default bank number IBAN/BIC for thirdparty reported by verif() ".$tmpinvoice->socid." ".$soc->name, LOG_WARNING);
975  $this->invoice_in_error[$fac[0]] = "Error on default bank number IBAN/BIC for invoice ".$tmpinvoice->getNomUrl(0)." for thirdparty ".$soc->getNomUrl(0);
976  $this->thirdparty_in_error[$soc->id] = "Error on default bank number IBAN/BIC for invoice ".$tmpinvoice->getNomUrl(0)." for thirdparty ".$soc->getNomUrl(0);
977  }
978  } else {
979  dol_syslog(__METHOD__." Check BAN Failed to read company", LOG_WARNING);
980  }
981  } else {
982  dol_syslog(__METHOD__." Check BAN Failed to read invoice", LOG_WARNING);
983  }
984  }
985  } else {
986  dol_syslog(__METHOD__." Check BAN No invoice to process", LOG_WARNING);
987  }
988  }
989 
990  $ok = 0;
991 
992  // Withdraw invoices in factures_prev array
993  $out = count($factures_prev)." invoices will be included.";
994  //print $out."\n";
995  dol_syslog($out);
996 
997  // Return warning
998  /*$i=0;
999  foreach ($this->thirdparty_in_error as $key => $val)
1000  {
1001  if ($i < 10) setEventMessages($val, null, 'warnings');
1002  else setEventMessages('More error were discarded...', null, 'warnings');
1003  $i++;
1004  }*/
1005 
1006  if (count($factures_prev) > 0) {
1007  if ($mode == 'real') {
1008  $ok = 1;
1009  } else {
1010  print $langs->trans("ModeWarning"); // "Option for real mode was not set, we stop after this simulation\n";
1011  }
1012  }
1013 
1014  if ($ok) {
1015  /*
1016  * We are in real mode.
1017  * We create order and build file into disk
1018  */
1019  $this->db->begin();
1020 
1021  $now = dol_now();
1022  $ref = '';
1023 
1024  /*
1025  * Process order generation
1026  */
1027  if (!$error) {
1028  $ref = substr($year, -2).$month;
1029 
1030  // Get next free nuber for the ref of bon
1031  $sql = "SELECT substring(ref from char_length(ref) - 1)"; // To extract "YYMMXX" from "TYYMMXX"
1032  $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_bons";
1033  $sql .= " WHERE ref LIKE '_".$this->db->escape($ref)."%'";
1034  $sql .= " AND entity = ".((int) $conf->entity);
1035  $sql .= " ORDER BY ref DESC LIMIT 1";
1036 
1037  dol_syslog(get_class($this)." get next free number", LOG_DEBUG);
1038  $resql = $this->db->query($sql);
1039 
1040  if ($resql) {
1041  $row = $this->db->fetch_row($resql);
1042 
1043  // Build the new ref
1044  $ref = "T".$ref.sprintf("%02d", (intval($row[0]) + 1));
1045 
1046  // $conf->abc->dir_output may be:
1047  // /home/ldestailleur/git/dolibarr_15.0/documents/abc/
1048  // or
1049  // /home/ldestailleur/git/dolibarr_15.0/documents/X/abc with X >= 2 with multicompany.
1050  if ($type != 'bank-transfer') {
1051  $dir = $conf->prelevement->dir_output.'/receipts';
1052  } else {
1053  $dir = $conf->paymentbybanktransfer->dir_output.'/receipts';
1054  }
1055  if (!is_dir($dir)) {
1056  dol_mkdir($dir);
1057  }
1058 
1059  $this->filename = $dir.'/'.$ref.'.xml';
1060 
1061  // Create withdraw order in database
1062  $sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevement_bons (";
1063  $sql .= "ref, entity, datec, type, fk_bank_account";
1064  $sql .= ") VALUES (";
1065  $sql .= "'".$this->db->escape($ref)."'";
1066  $sql .= ", ".((int) $conf->entity);
1067  $sql .= ", '".$this->db->idate($now)."'";
1068  $sql .= ", '".($type == 'bank-transfer' ? 'bank-transfer' : 'debit-order')."'";
1069  $sql .= ", ".((int) $fk_bank_account);
1070  $sql .= ")";
1071 
1072  $resql = $this->db->query($sql);
1073  if ($resql) {
1074  $prev_id = $this->db->last_insert_id(MAIN_DB_PREFIX."prelevement_bons");
1075  $this->id = $prev_id;
1076  $this->ref = $ref;
1077  } else {
1078  $error++;
1079  dol_syslog(__METHOD__." Create withdraw receipt ".$this->db->lasterror(), LOG_ERR);
1080  }
1081  } else {
1082  $error++;
1083  dol_syslog(__METHOD__." Get last withdraw receipt ".$this->db->lasterror(), LOG_ERR);
1084  }
1085  }
1086 
1087  if (!$error) {
1088  if ($type != 'bank-transfer') {
1089  $fact = new Facture($this->db);
1090  } else {
1091  $fact = new FactureFournisseur($this->db);
1092  }
1093 
1094  // Add lines for the bon
1095  if (count($factures_prev) > 0) {
1096  foreach ($factures_prev as $fac) { // Add a link in database for each invoice
1097  // Fetch invoice
1098  $result = $fact->fetch($fac[0]);
1099  if ($result < 0) {
1100  $this->error = 'ERRORBONPRELEVEMENT Failed to load invoice with id '.$fac[0];
1101  break;
1102  }
1103 
1104  /*
1105  * Add standing order. This add record into llx_prelevement_lignes and llx_prelevement
1106  *
1107  * $fac[0] : invoice_id
1108  * $fac[1] : ???
1109  * $fac[2] : third party id
1110  * $fac[3] : banque
1111  * $fac[4] : guichet
1112  * $fac[5] : number
1113  * $fac[6] : cle rib
1114  * $fac[7] : amount
1115  * $fac[8] : client nom
1116  */
1117  $ri = $this->AddFacture($fac[0], $fac[2], $fac[8], $fac[7], $fac[3], $fac[4], $fac[5], $fac[6], $type);
1118  if ($ri <> 0) {
1119  $error++;
1120  }
1121 
1122  // Update invoice requests as done
1123  $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_demande";
1124  $sql .= " SET traite = 1";
1125  $sql .= ", date_traite = '".$this->db->idate($now)."'";
1126  $sql .= ", fk_prelevement_bons = ".((int) $this->id);
1127  $sql .= " WHERE rowid = ".((int) $fac[1]);
1128 
1129  $resql = $this->db->query($sql);
1130  if (!$resql) {
1131  $error++;
1132  $this->errors[] = $this->db->lasterror();
1133  dol_syslog(__METHOD__." Update Error=".$this->db->lasterror(), LOG_ERR);
1134  }
1135  }
1136  }
1137  }
1138 
1139  if (!$error) {
1140  /*
1141  * Create file of type='direct-debit' for direct debit order or type='bank-transfer' for credit transfer into a XML file
1142  */
1143 
1144  dol_syslog(__METHOD__." Init direct debit or credit transfer file for ".count($factures_prev)." invoices", LOG_DEBUG);
1145 
1146  if (count($factures_prev) > 0) {
1147  $this->date_echeance = $datetimeprev;
1148  $this->reference_remise = $ref;
1149 
1150  $account = new Account($this->db);
1151  if ($account->fetch($fk_bank_account) > 0) {
1152  $this->emetteur_code_banque = $account->code_banque;
1153  $this->emetteur_code_guichet = $account->code_guichet;
1154  $this->emetteur_numero_compte = $account->number;
1155  $this->emetteur_number_key = $account->cle_rib;
1156  $this->sepa_xml_pti_in_ctti = (bool) $account->pti_in_ctti;
1157  $this->emetteur_iban = $account->iban;
1158  $this->emetteur_bic = $account->bic;
1159 
1160  $this->emetteur_ics = ($type == 'bank-transfer' ? $account->ics_transfer : $account->ics);
1161 
1162  $this->raison_sociale = $account->proprio;
1163  }
1164 
1165  $this->factures = $factures_prev_id;
1166  $this->context['factures_prev'] = $factures_prev;
1167 
1168  // Generation of direct debit or credti transfer file $this->filename (May be a SEPA file for european countries)
1169  // This also set the property $this->total with amount that is included into file
1170  $result = $this->generate($format, $executiondate, $type);
1171  if ($result < 0) {
1172  //var_dump($this->error);
1173  //var_dump($this->invoice_in_error);
1174  $error++;
1175  }
1176  }
1177  dol_syslog(__METHOD__." Bank order file has been generated under filename ".$this->filename, LOG_DEBUG);
1178  }
1179  //var_dump($this->total);exit;
1180 
1181  /*
1182  * Update total defined after generation of file
1183  */
1184  if (!$error) {
1185  $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_bons";
1186  $sql .= " SET amount = ".price2num($this->total);
1187  $sql .= " WHERE rowid = ".((int) $this->id);
1188  $sql .= " AND entity = ".((int) $conf->entity);
1189 
1190  $resql = $this->db->query($sql);
1191  if (!$resql) {
1192  $error++;
1193  dol_syslog(__METHOD__." Error update total: ".$this->db->error(), LOG_ERR);
1194  }
1195  }
1196 
1197  if (!$error && !$notrigger) {
1198  $triggername = 'DIRECT_DEBIT_ORDER_CREATE';
1199  if ($type != 'bank-transfer') {
1200  $triggername = 'CREDIT_TRANSFER_ORDER_CREATE';
1201  }
1202 
1203  // Call trigger
1204  $result = $this->call_trigger($triggername, $user);
1205  if ($result < 0) {
1206  $error++;
1207  }
1208  // End call triggers
1209  }
1210 
1211  if (!$error) {
1212  $this->db->commit();
1213  return count($factures_prev);
1214  } else {
1215  $this->db->rollback();
1216  return -1;
1217  }
1218  } else {
1219  return 0;
1220  }
1221  }
1222 
1223 
1231  public function delete($user = null, $notrigger = 0)
1232  {
1233  $this->db->begin();
1234 
1235  $error = 0;
1236  $resql1 = $resql2 = $resql3 = $resql4 = 0;
1237 
1238  if (!$notrigger) {
1239  $triggername = 'DIRECT_DEBIT_ORDER_DELETE';
1240  if ($this->type == 'bank-transfer') {
1241  $triggername = 'PAYMENTBYBANKTRANFER_DELETE';
1242  }
1243  // Call trigger
1244  $result = $this->call_trigger($triggername, $user);
1245  if ($result < 0) {
1246  $error++;
1247  }
1248  // End call triggers
1249  }
1250 
1251  if (!$error) {
1252  $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).")";
1253  $resql1 = $this->db->query($sql);
1254  if (!$resql1) {
1255  dol_print_error($this->db);
1256  }
1257  }
1258 
1259  if (!$error) {
1260  $sql = "DELETE FROM ".MAIN_DB_PREFIX."prelevement_lignes WHERE fk_prelevement_bons = ".((int) $this->id);
1261  $resql2 = $this->db->query($sql);
1262  if (!$resql2) {
1263  dol_print_error($this->db);
1264  }
1265  }
1266 
1267  if (!$error) {
1268  $sql = "DELETE FROM ".MAIN_DB_PREFIX."prelevement_bons WHERE rowid = ".((int) $this->id);
1269  $resql3 = $this->db->query($sql);
1270  if (!$resql3) {
1271  dol_print_error($this->db);
1272  }
1273  }
1274 
1275  if (!$error) {
1276  $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_demande SET fk_prelevement_bons = NULL, traite = 0 WHERE fk_prelevement_bons = ".((int) $this->id);
1277  $resql4 = $this->db->query($sql);
1278  if (!$resql4) {
1279  dol_print_error($this->db);
1280  }
1281  }
1282 
1283  if ($resql1 && $resql2 && $resql3 && $resql4 && !$error) {
1284  $this->db->commit();
1285  return 1;
1286  } else {
1287  $this->db->rollback();
1288  return -1;
1289  }
1290  }
1291 
1292 
1303  public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1304  {
1305  global $conf, $langs, $hookmanager;
1306 
1307  if (!empty($conf->dol_no_mouse_hover)) {
1308  $notooltip = 1; // Force disable tooltips
1309  }
1310 
1311  $result = '';
1312 
1313  $labeltoshow = 'PaymentByDirectDebit';
1314  if (!empty($this->type) && $this->type == 'bank-transfer') {
1315  $labeltoshow = 'PaymentByBankTransfer';
1316  }
1317 
1318  $label = img_picto('', $this->picto).' <u>'.$langs->trans($labeltoshow).'</u> '.$this->getLibStatut(5);
1319  $label .= '<br>';
1320  $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
1321  if (isset($this->amount)) {
1322  $label .= '<br><b>'.$langs->trans("Amount").":</b> ".price($this->amount);
1323  }
1324  if (isset($this->date_trans)) {
1325  $label .= '<br><b>'.$langs->trans("TransData").":</b> ".dol_print_date($this->date_trans, 'dayhour', 'tzuserrel');
1326  }
1327  /*if (isset($this->date_credit)) {
1328  $label .= '<br><b>'.$langs->trans("TransData").":</b> ".dol_print_date($this->date_credit, 'dayhour', 'tzuserrel');
1329  }*/
1330 
1331  $url = DOL_URL_ROOT.'/compta/prelevement/card.php?id='.$this->id;
1332  if (!empty($this->type) && $this->type == 'bank-transfer') {
1333  $url = DOL_URL_ROOT.'/compta/prelevement/card.php?id='.$this->id;
1334  }
1335 
1336  if ($option != 'nolink') {
1337  // Add param to save lastsearch_values or not
1338  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1339  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1340  $add_save_lastsearch_values = 1;
1341  }
1342  if ($add_save_lastsearch_values) {
1343  $url .= '&save_lastsearch_values=1';
1344  }
1345  }
1346 
1347  $linkclose = '';
1348  if (empty($notooltip)) {
1349  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1350  $label = $langs->trans("ShowMyObject");
1351  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1352  }
1353  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1354  $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1355  } else {
1356  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1357  }
1358 
1359  $linkstart = '<a href="'.$url.'"';
1360  $linkstart .= $linkclose.'>';
1361  $linkend = '</a>';
1362 
1363  $result .= $linkstart;
1364  if ($withpicto) {
1365  $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);
1366  }
1367  if ($withpicto != 2) {
1368  $result .= $this->ref;
1369  }
1370  $result .= $linkend;
1371 
1372  global $action, $hookmanager;
1373  $hookmanager->initHooks(array('banktransferdao'));
1374  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1375  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1376  if ($reshook > 0) {
1377  $result = $hookmanager->resPrint;
1378  } else {
1379  $result .= $hookmanager->resPrint;
1380  }
1381 
1382  return $result;
1383  }
1384 
1385 
1392  public function deleteNotificationById($rowid)
1393  {
1394  $sql = "DELETE FROM ".MAIN_DB_PREFIX."notify_def";
1395  $sql .= " WHERE rowid = ".((int) $rowid);
1396 
1397  if ($this->db->query($sql)) {
1398  return 0;
1399  } else {
1400  return -1;
1401  }
1402  }
1403 
1411  public function deleteNotification($user, $action)
1412  {
1413  if (is_object($user)) {
1414  $userid = $user->id;
1415  } else { // If user is an id
1416  $userid = $user;
1417  }
1418 
1419  $sql = "DELETE FROM ".MAIN_DB_PREFIX."notify_def";
1420  $sql .= " WHERE fk_user=".((int) $userid)." AND fk_action='".$this->db->escape($action)."'";
1421 
1422  if ($this->db->query($sql)) {
1423  return 0;
1424  } else {
1425  return -1;
1426  }
1427  }
1428 
1429  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1438  public function addNotification($db, $user, $action)
1439  {
1440  // phpcs:enable
1441  $result = 0;
1442 
1443  if (is_object($user)) {
1444  $userid = $user->id;
1445  } else { // If user is an id
1446  $userid = $user;
1447  }
1448 
1449  if ($this->deleteNotification($user, $action) == 0) {
1450  $now = dol_now();
1451 
1452  $sql = "INSERT INTO ".MAIN_DB_PREFIX."notify_def (datec,fk_user, fk_soc, fk_contact, fk_action)";
1453  $sql .= " VALUES ('".$this->db->idate($now)."', ".((int) $userid).", 'NULL', 'NULL', '".$this->db->escape($action)."')";
1454 
1455  dol_syslog("adnotiff: ".$sql);
1456  if ($this->db->query($sql)) {
1457  $result = 0;
1458  } else {
1459  $result = -1;
1460  dol_syslog(get_class($this)."::addNotification Error $result");
1461  }
1462  }
1463 
1464  return $result;
1465  }
1466 
1467 
1481  public function generate($format = 'ALL', $executiondate = 0, $type = 'direct-debit', $fk_bank_account = 0)
1482  {
1483  global $conf, $langs, $mysoc;
1484 
1485  //TODO: Optimize code to read lines in a single function
1486 
1487  // Clean params
1488  if (empty($fk_bank_account)) {
1489  $fk_bank_account = ($type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
1490  }
1491 
1492  $result = 0;
1493 
1494  dol_syslog(get_class($this)."::generate build file=".$this->filename." type=".$type);
1495 
1496  $this->file = fopen($this->filename, "w");
1497  if (empty($this->file)) {
1498  $this->error = $langs->trans('ErrorFailedToOpenFile', $this->filename);
1499  return -1;
1500  }
1501 
1502  $found = 0;
1503  $this->total = 0;
1504 
1505  // Build file for European countries
1506  if ($mysoc->isInEEC()) {
1507  $found++;
1508 
1509  if ($type != 'bank-transfer') {
1513  // SEPA Initialisation
1514  $CrLf = "\n";
1515 
1516  $now = dol_now();
1517 
1518  $dateTime_ECMA = dol_print_date($now, '%Y-%m-%dT%H:%M:%S');
1519 
1520  $date_actu = $now;
1521  if (!empty($executiondate)) {
1522  $date_actu = $executiondate;
1523  }
1524 
1525  $dateTime_YMD = dol_print_date($date_actu, '%Y%m%d');
1526  $dateTime_YMDHMS = dol_print_date($date_actu, '%Y%m%d%H%M%S');
1527  $fileDebiteurSection = '';
1528  $fileEmetteurSection = '';
1529  $i = 0;
1530 
1531  /*
1532  * Section Debitor (sepa Debiteurs bloc lines)
1533  */
1534 
1535  $sql = "SELECT soc.rowid as socid, soc.code_client as code, soc.address, soc.zip, soc.town, c.code as country_code,";
1536  $sql .= " pl.client_nom as nom, pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, pl.amount as somme,";
1537  $sql .= " f.ref as fac, pf.fk_facture as idfac,";
1538  $sql .= " rib.rowid, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum, rib.rum, rib.date_rum";
1539  $sql .= " FROM";
1540  $sql .= " ".MAIN_DB_PREFIX."prelevement_lignes as pl,";
1541  $sql .= " ".MAIN_DB_PREFIX."facture as f,";
1542  $sql .= " ".MAIN_DB_PREFIX."prelevement as pf,";
1543  $sql .= " ".MAIN_DB_PREFIX."societe as soc,";
1544  $sql .= " ".MAIN_DB_PREFIX."c_country as c,";
1545  $sql .= " ".MAIN_DB_PREFIX."societe_rib as rib";
1546  $sql .= " WHERE pl.fk_prelevement_bons = ".((int) $this->id);
1547  $sql .= " AND pl.rowid = pf.fk_prelevement_lignes";
1548  $sql .= " AND pf.fk_facture = f.rowid";
1549  $sql .= " AND f.fk_soc = soc.rowid";
1550  $sql .= " AND soc.fk_pays = c.rowid";
1551  $sql .= " AND rib.fk_soc = f.fk_soc";
1552  $sql .= " AND rib.default_rib = 1";
1553  $sql .= " AND rib.type = 'ban'";
1554 
1555  // Define $fileDebiteurSection. One section DrctDbtTxInf per invoice.
1556  $resql = $this->db->query($sql);
1557  if ($resql) {
1558  $cachearraytotestduplicate = array();
1559 
1560  $num = $this->db->num_rows($resql);
1561  while ($i < $num) {
1562  $obj = $this->db->fetch_object($resql);
1563 
1564  if (!empty($cachearraytotestduplicate[$obj->idfac])) {
1565  $this->error = $langs->trans('ErrorCompanyHasDuplicateDefaultBAN', $obj->socid);
1566  $this->invoice_in_error[$obj->idfac] = $this->error;
1567  $result = -2;
1568  break;
1569  }
1570  $cachearraytotestduplicate[$obj->idfac] = $obj->rowid;
1571 
1572  $daterum = (!empty($obj->date_rum)) ? $this->db->jdate($obj->date_rum) : $this->db->jdate($obj->datec);
1573  $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->fac, $obj->idfac, $obj->iban, $obj->bic, $daterum, $obj->drum, $obj->rum, $type);
1574  $this->total = $this->total + $obj->somme;
1575  $i++;
1576  }
1577  $nbtotalDrctDbtTxInf = $i;
1578  } else {
1579  $this->error = $this->db->lasterror();
1580  fputs($this->file, 'ERROR DEBITOR '.$sql.$CrLf); // DEBITOR = Customers
1581  $result = -2;
1582  }
1583 
1584  // Define $fileEmetteurSection. Start of bloc PmtInf. Will contains all $nbtotalDrctDbtTxInf
1585  if ($result != -2) {
1586  $fileEmetteurSection .= $this->EnregEmetteurSEPA($conf, $date_actu, $nbtotalDrctDbtTxInf, $this->total, $CrLf, $format, $type, $fk_bank_account);
1587  }
1588 
1592  // SEPA File Header
1593  fputs($this->file, '<'.'?xml version="1.0" encoding="UTF-8" standalone="yes"?'.'>'.$CrLf);
1594  fputs($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);
1595  fputs($this->file, ' <CstmrDrctDbtInitn>'.$CrLf);
1596  // SEPA Group header
1597  fputs($this->file, ' <GrpHdr>'.$CrLf);
1598  fputs($this->file, ' <MsgId>'.('DD/'.$dateTime_YMD.'/REF'.$this->id).'</MsgId>'.$CrLf);
1599  fputs($this->file, ' <CreDtTm>'.$dateTime_ECMA.'</CreDtTm>'.$CrLf);
1600  fputs($this->file, ' <NbOfTxs>'.$i.'</NbOfTxs>'.$CrLf);
1601  fputs($this->file, ' <CtrlSum>'.$this->total.'</CtrlSum>'.$CrLf);
1602  fputs($this->file, ' <InitgPty>'.$CrLf);
1603  fputs($this->file, ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf);
1604  fputs($this->file, ' <Id>'.$CrLf);
1605  fputs($this->file, ' <PrvtId>'.$CrLf);
1606  fputs($this->file, ' <Othr>'.$CrLf);
1607  fputs($this->file, ' <Id>'.$this->emetteur_ics.'</Id>'.$CrLf);
1608  fputs($this->file, ' </Othr>'.$CrLf);
1609  fputs($this->file, ' </PrvtId>'.$CrLf);
1610  fputs($this->file, ' </Id>'.$CrLf);
1611  fputs($this->file, ' </InitgPty>'.$CrLf);
1612  fputs($this->file, ' </GrpHdr>'.$CrLf);
1613  // SEPA File Emetteur
1614  if ($result != -2) {
1615  fputs($this-> file, $fileEmetteurSection);
1616  }
1617  // SEPA File Debiteurs
1618  if ($result != -2) {
1619  fputs($this-> file, $fileDebiteurSection);
1620  }
1621  // SEPA FILE FOOTER
1622  fputs($this->file, ' </PmtInf>'.$CrLf);
1623  fputs($this->file, ' </CstmrDrctDbtInitn>'.$CrLf);
1624  fputs($this->file, '</Document>'.$CrLf);
1625  } else {
1629  // SEPA Initialisation
1630  $CrLf = "\n";
1631 
1632  $now = dol_now();
1633 
1634  $dateTime_ECMA = dol_print_date($now, '%Y-%m-%dT%H:%M:%S');
1635 
1636  $date_actu = $now;
1637  if (!empty($executiondate)) {
1638  $date_actu = $executiondate;
1639  }
1640 
1641  $dateTime_YMD = dol_print_date($date_actu, '%Y%m%d');
1642  $dateTime_YMDHMS = dol_print_date($date_actu, '%Y%m%d%H%M%S');
1643  $fileCrediteurSection = '';
1644  $fileEmetteurSection = '';
1645  $i = 0;
1646 
1647  /*
1648  * Section Creditor (sepa Crediteurs bloc lines)
1649  */
1650 
1651  $sql = "SELECT soc.rowid as socid, soc.code_client as code, soc.address, soc.zip, soc.town, c.code as country_code,";
1652  $sql .= " pl.client_nom as nom, pl.code_banque as cb, pl.code_guichet as cg, pl.number as cc, pl.amount as somme,";
1653  $sql .= " f.ref as fac, pf.fk_facture_fourn as idfac, f.ref_supplier as fac_ref_supplier,";
1654  $sql .= " rib.rowid, rib.datec, rib.iban_prefix as iban, rib.bic as bic, rib.rowid as drum, rib.rum, rib.date_rum";
1655  $sql .= " FROM";
1656  $sql .= " ".MAIN_DB_PREFIX."prelevement_lignes as pl,";
1657  $sql .= " ".MAIN_DB_PREFIX."facture_fourn as f,";
1658  $sql .= " ".MAIN_DB_PREFIX."prelevement as pf,";
1659  $sql .= " ".MAIN_DB_PREFIX."societe as soc,";
1660  $sql .= " ".MAIN_DB_PREFIX."c_country as c,";
1661  $sql .= " ".MAIN_DB_PREFIX."societe_rib as rib";
1662  $sql .= " WHERE pl.fk_prelevement_bons = ".((int) $this->id);
1663  $sql .= " AND pl.rowid = pf.fk_prelevement_lignes";
1664  $sql .= " AND pf.fk_facture_fourn = f.rowid";
1665  $sql .= " AND f.fk_soc = soc.rowid";
1666  $sql .= " AND soc.fk_pays = c.rowid";
1667  $sql .= " AND rib.fk_soc = f.fk_soc";
1668  $sql .= " AND rib.default_rib = 1";
1669  $sql .= " AND rib.type = 'ban'";
1670 
1671  // Define $fileCrediteurSection. One section DrctDbtTxInf per invoice.
1672  $resql = $this->db->query($sql);
1673  if ($resql) {
1674  $cachearraytotestduplicate = array();
1675 
1676  $num = $this->db->num_rows($resql);
1677  while ($i < $num) {
1678  $obj = $this->db->fetch_object($resql);
1679 
1680  if (!empty($cachearraytotestduplicate[$obj->idfac])) {
1681  $this->error = $langs->trans('ErrorCompanyHasDuplicateDefaultBAN', $obj->socid);
1682  $this->invoice_in_error[$obj->idfac] = $this->error;
1683  $result = -2;
1684  break;
1685  }
1686  $cachearraytotestduplicate[$obj->idfac] = $obj->rowid;
1687 
1688  $daterum = (!empty($obj->date_rum)) ? $this->db->jdate($obj->date_rum) : $this->db->jdate($obj->datec);
1689  $fileCrediteurSection .= $this->EnregDestinataireSEPA($obj->code, $obj->nom, $obj->address, $obj->zip, $obj->town, $obj->country_code, $obj->cb, $obj->cg, $obj->cc, $obj->somme, $obj->fac_ref_supplier, $obj->idfac, $obj->iban, $obj->bic, $daterum, $obj->drum, $obj->rum, $type);
1690  $this->total = $this->total + $obj->somme;
1691  $i++;
1692  }
1693  $nbtotalDrctDbtTxInf = $i;
1694  } else {
1695  $this->error = $this->db->lasterror();
1696  fputs($this->file, 'ERROR CREDITOR '.$sql.$CrLf); // CREDITORS = Suppliers
1697  $result = -2;
1698  }
1699 
1700  // Define $fileEmetteurSection. Start of bloc PmtInf. Will contains all $nbtotalDrctDbtTxInf
1701  if ($result != -2) {
1702  $fileEmetteurSection .= $this->EnregEmetteurSEPA($conf, $date_actu, $nbtotalDrctDbtTxInf, $this->total, $CrLf, $format, $type);
1703  }
1704 
1708  // SEPA File Header
1709  fputs($this->file, '<'.'?xml version="1.0" encoding="UTF-8" standalone="yes"?'.'>'.$CrLf);
1710  fputs($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);
1711  fputs($this->file, ' <CstmrCdtTrfInitn>'.$CrLf);
1712  // SEPA Group header
1713  fputs($this->file, ' <GrpHdr>'.$CrLf);
1714  fputs($this->file, ' <MsgId>'.('TRF/'.$dateTime_YMD.'/REF'.$this->id).'</MsgId>'.$CrLf);
1715  fputs($this->file, ' <CreDtTm>'.$dateTime_ECMA.'</CreDtTm>'.$CrLf);
1716  fputs($this->file, ' <NbOfTxs>'.$i.'</NbOfTxs>'.$CrLf);
1717  fputs($this->file, ' <CtrlSum>'.$this->total.'</CtrlSum>'.$CrLf);
1718  fputs($this->file, ' <InitgPty>'.$CrLf);
1719  fputs($this->file, ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf);
1720  fputs($this->file, ' <Id>'.$CrLf);
1721  fputs($this->file, ' <PrvtId>'.$CrLf);
1722  fputs($this->file, ' <Othr>'.$CrLf);
1723  fputs($this->file, ' <Id>'.$this->emetteur_ics.'</Id>'.$CrLf);
1724  fputs($this->file, ' </Othr>'.$CrLf);
1725  fputs($this->file, ' </PrvtId>'.$CrLf);
1726  fputs($this->file, ' </Id>'.$CrLf);
1727  fputs($this->file, ' </InitgPty>'.$CrLf);
1728  fputs($this->file, ' </GrpHdr>'.$CrLf);
1729  // SEPA File Emetteur (mycompany)
1730  if ($result != -2) {
1731  fputs($this-> file, $fileEmetteurSection);
1732  }
1733  // SEPA File Creditors
1734  if ($result != -2) {
1735  fputs($this-> file, $fileCrediteurSection);
1736  }
1737  // SEPA FILE FOOTER
1738  fputs($this->file, ' </PmtInf>'.$CrLf);
1739  fputs($this->file, ' </CstmrCdtTrfInitn>'.$CrLf);
1740  fputs($this->file, '</Document>'.$CrLf);
1741  }
1742  }
1743 
1744  // Build file for Other Countries with unknow format
1745  if (!$found) {
1746  if ($type != 'bank-transfer') {
1747  $sql = "SELECT pl.amount";
1748  $sql .= " FROM";
1749  $sql .= " ".MAIN_DB_PREFIX."prelevement_lignes as pl,";
1750  $sql .= " ".MAIN_DB_PREFIX."facture as f,";
1751  $sql .= " ".MAIN_DB_PREFIX."prelevement as pf";
1752  $sql .= " WHERE pl.fk_prelevement_bons = ".((int) $this->id);
1753  $sql .= " AND pl.rowid = pf.fk_prelevement_lignes";
1754  $sql .= " AND pf.fk_facture = f.rowid";
1755 
1756  // Lines
1757  $i = 0;
1758  $resql = $this->db->query($sql);
1759  if ($resql) {
1760  $num = $this->db->num_rows($resql);
1761 
1762  while ($i < $num) {
1763  $obj = $this->db->fetch_object($resql);
1764  $this->total = $this->total + $obj->amount;
1765 
1766  // TODO Write record into file
1767  $i++;
1768  }
1769  } else {
1770  $result = -2;
1771  }
1772  } else {
1773  $sql = "SELECT pl.amount";
1774  $sql .= " FROM";
1775  $sql .= " ".MAIN_DB_PREFIX."prelevement_lignes as pl,";
1776  $sql .= " ".MAIN_DB_PREFIX."facture_fourn as f,";
1777  $sql .= " ".MAIN_DB_PREFIX."prelevement as pf";
1778  $sql .= " WHERE pl.fk_prelevement_bons = ".((int) $this->id);
1779  $sql .= " AND pl.rowid = pf.fk_prelevement_lignes";
1780  $sql .= " AND pf.fk_facture_fourn = f.rowid";
1781 
1782  // Lines
1783  $i = 0;
1784  $resql = $this->db->query($sql);
1785  if ($resql) {
1786  $num = $this->db->num_rows($resql);
1787 
1788  while ($i < $num) {
1789  $obj = $this->db->fetch_object($resql);
1790  $this->total = $this->total + $obj->amount;
1791 
1792  // TODO Write record into file
1793  $i++;
1794  }
1795  } else {
1796  $result = -2;
1797  }
1798  }
1799 
1800  $langs->load('withdrawals');
1801 
1802  // TODO Add here code to generate a generic file
1803  fputs($this->file, $langs->transnoentitiesnoconv('WithdrawalFileNotCapable', $mysoc->country_code));
1804  }
1805 
1806  fclose($this->file);
1807  dolChmod($this->filename);
1808 
1809  return $result;
1810  }
1811 
1812 
1821  public static function buildRumNumber($row_code_client, $row_datec, $row_drum)
1822  {
1823  global $langs;
1824 
1825  $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)
1826 
1827  // 3 char + '-' + 12 + '-' + id + '-' + code Must be lower than 32.
1828  return $pre.'-'.dol_print_date($row_datec, 'dayhourlogsmall').'-'.dol_trunc($row_drum.($row_code_client ? '-'.$row_code_client : ''), 13, 'right', 'UTF-8', 1);
1829  }
1830 
1831 
1832  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1849  public function EnregDestinataire($rowid, $client_nom, $rib_banque, $rib_guichet, $rib_number, $amount, $ref, $facid, $rib_dom = '', $type = 'direct-debit')
1850  {
1851  // phpcs:enable
1852  fputs($this->file, "06");
1853  fputs($this->file, "08"); // Prelevement ordinaire
1854 
1855  fputs($this->file, " "); // Zone Reservee B2
1856 
1857  fputs($this->file, $this->emetteur_ics); // ICS
1858 
1859  // Date d'echeance C1
1860 
1861  fputs($this->file, " ");
1862  fputs($this->file, dol_print_date($this->date_echeance, "%d%m", 'gmt'));
1863  fputs($this->file, substr(dol_print_date($this->date_echeance, "%y", 'gmt'), 1));
1864 
1865  // Raison Sociale Destinataire C2
1866 
1867  fputs($this->file, substr(strtoupper($client_nom)." ", 0, 24));
1868 
1869  // Domiciliation facultative D1
1870  $domiciliation = strtr($rib_dom, array(" " => "-", CHR(13) => " ", CHR(10) => ""));
1871  fputs($this->file, substr($domiciliation." ", 0, 24));
1872 
1873  // Zone Reservee D2
1874 
1875  fputs($this->file, substr(" ", 0, 8));
1876 
1877  // Code Guichet D3
1878 
1879  fputs($this->file, $rib_guichet);
1880 
1881  // Numero de compte D4
1882 
1883  fputs($this->file, substr("000000000000000".$rib_number, -11));
1884 
1885  // Zone E Montant
1886 
1887  $montant = (round($amount, 2) * 100);
1888 
1889  fputs($this->file, substr("000000000000000".$montant, -16));
1890 
1891  // Libelle F
1892 
1893  fputs($this->file, substr("*_".$ref."_RDVnet".$rowid." ", 0, 31));
1894 
1895  // Code etablissement G1
1896 
1897  fputs($this->file, $rib_banque);
1898 
1899  // Zone Reservee G2
1900 
1901  fputs($this->file, substr(" ", 0, 5));
1902 
1903  fputs($this->file, "\n");
1904  }
1905 
1906  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1931  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')
1932  {
1933  // phpcs:enable
1934  global $conf;
1935 
1936  include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
1937 
1938  $CrLf = "\n";
1939  $Rowing = sprintf("%010d", $row_idfac);
1940 
1941  // Define value for RUM
1942  // Example: RUM-CustomerCode-CustomerBankAccountId-01424448606 (note: Date is the timestamp of the date of creation of CustomerBankAccountId)
1943  $Rum = (empty($row_rum) ? $this->buildRumNumber($row_code_client, $row_datec, $row_drum) : $row_rum);
1944 
1945  // Define date of RUM signature
1946  $DtOfSgntr = dol_print_date($row_datec, '%Y-%m-%d');
1947 
1948  if ($type != 'bank-transfer') {
1949  // SEPA Paiement Information of buyer for Direct Debit
1950  $XML_DEBITOR = '';
1951  $XML_DEBITOR .= ' <DrctDbtTxInf>'.$CrLf;
1952  $XML_DEBITOR .= ' <PmtId>'.$CrLf;
1953  // Add EndToEndId. Must be a unique ID for each payment (for example by including bank, buyer or seller, date, checksum)
1954  $XML_DEBITOR .= ' <EndToEndId>'.(($conf->global->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
1955  $XML_DEBITOR .= ' </PmtId>'.$CrLf;
1956  $XML_DEBITOR .= ' <InstdAmt Ccy="EUR">'.round($row_somme, 2).'</InstdAmt>'.$CrLf;
1957  $XML_DEBITOR .= ' <DrctDbtTx>'.$CrLf;
1958  $XML_DEBITOR .= ' <MndtRltdInf>'.$CrLf;
1959  $XML_DEBITOR .= ' <MndtId>'.$Rum.'</MndtId>'.$CrLf;
1960  $XML_DEBITOR .= ' <DtOfSgntr>'.$DtOfSgntr.'</DtOfSgntr>'.$CrLf;
1961  $XML_DEBITOR .= ' <AmdmntInd>false</AmdmntInd>'.$CrLf;
1962  $XML_DEBITOR .= ' </MndtRltdInf>'.$CrLf;
1963  $XML_DEBITOR .= ' </DrctDbtTx>'.$CrLf;
1964  $XML_DEBITOR .= ' <DbtrAgt>'.$CrLf;
1965  $XML_DEBITOR .= ' <FinInstnId>'.$CrLf;
1966  $XML_DEBITOR .= ' <BIC>'.$row_bic.'</BIC>'.$CrLf;
1967  $XML_DEBITOR .= ' </FinInstnId>'.$CrLf;
1968  $XML_DEBITOR .= ' </DbtrAgt>'.$CrLf;
1969  $XML_DEBITOR .= ' <Dbtr>'.$CrLf;
1970  $XML_DEBITOR .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($row_nom), ' '))).'</Nm>'.$CrLf;
1971  $XML_DEBITOR .= ' <PstlAdr>'.$CrLf;
1972  $XML_DEBITOR .= ' <Ctry>'.$row_country_code.'</Ctry>'.$CrLf;
1973  $addressline1 = strtr($row_address, array(CHR(13) => ", ", CHR(10) => ""));
1974  $addressline2 = strtr($row_zip.(($row_zip && $row_town) ? ' ' : (string) $row_town), array(CHR(13) => ", ", CHR(10) => ""));
1975  if (trim($addressline1)) {
1976  $XML_DEBITOR .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
1977  }
1978  if (trim($addressline2)) {
1979  $XML_DEBITOR .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
1980  }
1981  $XML_DEBITOR .= ' </PstlAdr>'.$CrLf;
1982  $XML_DEBITOR .= ' </Dbtr>'.$CrLf;
1983  $XML_DEBITOR .= ' <DbtrAcct>'.$CrLf;
1984  $XML_DEBITOR .= ' <Id>'.$CrLf;
1985  $XML_DEBITOR .= ' <IBAN>'.preg_replace('/\s/', '', $row_iban).'</IBAN>'.$CrLf;
1986  $XML_DEBITOR .= ' </Id>'.$CrLf;
1987  $XML_DEBITOR .= ' </DbtrAcct>'.$CrLf;
1988  $XML_DEBITOR .= ' <RmtInf>'.$CrLf;
1989  // A string with some information on payment - 140 max
1990  $XML_DEBITOR .= ' <Ustrd>'.(($conf->global->PRELEVEMENT_USTRD != "") ? $conf->global->PRELEVEMENT_USTRD : dol_trunc($row_ref, 135, 'right', 'UTF-8', 1)).'</Ustrd>'.$CrLf; // 140 max
1991  $XML_DEBITOR .= ' </RmtInf>'.$CrLf;
1992  $XML_DEBITOR .= ' </DrctDbtTxInf>'.$CrLf;
1993  return $XML_DEBITOR;
1994  } else {
1995  // SEPA Paiement Information of seller for Credit Transfer
1996  $XML_CREDITOR = '';
1997  $XML_CREDITOR .= ' <CdtTrfTxInf>'.$CrLf;
1998  $XML_CREDITOR .= ' <PmtId>'.$CrLf;
1999  // Add EndToEndId. Must be a unique ID for each payment (for example by including bank, buyer or seller, date, checksum)
2000  $XML_CREDITOR .= ' <EndToEndId>'.(($conf->global->PRELEVEMENT_END_TO_END != "") ? $conf->global->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
2001  $XML_CREDITOR .= ' </PmtId>'.$CrLf;
2002  if (!empty($this->sepa_xml_pti_in_ctti)) {
2003  $XML_CREDITOR .= ' <PmtTpInf>' . $CrLf;
2004 
2005  // Can be 'NORM' for normal or 'HIGH' for high priority level
2006  if (!empty($conf->global->PAYMENTBYBANKTRANSFER_FORCE_HIGH_PRIORITY)) {
2007  $instrprty = 'HIGH';
2008  } else {
2009  $instrprty = 'NORM';
2010  }
2011  $XML_CREDITOR .= ' <InstrPrty>'.$instrprty.'</InstrPrty>' . $CrLf;
2012  $XML_CREDITOR .= ' <SvcLvl>' . $CrLf;
2013  $XML_CREDITOR .= ' <Cd>SEPA</Cd>' . $CrLf;
2014  $XML_CREDITOR .= ' </SvcLvl>' . $CrLf;
2015  $XML_CREDITOR .= ' <CtgyPurp>' . $CrLf;
2016  $XML_CREDITOR .= ' <Cd>CORE</Cd>' . $CrLf;
2017  $XML_CREDITOR .= ' </CtgyPurp>' . $CrLf;
2018  $XML_CREDITOR .= ' </PmtTpInf>' . $CrLf;
2019  }
2020  $XML_CREDITOR .= ' <Amt>'.$CrLf;
2021  $XML_CREDITOR .= ' <InstdAmt Ccy="EUR">'.round($row_somme, 2).'</InstdAmt>'.$CrLf;
2022  $XML_CREDITOR .= ' </Amt>'.$CrLf;
2023  /*
2024  $XML_CREDITOR .= ' <DrctDbtTx>'.$CrLf;
2025  $XML_CREDITOR .= ' <MndtRltdInf>'.$CrLf;
2026  $XML_CREDITOR .= ' <MndtId>'.$Rum.'</MndtId>'.$CrLf;
2027  $XML_CREDITOR .= ' <DtOfSgntr>'.$DtOfSgntr.'</DtOfSgntr>'.$CrLf;
2028  $XML_CREDITOR .= ' <AmdmntInd>false</AmdmntInd>'.$CrLf;
2029  $XML_CREDITOR .= ' </MndtRltdInf>'.$CrLf;
2030  $XML_CREDITOR .= ' </DrctDbtTx>'.$CrLf;
2031  */
2032  //$XML_CREDITOR .= ' <ChrgBr>SLEV</ChrgBr>'.$CrLf;
2033  $XML_CREDITOR .= ' <CdtrAgt>'.$CrLf;
2034  $XML_CREDITOR .= ' <FinInstnId>'.$CrLf;
2035  $XML_CREDITOR .= ' <BIC>'.$row_bic.'</BIC>'.$CrLf;
2036  $XML_CREDITOR .= ' </FinInstnId>'.$CrLf;
2037  $XML_CREDITOR .= ' </CdtrAgt>'.$CrLf;
2038  $XML_CREDITOR .= ' <Cdtr>'.$CrLf;
2039  $XML_CREDITOR .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($row_nom), ' '))).'</Nm>'.$CrLf;
2040  $XML_CREDITOR .= ' <PstlAdr>'.$CrLf;
2041  $XML_CREDITOR .= ' <Ctry>'.$row_country_code.'</Ctry>'.$CrLf;
2042  $addressline1 = strtr($row_address, array(CHR(13) => ", ", CHR(10) => ""));
2043  $addressline2 = strtr($row_zip.(($row_zip && $row_town) ? ' ' : (string) $row_town), array(CHR(13) => ", ", CHR(10) => ""));
2044  if (trim($addressline1)) {
2045  $XML_CREDITOR .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
2046  }
2047  if (trim($addressline2)) {
2048  $XML_CREDITOR .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
2049  }
2050  $XML_CREDITOR .= ' </PstlAdr>'.$CrLf;
2051  $XML_CREDITOR .= ' </Cdtr>'.$CrLf;
2052  $XML_CREDITOR .= ' <CdtrAcct>'.$CrLf;
2053  $XML_CREDITOR .= ' <Id>'.$CrLf;
2054  $XML_CREDITOR .= ' <IBAN>'.preg_replace('/\s/', '', $row_iban).'</IBAN>'.$CrLf;
2055  $XML_CREDITOR .= ' </Id>'.$CrLf;
2056  $XML_CREDITOR .= ' </CdtrAcct>'.$CrLf;
2057  $XML_CREDITOR .= ' <RmtInf>'.$CrLf;
2058  // A string with some information on payment - 140 max
2059  $XML_CREDITOR .= ' <Ustrd>'.(($conf->global->PRELEVEMENT_USTRD != "") ? $conf->global->PRELEVEMENT_USTRD : dol_trunc($row_ref, 135, 'right', 'UTF-8', 1)).'</Ustrd>'.$CrLf; // 140 max
2060  $XML_CREDITOR .= ' </RmtInf>'.$CrLf;
2061  $XML_CREDITOR .= ' </CdtTrfTxInf>'.$CrLf;
2062  return $XML_CREDITOR;
2063  }
2064  }
2065 
2066 
2067  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2075  public function EnregEmetteur($type = 'direct-debit')
2076  {
2077  // phpcs:enable
2078  fputs($this->file, "03");
2079  fputs($this->file, "08"); // Prelevement ordinaire
2080 
2081  fputs($this->file, " "); // Zone Reservee B2
2082 
2083  fputs($this->file, $this->emetteur_ics); // ICS
2084 
2085  // Date d'echeance C1
2086 
2087  fputs($this->file, " ");
2088  fputs($this->file, dol_print_date($this->date_echeance, "%d%m", 'gmt'));
2089  fputs($this->file, substr(dol_print_date($this->date_echeance, "%y", 'gmt'), 1));
2090 
2091  // Raison Sociale C2
2092 
2093  fputs($this->file, substr($this->raison_sociale." ", 0, 24));
2094 
2095  // Reference de la remise creancier D1 sur 7 caracteres
2096 
2097  fputs($this->file, substr($this->reference_remise." ", 0, 7));
2098 
2099  // Zone Reservee D1-2
2100 
2101  fputs($this->file, substr(" ", 0, 17));
2102 
2103  // Zone Reservee D2
2104 
2105  fputs($this->file, substr(" ", 0, 2));
2106  fputs($this->file, "E");
2107  fputs($this->file, substr(" ", 0, 5));
2108 
2109  // Code Guichet D3
2110 
2111  fputs($this->file, $this->emetteur_code_guichet);
2112 
2113  // Numero de compte D4
2114 
2115  fputs($this->file, substr("000000000000000".$this->emetteur_numero_compte, -11));
2116 
2117  // Zone Reservee E
2118 
2119  fputs($this->file, substr(" ", 0, 16));
2120 
2121  // Zone Reservee F
2122 
2123  fputs($this->file, substr(" ", 0, 31));
2124 
2125  // Code etablissement
2126 
2127  fputs($this->file, $this->emetteur_code_banque);
2128 
2129  // Zone Reservee G
2130 
2131  fputs($this->file, substr(" ", 0, 5));
2132 
2133  fputs($this->file, "\n");
2134  }
2135 
2136  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2152  public function EnregEmetteurSEPA($configuration, $ladate, $nombre, $total, $CrLf = '\n', $format = 'FRST', $type = 'direct-debit', $fk_bank_account = 0)
2153  {
2154  // phpcs:enable
2155  // SEPA INITIALISATION
2156  global $conf;
2157 
2158  // Clean parameters
2159  $dateTime_YMD = dol_print_date($ladate, '%Y%m%d');
2160  $dateTime_ETAD = dol_print_date($ladate, '%Y-%m-%d');
2161  $dateTime_YMDHMS = dol_print_date($ladate, '%Y-%m-%dT%H:%M:%S');
2162 
2163  // Clean params
2164  if (empty($fk_bank_account)) {
2165  $fk_bank_account = ($type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
2166  }
2167 
2168  // Get data of bank account
2169  $account = new Account($this->db);
2170  if ($account->fetch($fk_bank_account) > 0) {
2171  $this->emetteur_code_banque = $account->code_banque;
2172  $this->emetteur_code_guichet = $account->code_guichet;
2173  $this->emetteur_numero_compte = $account->number;
2174  $this->emetteur_number_key = $account->cle_rib;
2175  $this->sepa_xml_pti_in_ctti = (bool) $account->pti_in_ctti;
2176  $this->emetteur_iban = $account->iban;
2177  $this->emetteur_bic = $account->bic;
2178 
2179  $this->emetteur_ics = ($type == 'bank-transfer' ? $account->ics_transfer : $account->ics); // Ex: PRELEVEMENT_ICS = "FR78ZZZ123456";
2180 
2181  $this->raison_sociale = $account->proprio;
2182  }
2183 
2184  // Get pending payments
2185  $sql = "SELECT rowid, ref";
2186  $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_bons as pb";
2187  $sql .= " WHERE pb.rowid = ".((int) $this->id);
2188 
2189  $resql = $this->db->query($sql);
2190  if ($resql) {
2191  $obj = $this->db->fetch_object($resql);
2192 
2193  $country = explode(':', $configuration->global->MAIN_INFO_SOCIETE_COUNTRY);
2194  $IdBon = sprintf("%05d", $obj->rowid);
2195  $RefBon = $obj->ref;
2196 
2197  if ($type != 'bank-transfer') {
2198  // SEPA Paiement Information of my company for Direct Debit
2199  $XML_SEPA_INFO = '';
2200  $XML_SEPA_INFO .= ' <PmtInf>'.$CrLf;
2201  $XML_SEPA_INFO .= ' <PmtInfId>'.('DD/'.$dateTime_YMD.'/ID'.$IdBon.'-'.$RefBon).'</PmtInfId>'.$CrLf;
2202  $XML_SEPA_INFO .= ' <PmtMtd>DD</PmtMtd>'.$CrLf;
2203  $XML_SEPA_INFO .= ' <NbOfTxs>'.$nombre.'</NbOfTxs>'.$CrLf;
2204  $XML_SEPA_INFO .= ' <CtrlSum>'.$total.'</CtrlSum>'.$CrLf;
2205  $XML_SEPA_INFO .= ' <PmtTpInf>'.$CrLf;
2206  $XML_SEPA_INFO .= ' <SvcLvl>'.$CrLf;
2207  $XML_SEPA_INFO .= ' <Cd>SEPA</Cd>'.$CrLf;
2208  $XML_SEPA_INFO .= ' </SvcLvl>'.$CrLf;
2209  $XML_SEPA_INFO .= ' <LclInstrm>'.$CrLf;
2210  $XML_SEPA_INFO .= ' <Cd>CORE</Cd>'.$CrLf;
2211  $XML_SEPA_INFO .= ' </LclInstrm>'.$CrLf;
2212  $XML_SEPA_INFO .= ' <SeqTp>'.$format.'</SeqTp>'.$CrLf;
2213  $XML_SEPA_INFO .= ' </PmtTpInf>'.$CrLf;
2214  $XML_SEPA_INFO .= ' <ReqdColltnDt>'.$dateTime_ETAD.'</ReqdColltnDt>'.$CrLf;
2215  $XML_SEPA_INFO .= ' <Cdtr>'.$CrLf;
2216  $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
2217  $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
2218  $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
2219  $addressline1 = strtr($configuration->global->MAIN_INFO_SOCIETE_ADDRESS, array(CHR(13) => ", ", CHR(10) => ""));
2220  $addressline2 = strtr($configuration->global->MAIN_INFO_SOCIETE_ZIP.(($configuration->global->MAIN_INFO_SOCIETE_ZIP || ' '.$configuration->global->MAIN_INFO_SOCIETE_TOWN) ? ' ' : '').$configuration->global->MAIN_INFO_SOCIETE_TOWN, array(CHR(13) => ", ", CHR(10) => ""));
2221  if ($addressline1) {
2222  $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
2223  }
2224  if ($addressline2) {
2225  $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
2226  }
2227  $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
2228  $XML_SEPA_INFO .= ' </Cdtr>'.$CrLf;
2229  $XML_SEPA_INFO .= ' <CdtrAcct>'.$CrLf;
2230  $XML_SEPA_INFO .= ' <Id>'.$CrLf;
2231  $XML_SEPA_INFO .= ' <IBAN>'.preg_replace('/\s/', '', $this->emetteur_iban).'</IBAN>'.$CrLf;
2232  $XML_SEPA_INFO .= ' </Id>'.$CrLf;
2233  $XML_SEPA_INFO .= ' </CdtrAcct>'.$CrLf;
2234  $XML_SEPA_INFO .= ' <CdtrAgt>'.$CrLf;
2235  $XML_SEPA_INFO .= ' <FinInstnId>'.$CrLf;
2236  $XML_SEPA_INFO .= ' <BIC>'.$this->emetteur_bic.'</BIC>'.$CrLf;
2237  $XML_SEPA_INFO .= ' </FinInstnId>'.$CrLf;
2238  $XML_SEPA_INFO .= ' </CdtrAgt>'.$CrLf;
2239  /* $XML_SEPA_INFO .= ' <UltmtCdtr>'.$CrLf;
2240  $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
2241  $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
2242  $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
2243  $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_string_nospecial(dol_string_unaccent($conf->global->MAIN_INFO_SOCIETE_ADDRESS), ' ')).'</AdrLine>'.$CrLf;
2244  $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_string_nospecial(dol_string_unaccent($conf->global->MAIN_INFO_SOCIETE_ZIP.' '.$conf->global->MAIN_INFO_SOCIETE_TOWN), ' ')).'</AdrLine>'.$CrLf;
2245  $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
2246  $XML_SEPA_INFO .= ' </UltmtCdtr>'.$CrLf;*/
2247  $XML_SEPA_INFO .= ' <ChrgBr>SLEV</ChrgBr>'.$CrLf; // Field "Responsible of fees". Must be SLEV
2248  $XML_SEPA_INFO .= ' <CdtrSchmeId>'.$CrLf;
2249  $XML_SEPA_INFO .= ' <Id>'.$CrLf;
2250  $XML_SEPA_INFO .= ' <PrvtId>'.$CrLf;
2251  $XML_SEPA_INFO .= ' <Othr>'.$CrLf;
2252  $XML_SEPA_INFO .= ' <Id>'.$this->emetteur_ics.'</Id>'.$CrLf;
2253  $XML_SEPA_INFO .= ' <SchmeNm>'.$CrLf;
2254  $XML_SEPA_INFO .= ' <Prtry>SEPA</Prtry>'.$CrLf;
2255  $XML_SEPA_INFO .= ' </SchmeNm>'.$CrLf;
2256  $XML_SEPA_INFO .= ' </Othr>'.$CrLf;
2257  $XML_SEPA_INFO .= ' </PrvtId>'.$CrLf;
2258  $XML_SEPA_INFO .= ' </Id>'.$CrLf;
2259  $XML_SEPA_INFO .= ' </CdtrSchmeId>'.$CrLf;
2260  } else {
2261  // SEPA Paiement Information of my company for Credit Transfer
2262  $XML_SEPA_INFO = '';
2263  $XML_SEPA_INFO .= ' <PmtInf>'.$CrLf;
2264  $XML_SEPA_INFO .= ' <PmtInfId>'.('TRF/'.$dateTime_YMD.'/ID'.$IdBon.'-'.$RefBon).'</PmtInfId>'.$CrLf;
2265  $XML_SEPA_INFO .= ' <PmtMtd>TRF</PmtMtd>'.$CrLf;
2266  //$XML_SEPA_INFO .= ' <BtchBookg>False</BtchBookg>'.$CrLf;
2267  $XML_SEPA_INFO .= ' <NbOfTxs>'.$nombre.'</NbOfTxs>'.$CrLf;
2268  $XML_SEPA_INFO .= ' <CtrlSum>'.$total.'</CtrlSum>'.$CrLf;
2269  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.
2270  $XML_SEPA_INFO .= ' <PmtTpInf>' . $CrLf;
2271  $XML_SEPA_INFO .= ' <SvcLvl>' . $CrLf;
2272  $XML_SEPA_INFO .= ' <Cd>SEPA</Cd>' . $CrLf;
2273  $XML_SEPA_INFO .= ' </SvcLvl>' . $CrLf;
2274  $XML_SEPA_INFO .= ' <LclInstrm>' . $CrLf;
2275  $XML_SEPA_INFO .= ' <Cd>CORE</Cd>' . $CrLf;
2276  $XML_SEPA_INFO .= ' </LclInstrm>' . $CrLf;
2277  $XML_SEPA_INFO .= ' <SeqTp>' . $format . '</SeqTp>' . $CrLf;
2278  $XML_SEPA_INFO .= ' </PmtTpInf>' . $CrLf;
2279  }
2280  $XML_SEPA_INFO .= ' <ReqdExctnDt>'.dol_print_date($dateTime_ETAD, 'dayrfc').'</ReqdExctnDt>'.$CrLf;
2281  $XML_SEPA_INFO .= ' <Dbtr>'.$CrLf;
2282  $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
2283  $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
2284  $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
2285  $addressline1 = strtr($configuration->global->MAIN_INFO_SOCIETE_ADDRESS, array(CHR(13) => ", ", CHR(10) => ""));
2286  $addressline2 = strtr($configuration->global->MAIN_INFO_SOCIETE_ZIP.(($configuration->global->MAIN_INFO_SOCIETE_ZIP || ' '.$configuration->global->MAIN_INFO_SOCIETE_TOWN) ? ' ' : '').$configuration->global->MAIN_INFO_SOCIETE_TOWN, array(CHR(13) => ", ", CHR(10) => ""));
2287  if ($addressline1) {
2288  $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline1), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
2289  }
2290  if ($addressline2) {
2291  $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_trunc(dol_string_nospecial(dol_string_unaccent($addressline2), ' '), 70, 'right', 'UTF-8', 1)).'</AdrLine>'.$CrLf;
2292  }
2293  $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
2294  $XML_SEPA_INFO .= ' </Dbtr>'.$CrLf;
2295  $XML_SEPA_INFO .= ' <DbtrAcct>'.$CrLf;
2296  $XML_SEPA_INFO .= ' <Id>'.$CrLf;
2297  $XML_SEPA_INFO .= ' <IBAN>'.preg_replace('/\s/', '', $this->emetteur_iban).'</IBAN>'.$CrLf;
2298  $XML_SEPA_INFO .= ' </Id>'.$CrLf;
2299  $XML_SEPA_INFO .= ' </DbtrAcct>'.$CrLf;
2300  $XML_SEPA_INFO .= ' <DbtrAgt>'.$CrLf;
2301  $XML_SEPA_INFO .= ' <FinInstnId>'.$CrLf;
2302  $XML_SEPA_INFO .= ' <BIC>'.$this->emetteur_bic.'</BIC>'.$CrLf;
2303  $XML_SEPA_INFO .= ' </FinInstnId>'.$CrLf;
2304  $XML_SEPA_INFO .= ' </DbtrAgt>'.$CrLf;
2305  /* $XML_SEPA_INFO .= ' <UltmtCdtr>'.$CrLf;
2306  $XML_SEPA_INFO .= ' <Nm>'.dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($this->raison_sociale), ' '))).'</Nm>'.$CrLf;
2307  $XML_SEPA_INFO .= ' <PstlAdr>'.$CrLf;
2308  $XML_SEPA_INFO .= ' <Ctry>'.$country[1].'</Ctry>'.$CrLf;
2309  $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_string_nospecial(dol_string_unaccent($conf->global->MAIN_INFO_SOCIETE_ADDRESS), ' ')).'</AdrLine>'.$CrLf;
2310  $XML_SEPA_INFO .= ' <AdrLine>'.dolEscapeXML(dol_string_nospecial(dol_string_unaccent($conf->global->MAIN_INFO_SOCIETE_ZIP.' '.$conf->global->MAIN_INFO_SOCIETE_TOWN), ' ')).'</AdrLine>'.$CrLf;
2311  $XML_SEPA_INFO .= ' </PstlAdr>'.$CrLf;
2312  $XML_SEPA_INFO .= ' </UltmtCdtr>'.$CrLf;*/
2313  $XML_SEPA_INFO .= ' <ChrgBr>SLEV</ChrgBr>'.$CrLf; // Field "Responsible of fees". Must be SLEV
2314  /*$XML_SEPA_INFO .= ' <CdtrSchmeId>'.$CrLf;
2315  $XML_SEPA_INFO .= ' <Id>'.$CrLf;
2316  $XML_SEPA_INFO .= ' <PrvtId>'.$CrLf;
2317  $XML_SEPA_INFO .= ' <Othr>'.$CrLf;
2318  $XML_SEPA_INFO .= ' <Id>'.$this->emetteur_ics.'</Id>'.$CrLf;
2319  $XML_SEPA_INFO .= ' <SchmeNm>'.$CrLf;
2320  $XML_SEPA_INFO .= ' <Prtry>SEPA</Prtry>'.$CrLf;
2321  $XML_SEPA_INFO .= ' </SchmeNm>'.$CrLf;
2322  $XML_SEPA_INFO .= ' </Othr>'.$CrLf;
2323  $XML_SEPA_INFO .= ' </PrvtId>'.$CrLf;
2324  $XML_SEPA_INFO .= ' </Id>'.$CrLf;
2325  $XML_SEPA_INFO .= ' </CdtrSchmeId>'.$CrLf;*/
2326  }
2327  } else {
2328  fputs($this->file, 'INCORRECT EMETTEUR '.$this->raison_sociale.$CrLf);
2329  $XML_SEPA_INFO = '';
2330  }
2331  return $XML_SEPA_INFO;
2332  }
2333 
2334  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2341  public function EnregTotal($total)
2342  {
2343  // phpcs:enable
2344  fputs($this->file, "08");
2345  fputs($this->file, "08"); // Prelevement ordinaire
2346 
2347  fputs($this->file, " "); // Zone Reservee B2
2348 
2349  fputs($this->file, $this->emetteur_ics); // ICS
2350 
2351  // Reserve C1
2352 
2353  fputs($this->file, substr(" ", 0, 12));
2354 
2355 
2356  // Raison Sociale C2
2357 
2358  fputs($this->file, substr(" ", 0, 24));
2359 
2360  // D1
2361 
2362  fputs($this->file, substr(" ", 0, 24));
2363 
2364  // Zone Reservee D2
2365 
2366  fputs($this->file, substr(" ", 0, 8));
2367 
2368  // Code Guichet D3
2369 
2370  fputs($this->file, substr(" ", 0, 5));
2371 
2372  // Numero de compte D4
2373 
2374  fputs($this->file, substr(" ", 0, 11));
2375 
2376  // Zone E Montant
2377 
2378  $montant = ($total * 100);
2379 
2380  fputs($this->file, substr("000000000000000".$montant, -16));
2381 
2382  // Zone Reservee F
2383 
2384  fputs($this->file, substr(" ", 0, 31));
2385 
2386  // Code etablissement
2387 
2388  fputs($this->file, substr(" ", 0, 5));
2389 
2390  // Zone Reservee F
2391 
2392  fputs($this->file, substr(" ", 0, 5));
2393 
2394  fputs($this->file, "\n");
2395  }
2396 
2403  public function getLibStatut($mode = 0)
2404  {
2405  return $this->LibStatut($this->statut, $mode);
2406  }
2407 
2408  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2416  public function LibStatut($status, $mode = 0)
2417  {
2418  // phpcs:enable
2419  if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
2420  global $langs;
2421  //$langs->load("mymodule");
2422  $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('StatusWaiting');
2423  $this->labelStatus[self::STATUS_TRANSFERED] = $langs->transnoentitiesnoconv('StatusTrans');
2424  $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('StatusWaiting');
2425  $this->labelStatusShort[self::STATUS_TRANSFERED] = $langs->transnoentitiesnoconv('StatusTrans');
2426  if ($this->type == 'bank-transfer') {
2427  $this->labelStatus[self::STATUS_DEBITED] = $langs->transnoentitiesnoconv('StatusDebited');
2428  $this->labelStatusShort[self::STATUS_DEBITED] = $langs->transnoentitiesnoconv('StatusDebited');
2429  } else {
2430  $this->labelStatus[self::STATUS_CREDITED] = $langs->transnoentitiesnoconv('StatusCredited');
2431  $this->labelStatusShort[self::STATUS_CREDITED] = $langs->transnoentitiesnoconv('StatusCredited');
2432  }
2433  }
2434 
2435  $statusType = 'status1';
2436  if ($status == self::STATUS_TRANSFERED) {
2437  $statusType = 'status3';
2438  }
2439  if ($status == self::STATUS_CREDITED || $status == self::STATUS_DEBITED) {
2440  $statusType = 'status6';
2441  }
2442 
2443  return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
2444  }
2445 
2446  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2454  public function load_board($user, $mode)
2455  {
2456  // phpcs:enable
2457  global $conf, $langs;
2458 
2459  if ($user->socid) {
2460  return -1; // protection pour eviter appel par utilisateur externe
2461  }
2462 
2463  /*
2464  if ($mode == 'direct_debit') {
2465  $sql = "SELECT b.rowid, f.datedue as datefin";
2466  $sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
2467  $sql .= " WHERE f.entity IN (".getEntity('facture').")";
2468  $sql .= " AND f.total_ttc > 0";
2469  } else {
2470  $sql = "SELECT b.rowid, f.datedue as datefin";
2471  $sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
2472  $sql .= " WHERE f.entity IN (".getEntity('facture_fourn').")";
2473  $sql .= " AND f.total_ttc > 0";
2474  }
2475 
2476  $resql = $this->db->query($sql);
2477  if ($resql) {
2478  $langs->load("banks");
2479  $now = dol_now();
2480 
2481  $response = new WorkboardResponse();
2482  if ($mode == 'direct_debit') {
2483  $response->warning_delay = $conf->prelevement->warning_delay / 60 / 60 / 24;
2484  $response->label = $langs->trans("PendingDirectDebitToComplete");
2485  $response->labelShort = $langs->trans("PendingDirectDebitToCompleteShort");
2486  $response->url = DOL_URL_ROOT.'/compta/prelevement/index.php?leftmenu=checks&mainmenu=bank';
2487  } else {
2488  $response->warning_delay = $conf->paymentbybanktransfer->warning_delay / 60 / 60 / 24;
2489  $response->label = $langs->trans("PendingCreditTransferToComplete");
2490  $response->labelShort = $langs->trans("PendingCreditTransferToCompleteShort");
2491  $response->url = DOL_URL_ROOT.'/compta/paymentbybanktransfer/index.php?leftmenu=checks&mainmenu=bank';
2492  }
2493  $response->img = img_object('', "payment");
2494 
2495  while ($obj = $this->db->fetch_object($resql)) {
2496  $response->nbtodo++;
2497 
2498  if ($this->db->jdate($obj->datefin) < ($now - $conf->withdraw->warning_delay)) {
2499  $response->nbtodolate++;
2500  }
2501  }
2502 
2503  $response->nbtodo = 0;
2504  $response->nbtodolate = 0;
2505  // Return workboard only if quantity is not 0
2506  if ($response->nbtodo) {
2507  return $response;
2508  } else {
2509  return 0;
2510  }
2511  } else {
2512  dol_print_error($this->db);
2513  $this->error = $this->db->error();
2514  return -1;
2515  }
2516  */
2517  return 0;
2518  }
2519 
2527  public function getKanbanView($option = '', $arraydata = null)
2528  {
2529  global $langs;
2530 
2531  $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
2532 
2533  $return = '<div class="box-flex-item box-flex-grow-zero">';
2534  $return .= '<div class="info-box info-box-sm">';
2535  $return .= '<span class="info-box-icon bg-infobox-action">';
2536  $return .= img_picto('', $this->picto);
2537  $return .= '</span>';
2538  $return .= '<div class="info-box-content">';
2539  $return .= '<span class="info-box-ref">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
2540  $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
2541 
2542  if (property_exists($this, 'date_echeance')) {
2543  $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>';
2544  }
2545  if (property_exists($this, 'total')) {
2546  $return .= '<br><span class="opacitymedium">'.$langs->trans("Amount").'</span> : <span class="amount">'.price($this->total).'</span>';
2547  }
2548  if (method_exists($this, 'LibStatut')) {
2549  $return .= '<br><div class="info-box-status margintoponly">'.$this->getLibStatut(3).'</div>';
2550  }
2551  $return .= '</div>';
2552  $return .= '</div>';
2553  $return .= '</div>';
2554  return $return;
2555  }
2556 }
Societe
Class to manage third parties objects (customers, suppliers, prospects...)
Definition: societe.class.php:50
db
$conf db
API class for accounts.
Definition: inc.php:41
BonPrelevement\deleteNotificationById
deleteNotificationById($rowid)
Delete a notification def by id.
Definition: bonprelevement.class.php:1392
dol_trunc
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.
Definition: functions.lib.php:3985
BonPrelevement\fetch
fetch($rowid, $ref='')
Get object and lines from database.
Definition: bonprelevement.class.php:358
$sql
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:745
FactureFournisseur
Class to manage suppliers invoices.
Definition: fournisseur.facture.class.php:51
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:5031
BonPrelevement\EnregEmetteur
EnregEmetteur($type='direct-debit')
Write sender of request (me).
Definition: bonprelevement.class.php:2075
BonPrelevement\nbOfInvoiceToPay
nbOfInvoiceToPay($mode='direct-debit')
Get number of invoices waiting for payment.
Definition: bonprelevement.class.php:767
Facture
Class to manage invoices.
Definition: facture.class.php:60
BonPrelevement\generate
generate($format='ALL', $executiondate=0, $type='direct-debit', $fk_bank_account=0)
Generate a direct debit or credit transfer file.
Definition: bonprelevement.class.php:1481
CommonObject
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Definition: commonobject.class.php:45
CompanyBankAccount
Class to manage bank accounts description of third parties.
Definition: companybankaccount.class.php:34
BonPrelevement\__construct
__construct($db)
Constructor.
Definition: bonprelevement.class.php:174
BonPrelevement\AddFacture
AddFacture($invoice_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key, $type='debit-order')
Add invoice to withdrawal.
Definition: bonprelevement.class.php:218
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5876
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2601
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:4061
dolChmod
dolChmod($filepath, $newmask='')
Change mod of a file.
Definition: functions.lib.php:6926
BonPrelevement\getErrorString
getErrorString($error)
Return error string.
Definition: bonprelevement.class.php:340
BonPrelevement
Class to manage withdrawal receipts.
Definition: bonprelevement.class.php:43
BonPrelevement\EnregDestinataireSEPA
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')
Write recipient of request (customer)
Definition: bonprelevement.class.php:1931
BonPrelevement\getLibStatut
getLibStatut($mode=0)
Return status label of object.
Definition: bonprelevement.class.php:2403
dol_string_nospecial
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='')
Clean a string from all punctuation characters to use it as a ref or login.
Definition: functions.lib.php:1438
dol_string_unaccent
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
Definition: functions.lib.php:1367
BonPrelevement\buildRumNumber
static buildRumNumber($row_code_client, $row_datec, $row_drum)
Generate dynamically a RUM number for a customer bank account.
Definition: bonprelevement.class.php:1821
BonPrelevement\update
update(User $user, $notrigger=false)
Update object into database.
Definition: bonprelevement.class.php:421
BonPrelevement\SommeAPrelever
SommeAPrelever($mode='direct-debit')
Returns amount waiting for direct debit payment or credit transfer payment.
Definition: bonprelevement.class.php:719
BonPrelevement\getKanbanView
getKanbanView($option='', $arraydata=null)
Return clicable link of object (with eventually picto)
Definition: bonprelevement.class.php:2527
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1669
CommonObject\updateCommon
updateCommon(User $user, $notrigger=false)
Update object into database.
Definition: commonobject.class.php:9590
BonPrelevement\deleteNotification
deleteNotification($user, $action)
Delete a notification.
Definition: bonprelevement.class.php:1411
BonPrelevement\load_board
load_board($user, $mode)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Definition: bonprelevement.class.php:2454
dolGetFirstLastname
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
Definition: functions.lib.php:8477
ref
$object ref
Definition: info.php:78
PaiementFourn
Class to manage payments for supplier invoices.
Definition: paiementfourn.class.php:38
User
Class to manage Dolibarr users.
Definition: user.class.php:46
Paiement
Class to manage payments of customer invoices.
Definition: paiement.class.php:42
BonPrelevement\LibStatut
LibStatut($status, $mode=0)
Return status label for a status.
Definition: bonprelevement.class.php:2416
BonPrelevement\EnregTotal
EnregTotal($total)
Write end.
Definition: bonprelevement.class.php:2341
BonPrelevement\EnregEmetteurSEPA
EnregEmetteurSEPA($configuration, $ladate, $nombre, $total, $CrLf='\n', $format='FRST', $type='direct-debit', $fk_bank_account=0)
Write sender of request (me).
Definition: bonprelevement.class.php:2152
dolGetStatus
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
Definition: functions.lib.php:10816
img_object
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
Definition: functions.lib.php:4398
BonPrelevement\NbFactureAPrelever
NbFactureAPrelever($type='direct-debit')
Get number of invoices to pay.
Definition: bonprelevement.class.php:779
BonPrelevement\addNotification
addNotification($db, $user, $action)
Add a notification.
Definition: bonprelevement.class.php:1438
BonPrelevement\set_infocredit
set_infocredit($user, $date)
Set direct debit or credit transfer order to "paid" status.
Definition: bonprelevement.class.php:435
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2982
BonPrelevement\set_infotrans
set_infotrans($user, $date, $method)
Set withdrawal to transmited status.
Definition: bonprelevement.class.php:597
BonPrelevement\addline
addline(&$line_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key)
Add line to withdrawal.
Definition: bonprelevement.class.php:274
price
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.
Definition: functions.lib.php:5750
CommonObject\call_trigger
call_trigger($triggerName, $user)
Call trigger based on this instance.
Definition: commonobject.class.php:5913
dol_mkdir
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
Definition: functions.lib.php:6855
BonPrelevement\create
create($banque=0, $agence=0, $mode='real', $format='ALL', $executiondate='', $notrigger=0, $type='direct-debit', $did=0, $fk_bank_account=0)
Create a BAN payment order:
Definition: bonprelevement.class.php:840
type
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:120
BonPrelevement\getListInvoices
getListInvoices($amounts=0)
Get invoice list.
Definition: bonprelevement.class.php:652
Account
Class to manage bank accounts.
Definition: account.class.php:40
BonPrelevement\EnregDestinataire
EnregDestinataire($rowid, $client_nom, $rib_banque, $rib_guichet, $rib_number, $amount, $ref, $facid, $rib_dom='', $type='direct-debit')
Write recipient of request (customer)
Definition: bonprelevement.class.php:1849
BonPrelevement\getNomUrl
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Returns clickable name (with picto)
Definition: bonprelevement.class.php:1303