dolibarr  18.0.0-alpha
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  const TYPE_STANDARD = 0;
40 
44  const TYPE_REPLACEMENT = 1;
45 
49  const TYPE_CREDIT_NOTE = 2;
50 
54  const TYPE_DEPOSIT = 3;
55 
60  const TYPE_PROFORMA = 4;
61 
65  const TYPE_SITUATION = 5;
66 
70  const STATUS_DRAFT = 0;
71 
75  const STATUS_VALIDATED = 1;
76 
84  const STATUS_CLOSED = 2;
85 
93  const STATUS_ABANDONED = 3;
94 
95 
96  public $totalpaid; // duplicate with sumpayed
97  public $totaldeposits; // duplicate with sumdeposit
98  public $totalcreditnotes; // duplicate with sumcreditnote
99 
100  public $sumpayed;
101  public $sumpayed_multicurrency;
102  public $sumdeposit;
103  public $sumdeposit_multicurrency;
104  public $sumcreditnote;
105  public $sumcreditnote_multicurrency;
106  public $remaintopay;
107 
108 
116  public function getRemainToPay($multicurrency = 0)
117  {
118  $alreadypaid = 0.0;
119  $alreadypaid += $this->getSommePaiement($multicurrency);
120  $alreadypaid += $this->getSumDepositsUsed($multicurrency);
121  $alreadypaid += $this->getSumCreditNotesUsed($multicurrency);
122 
123  $remaintopay = price2num($this->total_ttc - $alreadypaid, 'MT');
124  if ($this->statut == self::STATUS_CLOSED && $this->close_code == 'discount_vat') { // If invoice closed with discount for anticipated payment
125  $remaintopay = 0.0;
126  }
127  return $remaintopay;
128  }
129 
137  public function getSommePaiement($multicurrency = 0)
138  {
139  $table = 'paiement_facture';
140  $field = 'fk_facture';
141  if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') {
142  $table = 'paiementfourn_facturefourn';
143  $field = 'fk_facturefourn';
144  }
145 
146  $sql = "SELECT sum(amount) as amount, sum(multicurrency_amount) as multicurrency_amount";
147  $sql .= " FROM ".$this->db->prefix().$table;
148  $sql .= " WHERE ".$field." = ".((int) $this->id);
149 
150  dol_syslog(get_class($this)."::getSommePaiement", LOG_DEBUG);
151 
152  $resql = $this->db->query($sql);
153  if ($resql) {
154  $obj = $this->db->fetch_object($resql);
155 
156  $this->db->free($resql);
157 
158  if ($obj) {
159  if ($multicurrency < 0) {
160  $this->sumpayed = $obj->amount;
161  $this->sumpayed_multicurrency = $obj->multicurrency_amount;
162  return array('alreadypaid'=>(float) $obj->amount, 'alreadypaid_multicurrency'=>(float) $obj->multicurrency_amount);
163  } elseif ($multicurrency) {
164  $this->sumpayed_multicurrency = $obj->multicurrency_amount;
165  return (float) $obj->multicurrency_amount;
166  } else {
167  $this->sumpayed = $obj->amount;
168  return (float) $obj->amount;
169  }
170  } else {
171  return 0;
172  }
173  } else {
174  $this->error = $this->db->lasterror();
175  return -1;
176  }
177  }
178 
187  public function getSumDepositsUsed($multicurrency = 0)
188  {
189  /*if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') {
190  // 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.
191  return 0.0;
192  }*/
193 
194  require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
195 
196  $discountstatic = new DiscountAbsolute($this->db);
197  $result = $discountstatic->getSumDepositsUsed($this, $multicurrency);
198 
199  if ($result >= 0) {
200  if ($multicurrency) {
201  $this->sumdeposit_multicurrency = $result;
202  } else {
203  $this->sumdeposit = $result;
204  }
205 
206  return $result;
207  } else {
208  $this->error = $discountstatic->error;
209  return -1;
210  }
211  }
212 
219  public function getSumCreditNotesUsed($multicurrency = 0)
220  {
221  require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
222 
223  $discountstatic = new DiscountAbsolute($this->db);
224  $result = $discountstatic->getSumCreditNotesUsed($this, $multicurrency);
225  if ($result >= 0) {
226  if ($multicurrency) {
227  $this->sumcreditnote_multicurrency = $result;
228  } else {
229  $this->sumcreditnote = $result;
230  }
231 
232  return $result;
233  } else {
234  $this->error = $discountstatic->error;
235  return -1;
236  }
237  }
238 
245  public function getSumFromThisCreditNotesNotUsed($multicurrency = 0)
246  {
247  require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
248 
249  $discountstatic = new DiscountAbsolute($this->db);
250  $result = $discountstatic->getSumFromThisCreditNotesNotUsed($this, $multicurrency);
251  if ($result >= 0) {
252  return $result;
253  } else {
254  $this->error = $discountstatic->error;
255  return -1;
256  }
257  }
258 
264  public function getListIdAvoirFromInvoice()
265  {
266  $idarray = array();
267 
268  $sql = "SELECT rowid";
269  $sql .= " FROM ".$this->db->prefix().$this->table_element;
270  $sql .= " WHERE fk_facture_source = ".((int) $this->id);
271  $sql .= " AND type = 2";
272  $resql = $this->db->query($sql);
273  if ($resql) {
274  $num = $this->db->num_rows($resql);
275  $i = 0;
276  while ($i < $num) {
277  $row = $this->db->fetch_row($resql);
278  $idarray[] = $row[0];
279  $i++;
280  }
281  } else {
282  dol_print_error($this->db);
283  }
284  return $idarray;
285  }
286 
293  public function getIdReplacingInvoice($option = '')
294  {
295  $sql = "SELECT rowid";
296  $sql .= " FROM ".$this->db->prefix().$this->table_element;
297  $sql .= " WHERE fk_facture_source = ".((int) $this->id);
298  $sql .= " AND type < 2";
299  if ($option == 'validated') {
300  $sql .= ' AND fk_statut = 1';
301  }
302  // PROTECTION BAD DATA
303  // In case the database is corrupted and there is a valid replectement invoice
304  // and another no, priority is given to the valid one.
305  // Should not happen (unless concurrent access and 2 people have created a
306  // replacement invoice for the same invoice at the same time)
307  $sql .= " ORDER BY fk_statut DESC";
308 
309  $resql = $this->db->query($sql);
310  if ($resql) {
311  $obj = $this->db->fetch_object($resql);
312  if ($obj) {
313  // If there is any
314  return $obj->rowid;
315  } else {
316  // If no invoice replaces it
317  return 0;
318  }
319  } else {
320  return -1;
321  }
322  }
323 
330  public function getListOfPayments($filtertype = '')
331  {
332  $retarray = array();
333 
334  $table = 'paiement_facture';
335  $table2 = 'paiement';
336  $field = 'fk_facture';
337  $field2 = 'fk_paiement';
338  $field3 = ', p.ref_ext';
339  $field4 = ', p.fk_bank'; // Bank line id
340  $sharedentity = 'facture';
341  if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') {
342  $table = 'paiementfourn_facturefourn';
343  $table2 = 'paiementfourn';
344  $field = 'fk_facturefourn';
345  $field2 = 'fk_paiementfourn';
346  $field3 = '';
347  $sharedentity = 'facture_fourn';
348  }
349 
350  $sql = "SELECT p.ref, pf.amount, pf.multicurrency_amount, p.fk_paiement, p.datep, p.num_paiement as num, t.code".$field3 . $field4;
351  $sql .= " FROM ".$this->db->prefix().$table." as pf, ".$this->db->prefix().$table2." as p, ".$this->db->prefix()."c_paiement as t";
352  $sql .= " WHERE pf.".$field." = ".((int) $this->id);
353  $sql .= " AND pf.".$field2." = p.rowid";
354  $sql .= ' AND p.fk_paiement = t.id';
355  $sql .= ' AND p.entity IN ('.getEntity($sharedentity).')';
356  if ($filtertype) {
357  $sql .= " AND t.code='PRE'";
358  }
359 
360  dol_syslog(get_class($this)."::getListOfPayments", LOG_DEBUG);
361  $resql = $this->db->query($sql);
362  if ($resql) {
363  $num = $this->db->num_rows($resql);
364  $i = 0;
365  while ($i < $num) {
366  $obj = $this->db->fetch_object($resql);
367  $tmp = array('amount'=>$obj->amount, 'type'=>$obj->code, 'date'=>$obj->datep, 'num'=>$obj->num, 'ref'=>$obj->ref);
368  if (!empty($field3)) {
369  $tmp['ref_ext'] = $obj->ref_ext;
370  }
371  if (!empty($field4)) {
372  $tmp['fk_bank_line'] = $obj->fk_bank;
373  }
374  $retarray[] = $tmp;
375  $i++;
376  }
377  $this->db->free($resql);
378 
379  //look for credit notes and discounts and deposits
380  $sql = '';
381  if ($this->element == 'facture' || $this->element == 'invoice') {
382  $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";
383  $sql .= ' FROM '.$this->db->prefix().'societe_remise_except as rc, '.$this->db->prefix().'facture as f';
384  $sql .= ' WHERE rc.fk_facture_source=f.rowid AND rc.fk_facture = '.((int) $this->id);
385  $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)
386  } elseif ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') {
387  $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";
388  $sql .= ' FROM '.$this->db->prefix().'societe_remise_except as rc, '.$this->db->prefix().'facture_fourn as f';
389  $sql .= ' WHERE rc.fk_invoice_supplier_source=f.rowid AND rc.fk_invoice_supplier = '.((int) $this->id);
390  $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)
391  }
392 
393  if ($sql) {
394  $resql = $this->db->query($sql);
395  if ($resql) {
396  $num = $this->db->num_rows($resql);
397  $i = 0;
398  while ($i < $num) {
399  $obj = $this->db->fetch_object($resql);
400  if ($multicurrency) {
401  $retarray[] = array('amount'=>$obj->multicurrency_amount, 'type'=>$obj->type, 'date'=>$obj->date, 'num'=>'0', 'ref'=>$obj->ref);
402  } else {
403  $retarray[] = array('amount'=>$obj->amount, 'type'=>$obj->type, 'date'=>$obj->date, 'num'=>'', 'ref'=>$obj->ref);
404  }
405  $i++;
406  }
407  } else {
408  $this->error = $this->db->lasterror();
409  dol_print_error($this->db);
410  return array();
411  }
412  $this->db->free($resql);
413  }
414 
415  return $retarray;
416  } else {
417  $this->error = $this->db->lasterror();
418  dol_print_error($this->db);
419  return array();
420  }
421  }
422 
423 
424  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
438  public function is_erasable()
439  {
440  // phpcs:enable
441  global $conf;
442 
443  // We check if invoice is a temporary number (PROVxxxx)
444  $tmppart = substr($this->ref, 1, 4);
445 
446  if ($this->statut == self::STATUS_DRAFT && $tmppart === 'PROV') { // If draft invoice and ref not yet defined
447  return 1;
448  }
449 
450  if (!empty($conf->global->INVOICE_CAN_NEVER_BE_REMOVED)) {
451  return 0;
452  }
453 
454  // If not a draft invoice and not temporary invoice
455  if ($tmppart !== 'PROV') {
456  $ventilExportCompta = $this->getVentilExportCompta();
457  if ($ventilExportCompta != 0) {
458  return -1;
459  }
460 
461  // Get last number of validated invoice
462  if ($this->element != 'invoice_supplier') {
463  if (empty($this->thirdparty)) {
464  $this->fetch_thirdparty(); // We need to have this->thirdparty defined, in case of numbering rule use tags that depend on thirdparty (like {t} tag).
465  }
466  $maxref = $this->getNextNumRef($this->thirdparty, 'last');
467 
468  // If there is no invoice into the reset range and not already dispatched, we can delete
469  // If invoice to delete is last one and not already dispatched, we can delete
470  if (empty($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED) && $maxref != '' && $maxref != $this->ref) {
471  return -2;
472  }
473 
474  // TODO If there is payment in bookkeeping, check payment is not dispatched in accounting
475  // ...
476 
477  if ($this->situation_cycle_ref && method_exists($this, 'is_last_in_cycle')) {
478  $last = $this->is_last_in_cycle();
479  if (!$last) {
480  return -3;
481  }
482  }
483  }
484  }
485 
486  // Test if there is at least one payment. If yes, refuse to delete.
487  if (empty($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED) && $this->getSommePaiement() > 0) {
488  return -4;
489  }
490 
491  return 2;
492  }
493 
499  public function getVentilExportCompta()
500  {
501  $alreadydispatched = 0;
502 
503  $type = 'customer_invoice';
504  if ($this->element == 'invoice_supplier') {
505  $type = 'supplier_invoice';
506  }
507 
508  $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);
509  $resql = $this->db->query($sql);
510  if ($resql) {
511  $obj = $this->db->fetch_object($resql);
512  if ($obj) {
513  $alreadydispatched = $obj->nb;
514  }
515  } else {
516  $this->error = $this->db->lasterror();
517  return -1;
518  }
519 
520  if ($alreadydispatched) {
521  return 1;
522  }
523  return 0;
524  }
525 
526 
533  public function getLibType($withbadge = 0)
534  {
535  global $langs;
536 
537  $labellong = "Unknown";
538  if ($this->type == CommonInvoice::TYPE_STANDARD) {
539  $labellong = "InvoiceStandard";
540  $labelshort = "InvoiceStandardShort";
541  } elseif ($this->type == CommonInvoice::TYPE_REPLACEMENT) {
542  $labellong = "InvoiceReplacement";
543  $labelshort = "InvoiceReplacementShort";
544  } elseif ($this->type == CommonInvoice::TYPE_CREDIT_NOTE) {
545  $labellong = "InvoiceAvoir";
546  $labelshort = "CreditNote";
547  } elseif ($this->type == CommonInvoice::TYPE_DEPOSIT) {
548  $labellong = "InvoiceDeposit";
549  $labelshort = "Deposit";
550  } elseif ($this->type == CommonInvoice::TYPE_PROFORMA) {
551  $labellong = "InvoiceProForma"; // Not used.
552  $labelshort = "ProForma";
553  } elseif ($this->type == CommonInvoice::TYPE_SITUATION) {
554  $labellong = "InvoiceSituation";
555  $labelshort = "Situation";
556  }
557 
558  $out = '';
559  if ($withbadge) {
560  $out .= '<span class="badgeneutral" title="'.dol_escape_htmltag($langs->trans($labellong)).'">';
561  }
562  $out .= $langs->trans($withbadge == 2 ? $labelshort : $labellong);
563  if ($withbadge) {
564  $out .= '</span>';
565  }
566  return $out;
567  }
568 
576  public function getLibStatut($mode = 0, $alreadypaid = -1)
577  {
578  return $this->LibStatut($this->paye, $this->statut, $mode, $alreadypaid, $this->type);
579  }
580 
581  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
592  public function LibStatut($paye, $status, $mode = 0, $alreadypaid = -1, $type = -1)
593  {
594  // phpcs:enable
595  global $langs, $hookmanager;
596  $langs->load('bills');
597 
598  if ($type == -1) {
599  $type = $this->type;
600  }
601 
602  $statusType = 'status0';
603  $prefix = 'Short';
604  if (!$paye) {
605  if ($status == 0) {
606  $labelStatus = $langs->transnoentitiesnoconv('BillStatusDraft');
607  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusDraft');
608  } elseif (($status == 3 || $status == 2) && $alreadypaid <= 0) {
609  if ($status == 3) {
610  $labelStatus = $langs->transnoentitiesnoconv('BillStatusCanceled');
611  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusCanceled');
612  } else {
613  $labelStatus = $langs->transnoentitiesnoconv('BillStatusClosedUnpaid');
614  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusClosedUnpaid');
615  }
616  $statusType = 'status5';
617  } elseif (($status == 3 || $status == 2) && $alreadypaid > 0) {
618  $labelStatus = $langs->transnoentitiesnoconv('BillStatusClosedPaidPartially');
619  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusClosedPaidPartially');
620  $statusType = 'status9';
621  } elseif ($alreadypaid == 0) {
622  $labelStatus = $langs->transnoentitiesnoconv('BillStatusNotPaid');
623  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusNotPaid');
624  $statusType = 'status1';
625  } else {
626  $labelStatus = $langs->transnoentitiesnoconv('BillStatusStarted');
627  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusStarted');
628  $statusType = 'status3';
629  }
630  } else {
631  $statusType = 'status6';
632 
633  if ($type == self::TYPE_CREDIT_NOTE) {
634  $labelStatus = $langs->transnoentitiesnoconv('BillStatusPaidBackOrConverted'); // credit note
635  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusPaidBackOrConverted'); // credit note
636  } elseif ($type == self::TYPE_DEPOSIT) {
637  $labelStatus = $langs->transnoentitiesnoconv('BillStatusConverted'); // deposit invoice
638  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusConverted'); // deposit invoice
639  } else {
640  $labelStatus = $langs->transnoentitiesnoconv('BillStatusPaid');
641  $labelStatusShort = $langs->transnoentitiesnoconv('Bill'.$prefix.'StatusPaid');
642  }
643  }
644 
645  $parameters = array(
646  'status' => $status,
647  'mode' => $mode,
648  'paye' => $paye,
649  'alreadypaid' => $alreadypaid,
650  'type' => $type
651  );
652 
653  $reshook = $hookmanager->executeHooks('LibStatut', $parameters, $this); // Note that $action and $object may have been modified by hook
654 
655  if ($reshook > 0) {
656  return $hookmanager->resPrint;
657  }
658 
659 
660 
661  return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
662  }
663 
664  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
672  public function calculate_date_lim_reglement($cond_reglement = 0)
673  {
674  // phpcs:enable
675  if (!$cond_reglement) {
676  $cond_reglement = $this->cond_reglement_code;
677  }
678  if (!$cond_reglement) {
679  $cond_reglement = $this->cond_reglement_id;
680  }
681  if (!$cond_reglement) {
682  return $this->date;
683  }
684 
685  $cdr_nbjour = 0;
686  $cdr_type = 0;
687  $cdr_decalage = 0;
688 
689  $sqltemp = "SELECT c.type_cdr, c.nbjour, c.decalage";
690  $sqltemp .= " FROM ".$this->db->prefix()."c_payment_term as c";
691  if (is_numeric($cond_reglement)) {
692  $sqltemp .= " WHERE c.rowid=".((int) $cond_reglement);
693  } else {
694  $sqltemp .= " WHERE c.entity IN (".getEntity('c_payment_term').")";
695  $sqltemp .= " AND c.code = '".$this->db->escape($cond_reglement)."'";
696  }
697 
698  dol_syslog(get_class($this).'::calculate_date_lim_reglement', LOG_DEBUG);
699  $resqltemp = $this->db->query($sqltemp);
700  if ($resqltemp) {
701  if ($this->db->num_rows($resqltemp)) {
702  $obj = $this->db->fetch_object($resqltemp);
703  $cdr_nbjour = $obj->nbjour;
704  $cdr_type = $obj->type_cdr;
705  $cdr_decalage = $obj->decalage;
706  }
707  } else {
708  $this->error = $this->db->error();
709  return -1;
710  }
711  $this->db->free($resqltemp);
712 
713  /* Definition de la date limite */
714 
715  // 0 : adding the number of days
716  if ($cdr_type == 0) {
717  $datelim = $this->date + ($cdr_nbjour * 3600 * 24);
718 
719  $datelim += ($cdr_decalage * 3600 * 24);
720  } elseif ($cdr_type == 1) {
721  // 1 : application of the "end of the month" rule
722  $datelim = $this->date + ($cdr_nbjour * 3600 * 24);
723 
724  $mois = date('m', $datelim);
725  $annee = date('Y', $datelim);
726  if ($mois == 12) {
727  $mois = 1;
728  $annee += 1;
729  } else {
730  $mois += 1;
731  }
732  // We move at the beginning of the next month, and we take a day off
733  $datelim = dol_mktime(12, 0, 0, $mois, 1, $annee);
734  $datelim -= (3600 * 24);
735 
736  $datelim += ($cdr_decalage * 3600 * 24);
737  } elseif ($cdr_type == 2 && !empty($cdr_decalage)) {
738  // 2 : application of the rule, the N of the current or next month
739  include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
740  $datelim = $this->date + ($cdr_nbjour * 3600 * 24);
741 
742  $date_piece = dol_mktime(0, 0, 0, date('m', $datelim), date('d', $datelim), date('Y', $datelim)); // Sans les heures minutes et secondes
743  $date_lim_current = dol_mktime(0, 0, 0, date('m', $datelim), $cdr_decalage, date('Y', $datelim)); // Sans les heures minutes et secondes
744  $date_lim_next = dol_time_plus_duree($date_lim_current, 1, 'm'); // Add 1 month
745 
746  $diff = $date_piece - $date_lim_current;
747 
748  if ($diff < 0) {
749  $datelim = $date_lim_current;
750  } else {
751  $datelim = $date_lim_next;
752  }
753  } else {
754  return 'Bad value for type_cdr in database for record cond_reglement = '.$cond_reglement;
755  }
756 
757  return $datelim;
758  }
759 
760  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
771  public function demande_prelevement($fuser, $amount = 0, $type = 'direct-debit', $sourcetype = 'facture')
772  {
773  // phpcs:enable
774  global $conf;
775 
776  $error = 0;
777 
778  dol_syslog(get_class($this)."::demande_prelevement", LOG_DEBUG);
779 
780  if ($this->statut > self::STATUS_DRAFT && $this->paye == 0) {
781  require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php';
782  $bac = new CompanyBankAccount($this->db);
783  $bac->fetch(0, $this->socid);
784 
785  $sql = "SELECT count(*)";
786  $sql .= " FROM ".$this->db->prefix()."prelevement_demande";
787  if ($type == 'bank-transfer') {
788  $sql .= " WHERE fk_facture_fourn = ".((int) $this->id);
789  } else {
790  $sql .= " WHERE fk_facture = ".((int) $this->id);
791  }
792  $sql .= " AND type = 'ban'"; // To exclude record done for some online payments
793  $sql .= " AND traite = 0";
794 
795  dol_syslog(get_class($this)."::demande_prelevement", LOG_DEBUG);
796  $resql = $this->db->query($sql);
797  if ($resql) {
798  $row = $this->db->fetch_row($resql);
799  if ($row[0] == 0) {
800  $now = dol_now();
801 
802  $totalpaid = $this->getSommePaiement();
803  $totalcreditnotes = $this->getSumCreditNotesUsed();
804  $totaldeposits = $this->getSumDepositsUsed();
805  //print "totalpaid=".$totalpaid." totalcreditnotes=".$totalcreditnotes." totaldeposts=".$totaldeposits;
806 
807  // We can also use bcadd to avoid pb with floating points
808  // For example print 239.2 - 229.3 - 9.9; does not return 0.
809  //$resteapayer=bcadd($this->total_ttc,$totalpaid,$conf->global->MAIN_MAX_DECIMALS_TOT);
810  //$resteapayer=bcadd($resteapayer,$totalavoir,$conf->global->MAIN_MAX_DECIMALS_TOT);
811  if (empty($amount)) {
812  $amount = price2num($this->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT');
813  }
814 
815  if (is_numeric($amount) && $amount != 0) {
816  $sql = 'INSERT INTO '.$this->db->prefix().'prelevement_demande(';
817  if ($type == 'bank-transfer') {
818  $sql .= 'fk_facture_fourn, ';
819  } else {
820  $sql .= 'fk_facture, ';
821  }
822  $sql .= ' amount, date_demande, fk_user_demande, code_banque, code_guichet, number, cle_rib, sourcetype, type, entity)';
823  $sql .= " VALUES (".((int) $this->id);
824  $sql .= ", ".((float) price2num($amount));
825  $sql .= ", '".$this->db->idate($now)."'";
826  $sql .= ", ".((int) $fuser->id);
827  $sql .= ", '".$this->db->escape($bac->code_banque)."'";
828  $sql .= ", '".$this->db->escape($bac->code_guichet)."'";
829  $sql .= ", '".$this->db->escape($bac->number)."'";
830  $sql .= ", '".$this->db->escape($bac->cle_rib)."'";
831  $sql .= ", '".$this->db->escape($sourcetype)."'";
832  $sql .= ", 'ban'";
833  $sql .= ", ".((int) $conf->entity);
834  $sql .= ")";
835 
836  dol_syslog(get_class($this)."::demande_prelevement", LOG_DEBUG);
837  $resql = $this->db->query($sql);
838  if (!$resql) {
839  $this->error = $this->db->lasterror();
840  dol_syslog(get_class($this).'::demandeprelevement Erreur');
841  $error++;
842  }
843  } else {
844  $this->error = 'WithdrawRequestErrorNilAmount';
845  dol_syslog(get_class($this).'::demandeprelevement WithdrawRequestErrorNilAmount');
846  $error++;
847  }
848 
849  if (!$error) {
850  // Force payment mode of invoice to withdraw
851  $payment_mode_id = dol_getIdFromCode($this->db, ($type == 'bank-transfer' ? 'VIR' : 'PRE'), 'c_paiement', 'code', 'id', 1);
852  if ($payment_mode_id > 0) {
853  $result = $this->setPaymentMethods($payment_mode_id);
854  }
855  }
856 
857  if ($error) {
858  return -1;
859  }
860  return 1;
861  } else {
862  $this->error = "A request already exists";
863  dol_syslog(get_class($this).'::demandeprelevement Impossible de creer une demande, demande deja en cours');
864  return 0;
865  }
866  } else {
867  $this->error = $this->db->error();
868  dol_syslog(get_class($this).'::demandeprelevement Erreur -2');
869  return -2;
870  }
871  } else {
872  $this->error = "Status of invoice does not allow this";
873  dol_syslog(get_class($this)."::demandeprelevement ".$this->error." $this->statut, $this->paye, $this->mode_reglement_id");
874  return -3;
875  }
876  }
877 
878 
889  public function makeStripeSepaRequest($fuser, $did = 0, $type = 'direct-debit', $sourcetype = 'facture')
890  {
891  global $conf, $mysoc, $user, $langs;
892 
893  if (empty($conf->global->STRIPE_SEPA_DIRECT_DEBIT)) {
894  //exit
895  return 0;
896  }
897 
898  $error = 0;
899 
900  dol_syslog(get_class($this)."::makeStripeSepaRequest start", LOG_DEBUG);
901 
902  if ($this->statut > self::STATUS_DRAFT && $this->paye == 0) {
903  // Get the default payment mode for BAN payment of the third party
904  require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php';
905  $bac = new CompanyBankAccount($this->db); // table societe_rib
906  $result = $bac->fetch(0, $this->socid, 1, 'ban');
907  if ($result <= 0 || empty($bac->id)) {
908  $this->error = $langs->trans("ThirdpartyHasNoDefaultBanAccount");
909  $this->errors[] = $this->error;
910  dol_syslog(get_class($this)."::makeStripeSepaRequest ".$this->error);
911  return -1;
912  }
913 
914  // Load the request to process
915  $sql = "SELECT rowid, date_demande, amount, fk_facture, fk_facture_fourn, fk_prelevement_bons";
916  $sql .= " FROM ".$this->db->prefix()."prelevement_demande";
917  $sql .= " WHERE rowid = ".((int) $did);
918  $sql .= " AND fk_facture = ".((int) $this->id); // Add a protection to not pay another invoice than current one
919  $sql .= " AND traite = 0"; // Add a protection to not process twice
920 
921  dol_syslog(get_class($this)."::makeStripeSepaRequest load requests to process", LOG_DEBUG);
922  $resql = $this->db->query($sql);
923  if ($resql) {
924  $obj = $this->db->fetch_object($resql);
925  if (!$obj) {
926  dol_print_error($this->db, 'CantFindRequestWithId');
927  return -2;
928  }
929 
930  // amount to pay
931  $amount = $obj->amount;
932 
933  if (is_numeric($amount) && $amount != 0) {
934  require_once DOL_DOCUMENT_ROOT.'/societe/class/companypaymentmode.class.php';
935  $companypaymentmode = new CompanyPaymentMode($this->db); // table societe_rib
936  $companypaymentmode->fetch($bac->id);
937 
938  // Start code for Stripe
939  // TODO This must come from a parameter ? or the method may not work as expected when used from a batch ?
940  $service = 'StripeTest';
941  $servicestatus = 0;
942  if (!empty($conf->global->STRIPE_LIVE) && !GETPOST('forcesandbox', 'alpha')) {
943  $service = 'StripeLive';
944  $servicestatus = 1;
945  }
946 
947  dol_syslog("makeStripeSepaRequest amount = ".$amount." service=" . $service . " servicestatus=" . $servicestatus . " thirdparty_id=" . $this->socid." did=".$did);
948 
949  $this->stripechargedone = 0;
950  $this->stripechargeerror = 0;
951 
952  $now = dol_now();
953 
954  $currency = $conf->currency;
955 
956  global $stripearrayofkeysbyenv;
957 
958  $errorforinvoice = 0; // We reset the $errorforinvoice at each invoice loop
959 
960  $this->fetch_thirdparty();
961 
962  dol_syslog("--- Process payment request thirdparty_id=" . $this->thirdparty->id . ", thirdparty_name=" . $this->thirdparty->name . " ban id=" . $bac->id, LOG_DEBUG);
963 
964  //$alreadypayed = $this->getSommePaiement();
965  //$amount_credit_notes_included = $this->getSumCreditNotesUsed();
966  //$amounttopay = $this->total_ttc - $alreadypayed - $amount_credit_notes_included;
967  $amounttopay = $amount;
968 
969  // Correct the amount according to unit of currency
970  // See https://support.stripe.com/questions/which-zero-decimal-currencies-does-stripe-support
971  $arrayzerounitcurrency = ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF'];
972  $amountstripe = $amounttopay;
973  if (!in_array($currency, $arrayzerounitcurrency)) {
974  $amountstripe = $amountstripe * 100;
975  }
976 
977  $fk_bank_account = getDolGlobalInt('STRIPE_BANK_ACCOUNT_FOR_PAYMENTS');
978  if (!($fk_bank_account > 0)) {
979  $error++;
980  $errorforinvoice++;
981  dol_syslog("Error no bank account defined for Stripe payments", LOG_ERR);
982  $this->errors[] = "Error bank account for Stripe payments not defined into Stripe module";
983  }
984 
985  $this->db->begin();
986 
987  // Create a prelevement_bon
988  $bon = new BonPrelevement($this->db);
989  if (!$error) {
990  if (empty($obj->fk_prelevement_bons)) {
991  // This create record into llx_prelevment_bons and update link with llx_prelevement_demande
992  $nbinvoices = $bon->create(0, 0, 'real', 'ALL', '', 0, 'direct-debit', $did, $fk_bank_account);
993  if ($nbinvoices <= 0) {
994  $error++;
995  $errorforinvoice++;
996  dol_syslog("Error on BonPrelevement creation", LOG_ERR);
997  $this->errors[] = "Error on BonPrelevement creation";
998  }
999  /*
1000  if (!$error) {
1001  // Update the direct debit payment request of the processed request to save the id of the prelevement_bon
1002  $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_demande SET";
1003  $sql .= " fk_prelevement_bons = ".((int) $bon->id);
1004  $sql .= " WHERE rowid = ".((int) $did);
1005 
1006  $result = $this->db->query($sql);
1007  if ($result < 0) {
1008  $error++;
1009  $this->errors[] = "Error on updateing fk_prelevement_bons to ".$bon->id;
1010  }
1011  }
1012  */
1013  } else {
1014  $error++;
1015  $errorforinvoice++;
1016  dol_syslog("Error Line already part of a bank payment order", LOG_ERR);
1017  $this->errors[] = "The line is already included into a bank payment order. Delete the bank payment order first.";
1018  }
1019  }
1020 
1021  if (!$error) {
1022  if ($amountstripe > 0) {
1023  try {
1024  //var_dump($companypaymentmode);
1025  dol_syslog("We will try to pay with companypaymentmodeid=" . $companypaymentmode->id . " stripe_card_ref=" . $companypaymentmode->stripe_card_ref . " mode=" . $companypaymentmode->status, LOG_DEBUG);
1026 
1027  $thirdparty = new Societe($this->db);
1028  $resultthirdparty = $thirdparty->fetch($this->socid);
1029 
1030  include_once DOL_DOCUMENT_ROOT . '/stripe/class/stripe.class.php'; // This include the include of htdocs/stripe/config.php
1031  // So it inits or erases the $stripearrayofkeysbyenv
1032  $stripe = new Stripe($this->db);
1033 
1034  dol_syslog("makeStripeSepaRequest Current Stripe environment is " . $stripearrayofkeysbyenv[$servicestatus]['publishable_key']);
1035 
1036  $stripearrayofkeys = $stripearrayofkeysbyenv[$servicestatus];
1037  \Stripe\Stripe::setApiKey($stripearrayofkeys['secret_key']);
1038 
1039 
1040  dol_syslog("makeStripeSepaRequest get stripe connet account", LOG_DEBUG);
1041  $stripeacc = $stripe->getStripeAccount($service, $this->socid); // Get Stripe OAuth connect account if it exists (no network access here)
1042  dol_syslog("makeStripeSepaRequest get stripe connect account return " . json_encode($stripeacc), LOG_DEBUG);
1043 
1044  $customer = $stripe->customerStripe($thirdparty, $stripeacc, $servicestatus, 0);
1045  if (empty($customer) && !empty($stripe->error)) {
1046  $this->errors[] = $stripe->error;
1047  }
1048 
1049  // $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)
1050  // $nbdaysbeforeendoftries = (empty($conf->global->SELLYOURSAAS_NBDAYSBEFOREENDOFTRIES) ? 35 : $conf->global->SELLYOURSAAS_NBDAYSBEFOREENDOFTRIES);
1051  $postactionmessages = [];
1052 
1053  if ($resultthirdparty > 0 && !empty($customer)) {
1054  if (!$error) { // Payment was not canceled
1055  $sepaMode = false;
1056  $stripecard = null;
1057  if ($companypaymentmode->type == 'ban') {
1058  $sepaMode = true;
1059  // Check into societe_rib if a payment mode for Stripe and ban payment exists
1060  // To make a Stripe SEPA payment request, we must have the payment mode source already saved into societe_rib and retreived with ->sepaStripe
1061  // The payment mode source is created when we create the bank account on Stripe with paymentmodes.php?action=create
1062  $stripecard = $stripe->sepaStripe($customer, $companypaymentmode, $stripeacc, $servicestatus, 0);
1063  }
1064 
1065  if ($stripecard) { // Can be src_... (for sepa) or pm_... (new card mode). Note that card_... (old card mode) should not happen here.
1066  $FULLTAG = 'DID='.$did.'-INV=' . $this->id . '-CUS=' . $thirdparty->id;
1067  $description = 'Stripe payment from makeStripeSepaRequest: ' . $FULLTAG . ' did='.$did.' ref=' . $this->ref;
1068 
1069  $stripefailurecode = '';
1070  $stripefailuremessage = '';
1071  $stripefailuredeclinecode = '';
1072 
1073  // Using new SCA method
1074  dol_syslog("* Create payment on SEPA " . $stripecard->id . ", amounttopay=" . $amounttopay . ", amountstripe=" . $amountstripe . ", FULLTAG=" . $FULLTAG, LOG_DEBUG);
1075 
1076  // Create payment intent and charge payment (confirmnow = true)
1077  $paymentintent = $stripe->getPaymentIntent($amounttopay, $currency, $FULLTAG, $description, $this, $customer->id, $stripeacc, $servicestatus, 0, 'automatic', true, $stripecard->id, 1, 1, $did);
1078 
1079  $charge = new stdClass();
1080 
1081  if ($paymentintent->status === 'succeeded' || $paymentintent->status === 'processing') {
1082  $charge->status = 'ok';
1083  $charge->id = $paymentintent->id;
1084  $charge->customer = $customer->id;
1085  } elseif ($paymentintent->status === 'requires_action') {
1086  //paymentintent->status may be => 'requires_action' (no error in such a case)
1087  dol_syslog(var_export($paymentintent, true), LOG_DEBUG);
1088 
1089  $charge->status = 'failed';
1090  $charge->customer = $customer->id;
1091  $charge->failure_code = $stripe->code;
1092  $charge->failure_message = $stripe->error;
1093  $charge->failure_declinecode = $stripe->declinecode;
1094  $stripefailurecode = $stripe->code;
1095  $stripefailuremessage = 'Action required. Contact the support at ';// . $conf->global->SELLYOURSAAS_MAIN_EMAIL;
1096  $stripefailuredeclinecode = $stripe->declinecode;
1097  } else {
1098  dol_syslog(var_export($paymentintent, true), LOG_DEBUG);
1099 
1100  $charge->status = 'failed';
1101  $charge->customer = $customer->id;
1102  $charge->failure_code = $stripe->code;
1103  $charge->failure_message = $stripe->error;
1104  $charge->failure_declinecode = $stripe->declinecode;
1105  $stripefailurecode = $stripe->code;
1106  $stripefailuremessage = $stripe->error;
1107  $stripefailuredeclinecode = $stripe->declinecode;
1108  }
1109 
1110  //var_dump("stripefailurecode=".$stripefailurecode." stripefailuremessage=".$stripefailuremessage." stripefailuredeclinecode=".$stripefailuredeclinecode);
1111  //exit;
1112 
1113 
1114  // Return $charge = array('id'=>'ch_XXXX', 'status'=>'succeeded|pending|failed', 'failure_code'=>, 'failure_message'=>...)
1115  if (empty($charge) || $charge->status == 'failed') {
1116  dol_syslog('Failed to charge payment mode ' . $stripecard->id . ' stripefailurecode=' . $stripefailurecode . ' stripefailuremessage=' . $stripefailuremessage . ' stripefailuredeclinecode=' . $stripefailuredeclinecode, LOG_WARNING);
1117 
1118  // Save a stripe payment was in error
1119  $this->stripechargeerror++;
1120 
1121  $error++;
1122  $errorforinvoice++;
1123  $errmsg = $langs->trans("FailedToChargeCard");
1124  if (!empty($charge)) {
1125  if ($stripefailuredeclinecode == 'authentication_required') {
1126  $errauthenticationmessage = $langs->trans("ErrSCAAuthentication");
1127  $errmsg = $errauthenticationmessage;
1128  } elseif (in_array($stripefailuredeclinecode, ['insufficient_funds', 'generic_decline'])) {
1129  $errmsg .= ': ' . $charge->failure_code;
1130  $errmsg .= ($charge->failure_message ? ' - ' : '') . ' ' . $charge->failure_message;
1131  if (empty($stripefailurecode)) {
1132  $stripefailurecode = $charge->failure_code;
1133  }
1134  if (empty($stripefailuremessage)) {
1135  $stripefailuremessage = $charge->failure_message;
1136  }
1137  } else {
1138  $errmsg .= ': failure_code=' . $charge->failure_code;
1139  $errmsg .= ($charge->failure_message ? ' - ' : '') . ' failure_message=' . $charge->failure_message;
1140  if (empty($stripefailurecode)) {
1141  $stripefailurecode = $charge->failure_code;
1142  }
1143  if (empty($stripefailuremessage)) {
1144  $stripefailuremessage = $charge->failure_message;
1145  }
1146  }
1147  } else {
1148  $errmsg .= ': ' . $stripefailurecode . ' - ' . $stripefailuremessage;
1149  $errmsg .= ($stripefailuredeclinecode ? ' - ' . $stripefailuredeclinecode : '');
1150  }
1151 
1152  $description = 'Stripe payment ERROR from makeStripeSepaRequest: ' . $FULLTAG;
1153  $postactionmessages[] = $errmsg . ' (' . $stripearrayofkeys['publishable_key'] . ')';
1154  $this->errors[] = $errmsg;
1155  } else {
1156  dol_syslog('Successfuly request direct debit ' . $stripecard->id);
1157 
1158  $postactionmessages[] = 'Success to request direct debit (' . $charge->id . ' with ' . $stripearrayofkeys['publishable_key'] . ')';
1159 
1160  // Save a stripe payment was done in realy life so later we will be able to force a commit on recorded payments
1161  // even if in batch mode (method doTakePaymentStripe), we will always make all action in one transaction with a forced commit.
1162  $this->stripechargedone++;
1163 
1164  // Default description used for label of event. Will be overwrite by another value later.
1165  $description = 'Stripe payment request OK (' . $charge->id . ') from makeStripeSepaRequest: ' . $FULLTAG;
1166  }
1167 
1168  $object = $this;
1169 
1170  // Track an event
1171  if (empty($charge) || $charge->status == 'failed') {
1172  $actioncode = 'PAYMENT_STRIPE_KO';
1173  $extraparams = $stripefailurecode;
1174  $extraparams .= (($extraparams && $stripefailuremessage) ? ' - ' : '') . $stripefailuremessage;
1175  $extraparams .= (($extraparams && $stripefailuredeclinecode) ? ' - ' : '') . $stripefailuredeclinecode;
1176  } else {
1177  $actioncode = 'PAYMENT_STRIPE_OK';
1178  $extraparams = '';
1179  }
1180  } else {
1181  $error++;
1182  $errorforinvoice++;
1183  dol_syslog("No direct debit payment method found for this stripe customer " . $customer->id, LOG_WARNING);
1184  $this->errors[] = 'Failed to get direct debit payment method for stripe customer = ' . $customer->id;
1185 
1186  $description = 'Failed to find or use the payment mode - no credit card defined for the customer account';
1187  $stripefailurecode = 'BADPAYMENTMODE';
1188  $stripefailuremessage = 'Failed to find or use the payment mode - no credit card defined for the customer account';
1189  $postactionmessages[] = $description . ' (' . $stripearrayofkeys['publishable_key'] . ')';
1190 
1191  $object = $this;
1192 
1193  $actioncode = 'PAYMENT_STRIPE_KO';
1194  $extraparams = '';
1195  }
1196  } else {
1197  // If error because payment was canceled for a logical reason, we do nothing (no event added)
1198  $description = '';
1199  $stripefailurecode = '';
1200  $stripefailuremessage = '';
1201 
1202  $object = $this;
1203 
1204  $actioncode = '';
1205  $extraparams = '';
1206  }
1207  } else { // Else of the if ($resultthirdparty > 0 && ! empty($customer)) {
1208  if ($resultthirdparty <= 0) {
1209  dol_syslog('SellYourSaasUtils Failed to load customer for thirdparty_id = ' . $thirdparty->id, LOG_WARNING);
1210  $this->errors[] = 'Failed to load customer for thirdparty_id = ' . $thirdparty->id;
1211  } else { // $customer stripe not found
1212  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);
1213  $this->errors[] = 'Failed to get Stripe customer id for thirdparty_id = ' . $thirdparty->id . " in mode " . $servicestatus . " in Stripe env " . $stripearrayofkeysbyenv[$servicestatus]['publishable_key'];
1214  }
1215  $error++;
1216  $errorforinvoice++;
1217 
1218  $description = 'Failed to find or use your payment mode (no payment mode for this customer id)';
1219  $stripefailurecode = 'BADPAYMENTMODE';
1220  $stripefailuremessage = 'Failed to find or use your payment mode (no payment mode for this customer id)';
1221  $postactionmessages = [];
1222 
1223  $object = $this;
1224 
1225  $actioncode = 'PAYMENT_STRIPE_KO';
1226  $extraparams = '';
1227  }
1228 
1229  if ($description) {
1230  dol_syslog("* Record event for credit transfer or direct debit request result - " . $description);
1231  require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
1232 
1233  // Insert record of payment (success or error)
1234  $actioncomm = new ActionComm($this->db);
1235 
1236  $actioncomm->type_code = 'AC_OTH_AUTO'; // Type of event ('AC_OTH', 'AC_OTH_AUTO', 'AC_XXX'...)
1237  $actioncomm->code = 'AC_' . $actioncode;
1238  $actioncomm->label = $description;
1239  $actioncomm->note_private = join(",\n", $postactionmessages);
1240  $actioncomm->fk_project = $this->fk_project;
1241  $actioncomm->datep = $now;
1242  $actioncomm->datef = $now;
1243  $actioncomm->percentage = -1; // Not applicable
1244  $actioncomm->socid = $thirdparty->id;
1245  $actioncomm->contactid = 0;
1246  $actioncomm->authorid = $user->id; // User saving action
1247  $actioncomm->userownerid = $user->id; // Owner of action
1248  // Fields when action is a real email (content is already into note)
1249  /*$actioncomm->email_msgid = $object->email_msgid;
1250  $actioncomm->email_from = $object->email_from;
1251  $actioncomm->email_sender= $object->email_sender;
1252  $actioncomm->email_to = $object->email_to;
1253  $actioncomm->email_tocc = $object->email_tocc;
1254  $actioncomm->email_tobcc = $object->email_tobcc;
1255  $actioncomm->email_subject = $object->email_subject;
1256  $actioncomm->errors_to = $object->errors_to;*/
1257  $actioncomm->fk_element = $this->id;
1258  $actioncomm->elementtype = $this->element;
1259  $actioncomm->extraparams = dol_trunc($extraparams, 250);
1260 
1261  $actioncomm->create($user);
1262  }
1263 
1264  $this->description = $description;
1265  $this->postactionmessages = $postactionmessages;
1266  } catch (Exception $e) {
1267  $error++;
1268  $errorforinvoice++;
1269  dol_syslog('Error ' . $e->getMessage(), LOG_ERR);
1270  $this->errors[] = 'Error ' . $e->getMessage();
1271  }
1272  } else { // If remain to pay is null
1273  $error++;
1274  $errorforinvoice++;
1275  dol_syslog("Remain to pay is null for the invoice " . $this->id . " " . $this->ref . ". Why is the invoice not classified 'Paid' ?", LOG_WARNING);
1276  $this->errors[] = "Remain to pay is null for the invoice " . $this->id . " " . $this->ref . ". Why is the invoice not classified 'Paid' ?";
1277  }
1278  }
1279 
1280  // Set status of the order to "Transferred" with method 'api'
1281  if (!$error && !$errorforinvoice) {
1282  $result = $bon->set_infotrans($user, $now, 3);
1283  if ($result < 0) {
1284  $error++;
1285  $errorforinvoice++;
1286  dol_syslog("Error on BonPrelevement creation", LOG_ERR);
1287  $this->errors[] = "Error on BonPrelevement creation";
1288  }
1289  }
1290 
1291  if (!$error && !$errorforinvoice) {
1292  // Update the direct debit payment request of the processed invoice to save the id of the prelevement_bon
1293  $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_demande SET";
1294  $sql .= " ext_payment_id = '".$this->db->escape($paymentintent->id)."',";
1295  $sql .= " ext_payment_site = '".$this->db->escape($service)."'";
1296  $sql .= " WHERE rowid = ".((int) $did);
1297 
1298  dol_syslog(get_class($this)."::makeStripeSepaRequest update to save stripe paymentintent ids", LOG_DEBUG);
1299  $resql = $this->db->query($sql);
1300  if (!$resql) {
1301  $this->error = $this->db->lasterror();
1302  dol_syslog(get_class($this).'::makeStripeSepaRequest Erreur');
1303  $error++;
1304  }
1305  }
1306 
1307  if (!$error && !$errorforinvoice) {
1308  $this->db->commit();
1309  } else {
1310  $this->db->rollback();
1311  }
1312  } else {
1313  $this->error = 'WithdrawRequestErrorNilAmount';
1314  dol_syslog(get_class($this).'::makeStripeSepaRequest WithdrawRequestErrorNilAmount');
1315  $error++;
1316  }
1317 
1318  /*
1319  if (!$error) {
1320  // Force payment mode of the invoice to withdraw
1321  $payment_mode_id = dol_getIdFromCode($this->db, ($type == 'bank-transfer' ? 'VIR' : 'PRE'), 'c_paiement', 'code', 'id', 1);
1322  if ($payment_mode_id > 0) {
1323  $result = $this->setPaymentMethods($payment_mode_id);
1324  }
1325  }*/
1326 
1327  if ($error) {
1328  return -1;
1329  }
1330  return 1;
1331  } else {
1332  $this->error = $this->db->error();
1333  dol_syslog(get_class($this).'::makeStripeSepaRequest Erreur -2');
1334  return -2;
1335  }
1336  } else {
1337  $this->error = "Status of invoice does not allow this";
1338  dol_syslog(get_class($this)."::makeStripeSepaRequest ".$this->error." $this->statut, $this->paye, $this->mode_reglement_id");
1339  return -3;
1340  }
1341  }
1342 
1343  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1351  public function demande_prelevement_delete($fuser, $did)
1352  {
1353  // phpcs:enable
1354  $sql = 'DELETE FROM '.$this->db->prefix().'prelevement_demande';
1355  $sql .= ' WHERE rowid = '.((int) $did);
1356  $sql .= ' AND traite = 0';
1357  if ($this->db->query($sql)) {
1358  return 0;
1359  } else {
1360  $this->error = $this->db->lasterror();
1361  dol_syslog(get_class($this).'::demande_prelevement_delete Error '.$this->error);
1362  return -1;
1363  }
1364  }
1365 
1366 
1372  public function buildZATCAQRString()
1373  {
1374  global $conf, $mysoc;
1375 
1376  $tmplang = new Translate('', $conf);
1377  $tmplang->setDefaultLang('en_US');
1378  $tmplang->load("main");
1379 
1380  $datestring = dol_print_date($this->date, 'dayhourrfc');
1381  //$pricewithtaxstring = price($this->total_ttc, 0, $tmplang, 0, -1, 2);
1382  //$pricetaxstring = price($this->total_tva, 0, $tmplang, 0, -1, 2);
1383  $pricewithtaxstring = price2num($this->total_ttc, 2, 1);
1384  $pricetaxstring = price2num($this->total_tva, 2, 1);
1385 
1386  /*
1387  $name = implode(unpack("H*", $this->thirdparty->name));
1388  $vatnumber = implode(unpack("H*", $this->thirdparty->tva_intra));
1389  $date = implode(unpack("H*", $datestring));
1390  $pricewithtax = implode(unpack("H*", price2num($pricewithtaxstring, 2)));
1391  $pricetax = implode(unpack("H*", $pricetaxstring));
1392 
1393  //var_dump(strlen($this->thirdparty->name));
1394  //var_dump(str_pad(dechex('9'), 2, '0', STR_PAD_LEFT));
1395  //var_dump($this->thirdparty->name);
1396  //var_dump(implode(unpack("H*", $this->thirdparty->name)));
1397  //var_dump(price($this->total_tva, 0, $tmplang, 0, -1, 2));
1398 
1399  $s = '01'.str_pad(dechex(strlen($this->thirdparty->name)), 2, '0', STR_PAD_LEFT).$name;
1400  $s .= '02'.str_pad(dechex(strlen($this->thirdparty->tva_intra)), 2, '0', STR_PAD_LEFT).$vatnumber;
1401  $s .= '03'.str_pad(dechex(strlen($datestring)), 2, '0', STR_PAD_LEFT).$date;
1402  $s .= '04'.str_pad(dechex(strlen($pricewithtaxstring)), 2, '0', STR_PAD_LEFT).$pricewithtax;
1403  $s .= '05'.str_pad(dechex(strlen($pricetaxstring)), 2, '0', STR_PAD_LEFT).$pricetax;
1404  $s .= ''; // Hash of xml invoice
1405  $s .= ''; // ecda signature
1406  $s .= ''; // ecda public key
1407  $s .= ''; // ecda signature of public key stamp
1408  */
1409 
1410  // Using TLV format
1411  $s = pack('C1', 1).pack('C1', strlen($mysoc->name)).$mysoc->name;
1412  $s .= pack('C1', 2).pack('C1', strlen($mysoc->tva_intra)).$mysoc->tva_intra;
1413  $s .= pack('C1', 3).pack('C1', strlen($datestring)).$datestring;
1414  $s .= pack('C1', 4).pack('C1', strlen($pricewithtaxstring)).$pricewithtaxstring;
1415  $s .= pack('C1', 5).pack('C1', strlen($pricetaxstring)).$pricetaxstring;
1416  $s .= ''; // Hash of xml invoice
1417  $s .= ''; // ecda signature
1418  $s .= ''; // ecda public key
1419  $s .= ''; // ecda signature of public key stamp
1420 
1421  $s = base64_encode($s);
1422 
1423  return $s;
1424  }
1425 
1426 
1432  public function buildSwitzerlandQRString()
1433  {
1434  global $conf, $mysoc;
1435 
1436  $tmplang = new Translate('', $conf);
1437  $tmplang->setDefaultLang('en_US');
1438  $tmplang->load("main");
1439 
1440  $pricewithtaxstring = price2num($this->total_ttc, 2, 1);
1441  $pricetaxstring = price2num($this->total_tva, 2, 1);
1442 
1443  $complementaryinfo = '';
1444  /*
1445  Example: //S1/10/10201409/11/190512/20/1400.000-53/30/106017086/31/180508/32/7.7/40/2:10;0:30
1446  /10/ Numéro de facture – 10201409
1447  /11/ Date de facture – 12.05.2019
1448  /20/ Référence client – 1400.000-53
1449  /30/ Numéro IDE pour la TVA – CHE-106.017.086 TVA
1450  /31/ Date de la prestation pour la comptabilisation de la TVA – 08.05.2018
1451  /32/ Taux de TVA sur le montant total de la facture – 7.7%
1452  /40/ Conditions – 2% d’escompte à 10 jours, paiement net à 30 jours
1453  */
1454  $datestring = dol_print_date($this->date, '%y%m%d');
1455  //$pricewithtaxstring = price($this->total_ttc, 0, $tmplang, 0, -1, 2);
1456  //$pricetaxstring = price($this->total_tva, 0, $tmplang, 0, -1, 2);
1457  $complementaryinfo = '//S1/10/'.str_replace('/', '', $this->ref).'/11/'.$datestring;
1458  if ($this->ref_client) {
1459  $complementaryinfo .= '/20/'.$this->ref_client;
1460  }
1461  if ($this->thirdparty->tva_intra) {
1462  $complementaryinfo .= '/30/'.$this->thirdparty->tva_intra;
1463  }
1464 
1465  include_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
1466  $bankaccount = new Account($this->db);
1467 
1468  // Header
1469  $s = '';
1470  $s .= "SPC\n";
1471  $s .= "0200\n";
1472  $s .= "1\n";
1473  // Info Seller ("Compte / Payable à")
1474  if ($this->fk_account > 0) {
1475  // Bank BAN if country is LI or CH. TODO Add a test to check than IBAN start with CH or LI
1476  $bankaccount->fetch($this->fk_account);
1477  $s .= $bankaccount->iban."\n";
1478  } else {
1479  $s .= "\n";
1480  }
1481  if ($bankaccount->id > 0 && getDolGlobalString('PDF_SWISS_QRCODE_USE_OWNER_OF_ACCOUNT_AS_CREDITOR')) {
1482  // If a bank account is prodived and we ask to use it as creditor, we use the bank address
1483  // 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 ?
1484  $s .= "S\n";
1485  $s .= dol_trunc($bankaccount->proprio, 70, 'right', 'UTF-8', 1)."\n";
1486  $addresslinearray = explode("\n", $bankaccount->owner_address);
1487  $s .= dol_trunc(empty($addresslinearray[1]) ? '' : $addresslinearray[1], 70, 'right', 'UTF-8', 1)."\n"; // address line 1
1488  $s .= dol_trunc(empty($addresslinearray[2]) ? '' : $addresslinearray[2], 70, 'right', 'UTF-8', 1)."\n"; // address line 2
1489  /*$s .= dol_trunc($mysoc->zip, 16, 'right', 'UTF-8', 1)."\n";
1490  $s .= dol_trunc($mysoc->town, 35, 'right', 'UTF-8', 1)."\n";
1491  $s .= dol_trunc($mysoc->country_code, 2, 'right', 'UTF-8', 1)."\n";*/
1492  } else {
1493  $s .= "S\n";
1494  $s .= dol_trunc($mysoc->name, 70, 'right', 'UTF-8', 1)."\n";
1495  $addresslinearray = explode("\n", $mysoc->address);
1496  $s .= dol_trunc(empty($addresslinearray[1]) ? '' : $addresslinearray[1], 70, 'right', 'UTF-8', 1)."\n"; // address line 1
1497  $s .= dol_trunc(empty($addresslinearray[2]) ? '' : $addresslinearray[2], 70, 'right', 'UTF-8', 1)."\n"; // address line 2
1498  $s .= dol_trunc($mysoc->zip, 16, 'right', 'UTF-8', 1)."\n";
1499  $s .= dol_trunc($mysoc->town, 35, 'right', 'UTF-8', 1)."\n";
1500  $s .= dol_trunc($mysoc->country_code, 2, 'right', 'UTF-8', 1)."\n";
1501  }
1502  // Final seller (Ultimate seller) ("Créancier final" = "En faveur de")
1503  $s .= "\n";
1504  $s .= "\n";
1505  $s .= "\n";
1506  $s .= "\n";
1507  $s .= "\n";
1508  $s .= "\n";
1509  $s .= "\n";
1510  // Amount of payment (to do?)
1511  $s .= price($pricewithtaxstring, 0, 'none', 0, 0, 2)."\n";
1512  $s .= ($this->multicurrency_code ? $this->multicurrency_code : $conf->currency)."\n";
1513  // Buyer
1514  $s .= "S\n";
1515  $s .= dol_trunc($this->thirdparty->name, 70, 'right', 'UTF-8', 1)."\n";
1516  $addresslinearray = explode("\n", $this->thirdparty->address);
1517  $s .= dol_trunc(empty($addresslinearray[1]) ? '' : $addresslinearray[1], 70, 'right', 'UTF-8', 1)."\n"; // address line 1
1518  $s .= dol_trunc(empty($addresslinearray[2]) ? '' : $addresslinearray[2], 70, 'right', 'UTF-8', 1)."\n"; // address line 2
1519  $s .= dol_trunc($this->thirdparty->zip, 16, 'right', 'UTF-8', 1)."\n";
1520  $s .= dol_trunc($this->thirdparty->town, 35, 'right', 'UTF-8', 1)."\n";
1521  $s .= dol_trunc($this->thirdparty->country_code, 2, 'right', 'UTF-8', 1)."\n";
1522  // ID of payment
1523  $s .= "NON\n"; // NON or QRR
1524  $s .= "\n"; // QR Code reference if previous field is QRR
1525  // Free text
1526  if ($complementaryinfo) {
1527  $s .= $complementaryinfo."\n";
1528  } else {
1529  $s .= "\n";
1530  }
1531  $s .= "EPD\n";
1532  // More text, complementary info
1533  if ($complementaryinfo) {
1534  $s .= $complementaryinfo."\n";
1535  }
1536  $s .= "\n";
1537  //var_dump($s);exit;
1538  return $s;
1539  }
1540 }
1541 
1542 
1543 
1544 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
1545 
1549 abstract class CommonInvoiceLine extends CommonObjectLine
1550 {
1555  public $label;
1556 
1561  public $ref; // Product ref (deprecated)
1566  public $libelle; // Product label (deprecated)
1567 
1572  public $product_type = 0;
1573 
1578  public $product_ref;
1579 
1584  public $product_label;
1585 
1590  public $product_desc;
1591 
1596  public $qty;
1597 
1602  public $subprice;
1603 
1609  public $price;
1610 
1615  public $fk_product;
1616 
1621  public $vat_src_code;
1622 
1627  public $tva_tx;
1628 
1633  public $localtax1_tx;
1634 
1639  public $localtax2_tx;
1640 
1645  public $localtax1_type;
1646 
1651  public $localtax2_type;
1652 
1657  public $remise_percent;
1658 
1664  public $remise;
1665 
1670  public $total_ht;
1671 
1676  public $total_tva;
1677 
1682  public $total_localtax1;
1683 
1688  public $total_localtax2;
1689 
1694  public $total_ttc;
1695 
1696  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
1697  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
1698 
1699  public $buy_price_ht;
1700  public $buyprice; // For backward compatibility
1701  public $pa_ht; // For backward compatibility
1702 
1703  public $marge_tx;
1704  public $marque_tx;
1705 
1712  public $info_bits = 0;
1713 
1714  public $special_code = 0;
1715 
1716  public $fk_multicurrency;
1717  public $multicurrency_code;
1718  public $multicurrency_subprice;
1719  public $multicurrency_total_ht;
1720  public $multicurrency_total_tva;
1721  public $multicurrency_total_ttc;
1722 
1723  public $fk_user_author;
1724  public $fk_user_modif;
1725 
1726  public $fk_accounting_account;
1727 }
CommonInvoice\getSommePaiement
getSommePaiement($multicurrency=0)
Return amount of payments already done.
Definition: commoninvoice.class.php:137
CommonInvoice\buildZATCAQRString
buildZATCAQRString()
Build string for ZATCA QR Code (Arabi Saudia)
Definition: commoninvoice.class.php:1372
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
CommonInvoice\TYPE_DEPOSIT
const TYPE_DEPOSIT
Deposit invoice.
Definition: commoninvoice.class.php:54
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:3950
CommonInvoice\getSumCreditNotesUsed
getSumCreditNotesUsed($multicurrency=0)
Return amount (with tax) of all credit notes invoices + excess received used by invoice.
Definition: commoninvoice.class.php:219
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\getVentilExportCompta
getVentilExportCompta()
Return if an invoice was dispatched into bookkeeping.
Definition: commoninvoice.class.php:499
CommonInvoice\getIdReplacingInvoice
getIdReplacingInvoice($option='')
Returns the id of the invoice that replaces it.
Definition: commoninvoice.class.php:293
$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
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:530
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:4994
CommonInvoice\TYPE_STANDARD
const TYPE_STANDARD
Standard invoice.
Definition: commoninvoice.class.php:39
CommonInvoice\getRemainToPay
getRemainToPay($multicurrency=0)
Return remain amount to pay.
Definition: commoninvoice.class.php:116
CommonInvoice\getLibType
getLibType($withbadge=0)
Return label of type of invoice.
Definition: commoninvoice.class.php:533
Translate
Class to manage translations.
Definition: translate.class.php:30
CommonIncoterm
trait CommonIncoterm
Superclass for incoterm classes.
Definition: commonincoterm.class.php:29
CommonInvoice\TYPE_PROFORMA
const TYPE_PROFORMA
Proforma invoice.
Definition: commoninvoice.class.php:60
CommonInvoice\TYPE_SITUATION
const TYPE_SITUATION
Situation invoice.
Definition: commoninvoice.class.php:65
CommonInvoice\makeStripeSepaRequest
makeStripeSepaRequest($fuser, $did=0, $type='direct-debit', $sourcetype='facture')
Create a payment order for a prelevement_demande Then send the payment order to Stripe (for a direct ...
Definition: commoninvoice.class.php:889
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:1351
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:5834
CommonInvoice\buildSwitzerlandQRString
buildSwitzerlandQRString()
Build string for QR-Bill (Switzerland)
Definition: commoninvoice.class.php:1432
CommonInvoiceLine\$label
$label
Custom label of line.
Definition: commoninvoice.class.php:1555
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:2566
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:1785
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:245
CommonInvoice\getLibStatut
getLibStatut($mode=0, $alreadypaid=-1)
Return label of object status.
Definition: commoninvoice.class.php:576
Exception
CommonInvoice\getListIdAvoirFromInvoice
getListIdAvoirFromInvoice()
Returns array of credit note ids from the invoice.
Definition: commoninvoice.class.php:264
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:8911
CommonInvoice\STATUS_DRAFT
const STATUS_DRAFT
Draft status.
Definition: commoninvoice.class.php:70
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:771
CommonInvoice\STATUS_VALIDATED
const STATUS_VALIDATED
Validated (need to be paid)
Definition: commoninvoice.class.php:75
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1639
DiscountAbsolute
Class to manage absolute discounts.
Definition: discount.class.php:29
CommonInvoice\TYPE_REPLACEMENT
const TYPE_REPLACEMENT
Replacement invoice.
Definition: commoninvoice.class.php:44
CommonInvoiceLine\$ref
$ref
Definition: commoninvoice.class.php:1561
CommonInvoice\STATUS_ABANDONED
const STATUS_ABANDONED
Classified abandoned and no payment done.
Definition: commoninvoice.class.php:93
getDolGlobalString
if(!function_exists('utf8_encode')) if(!function_exists('utf8_decode')) getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
Definition: functions.lib.php:82
CommonInvoice\getSumDepositsUsed
getSumDepositsUsed($multicurrency=0)
Return amount (with tax) of all deposits invoices used by invoice.
Definition: commoninvoice.class.php:187
ref
$object ref
Definition: info.php:78
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:84
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:10767
CommonInvoice\getListOfPayments
getListOfPayments($filtertype='')
Return list of payments.
Definition: commoninvoice.class.php:330
CommonInvoiceLine
Parent class of all other business classes for details of elements (invoices, contracts,...
Definition: commoninvoice.class.php:1549
CommonObject\setPaymentMethods
setPaymentMethods($id)
Change the payments methods.
Definition: commonobject.class.php:2453
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:438
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2947
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:5708
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:592
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:672
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:2859
getDolGlobalInt
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
Definition: functions.lib.php:96
CommonInvoice\TYPE_CREDIT_NOTE
const TYPE_CREDIT_NOTE
Credit note invoice.
Definition: commoninvoice.class.php:49
type
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:119
Account
Class to manage bank accounts.
Definition: account.class.php:39
CommonInvoiceLine\$libelle
$libelle
Definition: commoninvoice.class.php:1566
if
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
Definition: journals_list.php:25