dolibarr  19.0.0-dev
commoninvoice.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2012 Regis Houssin <regis.houssin@inodbox.com>
3  * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr>
4  * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <https://www.gnu.org/licenses/>.
18  */
19 
26 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
27 require_once DOL_DOCUMENT_ROOT.'/core/class/commonincoterm.class.php';
28 
32 abstract class CommonInvoice extends CommonObject
33 {
34  use CommonIncoterm;
35 
39  public $type = self::TYPE_STANDARD;
40 
44  public $subtype;
45 
49  const TYPE_STANDARD = 0;
50 
54  const TYPE_REPLACEMENT = 1;
55 
59  const TYPE_CREDIT_NOTE = 2;
60 
64  const TYPE_DEPOSIT = 3;
65 
70  const TYPE_PROFORMA = 4;
71 
75  const TYPE_SITUATION = 5;
76 
80  const STATUS_DRAFT = 0;
81 
85  const STATUS_VALIDATED = 1;
86 
94  const STATUS_CLOSED = 2;
95 
103  const STATUS_ABANDONED = 3;
104 
105 
106  public $totalpaid; // duplicate with sumpayed
107  public $totaldeposits; // duplicate with sumdeposit
108  public $totalcreditnotes; // duplicate with sumcreditnote
109 
110  public $sumpayed;
111  public $sumpayed_multicurrency;
112  public $sumdeposit;
113  public $sumdeposit_multicurrency;
114  public $sumcreditnote;
115  public $sumcreditnote_multicurrency;
116  public $remaintopay;
117 
118 
126  public function getRemainToPay($multicurrency = 0)
127  {
128  $alreadypaid = 0.0;
129  $alreadypaid += $this->getSommePaiement($multicurrency);
130  $alreadypaid += $this->getSumDepositsUsed($multicurrency);
131  $alreadypaid += $this->getSumCreditNotesUsed($multicurrency);
132 
133  $remaintopay = price2num($this->total_ttc - $alreadypaid, 'MT');
134  if ($this->statut == self::STATUS_CLOSED && $this->close_code == 'discount_vat') { // If invoice closed with discount for anticipated payment
135  $remaintopay = 0.0;
136  }
137  return $remaintopay;
138  }
139 
147  public function getSommePaiement($multicurrency = 0)
148  {
149  $table = 'paiement_facture';
150  $field = 'fk_facture';
151  if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') {
152  $table = 'paiementfourn_facturefourn';
153  $field = 'fk_facturefourn';
154  }
155 
156  $sql = "SELECT sum(amount) as amount, sum(multicurrency_amount) as multicurrency_amount";
157  $sql .= " FROM ".$this->db->prefix().$table;
158  $sql .= " WHERE ".$field." = ".((int) $this->id);
159 
160  dol_syslog(get_class($this)."::getSommePaiement", LOG_DEBUG);
161 
162  $resql = $this->db->query($sql);
163  if ($resql) {
164  $obj = $this->db->fetch_object($resql);
165 
166  $this->db->free($resql);
167 
168  if ($obj) {
169  if ($multicurrency < 0) {
170  $this->sumpayed = $obj->amount;
171  $this->sumpayed_multicurrency = $obj->multicurrency_amount;
172  return array('alreadypaid'=>(float) $obj->amount, 'alreadypaid_multicurrency'=>(float) $obj->multicurrency_amount);
173  } elseif ($multicurrency) {
174  $this->sumpayed_multicurrency = $obj->multicurrency_amount;
175  return (float) $obj->multicurrency_amount;
176  } else {
177  $this->sumpayed = $obj->amount;
178  return (float) $obj->amount;
179  }
180  } else {
181  return 0;
182  }
183  } else {
184  $this->error = $this->db->lasterror();
185  return -1;
186  }
187  }
188 
197  public function getSumDepositsUsed($multicurrency = 0)
198  {
199  /*if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') {
200  // FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS was never supported for purchase invoice, so we can return 0 with no need of SQL for this case.
201  return 0.0;
202  }*/
203 
204  require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
205 
206  $discountstatic = new DiscountAbsolute($this->db);
207  $result = $discountstatic->getSumDepositsUsed($this, $multicurrency);
208 
209  if ($result >= 0) {
210  if ($multicurrency) {
211  $this->sumdeposit_multicurrency = $result;
212  } else {
213  $this->sumdeposit = $result;
214  }
215 
216  return $result;
217  } else {
218  $this->error = $discountstatic->error;
219  return -1;
220  }
221  }
222 
229  public function getSumCreditNotesUsed($multicurrency = 0)
230  {
231  require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
232 
233  $discountstatic = new DiscountAbsolute($this->db);
234  $result = $discountstatic->getSumCreditNotesUsed($this, $multicurrency);
235  if ($result >= 0) {
236  if ($multicurrency) {
237  $this->sumcreditnote_multicurrency = $result;
238  } else {
239  $this->sumcreditnote = $result;
240  }
241 
242  return $result;
243  } else {
244  $this->error = $discountstatic->error;
245  return -1;
246  }
247  }
248 
255  public function getSumFromThisCreditNotesNotUsed($multicurrency = 0)
256  {
257  require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
258 
259  $discountstatic = new DiscountAbsolute($this->db);
260  $result = $discountstatic->getSumFromThisCreditNotesNotUsed($this, $multicurrency);
261  if ($result >= 0) {
262  return $result;
263  } else {
264  $this->error = $discountstatic->error;
265  return -1;
266  }
267  }
268 
274  public function getListIdAvoirFromInvoice()
275  {
276  $idarray = array();
277 
278  $sql = "SELECT rowid";
279  $sql .= " FROM ".$this->db->prefix().$this->table_element;
280  $sql .= " WHERE fk_facture_source = ".((int) $this->id);
281  $sql .= " AND type = 2";
282  $resql = $this->db->query($sql);
283  if ($resql) {
284  $num = $this->db->num_rows($resql);
285  $i = 0;
286  while ($i < $num) {
287  $row = $this->db->fetch_row($resql);
288  $idarray[] = $row[0];
289  $i++;
290  }
291  } else {
292  dol_print_error($this->db);
293  }
294  return $idarray;
295  }
296 
303  public function getIdReplacingInvoice($option = '')
304  {
305  $sql = "SELECT rowid";
306  $sql .= " FROM ".$this->db->prefix().$this->table_element;
307  $sql .= " WHERE fk_facture_source = ".((int) $this->id);
308  $sql .= " AND type < 2";
309  if ($option == 'validated') {
310  $sql .= ' AND fk_statut = 1';
311  }
312  // PROTECTION BAD DATA
313  // In case the database is corrupted and there is a valid replectement invoice
314  // and another no, priority is given to the valid one.
315  // Should not happen (unless concurrent access and 2 people have created a
316  // replacement invoice for the same invoice at the same time)
317  $sql .= " ORDER BY fk_statut DESC";
318 
319  $resql = $this->db->query($sql);
320  if ($resql) {
321  $obj = $this->db->fetch_object($resql);
322  if ($obj) {
323  // If there is any
324  return $obj->rowid;
325  } else {
326  // If no invoice replaces it
327  return 0;
328  }
329  } else {
330  return -1;
331  }
332  }
333 
340  public function getListOfPayments($filtertype = '')
341  {
342  $retarray = array();
343 
344  $table = 'paiement_facture';
345  $table2 = 'paiement';
346  $field = 'fk_facture';
347  $field2 = 'fk_paiement';
348  $field3 = ', p.ref_ext';
349  $field4 = ', p.fk_bank'; // Bank line id
350  $sharedentity = 'facture';
351  if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') {
352  $table = 'paiementfourn_facturefourn';
353  $table2 = 'paiementfourn';
354  $field = 'fk_facturefourn';
355  $field2 = 'fk_paiementfourn';
356  $field3 = '';
357  $sharedentity = 'facture_fourn';
358  }
359 
360  $sql = "SELECT p.ref, pf.amount, pf.multicurrency_amount, p.fk_paiement, p.datep, p.num_paiement as num, t.code".$field3 . $field4;
361  $sql .= " FROM ".$this->db->prefix().$table." as pf, ".$this->db->prefix().$table2." as p, ".$this->db->prefix()."c_paiement as t";
362  $sql .= " WHERE pf.".$field." = ".((int) $this->id);
363  $sql .= " AND pf.".$field2." = p.rowid";
364  $sql .= ' AND p.fk_paiement = t.id';
365  $sql .= ' AND p.entity IN ('.getEntity($sharedentity).')';
366  if ($filtertype) {
367  $sql .= " AND t.code='PRE'";
368  }
369 
370  dol_syslog(get_class($this)."::getListOfPayments", LOG_DEBUG);
371  $resql = $this->db->query($sql);
372  if ($resql) {
373  $num = $this->db->num_rows($resql);
374  $i = 0;
375  while ($i < $num) {
376  $obj = $this->db->fetch_object($resql);
377  $tmp = array('amount'=>$obj->amount, 'type'=>$obj->code, 'date'=>$obj->datep, 'num'=>$obj->num, 'ref'=>$obj->ref);
378  if (!empty($field3)) {
379  $tmp['ref_ext'] = $obj->ref_ext;
380  }
381  if (!empty($field4)) {
382  $tmp['fk_bank_line'] = $obj->fk_bank;
383  }
384  $retarray[] = $tmp;
385  $i++;
386  }
387  $this->db->free($resql);
388 
389  //look for credit notes and discounts and deposits
390  $sql = '';
391  if ($this->element == 'facture' || $this->element == 'invoice') {
392  $sql = "SELECT rc.amount_ttc as amount, rc.multicurrency_amount_ttc as multicurrency_amount, rc.datec as date, f.ref as ref, rc.description as type";
393  $sql .= ' FROM '.$this->db->prefix().'societe_remise_except as rc, '.$this->db->prefix().'facture as f';
394  $sql .= ' WHERE rc.fk_facture_source=f.rowid AND rc.fk_facture = '.((int) $this->id);
395  $sql .= ' AND (f.type = 2 OR f.type = 0 OR f.type = 3)'; // Find discount coming from credit note or excess received or deposits (payments from deposits are always null except if FACTURE_DEPOSITS_ARE_JUST_PAYMENTS is set)
396  } elseif ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') {
397  $sql = "SELECT rc.amount_ttc as amount, rc.multicurrency_amount_ttc as multicurrency_amount, rc.datec as date, f.ref as ref, rc.description as type";
398  $sql .= ' FROM '.$this->db->prefix().'societe_remise_except as rc, '.$this->db->prefix().'facture_fourn as f';
399  $sql .= ' WHERE rc.fk_invoice_supplier_source=f.rowid AND rc.fk_invoice_supplier = '.((int) $this->id);
400  $sql .= ' AND (f.type = 2 OR f.type = 0 OR f.type = 3)'; // Find discount coming from credit note or excess received or deposits (payments from deposits are always null except if FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS is set)
401  }
402 
403  if ($sql) {
404  $resql = $this->db->query($sql);
405  if ($resql) {
406  $num = $this->db->num_rows($resql);
407  $i = 0;
408  while ($i < $num) {
409  $obj = $this->db->fetch_object($resql);
410  if ($multicurrency) {
411  $retarray[] = array('amount'=>$obj->multicurrency_amount, 'type'=>$obj->type, 'date'=>$obj->date, 'num'=>'0', 'ref'=>$obj->ref);
412  } else {
413  $retarray[] = array('amount'=>$obj->amount, 'type'=>$obj->type, 'date'=>$obj->date, 'num'=>'', 'ref'=>$obj->ref);
414  }
415  $i++;
416  }
417  } else {
418  $this->error = $this->db->lasterror();
419  dol_print_error($this->db);
420  return array();
421  }
422  $this->db->free($resql);
423  }
424 
425  return $retarray;
426  } else {
427  $this->error = $this->db->lasterror();
428  dol_print_error($this->db);
429  return array();
430  }
431  }
432 
433 
434  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
448  public function is_erasable()
449  {
450  // phpcs:enable
451  global $conf;
452 
453  // We check if invoice is a temporary number (PROVxxxx)
454  $tmppart = substr($this->ref, 1, 4);
455 
456  if ($this->statut == self::STATUS_DRAFT && $tmppart === 'PROV') { // If draft invoice and ref not yet defined
457  return 1;
458  }
459 
460  if (!empty($conf->global->INVOICE_CAN_NEVER_BE_REMOVED)) {
461  return 0;
462  }
463 
464  // If not a draft invoice and not temporary invoice
465  if ($tmppart !== 'PROV') {
466  $ventilExportCompta = $this->getVentilExportCompta();
467  if ($ventilExportCompta != 0) {
468  return -1;
469  }
470 
471  // Get last number of validated invoice
472  if ($this->element != 'invoice_supplier') {
473  if (empty($this->thirdparty)) {
474  $this->fetch_thirdparty(); // We need to have this->thirdparty defined, in case of numbering rule use tags that depend on thirdparty (like {t} tag).
475  }
476  $maxref = $this->getNextNumRef($this->thirdparty, 'last');
477 
478  // If there is no invoice into the reset range and not already dispatched, we can delete
479  // If invoice to delete is last one and not already dispatched, we can delete
480  if (empty($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED) && $maxref != '' && $maxref != $this->ref) {
481  return -2;
482  }
483 
484  // TODO If there is payment in bookkeeping, check payment is not dispatched in accounting
485  // ...
486 
487  if ($this->situation_cycle_ref && method_exists($this, 'is_last_in_cycle')) {
488  $last = $this->is_last_in_cycle();
489  if (!$last) {
490  return -3;
491  }
492  }
493  }
494  }
495 
496  // Test if there is at least one payment. If yes, refuse to delete.
497  if (empty($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED) && $this->getSommePaiement() > 0) {
498  return -4;
499  }
500 
501  return 2;
502  }
503 
509  public function getVentilExportCompta()
510  {
511  $alreadydispatched = 0;
512 
513  $type = 'customer_invoice';
514  if ($this->element == 'invoice_supplier') {
515  $type = 'supplier_invoice';
516  }
517 
518  $sql = " SELECT COUNT(ab.rowid) as nb FROM ".$this->db->prefix()."accounting_bookkeeping as ab WHERE ab.doc_type='".$this->db->escape($type)."' AND ab.fk_doc = ".((int) $this->id);
519  $resql = $this->db->query($sql);
520  if ($resql) {
521  $obj = $this->db->fetch_object($resql);
522  if ($obj) {
523  $alreadydispatched = $obj->nb;
524  }
525  } else {
526  $this->error = $this->db->lasterror();
527  return -1;
528  }
529 
530  if ($alreadydispatched) {
531  return 1;
532  }
533  return 0;
534  }
535 
536 
543  public function getLibType($withbadge = 0)
544  {
545  global $langs;
546 
547  $labellong = "Unknown";
548  if ($this->type == CommonInvoice::TYPE_STANDARD) {
549  $labellong = "InvoiceStandard";
550  $labelshort = "InvoiceStandardShort";
551  } elseif ($this->type == CommonInvoice::TYPE_REPLACEMENT) {
552  $labellong = "InvoiceReplacement";
553  $labelshort = "InvoiceReplacementShort";
554  } elseif ($this->type == CommonInvoice::TYPE_CREDIT_NOTE) {
555  $labellong = "InvoiceAvoir";
556  $labelshort = "CreditNote";
557  } elseif ($this->type == CommonInvoice::TYPE_DEPOSIT) {
558  $labellong = "InvoiceDeposit";
559  $labelshort = "Deposit";
560  } elseif ($this->type == CommonInvoice::TYPE_PROFORMA) {
561  $labellong = "InvoiceProForma"; // Not used.
562  $labelshort = "ProForma";
563  } elseif ($this->type == CommonInvoice::TYPE_SITUATION) {
564  $labellong = "InvoiceSituation";
565  $labelshort = "Situation";
566  }
567 
568  $out = '';
569  if ($withbadge) {
570  $out .= '<span class="badgeneutral" title="'.dol_escape_htmltag($langs->trans($labellong)).'">';
571  }
572  $out .= $langs->trans($withbadge == 2 ? $labelshort : $labellong);
573  if ($withbadge) {
574  $out .= '</span>';
575  }
576  return $out;
577  }
578 
586  public function getLibStatut($mode = 0, $alreadypaid = -1)
587  {
588  return $this->LibStatut($this->paye, $this->statut, $mode, $alreadypaid, $this->type);
589  }
590 
591  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
602  public function LibStatut($paye, $status, $mode = 0, $alreadypaid = -1, $type = -1)
603  {
604  // phpcs:enable
605  global $langs, $hookmanager;
606  $langs->load('bills');
607 
608  if ($type == -1) {
609  $type = $this->type;
610  }
611 
612  $statusType = 'status0';
613  $prefix = 'Short';
614  if (!$paye) {
615  if ($status == 0) {
616  $labelStatus = $langs->transnoentitiesnoconv('BillStatusDraft');
617  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusDraft');
618  } elseif (($status == 3 || $status == 2) && $alreadypaid <= 0) {
619  if ($status == 3) {
620  $labelStatus = $langs->transnoentitiesnoconv('BillStatusCanceled');
621  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusCanceled');
622  } else {
623  $labelStatus = $langs->transnoentitiesnoconv('BillStatusClosedUnpaid');
624  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusClosedUnpaid');
625  }
626  $statusType = 'status5';
627  } elseif (($status == 3 || $status == 2) && $alreadypaid > 0) {
628  $labelStatus = $langs->transnoentitiesnoconv('BillStatusClosedPaidPartially');
629  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusClosedPaidPartially');
630  $statusType = 'status9';
631  } elseif ($alreadypaid == 0) {
632  $labelStatus = $langs->transnoentitiesnoconv('BillStatusNotPaid');
633  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusNotPaid');
634  $statusType = 'status1';
635  } else {
636  $labelStatus = $langs->transnoentitiesnoconv('BillStatusStarted');
637  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusStarted');
638  $statusType = 'status3';
639  }
640  } else {
641  $statusType = 'status6';
642 
643  if ($type == self::TYPE_CREDIT_NOTE) {
644  $labelStatus = $langs->transnoentitiesnoconv('BillStatusPaidBackOrConverted'); // credit note
645  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusPaidBackOrConverted'); // credit note
646  } elseif ($type == self::TYPE_DEPOSIT) {
647  $labelStatus = $langs->transnoentitiesnoconv('BillStatusConverted'); // deposit invoice
648  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusConverted'); // deposit invoice
649  } else {
650  $labelStatus = $langs->transnoentitiesnoconv('BillStatusPaid');
651  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusPaid');
652  }
653  }
654 
655  $parameters = array(
656  'status' => $status,
657  'mode' => $mode,
658  'paye' => $paye,
659  'alreadypaid' => $alreadypaid,
660  'type' => $type
661  );
662 
663  $reshook = $hookmanager->executeHooks('LibStatut', $parameters, $this); // Note that $action and $object may have been modified by hook
664 
665  if ($reshook > 0) {
666  return $hookmanager->resPrint;
667  }
668 
669 
670 
671  return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
672  }
673 
674  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
682  public function calculate_date_lim_reglement($cond_reglement = 0)
683  {
684  // phpcs:enable
685  if (!$cond_reglement) {
686  $cond_reglement = $this->cond_reglement_code;
687  }
688  if (!$cond_reglement) {
689  $cond_reglement = $this->cond_reglement_id;
690  }
691  if (!$cond_reglement) {
692  return $this->date;
693  }
694 
695  $cdr_nbjour = 0;
696  $cdr_type = 0;
697  $cdr_decalage = 0;
698 
699  $sqltemp = "SELECT c.type_cdr, c.nbjour, c.decalage";
700  $sqltemp .= " FROM ".$this->db->prefix()."c_payment_term as c";
701  if (is_numeric($cond_reglement)) {
702  $sqltemp .= " WHERE c.rowid=".((int) $cond_reglement);
703  } else {
704  $sqltemp .= " WHERE c.entity IN (".getEntity('c_payment_term').")";
705  $sqltemp .= " AND c.code = '".$this->db->escape($cond_reglement)."'";
706  }
707 
708  dol_syslog(get_class($this).'::calculate_date_lim_reglement', LOG_DEBUG);
709  $resqltemp = $this->db->query($sqltemp);
710  if ($resqltemp) {
711  if ($this->db->num_rows($resqltemp)) {
712  $obj = $this->db->fetch_object($resqltemp);
713  $cdr_nbjour = $obj->nbjour;
714  $cdr_type = $obj->type_cdr;
715  $cdr_decalage = $obj->decalage;
716  }
717  } else {
718  $this->error = $this->db->error();
719  return -1;
720  }
721  $this->db->free($resqltemp);
722 
723  /* Definition de la date limite */
724 
725  // 0 : adding the number of days
726  if ($cdr_type == 0) {
727  $datelim = $this->date + ($cdr_nbjour * 3600 * 24);
728 
729  $datelim += ($cdr_decalage * 3600 * 24);
730  } elseif ($cdr_type == 1) {
731  // 1 : application of the "end of the month" rule
732  $datelim = $this->date + ($cdr_nbjour * 3600 * 24);
733 
734  $mois = date('m', $datelim);
735  $annee = date('Y', $datelim);
736  if ($mois == 12) {
737  $mois = 1;
738  $annee += 1;
739  } else {
740  $mois += 1;
741  }
742  // We move at the beginning of the next month, and we take a day off
743  $datelim = dol_mktime(12, 0, 0, $mois, 1, $annee);
744  $datelim -= (3600 * 24);
745 
746  $datelim += ($cdr_decalage * 3600 * 24);
747  } elseif ($cdr_type == 2 && !empty($cdr_decalage)) {
748  // 2 : application of the rule, the N of the current or next month
749  include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
750  $datelim = $this->date + ($cdr_nbjour * 3600 * 24);
751 
752  $date_piece = dol_mktime(0, 0, 0, date('m', $datelim), date('d', $datelim), date('Y', $datelim)); // Sans les heures minutes et secondes
753  $date_lim_current = dol_mktime(0, 0, 0, date('m', $datelim), $cdr_decalage, date('Y', $datelim)); // Sans les heures minutes et secondes
754  $date_lim_next = dol_time_plus_duree($date_lim_current, 1, 'm'); // Add 1 month
755 
756  $diff = $date_piece - $date_lim_current;
757 
758  if ($diff < 0) {
759  $datelim = $date_lim_current;
760  } else {
761  $datelim = $date_lim_next;
762  }
763  } else {
764  return 'Bad value for type_cdr in database for record cond_reglement = '.$cond_reglement;
765  }
766 
767  return $datelim;
768  }
769 
770  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
781  public function demande_prelevement($fuser, $amount = 0, $type = 'direct-debit', $sourcetype = 'facture')
782  {
783  // phpcs:enable
784  global $conf;
785 
786  $error = 0;
787 
788  dol_syslog(get_class($this)."::demande_prelevement", LOG_DEBUG);
789 
790  if ($this->statut > self::STATUS_DRAFT && $this->paye == 0) {
791  require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php';
792  $bac = new CompanyBankAccount($this->db);
793  $bac->fetch(0, $this->socid);
794 
795  $sql = "SELECT count(*)";
796  $sql .= " FROM ".$this->db->prefix()."prelevement_demande";
797  if ($type == 'bank-transfer') {
798  $sql .= " WHERE fk_facture_fourn = ".((int) $this->id);
799  } else {
800  $sql .= " WHERE fk_facture = ".((int) $this->id);
801  }
802  $sql .= " AND type = 'ban'"; // To exclude record done for some online payments
803  $sql .= " AND traite = 0";
804 
805  dol_syslog(get_class($this)."::demande_prelevement", LOG_DEBUG);
806  $resql = $this->db->query($sql);
807  if ($resql) {
808  $row = $this->db->fetch_row($resql);
809  if ($row[0] == 0) {
810  $now = dol_now();
811 
812  $totalpaid = $this->getSommePaiement();
813  $totalcreditnotes = $this->getSumCreditNotesUsed();
814  $totaldeposits = $this->getSumDepositsUsed();
815  //print "totalpaid=".$totalpaid." totalcreditnotes=".$totalcreditnotes." totaldeposts=".$totaldeposits;
816 
817  // We can also use bcadd to avoid pb with floating points
818  // For example print 239.2 - 229.3 - 9.9; does not return 0.
819  //$resteapayer=bcadd($this->total_ttc,$totalpaid,$conf->global->MAIN_MAX_DECIMALS_TOT);
820  //$resteapayer=bcadd($resteapayer,$totalavoir,$conf->global->MAIN_MAX_DECIMALS_TOT);
821  if (empty($amount)) {
822  $amount = price2num($this->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT');
823  }
824 
825  if (is_numeric($amount) && $amount != 0) {
826  $sql = 'INSERT INTO '.$this->db->prefix().'prelevement_demande(';
827  if ($type == 'bank-transfer') {
828  $sql .= 'fk_facture_fourn, ';
829  } else {
830  $sql .= 'fk_facture, ';
831  }
832  $sql .= ' amount, date_demande, fk_user_demande, code_banque, code_guichet, number, cle_rib, sourcetype, type, entity)';
833  $sql .= " VALUES (".((int) $this->id);
834  $sql .= ", ".((float) price2num($amount));
835  $sql .= ", '".$this->db->idate($now)."'";
836  $sql .= ", ".((int) $fuser->id);
837  $sql .= ", '".$this->db->escape($bac->code_banque)."'";
838  $sql .= ", '".$this->db->escape($bac->code_guichet)."'";
839  $sql .= ", '".$this->db->escape($bac->number)."'";
840  $sql .= ", '".$this->db->escape($bac->cle_rib)."'";
841  $sql .= ", '".$this->db->escape($sourcetype)."'";
842  $sql .= ", 'ban'";
843  $sql .= ", ".((int) $conf->entity);
844  $sql .= ")";
845 
846  dol_syslog(get_class($this)."::demande_prelevement", LOG_DEBUG);
847  $resql = $this->db->query($sql);
848  if (!$resql) {
849  $this->error = $this->db->lasterror();
850  dol_syslog(get_class($this).'::demandeprelevement Erreur');
851  $error++;
852  }
853  } else {
854  $this->error = 'WithdrawRequestErrorNilAmount';
855  dol_syslog(get_class($this).'::demandeprelevement WithdrawRequestErrorNilAmount');
856  $error++;
857  }
858 
859  if (!$error) {
860  // Force payment mode of invoice to withdraw
861  $payment_mode_id = dol_getIdFromCode($this->db, ($type == 'bank-transfer' ? 'VIR' : 'PRE'), 'c_paiement', 'code', 'id', 1);
862  if ($payment_mode_id > 0) {
863  $result = $this->setPaymentMethods($payment_mode_id);
864  }
865  }
866 
867  if ($error) {
868  return -1;
869  }
870  return 1;
871  } else {
872  $this->error = "A request already exists";
873  dol_syslog(get_class($this).'::demandeprelevement Impossible de creer une demande, demande deja en cours');
874  return 0;
875  }
876  } else {
877  $this->error = $this->db->error();
878  dol_syslog(get_class($this).'::demandeprelevement Erreur -2');
879  return -2;
880  }
881  } else {
882  $this->error = "Status of invoice does not allow this";
883  dol_syslog(get_class($this)."::demandeprelevement ".$this->error." $this->statut, $this->paye, $this->mode_reglement_id");
884  return -3;
885  }
886  }
887 
888 
900  public function makeStripeCardRequest($fuser, $id, $sourcetype = 'facture')
901  {
902  // TODO See in sellyoursaas
903  }
904 
915  public function makeStripeSepaRequest($fuser, $did, $type = 'direct-debit', $sourcetype = 'facture')
916  {
917  global $conf, $user, $langs;
918 
919  if ($type != 'bank-transfer' && $type != 'credit-transfer' && empty($conf->global->STRIPE_SEPA_DIRECT_DEBIT)) {
920  return 0;
921  }
922  if ($type != 'direct-debit' && empty($conf->global->STRIPE_SEPA_CREDIT_TRANSFER)) {
923  return 0;
924  }
925 
926  $error = 0;
927 
928  dol_syslog(get_class($this)."::makeStripeSepaRequest start", LOG_DEBUG);
929 
930  if ($this->statut > self::STATUS_DRAFT && $this->paye == 0) {
931  // Get the default payment mode for BAN payment of the third party
932  require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php';
933  $bac = new CompanyBankAccount($this->db); // table societe_rib
934  $result = $bac->fetch(0, $this->socid, 1, 'ban');
935  if ($result <= 0 || empty($bac->id)) {
936  $this->error = $langs->trans("ThirdpartyHasNoDefaultBanAccount");
937  $this->errors[] = $this->error;
938  dol_syslog(get_class($this)."::makeStripeSepaRequest ".$this->error);
939  return -1;
940  }
941 
942  // Load the pending payment requests to process
943  $sql = "SELECT rowid, date_demande, amount, fk_facture, fk_facture_fourn, fk_prelevement_bons";
944  $sql .= " FROM ".$this->db->prefix()."prelevement_demande";
945  $sql .= " WHERE rowid = ".((int) $did);
946  if ($type != 'bank-transfer' && $type != 'credit-transfer') {
947  $sql .= " AND fk_facture = ".((int) $this->id); // Add a protection to not pay another invoice than current one
948  }
949  if ($type != 'direct-debit') {
950  $sql .= " AND fk_facture_fourn = ".((int) $this->id); // Add a protection to not pay another invoice than current one
951  }
952  $sql .= " AND traite = 0"; // To not process payment request that were already converted into a direct debit or credit transfer order (Note: fk_prelevement_bons is also empty when traite = 0)
953 
954  dol_syslog(get_class($this)."::makeStripeSepaRequest load requests to process", LOG_DEBUG);
955  $resql = $this->db->query($sql);
956  if ($resql) {
957  $obj = $this->db->fetch_object($resql);
958  if (!$obj) {
959  dol_print_error($this->db, 'CantFindRequestWithId');
960  return -2;
961  }
962 
963  // amount to pay
964  $amount = $obj->amount;
965 
966  if (is_numeric($amount) && $amount != 0) {
967  require_once DOL_DOCUMENT_ROOT.'/societe/class/companypaymentmode.class.php';
968  $companypaymentmode = new CompanyPaymentMode($this->db); // table societe_rib
969  $companypaymentmode->fetch($bac->id);
970 
971  // Start code for Stripe
972  // TODO We may have this coming as a parameter from the caller.
973  $service = 'StripeTest';
974  $servicestatus = 0;
975  if (!empty($conf->global->STRIPE_LIVE) && !GETPOST('forcesandbox', 'alpha')) {
976  $service = 'StripeLive';
977  $servicestatus = 1;
978  }
979 
980  dol_syslog("makeStripeSepaRequest amount = ".$amount." service=" . $service . " servicestatus=" . $servicestatus . " thirdparty_id=" . $this->socid." did=".$did);
981 
982  $this->stripechargedone = 0;
983  $this->stripechargeerror = 0;
984 
985  $now = dol_now();
986 
987  $currency = $conf->currency;
988 
989  global $stripearrayofkeysbyenv;
990 
991  $errorforinvoice = 0; // We reset the $errorforinvoice at each invoice loop
992 
993  $this->fetch_thirdparty();
994 
995  dol_syslog("--- Process payment request thirdparty_id=" . $this->thirdparty->id . ", thirdparty_name=" . $this->thirdparty->name . " ban id=" . $bac->id, LOG_DEBUG);
996 
997  //$alreadypayed = $this->getSommePaiement();
998  //$amount_credit_notes_included = $this->getSumCreditNotesUsed();
999  //$amounttopay = $this->total_ttc - $alreadypayed - $amount_credit_notes_included;
1000  $amounttopay = $amount;
1001 
1002  // Correct the amount according to unit of currency
1003  // See https://support.stripe.com/questions/which-zero-decimal-currencies-does-stripe-support
1004  $arrayzerounitcurrency = ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF'];
1005  $amountstripe = $amounttopay;
1006  if (!in_array($currency, $arrayzerounitcurrency)) {
1007  $amountstripe = $amountstripe * 100;
1008  }
1009 
1010  $fk_bank_account = getDolGlobalInt('STRIPE_BANK_ACCOUNT_FOR_PAYMENTS'); // Bank account used for SEPA direct debit or credit transfer. Must be the Stripe account in Dolibarr.
1011  if (!($fk_bank_account > 0)) {
1012  $error++;
1013  $errorforinvoice++;
1014  dol_syslog("Error no bank account defined for Stripe payments", LOG_ERR);
1015  $this->errors[] = "Error bank account for Stripe payments not defined into Stripe module";
1016  }
1017 
1018  $this->db->begin();
1019 
1020  // Create a prelevement_bon
1021  require_once DOL_DOCUMENT_ROOT.'/compta/prelevement/class/bonprelevement.class.php';
1022  $bon = new BonPrelevement($this->db);
1023  if (!$error) {
1024  if (empty($obj->fk_prelevement_bons)) {
1025  // This create record into llx_prelevment_bons and update link with llx_prelevement_demande
1026  $nbinvoices = $bon->create(0, 0, 'real', 'ALL', '', 0, $type, $did, $fk_bank_account);
1027  if ($nbinvoices <= 0) {
1028  $error++;
1029  $errorforinvoice++;
1030  dol_syslog("Error on BonPrelevement creation", LOG_ERR);
1031  $this->errors[] = "Error on BonPrelevement creation";
1032  }
1033  /*
1034  if (!$error) {
1035  // Update the direct debit payment request of the processed request to save the id of the prelevement_bon
1036  $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_demande SET";
1037  $sql .= " fk_prelevement_bons = ".((int) $bon->id);
1038  $sql .= " WHERE rowid = ".((int) $did);
1039 
1040  $result = $this->db->query($sql);
1041  if ($result < 0) {
1042  $error++;
1043  $this->errors[] = "Error on updateing fk_prelevement_bons to ".$bon->id;
1044  }
1045  }
1046  */
1047  } else {
1048  $error++;
1049  $errorforinvoice++;
1050  dol_syslog("Error Line already part of a bank payment order", LOG_ERR);
1051  $this->errors[] = "The line is already included into a bank payment order. Delete the bank payment order first.";
1052  }
1053  }
1054 
1055  if (!$error) {
1056  if ($amountstripe > 0) {
1057  try {
1058  //var_dump($companypaymentmode);
1059  dol_syslog("We will try to pay with companypaymentmodeid=" . $companypaymentmode->id . " stripe_card_ref=" . $companypaymentmode->stripe_card_ref . " mode=" . $companypaymentmode->status, LOG_DEBUG);
1060 
1061  $thirdparty = new Societe($this->db);
1062  $resultthirdparty = $thirdparty->fetch($this->socid);
1063 
1064  include_once DOL_DOCUMENT_ROOT . '/stripe/class/stripe.class.php'; // This include the include of htdocs/stripe/config.php
1065  // So it inits or erases the $stripearrayofkeysbyenv
1066  $stripe = new Stripe($this->db);
1067 
1068  dol_syslog("makeStripeSepaRequest Current Stripe environment is " . $stripearrayofkeysbyenv[$servicestatus]['publishable_key']);
1069 
1070  $stripearrayofkeys = $stripearrayofkeysbyenv[$servicestatus];
1071  \Stripe\Stripe::setApiKey($stripearrayofkeys['secret_key']);
1072 
1073 
1074  dol_syslog("makeStripeSepaRequest get stripe connet account", LOG_DEBUG);
1075  $stripeacc = $stripe->getStripeAccount($service, $this->socid); // Get Stripe OAuth connect account if it exists (no network access here)
1076  dol_syslog("makeStripeSepaRequest get stripe connect account return " . json_encode($stripeacc), LOG_DEBUG);
1077 
1078  $customer = $stripe->customerStripe($thirdparty, $stripeacc, $servicestatus, 0);
1079  if (empty($customer) && !empty($stripe->error)) {
1080  $this->errors[] = $stripe->error;
1081  }
1082 
1083  // $nbhoursbetweentries = (empty($conf->global->SELLYOURSAAS_NBHOURSBETWEENTRIES) ? 49 : $conf->global->SELLYOURSAAS_NBHOURSBETWEENTRIES); // Must have more that 48 hours + 1 between each try (so 1 try every 3 daily batch)
1084  // $nbdaysbeforeendoftries = (empty($conf->global->SELLYOURSAAS_NBDAYSBEFOREENDOFTRIES) ? 35 : $conf->global->SELLYOURSAAS_NBDAYSBEFOREENDOFTRIES);
1085  $postactionmessages = [];
1086 
1087  if ($resultthirdparty > 0 && !empty($customer)) {
1088  if (!$error) { // Payment was not canceled
1089  $stripecard = null;
1090  if ($companypaymentmode->type == 'ban') {
1091  // Check into societe_rib if a payment mode for Stripe and ban payment exists
1092  // To make a Stripe SEPA payment request, we must have the payment mode source already saved into societe_rib and retreived with ->sepaStripe
1093  // The payment mode source is created when we create the bank account on Stripe with paymentmodes.php?action=create
1094  $stripecard = $stripe->sepaStripe($customer, $companypaymentmode, $stripeacc, $servicestatus, 0);
1095  } else {
1096  $error++;
1097  $this->error = 'The payment mode type is not "ban"';
1098  }
1099 
1100  if ($stripecard) { // Can be src_... (for sepa) or pm_... (new card mode). Note that card_... (old card mode) should not happen here.
1101  $FULLTAG = 'DID='.$did.'-INV=' . $this->id . '-CUS=' . $thirdparty->id;
1102  $description = 'Stripe payment from makeStripeSepaRequest: ' . $FULLTAG . ' did='.$did.' ref=' . $this->ref;
1103 
1104  $stripefailurecode = '';
1105  $stripefailuremessage = '';
1106  $stripefailuredeclinecode = '';
1107 
1108  // Using new SCA method
1109  dol_syslog("* Create payment on SEPA " . $stripecard->id . ", amounttopay=" . $amounttopay . ", amountstripe=" . $amountstripe . ", FULLTAG=" . $FULLTAG, LOG_DEBUG);
1110 
1111  // Create payment intent and charge payment (confirmnow = true)
1112  $paymentintent = $stripe->getPaymentIntent($amounttopay, $currency, $FULLTAG, $description, $this, $customer->id, $stripeacc, $servicestatus, 0, 'automatic', true, $stripecard->id, 1, 1, $did);
1113 
1114  $charge = new stdClass();
1115 
1116  if ($paymentintent->status === 'succeeded' || $paymentintent->status === 'processing') {
1117  $charge->status = 'ok';
1118  $charge->id = $paymentintent->id;
1119  $charge->customer = $customer->id;
1120  } elseif ($paymentintent->status === 'requires_action') {
1121  //paymentintent->status may be => 'requires_action' (no error in such a case)
1122  dol_syslog(var_export($paymentintent, true), LOG_DEBUG);
1123 
1124  $charge->status = 'failed';
1125  $charge->customer = $customer->id;
1126  $charge->failure_code = $stripe->code;
1127  $charge->failure_message = $stripe->error;
1128  $charge->failure_declinecode = $stripe->declinecode;
1129  $stripefailurecode = $stripe->code;
1130  $stripefailuremessage = 'Action required. Contact the support at ';// . $conf->global->SELLYOURSAAS_MAIN_EMAIL;
1131  $stripefailuredeclinecode = $stripe->declinecode;
1132  } else {
1133  dol_syslog(var_export($paymentintent, true), LOG_DEBUG);
1134 
1135  $charge->status = 'failed';
1136  $charge->customer = $customer->id;
1137  $charge->failure_code = $stripe->code;
1138  $charge->failure_message = $stripe->error;
1139  $charge->failure_declinecode = $stripe->declinecode;
1140  $stripefailurecode = $stripe->code;
1141  $stripefailuremessage = $stripe->error;
1142  $stripefailuredeclinecode = $stripe->declinecode;
1143  }
1144 
1145  //var_dump("stripefailurecode=".$stripefailurecode." stripefailuremessage=".$stripefailuremessage." stripefailuredeclinecode=".$stripefailuredeclinecode);
1146  //exit;
1147 
1148 
1149  // Return $charge = array('id'=>'ch_XXXX', 'status'=>'succeeded|pending|failed', 'failure_code'=>, 'failure_message'=>...)
1150  if (empty($charge) || $charge->status == 'failed') {
1151  dol_syslog('Failed to charge payment mode ' . $stripecard->id . ' stripefailurecode=' . $stripefailurecode . ' stripefailuremessage=' . $stripefailuremessage . ' stripefailuredeclinecode=' . $stripefailuredeclinecode, LOG_WARNING);
1152 
1153  // Save a stripe payment was in error
1154  $this->stripechargeerror++;
1155 
1156  $error++;
1157  $errorforinvoice++;
1158  $errmsg = $langs->trans("FailedToChargeCard");
1159  if (!empty($charge)) {
1160  if ($stripefailuredeclinecode == 'authentication_required') {
1161  $errauthenticationmessage = $langs->trans("ErrSCAAuthentication");
1162  $errmsg = $errauthenticationmessage;
1163  } elseif (in_array($stripefailuredeclinecode, ['insufficient_funds', 'generic_decline'])) {
1164  $errmsg .= ': ' . $charge->failure_code;
1165  $errmsg .= ($charge->failure_message ? ' - ' : '') . ' ' . $charge->failure_message;
1166  if (empty($stripefailurecode)) {
1167  $stripefailurecode = $charge->failure_code;
1168  }
1169  if (empty($stripefailuremessage)) {
1170  $stripefailuremessage = $charge->failure_message;
1171  }
1172  } else {
1173  $errmsg .= ': failure_code=' . $charge->failure_code;
1174  $errmsg .= ($charge->failure_message ? ' - ' : '') . ' failure_message=' . $charge->failure_message;
1175  if (empty($stripefailurecode)) {
1176  $stripefailurecode = $charge->failure_code;
1177  }
1178  if (empty($stripefailuremessage)) {
1179  $stripefailuremessage = $charge->failure_message;
1180  }
1181  }
1182  } else {
1183  $errmsg .= ': ' . $stripefailurecode . ' - ' . $stripefailuremessage;
1184  $errmsg .= ($stripefailuredeclinecode ? ' - ' . $stripefailuredeclinecode : '');
1185  }
1186 
1187  $description = 'Stripe payment ERROR from makeStripeSepaRequest: ' . $FULLTAG;
1188  $postactionmessages[] = $errmsg . ' (' . $stripearrayofkeys['publishable_key'] . ')';
1189  $this->errors[] = $errmsg;
1190  } else {
1191  dol_syslog('Successfuly request '.$type.' '.$stripecard->id);
1192 
1193  $postactionmessages[] = 'Success to request '.$type.' (' . $charge->id . ' with ' . $stripearrayofkeys['publishable_key'] . ')';
1194 
1195  // Save a stripe payment was done in realy life so later we will be able to force a commit on recorded payments
1196  // even if in batch mode (method doTakePaymentStripe), we will always make all action in one transaction with a forced commit.
1197  $this->stripechargedone++;
1198 
1199  // Default description used for label of event. Will be overwrite by another value later.
1200  $description = 'Stripe payment request OK (' . $charge->id . ') from makeStripeSepaRequest: ' . $FULLTAG;
1201  }
1202 
1203  $object = $this;
1204 
1205  // Track an event
1206  if (empty($charge) || $charge->status == 'failed') {
1207  $actioncode = 'PAYMENT_STRIPE_KO';
1208  $extraparams = $stripefailurecode;
1209  $extraparams .= (($extraparams && $stripefailuremessage) ? ' - ' : '') . $stripefailuremessage;
1210  $extraparams .= (($extraparams && $stripefailuredeclinecode) ? ' - ' : '') . $stripefailuredeclinecode;
1211  } else {
1212  $actioncode = 'PAYMENT_STRIPE_OK';
1213  $extraparams = '';
1214  }
1215  } else {
1216  $error++;
1217  $errorforinvoice++;
1218  dol_syslog("No ban payment method found for this stripe customer " . $customer->id, LOG_WARNING);
1219  $this->errors[] = 'Failed to get direct debit payment method for stripe customer = ' . $customer->id;
1220 
1221  $description = 'Failed to find or use the payment mode - no ban defined for the thirdparty account';
1222  $stripefailurecode = 'BADPAYMENTMODE';
1223  $stripefailuremessage = 'Failed to find or use the payment mode - no ban defined for the thirdparty account';
1224  $postactionmessages[] = $description . ' (' . $stripearrayofkeys['publishable_key'] . ')';
1225 
1226  $object = $this;
1227 
1228  $actioncode = 'PAYMENT_STRIPE_KO';
1229  $extraparams = '';
1230  }
1231  } else {
1232  // If error because payment was canceled for a logical reason, we do nothing (no event added)
1233  $description = '';
1234  $stripefailurecode = '';
1235  $stripefailuremessage = '';
1236 
1237  $object = $this;
1238 
1239  $actioncode = '';
1240  $extraparams = '';
1241  }
1242  } else { // Else of the if ($resultthirdparty > 0 && ! empty($customer)) {
1243  if ($resultthirdparty <= 0) {
1244  dol_syslog('SellYourSaasUtils Failed to load customer for thirdparty_id = ' . $thirdparty->id, LOG_WARNING);
1245  $this->errors[] = 'Failed to load Stripe account for thirdparty_id = ' . $thirdparty->id;
1246  } else { // $customer stripe not found
1247  dol_syslog('SellYourSaasUtils Failed to get Stripe customer id for thirdparty_id = ' . $thirdparty->id . " in mode " . $servicestatus . " in Stripe env " . $stripearrayofkeysbyenv[$servicestatus]['publishable_key'], LOG_WARNING);
1248  $this->errors[] = 'Failed to get Stripe account id for thirdparty_id = ' . $thirdparty->id . " in mode " . $servicestatus . " in Stripe env " . $stripearrayofkeysbyenv[$servicestatus]['publishable_key'];
1249  }
1250  $error++;
1251  $errorforinvoice++;
1252 
1253  $description = 'Failed to find or use your payment mode (no payment mode for this customer id)';
1254  $stripefailurecode = 'BADPAYMENTMODE';
1255  $stripefailuremessage = 'Failed to find or use your payment mode (no payment mode for this customer id)';
1256  $postactionmessages = [];
1257 
1258  $object = $this;
1259 
1260  $actioncode = 'PAYMENT_STRIPE_KO';
1261  $extraparams = '';
1262  }
1263 
1264  if ($description) {
1265  dol_syslog("* Record event for credit transfer or direct debit request result - " . $description);
1266  require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
1267 
1268  // Insert record of payment (success or error)
1269  $actioncomm = new ActionComm($this->db);
1270 
1271  $actioncomm->type_code = 'AC_OTH_AUTO'; // Type of event ('AC_OTH', 'AC_OTH_AUTO', 'AC_XXX'...)
1272  $actioncomm->code = 'AC_' . $actioncode;
1273  $actioncomm->label = $description;
1274  $actioncomm->note_private = join(",\n", $postactionmessages);
1275  $actioncomm->fk_project = $this->fk_project;
1276  $actioncomm->datep = $now;
1277  $actioncomm->datef = $now;
1278  $actioncomm->percentage = -1; // Not applicable
1279  $actioncomm->socid = $thirdparty->id;
1280  $actioncomm->contactid = 0;
1281  $actioncomm->authorid = $user->id; // User saving action
1282  $actioncomm->userownerid = $user->id; // Owner of action
1283  // Fields when action is a real email (content is already into note)
1284  /*$actioncomm->email_msgid = $object->email_msgid;
1285  $actioncomm->email_from = $object->email_from;
1286  $actioncomm->email_sender= $object->email_sender;
1287  $actioncomm->email_to = $object->email_to;
1288  $actioncomm->email_tocc = $object->email_tocc;
1289  $actioncomm->email_tobcc = $object->email_tobcc;
1290  $actioncomm->email_subject = $object->email_subject;
1291  $actioncomm->errors_to = $object->errors_to;*/
1292  $actioncomm->fk_element = $this->id;
1293  $actioncomm->elementtype = $this->element;
1294  $actioncomm->extraparams = dol_trunc($extraparams, 250);
1295 
1296  $actioncomm->create($user);
1297  }
1298 
1299  $this->description = $description;
1300  $this->postactionmessages = $postactionmessages;
1301  } catch (Exception $e) {
1302  $error++;
1303  $errorforinvoice++;
1304  dol_syslog('Error ' . $e->getMessage(), LOG_ERR);
1305  $this->errors[] = 'Error ' . $e->getMessage();
1306  }
1307  } else { // If remain to pay is null
1308  $error++;
1309  $errorforinvoice++;
1310  dol_syslog("Remain to pay is null for the invoice " . $this->id . " " . $this->ref . ". Why is the invoice not classified 'Paid' ?", LOG_WARNING);
1311  $this->errors[] = "Remain to pay is null for the invoice " . $this->id . " " . $this->ref . ". Why is the invoice not classified 'Paid' ?";
1312  }
1313  }
1314 
1315  // Set status of the order to "Transferred" with method 'api'
1316  if (!$error && !$errorforinvoice) {
1317  $result = $bon->set_infotrans($user, $now, 3);
1318  if ($result < 0) {
1319  $error++;
1320  $errorforinvoice++;
1321  dol_syslog("Error on BonPrelevement creation", LOG_ERR);
1322  $this->errors[] = "Error on BonPrelevement creation";
1323  }
1324  }
1325 
1326  if (!$error && !$errorforinvoice) {
1327  // Update the direct debit payment request of the processed invoice to save the id of the prelevement_bon
1328  $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_demande SET";
1329  $sql .= " ext_payment_id = '".$this->db->escape($paymentintent->id)."',";
1330  $sql .= " ext_payment_site = '".$this->db->escape($service)."'";
1331  $sql .= " WHERE rowid = ".((int) $did);
1332 
1333  dol_syslog(get_class($this)."::makeStripeSepaRequest update to save stripe paymentintent ids", LOG_DEBUG);
1334  $resql = $this->db->query($sql);
1335  if (!$resql) {
1336  $this->error = $this->db->lasterror();
1337  dol_syslog(get_class($this).'::makeStripeSepaRequest Erreur');
1338  $error++;
1339  }
1340  }
1341 
1342  if (!$error && !$errorforinvoice) {
1343  $this->db->commit();
1344  } else {
1345  $this->db->rollback();
1346  }
1347  } else {
1348  $this->error = 'WithdrawRequestErrorNilAmount';
1349  dol_syslog(get_class($this).'::makeStripeSepaRequest WithdrawRequestErrorNilAmount');
1350  $error++;
1351  }
1352 
1353  /*
1354  if (!$error) {
1355  // Force payment mode of the invoice to withdraw
1356  $payment_mode_id = dol_getIdFromCode($this->db, ($type == 'bank-transfer' ? 'VIR' : 'PRE'), 'c_paiement', 'code', 'id', 1);
1357  if ($payment_mode_id > 0) {
1358  $result = $this->setPaymentMethods($payment_mode_id);
1359  }
1360  }*/
1361 
1362  if ($error) {
1363  return -1;
1364  }
1365  return 1;
1366  } else {
1367  $this->error = $this->db->error();
1368  dol_syslog(get_class($this).'::makeStripeSepaRequest Erreur -2');
1369  return -2;
1370  }
1371  } else {
1372  $this->error = "Status of invoice does not allow this";
1373  dol_syslog(get_class($this)."::makeStripeSepaRequest ".$this->error." $this->statut, $this->paye, $this->mode_reglement_id");
1374  return -3;
1375  }
1376  }
1377 
1378  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1386  public function demande_prelevement_delete($fuser, $did)
1387  {
1388  // phpcs:enable
1389  $sql = 'DELETE FROM '.$this->db->prefix().'prelevement_demande';
1390  $sql .= ' WHERE rowid = '.((int) $did);
1391  $sql .= ' AND traite = 0';
1392  if ($this->db->query($sql)) {
1393  return 0;
1394  } else {
1395  $this->error = $this->db->lasterror();
1396  dol_syslog(get_class($this).'::demande_prelevement_delete Error '.$this->error);
1397  return -1;
1398  }
1399  }
1400 
1401 
1407  public function buildZATCAQRString()
1408  {
1409  global $conf, $mysoc;
1410 
1411  $tmplang = new Translate('', $conf);
1412  $tmplang->setDefaultLang('en_US');
1413  $tmplang->load("main");
1414 
1415  $datestring = dol_print_date($this->date, 'dayhourrfc');
1416  //$pricewithtaxstring = price($this->total_ttc, 0, $tmplang, 0, -1, 2);
1417  //$pricetaxstring = price($this->total_tva, 0, $tmplang, 0, -1, 2);
1418  $pricewithtaxstring = price2num($this->total_ttc, 2, 1);
1419  $pricetaxstring = price2num($this->total_tva, 2, 1);
1420 
1421  /*
1422  $name = implode(unpack("H*", $this->thirdparty->name));
1423  $vatnumber = implode(unpack("H*", $this->thirdparty->tva_intra));
1424  $date = implode(unpack("H*", $datestring));
1425  $pricewithtax = implode(unpack("H*", price2num($pricewithtaxstring, 2)));
1426  $pricetax = implode(unpack("H*", $pricetaxstring));
1427 
1428  //var_dump(strlen($this->thirdparty->name));
1429  //var_dump(str_pad(dechex('9'), 2, '0', STR_PAD_LEFT));
1430  //var_dump($this->thirdparty->name);
1431  //var_dump(implode(unpack("H*", $this->thirdparty->name)));
1432  //var_dump(price($this->total_tva, 0, $tmplang, 0, -1, 2));
1433 
1434  $s = '01'.str_pad(dechex(strlen($this->thirdparty->name)), 2, '0', STR_PAD_LEFT).$name;
1435  $s .= '02'.str_pad(dechex(strlen($this->thirdparty->tva_intra)), 2, '0', STR_PAD_LEFT).$vatnumber;
1436  $s .= '03'.str_pad(dechex(strlen($datestring)), 2, '0', STR_PAD_LEFT).$date;
1437  $s .= '04'.str_pad(dechex(strlen($pricewithtaxstring)), 2, '0', STR_PAD_LEFT).$pricewithtax;
1438  $s .= '05'.str_pad(dechex(strlen($pricetaxstring)), 2, '0', STR_PAD_LEFT).$pricetax;
1439  $s .= ''; // Hash of xml invoice
1440  $s .= ''; // ecda signature
1441  $s .= ''; // ecda public key
1442  $s .= ''; // ecda signature of public key stamp
1443  */
1444 
1445  // Using TLV format
1446  $s = pack('C1', 1).pack('C1', strlen($mysoc->name)).$mysoc->name;
1447  $s .= pack('C1', 2).pack('C1', strlen($mysoc->tva_intra)).$mysoc->tva_intra;
1448  $s .= pack('C1', 3).pack('C1', strlen($datestring)).$datestring;
1449  $s .= pack('C1', 4).pack('C1', strlen($pricewithtaxstring)).$pricewithtaxstring;
1450  $s .= pack('C1', 5).pack('C1', strlen($pricetaxstring)).$pricetaxstring;
1451  $s .= ''; // Hash of xml invoice
1452  $s .= ''; // ecda signature
1453  $s .= ''; // ecda public key
1454  $s .= ''; // ecda signature of public key stamp
1455 
1456  $s = base64_encode($s);
1457 
1458  return $s;
1459  }
1460 
1461 
1467  public function buildSwitzerlandQRString()
1468  {
1469  global $conf, $mysoc;
1470 
1471  $tmplang = new Translate('', $conf);
1472  $tmplang->setDefaultLang('en_US');
1473  $tmplang->load("main");
1474 
1475  $pricewithtaxstring = price2num($this->total_ttc, 2, 1);
1476  $pricetaxstring = price2num($this->total_tva, 2, 1);
1477 
1478  $complementaryinfo = '';
1479  /*
1480  Example: //S1/10/10201409/11/190512/20/1400.000-53/30/106017086/31/180508/32/7.7/40/2:10;0:30
1481  /10/ Numéro de facture – 10201409
1482  /11/ Date de facture – 12.05.2019
1483  /20/ Référence client – 1400.000-53
1484  /30/ Numéro IDE pour la TVA – CHE-106.017.086 TVA
1485  /31/ Date de la prestation pour la comptabilisation de la TVA – 08.05.2018
1486  /32/ Taux de TVA sur le montant total de la facture – 7.7%
1487  /40/ Conditions – 2% d’escompte à 10 jours, paiement net à 30 jours
1488  */
1489  $datestring = dol_print_date($this->date, '%y%m%d');
1490  //$pricewithtaxstring = price($this->total_ttc, 0, $tmplang, 0, -1, 2);
1491  //$pricetaxstring = price($this->total_tva, 0, $tmplang, 0, -1, 2);
1492  $complementaryinfo = '//S1/10/'.str_replace('/', '', $this->ref).'/11/'.$datestring;
1493  if ($this->ref_client) {
1494  $complementaryinfo .= '/20/'.$this->ref_client;
1495  }
1496  if ($this->thirdparty->tva_intra) {
1497  $complementaryinfo .= '/30/'.$this->thirdparty->tva_intra;
1498  }
1499 
1500  include_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
1501  $bankaccount = new Account($this->db);
1502 
1503  // Header
1504  $s = '';
1505  $s .= "SPC\n";
1506  $s .= "0200\n";
1507  $s .= "1\n";
1508  // Info Seller ("Compte / Payable à")
1509  if ($this->fk_account > 0) {
1510  // Bank BAN if country is LI or CH. TODO Add a test to check than IBAN start with CH or LI
1511  $bankaccount->fetch($this->fk_account);
1512  $s .= $bankaccount->iban."\n";
1513  } else {
1514  $s .= "\n";
1515  }
1516  if ($bankaccount->id > 0 && getDolGlobalString('PDF_SWISS_QRCODE_USE_OWNER_OF_ACCOUNT_AS_CREDITOR')) {
1517  // If a bank account is prodived and we ask to use it as creditor, we use the bank address
1518  // TODO In a future, we may always use this address, and if name/address/zip/town/country differs from $mysoc, we can use the address of $mysoc into the final seller field ?
1519  $s .= "S\n";
1520  $s .= dol_trunc($bankaccount->proprio, 70, 'right', 'UTF-8', 1)."\n";
1521  $addresslinearray = explode("\n", $bankaccount->owner_address);
1522  $s .= dol_trunc(empty($addresslinearray[1]) ? '' : $addresslinearray[1], 70, 'right', 'UTF-8', 1)."\n"; // address line 1
1523  $s .= dol_trunc(empty($addresslinearray[2]) ? '' : $addresslinearray[2], 70, 'right', 'UTF-8', 1)."\n"; // address line 2
1524  /*$s .= dol_trunc($mysoc->zip, 16, 'right', 'UTF-8', 1)."\n";
1525  $s .= dol_trunc($mysoc->town, 35, 'right', 'UTF-8', 1)."\n";
1526  $s .= dol_trunc($mysoc->country_code, 2, 'right', 'UTF-8', 1)."\n";*/
1527  } else {
1528  $s .= "S\n";
1529  $s .= dol_trunc($mysoc->name, 70, 'right', 'UTF-8', 1)."\n";
1530  $addresslinearray = explode("\n", $mysoc->address);
1531  $s .= dol_trunc(empty($addresslinearray[1]) ? '' : $addresslinearray[1], 70, 'right', 'UTF-8', 1)."\n"; // address line 1
1532  $s .= dol_trunc(empty($addresslinearray[2]) ? '' : $addresslinearray[2], 70, 'right', 'UTF-8', 1)."\n"; // address line 2
1533  $s .= dol_trunc($mysoc->zip, 16, 'right', 'UTF-8', 1)."\n";
1534  $s .= dol_trunc($mysoc->town, 35, 'right', 'UTF-8', 1)."\n";
1535  $s .= dol_trunc($mysoc->country_code, 2, 'right', 'UTF-8', 1)."\n";
1536  }
1537  // Final seller (Ultimate seller) ("Créancier final" = "En faveur de")
1538  $s .= "\n";
1539  $s .= "\n";
1540  $s .= "\n";
1541  $s .= "\n";
1542  $s .= "\n";
1543  $s .= "\n";
1544  $s .= "\n";
1545  // Amount of payment (to do?)
1546  $s .= price($pricewithtaxstring, 0, 'none', 0, 0, 2)."\n";
1547  $s .= ($this->multicurrency_code ? $this->multicurrency_code : $conf->currency)."\n";
1548  // Buyer
1549  $s .= "S\n";
1550  $s .= dol_trunc($this->thirdparty->name, 70, 'right', 'UTF-8', 1)."\n";
1551  $addresslinearray = explode("\n", $this->thirdparty->address);
1552  $s .= dol_trunc(empty($addresslinearray[1]) ? '' : $addresslinearray[1], 70, 'right', 'UTF-8', 1)."\n"; // address line 1
1553  $s .= dol_trunc(empty($addresslinearray[2]) ? '' : $addresslinearray[2], 70, 'right', 'UTF-8', 1)."\n"; // address line 2
1554  $s .= dol_trunc($this->thirdparty->zip, 16, 'right', 'UTF-8', 1)."\n";
1555  $s .= dol_trunc($this->thirdparty->town, 35, 'right', 'UTF-8', 1)."\n";
1556  $s .= dol_trunc($this->thirdparty->country_code, 2, 'right', 'UTF-8', 1)."\n";
1557  // ID of payment
1558  $s .= "NON\n"; // NON or QRR
1559  $s .= "\n"; // QR Code reference if previous field is QRR
1560  // Free text
1561  if ($complementaryinfo) {
1562  $s .= $complementaryinfo."\n";
1563  } else {
1564  $s .= "\n";
1565  }
1566  $s .= "EPD\n";
1567  // More text, complementary info
1568  if ($complementaryinfo) {
1569  $s .= $complementaryinfo."\n";
1570  }
1571  $s .= "\n";
1572  //var_dump($s);exit;
1573  return $s;
1574  }
1575 }
1576 
1577 
1578 
1579 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
1580 
1584 abstract class CommonInvoiceLine extends CommonObjectLine
1585 {
1590  public $label;
1591 
1596  public $ref; // Product ref (deprecated)
1601  public $libelle; // Product label (deprecated)
1602 
1607  public $product_type = 0;
1608 
1613  public $product_ref;
1614 
1619  public $product_label;
1620 
1625  public $product_desc;
1626 
1631  public $qty;
1632 
1637  public $subprice;
1638 
1644  public $price;
1645 
1650  public $fk_product;
1651 
1656  public $vat_src_code;
1657 
1662  public $tva_tx;
1663 
1668  public $localtax1_tx;
1669 
1674  public $localtax2_tx;
1675 
1680  public $localtax1_type;
1681 
1686  public $localtax2_type;
1687 
1692  public $remise_percent;
1693 
1699  public $remise;
1700 
1705  public $total_ht;
1706 
1711  public $total_tva;
1712 
1717  public $total_localtax1;
1718 
1723  public $total_localtax2;
1724 
1729  public $total_ttc;
1730 
1731  public $date_start_fill; // If set to 1, when invoice is created from a template invoice, it will also auto set the field date_start at creation
1732  public $date_end_fill; // If set to 1, when invoice is created from a template invoice, it will also auto set the field date_end at creation
1733 
1734  public $buy_price_ht;
1735  public $buyprice; // For backward compatibility
1736  public $pa_ht; // For backward compatibility
1737 
1738  public $marge_tx;
1739  public $marque_tx;
1740 
1747  public $info_bits = 0;
1748 
1749  public $special_code = 0;
1750 
1751  public $fk_multicurrency;
1752  public $multicurrency_code;
1753  public $multicurrency_subprice;
1754  public $multicurrency_total_ht;
1755  public $multicurrency_total_tva;
1756  public $multicurrency_total_ttc;
1757 
1758  public $fk_user_author;
1759  public $fk_user_modif;
1760 
1761  public $fk_accounting_account;
1762 }
CommonInvoice\getSommePaiement
getSommePaiement($multicurrency=0)
Return amount of payments already done.
Definition: commoninvoice.class.php:147
CommonInvoice\buildZATCAQRString
buildZATCAQRString()
Build string for ZATCA QR Code (Arabi Saudia)
Definition: commoninvoice.class.php:1407
Societe
Class to manage third parties objects (customers, suppliers, prospects...)
Definition: societe.class.php:51
CommonInvoice\TYPE_DEPOSIT
const TYPE_DEPOSIT
Deposit invoice.
Definition: commoninvoice.class.php:64
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:4059
CommonInvoice\getSumCreditNotesUsed
getSumCreditNotesUsed($multicurrency=0)
Return amount (with tax) of all credit notes invoices + excess received used by invoice.
Definition: commoninvoice.class.php:229
description
print *****$script_file(".$version.") pid cd cd cd description as description
Definition: email_expire_services_to_customers.php:83
ActionComm
Class to manage agenda events (actions)
Definition: actioncomm.class.php:38
CommonInvoice\makeStripeCardRequest
makeStripeCardRequest($fuser, $id, $sourcetype='facture')
Create a payment with Stripe card Must take amount using Stripe and record an event into llx_actionco...
Definition: commoninvoice.class.php:900
CommonInvoice\getVentilExportCompta
getVentilExportCompta()
Return if an invoice was dispatched into bookkeeping.
Definition: commoninvoice.class.php:509
CommonInvoice\getIdReplacingInvoice
getIdReplacingInvoice($option='')
Returns the id of the invoice that replaces it.
Definition: commoninvoice.class.php:303
GETPOST
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Definition: functions.lib.php:609
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:5107
CommonInvoice\TYPE_STANDARD
const TYPE_STANDARD
Standard invoice.
Definition: commoninvoice.class.php:49
CommonInvoice\getRemainToPay
getRemainToPay($multicurrency=0)
Return remain amount to pay.
Definition: commoninvoice.class.php:126
CommonInvoice\getLibType
getLibType($withbadge=0)
Return label of type of invoice.
Definition: commoninvoice.class.php:543
Translate
Class to manage translations.
Definition: translate.class.php:30
CommonIncoterm
trait CommonIncoterm
Superclass for incoterm classes.
Definition: commonincoterm.class.php:29
CommonInvoice\makeStripeSepaRequest
makeStripeSepaRequest($fuser, $did, $type='direct-debit', $sourcetype='facture')
Create a direct debit order into prelevement_bons then Send the payment order to Stripe (for a direct...
Definition: commoninvoice.class.php:915
CommonInvoice\TYPE_PROFORMA
const TYPE_PROFORMA
Proforma invoice.
Definition: commoninvoice.class.php:70
CommonInvoice\TYPE_SITUATION
const TYPE_SITUATION
Situation invoice.
Definition: commoninvoice.class.php:75
CommonObjectLine
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
Definition: commonobjectline.class.php:32
CommonObject
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Definition: commonobject.class.php:45
CommonInvoice\demande_prelevement_delete
demande_prelevement_delete($fuser, $did)
Remove a direct debit request or a credit transfer request.
Definition: commoninvoice.class.php:1386
CompanyBankAccount
Class to manage bank accounts description of third parties.
Definition: companybankaccount.class.php:34
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5955
CommonInvoice\buildSwitzerlandQRString
buildSwitzerlandQRString()
Build string for QR-Bill (Switzerland)
Definition: commoninvoice.class.php:1467
CommonInvoiceLine\$label
$label
Custom label of line.
Definition: commoninvoice.class.php:1590
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:2675
CommonObject\fetch_thirdparty
fetch_thirdparty($force_thirdparty_id=0)
Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty.
Definition: commonobject.class.php:1646
BonPrelevement
Class to manage withdrawal receipts.
Definition: bonprelevement.class.php:43
CommonInvoice\getSumFromThisCreditNotesNotUsed
getSumFromThisCreditNotesNotUsed($multicurrency=0)
Return amount (with tax) of all converted amount for this credit note.
Definition: commoninvoice.class.php:255
CommonInvoice\getLibStatut
getLibStatut($mode=0, $alreadypaid=-1)
Return label of object status.
Definition: commoninvoice.class.php:586
Exception
CommonInvoice\getListIdAvoirFromInvoice
getListIdAvoirFromInvoice()
Returns array of credit note ids from the invoice.
Definition: commoninvoice.class.php:274
dol_getIdFromCode
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
Definition: functions.lib.php:9091
CommonInvoice\STATUS_DRAFT
const STATUS_DRAFT
Draft status.
Definition: commoninvoice.class.php:80
CommonInvoice\demande_prelevement
demande_prelevement($fuser, $amount=0, $type='direct-debit', $sourcetype='facture')
Create a withdrawal request for a direct debit order or a credit transfer order.
Definition: commoninvoice.class.php:781
CommonInvoice\STATUS_VALIDATED
const STATUS_VALIDATED
Validated (need to be paid)
Definition: commoninvoice.class.php:85
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1741
DiscountAbsolute
Class to manage absolute discounts.
Definition: discount.class.php:29
CommonInvoice\TYPE_REPLACEMENT
const TYPE_REPLACEMENT
Replacement invoice.
Definition: commoninvoice.class.php:54
CommonInvoiceLine\$ref
$ref
Definition: commoninvoice.class.php:1596
CommonInvoice\STATUS_ABANDONED
const STATUS_ABANDONED
Classified abandoned and no payment done.
Definition: commoninvoice.class.php:103
$sql
if(isModEnabled('facture') && $user->hasRight('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') && $user->hasRight('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:746
CommonInvoice\getSumDepositsUsed
getSumDepositsUsed($multicurrency=0)
Return amount (with tax) of all deposits invoices used by invoice.
Definition: commoninvoice.class.php:197
ref
$object ref
Definition: info.php:78
getDolGlobalString
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
Definition: functions.lib.php:142
dol_time_plus_duree
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition: date.lib.php:122
CommonInvoice\STATUS_CLOSED
const STATUS_CLOSED
Classified paid.
Definition: commoninvoice.class.php:94
CommonInvoice
Superclass for invoices classes.
Definition: commoninvoice.class.php:32
dolGetStatus
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
Definition: functions.lib.php:10967
CommonInvoice\getListOfPayments
getListOfPayments($filtertype='')
Return list of payments.
Definition: commoninvoice.class.php:340
CommonInvoiceLine
Parent class of all other business classes for details of elements (invoices, contracts,...
Definition: commoninvoice.class.php:1584
CommonObject\setPaymentMethods
setPaymentMethods($id)
Change the payments methods.
Definition: commonobject.class.php:2350
CommonInvoice\is_erasable
is_erasable()
Return if an invoice can be deleted Rule is: If invoice is draft and has a temporary ref -> yes (1) I...
Definition: commoninvoice.class.php:448
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:3056
Stripe
Stripe class.
Definition: stripe.class.php:29
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:5829
CompanyPaymentMode
Class for CompanyPaymentMode.
Definition: companypaymentmode.class.php:33
CommonInvoice\LibStatut
LibStatut($paye, $status, $mode=0, $alreadypaid=-1, $type=-1)
Return label of a status.
Definition: commoninvoice.class.php:602
CommonInvoice\calculate_date_lim_reglement
calculate_date_lim_reglement($cond_reglement=0)
Returns an invoice payment deadline based on the invoice settlement conditions and billing date.
Definition: commoninvoice.class.php:682
dol_mktime
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
Definition: functions.lib.php:2968
getDolGlobalInt
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
Definition: functions.lib.php:156
CommonInvoice\TYPE_CREDIT_NOTE
const TYPE_CREDIT_NOTE
Credit note invoice.
Definition: commoninvoice.class.php:59
type
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:120
Account
Class to manage bank accounts.
Definition: account.class.php:40
CommonInvoiceLine\$libelle
$libelle
Definition: commoninvoice.class.php:1601
if
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
Definition: journals_list.php:25