dolibarr  18.0.0
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 
898  public function makeStripeSepaRequest($fuser, $did = 0, $type = 'direct-debit', $sourcetype = 'facture')
899  {
900  global $conf, $mysoc, $user, $langs;
901 
902  if ($type != 'bank-transfer' && $type != 'credit-transfer' && empty($conf->global->STRIPE_SEPA_DIRECT_DEBIT)) {
903  return 0;
904  }
905  if ($type != 'direct-debit' && empty($conf->global->STRIPE_SEPA_CREDIT_TRANSFER)) {
906  return 0;
907  }
908 
909  $error = 0;
910 
911  dol_syslog(get_class($this)."::makeStripeSepaRequest start", LOG_DEBUG);
912 
913  if ($this->statut > self::STATUS_DRAFT && $this->paye == 0) {
914  // Get the default payment mode for BAN payment of the third party
915  require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php';
916  $bac = new CompanyBankAccount($this->db); // table societe_rib
917  $result = $bac->fetch(0, $this->socid, 1, 'ban');
918  if ($result <= 0 || empty($bac->id)) {
919  $this->error = $langs->trans("ThirdpartyHasNoDefaultBanAccount");
920  $this->errors[] = $this->error;
921  dol_syslog(get_class($this)."::makeStripeSepaRequest ".$this->error);
922  return -1;
923  }
924 
925  // Load the request to process
926  $sql = "SELECT rowid, date_demande, amount, fk_facture, fk_facture_fourn, fk_prelevement_bons";
927  $sql .= " FROM ".$this->db->prefix()."prelevement_demande";
928  $sql .= " WHERE rowid = ".((int) $did);
929  if ($type != 'bank-transfer' && $type != 'credit-transfer') {
930  $sql .= " AND fk_facture = ".((int) $this->id); // Add a protection to not pay another invoice than current one
931  }
932  if ($type != 'direct-debit') {
933  $sql .= " AND fk_facture_fourn = ".((int) $this->id); // Add a protection to not pay another invoice than current one
934  }
935  $sql .= " AND traite = 0"; // Add a protection to not process twice
936 
937  dol_syslog(get_class($this)."::makeStripeSepaRequest load requests to process", LOG_DEBUG);
938  $resql = $this->db->query($sql);
939  if ($resql) {
940  $obj = $this->db->fetch_object($resql);
941  if (!$obj) {
942  dol_print_error($this->db, 'CantFindRequestWithId');
943  return -2;
944  }
945 
946  // amount to pay
947  $amount = $obj->amount;
948 
949  if (is_numeric($amount) && $amount != 0) {
950  require_once DOL_DOCUMENT_ROOT.'/societe/class/companypaymentmode.class.php';
951  $companypaymentmode = new CompanyPaymentMode($this->db); // table societe_rib
952  $companypaymentmode->fetch($bac->id);
953 
954  // Start code for Stripe
955  // TODO We may have this coming as a parameter from the caller.
956  $service = 'StripeTest';
957  $servicestatus = 0;
958  if (!empty($conf->global->STRIPE_LIVE) && !GETPOST('forcesandbox', 'alpha')) {
959  $service = 'StripeLive';
960  $servicestatus = 1;
961  }
962 
963  dol_syslog("makeStripeSepaRequest amount = ".$amount." service=" . $service . " servicestatus=" . $servicestatus . " thirdparty_id=" . $this->socid." did=".$did);
964 
965  $this->stripechargedone = 0;
966  $this->stripechargeerror = 0;
967 
968  $now = dol_now();
969 
970  $currency = $conf->currency;
971 
972  global $stripearrayofkeysbyenv;
973 
974  $errorforinvoice = 0; // We reset the $errorforinvoice at each invoice loop
975 
976  $this->fetch_thirdparty();
977 
978  dol_syslog("--- Process payment request thirdparty_id=" . $this->thirdparty->id . ", thirdparty_name=" . $this->thirdparty->name . " ban id=" . $bac->id, LOG_DEBUG);
979 
980  //$alreadypayed = $this->getSommePaiement();
981  //$amount_credit_notes_included = $this->getSumCreditNotesUsed();
982  //$amounttopay = $this->total_ttc - $alreadypayed - $amount_credit_notes_included;
983  $amounttopay = $amount;
984 
985  // Correct the amount according to unit of currency
986  // See https://support.stripe.com/questions/which-zero-decimal-currencies-does-stripe-support
987  $arrayzerounitcurrency = ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF'];
988  $amountstripe = $amounttopay;
989  if (!in_array($currency, $arrayzerounitcurrency)) {
990  $amountstripe = $amountstripe * 100;
991  }
992 
993  $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.
994  if (!($fk_bank_account > 0)) {
995  $error++;
996  $errorforinvoice++;
997  dol_syslog("Error no bank account defined for Stripe payments", LOG_ERR);
998  $this->errors[] = "Error bank account for Stripe payments not defined into Stripe module";
999  }
1000 
1001  $this->db->begin();
1002 
1003  // Create a prelevement_bon
1004  require_once DOL_DOCUMENT_ROOT.'/compta/prelevement/class/bonprelevement.class.php';
1005  $bon = new BonPrelevement($this->db);
1006  if (!$error) {
1007  if (empty($obj->fk_prelevement_bons)) {
1008  // This create record into llx_prelevment_bons and update link with llx_prelevement_demande
1009  $nbinvoices = $bon->create(0, 0, 'real', 'ALL', '', 0, $type, $did, $fk_bank_account);
1010  if ($nbinvoices <= 0) {
1011  $error++;
1012  $errorforinvoice++;
1013  dol_syslog("Error on BonPrelevement creation", LOG_ERR);
1014  $this->errors[] = "Error on BonPrelevement creation";
1015  }
1016  /*
1017  if (!$error) {
1018  // Update the direct debit payment request of the processed request to save the id of the prelevement_bon
1019  $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_demande SET";
1020  $sql .= " fk_prelevement_bons = ".((int) $bon->id);
1021  $sql .= " WHERE rowid = ".((int) $did);
1022 
1023  $result = $this->db->query($sql);
1024  if ($result < 0) {
1025  $error++;
1026  $this->errors[] = "Error on updateing fk_prelevement_bons to ".$bon->id;
1027  }
1028  }
1029  */
1030  } else {
1031  $error++;
1032  $errorforinvoice++;
1033  dol_syslog("Error Line already part of a bank payment order", LOG_ERR);
1034  $this->errors[] = "The line is already included into a bank payment order. Delete the bank payment order first.";
1035  }
1036  }
1037 
1038  if (!$error) {
1039  if ($amountstripe > 0) {
1040  try {
1041  //var_dump($companypaymentmode);
1042  dol_syslog("We will try to pay with companypaymentmodeid=" . $companypaymentmode->id . " stripe_card_ref=" . $companypaymentmode->stripe_card_ref . " mode=" . $companypaymentmode->status, LOG_DEBUG);
1043 
1044  $thirdparty = new Societe($this->db);
1045  $resultthirdparty = $thirdparty->fetch($this->socid);
1046 
1047  include_once DOL_DOCUMENT_ROOT . '/stripe/class/stripe.class.php'; // This include the include of htdocs/stripe/config.php
1048  // So it inits or erases the $stripearrayofkeysbyenv
1049  $stripe = new Stripe($this->db);
1050 
1051  dol_syslog("makeStripeSepaRequest Current Stripe environment is " . $stripearrayofkeysbyenv[$servicestatus]['publishable_key']);
1052 
1053  $stripearrayofkeys = $stripearrayofkeysbyenv[$servicestatus];
1054  \Stripe\Stripe::setApiKey($stripearrayofkeys['secret_key']);
1055 
1056 
1057  dol_syslog("makeStripeSepaRequest get stripe connet account", LOG_DEBUG);
1058  $stripeacc = $stripe->getStripeAccount($service, $this->socid); // Get Stripe OAuth connect account if it exists (no network access here)
1059  dol_syslog("makeStripeSepaRequest get stripe connect account return " . json_encode($stripeacc), LOG_DEBUG);
1060 
1061  $customer = $stripe->customerStripe($thirdparty, $stripeacc, $servicestatus, 0);
1062  if (empty($customer) && !empty($stripe->error)) {
1063  $this->errors[] = $stripe->error;
1064  }
1065 
1066  // $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)
1067  // $nbdaysbeforeendoftries = (empty($conf->global->SELLYOURSAAS_NBDAYSBEFOREENDOFTRIES) ? 35 : $conf->global->SELLYOURSAAS_NBDAYSBEFOREENDOFTRIES);
1068  $postactionmessages = [];
1069 
1070  if ($resultthirdparty > 0 && !empty($customer)) {
1071  if (!$error) { // Payment was not canceled
1072  $stripecard = null;
1073  if ($companypaymentmode->type == 'ban') {
1074  // Check into societe_rib if a payment mode for Stripe and ban payment exists
1075  // To make a Stripe SEPA payment request, we must have the payment mode source already saved into societe_rib and retreived with ->sepaStripe
1076  // The payment mode source is created when we create the bank account on Stripe with paymentmodes.php?action=create
1077  $stripecard = $stripe->sepaStripe($customer, $companypaymentmode, $stripeacc, $servicestatus, 0);
1078  } else {
1079  $error++;
1080  $this->error = 'The payment mode type is not "ban"';
1081  }
1082 
1083  if ($stripecard) { // Can be src_... (for sepa) or pm_... (new card mode). Note that card_... (old card mode) should not happen here.
1084  $FULLTAG = 'DID='.$did.'-INV=' . $this->id . '-CUS=' . $thirdparty->id;
1085  $description = 'Stripe payment from makeStripeSepaRequest: ' . $FULLTAG . ' did='.$did.' ref=' . $this->ref;
1086 
1087  $stripefailurecode = '';
1088  $stripefailuremessage = '';
1089  $stripefailuredeclinecode = '';
1090 
1091  // Using new SCA method
1092  dol_syslog("* Create payment on SEPA " . $stripecard->id . ", amounttopay=" . $amounttopay . ", amountstripe=" . $amountstripe . ", FULLTAG=" . $FULLTAG, LOG_DEBUG);
1093 
1094  // Create payment intent and charge payment (confirmnow = true)
1095  $paymentintent = $stripe->getPaymentIntent($amounttopay, $currency, $FULLTAG, $description, $this, $customer->id, $stripeacc, $servicestatus, 0, 'automatic', true, $stripecard->id, 1, 1, $did);
1096 
1097  $charge = new stdClass();
1098 
1099  if ($paymentintent->status === 'succeeded' || $paymentintent->status === 'processing') {
1100  $charge->status = 'ok';
1101  $charge->id = $paymentintent->id;
1102  $charge->customer = $customer->id;
1103  } elseif ($paymentintent->status === 'requires_action') {
1104  //paymentintent->status may be => 'requires_action' (no error in such a case)
1105  dol_syslog(var_export($paymentintent, true), LOG_DEBUG);
1106 
1107  $charge->status = 'failed';
1108  $charge->customer = $customer->id;
1109  $charge->failure_code = $stripe->code;
1110  $charge->failure_message = $stripe->error;
1111  $charge->failure_declinecode = $stripe->declinecode;
1112  $stripefailurecode = $stripe->code;
1113  $stripefailuremessage = 'Action required. Contact the support at ';// . $conf->global->SELLYOURSAAS_MAIN_EMAIL;
1114  $stripefailuredeclinecode = $stripe->declinecode;
1115  } else {
1116  dol_syslog(var_export($paymentintent, true), LOG_DEBUG);
1117 
1118  $charge->status = 'failed';
1119  $charge->customer = $customer->id;
1120  $charge->failure_code = $stripe->code;
1121  $charge->failure_message = $stripe->error;
1122  $charge->failure_declinecode = $stripe->declinecode;
1123  $stripefailurecode = $stripe->code;
1124  $stripefailuremessage = $stripe->error;
1125  $stripefailuredeclinecode = $stripe->declinecode;
1126  }
1127 
1128  //var_dump("stripefailurecode=".$stripefailurecode." stripefailuremessage=".$stripefailuremessage." stripefailuredeclinecode=".$stripefailuredeclinecode);
1129  //exit;
1130 
1131 
1132  // Return $charge = array('id'=>'ch_XXXX', 'status'=>'succeeded|pending|failed', 'failure_code'=>, 'failure_message'=>...)
1133  if (empty($charge) || $charge->status == 'failed') {
1134  dol_syslog('Failed to charge payment mode ' . $stripecard->id . ' stripefailurecode=' . $stripefailurecode . ' stripefailuremessage=' . $stripefailuremessage . ' stripefailuredeclinecode=' . $stripefailuredeclinecode, LOG_WARNING);
1135 
1136  // Save a stripe payment was in error
1137  $this->stripechargeerror++;
1138 
1139  $error++;
1140  $errorforinvoice++;
1141  $errmsg = $langs->trans("FailedToChargeCard");
1142  if (!empty($charge)) {
1143  if ($stripefailuredeclinecode == 'authentication_required') {
1144  $errauthenticationmessage = $langs->trans("ErrSCAAuthentication");
1145  $errmsg = $errauthenticationmessage;
1146  } elseif (in_array($stripefailuredeclinecode, ['insufficient_funds', 'generic_decline'])) {
1147  $errmsg .= ': ' . $charge->failure_code;
1148  $errmsg .= ($charge->failure_message ? ' - ' : '') . ' ' . $charge->failure_message;
1149  if (empty($stripefailurecode)) {
1150  $stripefailurecode = $charge->failure_code;
1151  }
1152  if (empty($stripefailuremessage)) {
1153  $stripefailuremessage = $charge->failure_message;
1154  }
1155  } else {
1156  $errmsg .= ': failure_code=' . $charge->failure_code;
1157  $errmsg .= ($charge->failure_message ? ' - ' : '') . ' failure_message=' . $charge->failure_message;
1158  if (empty($stripefailurecode)) {
1159  $stripefailurecode = $charge->failure_code;
1160  }
1161  if (empty($stripefailuremessage)) {
1162  $stripefailuremessage = $charge->failure_message;
1163  }
1164  }
1165  } else {
1166  $errmsg .= ': ' . $stripefailurecode . ' - ' . $stripefailuremessage;
1167  $errmsg .= ($stripefailuredeclinecode ? ' - ' . $stripefailuredeclinecode : '');
1168  }
1169 
1170  $description = 'Stripe payment ERROR from makeStripeSepaRequest: ' . $FULLTAG;
1171  $postactionmessages[] = $errmsg . ' (' . $stripearrayofkeys['publishable_key'] . ')';
1172  $this->errors[] = $errmsg;
1173  } else {
1174  dol_syslog('Successfuly request '.$type.' '.$stripecard->id);
1175 
1176  $postactionmessages[] = 'Success to request '.$type.' (' . $charge->id . ' with ' . $stripearrayofkeys['publishable_key'] . ')';
1177 
1178  // Save a stripe payment was done in realy life so later we will be able to force a commit on recorded payments
1179  // even if in batch mode (method doTakePaymentStripe), we will always make all action in one transaction with a forced commit.
1180  $this->stripechargedone++;
1181 
1182  // Default description used for label of event. Will be overwrite by another value later.
1183  $description = 'Stripe payment request OK (' . $charge->id . ') from makeStripeSepaRequest: ' . $FULLTAG;
1184  }
1185 
1186  $object = $this;
1187 
1188  // Track an event
1189  if (empty($charge) || $charge->status == 'failed') {
1190  $actioncode = 'PAYMENT_STRIPE_KO';
1191  $extraparams = $stripefailurecode;
1192  $extraparams .= (($extraparams && $stripefailuremessage) ? ' - ' : '') . $stripefailuremessage;
1193  $extraparams .= (($extraparams && $stripefailuredeclinecode) ? ' - ' : '') . $stripefailuredeclinecode;
1194  } else {
1195  $actioncode = 'PAYMENT_STRIPE_OK';
1196  $extraparams = '';
1197  }
1198  } else {
1199  $error++;
1200  $errorforinvoice++;
1201  dol_syslog("No ban payment method found for this stripe customer " . $customer->id, LOG_WARNING);
1202  $this->errors[] = 'Failed to get direct debit payment method for stripe customer = ' . $customer->id;
1203 
1204  $description = 'Failed to find or use the payment mode - no ban defined for the thirdparty account';
1205  $stripefailurecode = 'BADPAYMENTMODE';
1206  $stripefailuremessage = 'Failed to find or use the payment mode - no ban defined for the thirdparty account';
1207  $postactionmessages[] = $description . ' (' . $stripearrayofkeys['publishable_key'] . ')';
1208 
1209  $object = $this;
1210 
1211  $actioncode = 'PAYMENT_STRIPE_KO';
1212  $extraparams = '';
1213  }
1214  } else {
1215  // If error because payment was canceled for a logical reason, we do nothing (no event added)
1216  $description = '';
1217  $stripefailurecode = '';
1218  $stripefailuremessage = '';
1219 
1220  $object = $this;
1221 
1222  $actioncode = '';
1223  $extraparams = '';
1224  }
1225  } else { // Else of the if ($resultthirdparty > 0 && ! empty($customer)) {
1226  if ($resultthirdparty <= 0) {
1227  dol_syslog('SellYourSaasUtils Failed to load customer for thirdparty_id = ' . $thirdparty->id, LOG_WARNING);
1228  $this->errors[] = 'Failed to load Stripe account for thirdparty_id = ' . $thirdparty->id;
1229  } else { // $customer stripe not found
1230  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);
1231  $this->errors[] = 'Failed to get Stripe account id for thirdparty_id = ' . $thirdparty->id . " in mode " . $servicestatus . " in Stripe env " . $stripearrayofkeysbyenv[$servicestatus]['publishable_key'];
1232  }
1233  $error++;
1234  $errorforinvoice++;
1235 
1236  $description = 'Failed to find or use your payment mode (no payment mode for this customer id)';
1237  $stripefailurecode = 'BADPAYMENTMODE';
1238  $stripefailuremessage = 'Failed to find or use your payment mode (no payment mode for this customer id)';
1239  $postactionmessages = [];
1240 
1241  $object = $this;
1242 
1243  $actioncode = 'PAYMENT_STRIPE_KO';
1244  $extraparams = '';
1245  }
1246 
1247  if ($description) {
1248  dol_syslog("* Record event for credit transfer or direct debit request result - " . $description);
1249  require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
1250 
1251  // Insert record of payment (success or error)
1252  $actioncomm = new ActionComm($this->db);
1253 
1254  $actioncomm->type_code = 'AC_OTH_AUTO'; // Type of event ('AC_OTH', 'AC_OTH_AUTO', 'AC_XXX'...)
1255  $actioncomm->code = 'AC_' . $actioncode;
1256  $actioncomm->label = $description;
1257  $actioncomm->note_private = join(",\n", $postactionmessages);
1258  $actioncomm->fk_project = $this->fk_project;
1259  $actioncomm->datep = $now;
1260  $actioncomm->datef = $now;
1261  $actioncomm->percentage = -1; // Not applicable
1262  $actioncomm->socid = $thirdparty->id;
1263  $actioncomm->contactid = 0;
1264  $actioncomm->authorid = $user->id; // User saving action
1265  $actioncomm->userownerid = $user->id; // Owner of action
1266  // Fields when action is a real email (content is already into note)
1267  /*$actioncomm->email_msgid = $object->email_msgid;
1268  $actioncomm->email_from = $object->email_from;
1269  $actioncomm->email_sender= $object->email_sender;
1270  $actioncomm->email_to = $object->email_to;
1271  $actioncomm->email_tocc = $object->email_tocc;
1272  $actioncomm->email_tobcc = $object->email_tobcc;
1273  $actioncomm->email_subject = $object->email_subject;
1274  $actioncomm->errors_to = $object->errors_to;*/
1275  $actioncomm->fk_element = $this->id;
1276  $actioncomm->elementtype = $this->element;
1277  $actioncomm->extraparams = dol_trunc($extraparams, 250);
1278 
1279  $actioncomm->create($user);
1280  }
1281 
1282  $this->description = $description;
1283  $this->postactionmessages = $postactionmessages;
1284  } catch (Exception $e) {
1285  $error++;
1286  $errorforinvoice++;
1287  dol_syslog('Error ' . $e->getMessage(), LOG_ERR);
1288  $this->errors[] = 'Error ' . $e->getMessage();
1289  }
1290  } else { // If remain to pay is null
1291  $error++;
1292  $errorforinvoice++;
1293  dol_syslog("Remain to pay is null for the invoice " . $this->id . " " . $this->ref . ". Why is the invoice not classified 'Paid' ?", LOG_WARNING);
1294  $this->errors[] = "Remain to pay is null for the invoice " . $this->id . " " . $this->ref . ". Why is the invoice not classified 'Paid' ?";
1295  }
1296  }
1297 
1298  // Set status of the order to "Transferred" with method 'api'
1299  if (!$error && !$errorforinvoice) {
1300  $result = $bon->set_infotrans($user, $now, 3);
1301  if ($result < 0) {
1302  $error++;
1303  $errorforinvoice++;
1304  dol_syslog("Error on BonPrelevement creation", LOG_ERR);
1305  $this->errors[] = "Error on BonPrelevement creation";
1306  }
1307  }
1308 
1309  if (!$error && !$errorforinvoice) {
1310  // Update the direct debit payment request of the processed invoice to save the id of the prelevement_bon
1311  $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_demande SET";
1312  $sql .= " ext_payment_id = '".$this->db->escape($paymentintent->id)."',";
1313  $sql .= " ext_payment_site = '".$this->db->escape($service)."'";
1314  $sql .= " WHERE rowid = ".((int) $did);
1315 
1316  dol_syslog(get_class($this)."::makeStripeSepaRequest update to save stripe paymentintent ids", LOG_DEBUG);
1317  $resql = $this->db->query($sql);
1318  if (!$resql) {
1319  $this->error = $this->db->lasterror();
1320  dol_syslog(get_class($this).'::makeStripeSepaRequest Erreur');
1321  $error++;
1322  }
1323  }
1324 
1325  if (!$error && !$errorforinvoice) {
1326  $this->db->commit();
1327  } else {
1328  $this->db->rollback();
1329  }
1330  } else {
1331  $this->error = 'WithdrawRequestErrorNilAmount';
1332  dol_syslog(get_class($this).'::makeStripeSepaRequest WithdrawRequestErrorNilAmount');
1333  $error++;
1334  }
1335 
1336  /*
1337  if (!$error) {
1338  // Force payment mode of the invoice to withdraw
1339  $payment_mode_id = dol_getIdFromCode($this->db, ($type == 'bank-transfer' ? 'VIR' : 'PRE'), 'c_paiement', 'code', 'id', 1);
1340  if ($payment_mode_id > 0) {
1341  $result = $this->setPaymentMethods($payment_mode_id);
1342  }
1343  }*/
1344 
1345  if ($error) {
1346  return -1;
1347  }
1348  return 1;
1349  } else {
1350  $this->error = $this->db->error();
1351  dol_syslog(get_class($this).'::makeStripeSepaRequest Erreur -2');
1352  return -2;
1353  }
1354  } else {
1355  $this->error = "Status of invoice does not allow this";
1356  dol_syslog(get_class($this)."::makeStripeSepaRequest ".$this->error." $this->statut, $this->paye, $this->mode_reglement_id");
1357  return -3;
1358  }
1359  }
1360 
1361  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1369  public function demande_prelevement_delete($fuser, $did)
1370  {
1371  // phpcs:enable
1372  $sql = 'DELETE FROM '.$this->db->prefix().'prelevement_demande';
1373  $sql .= ' WHERE rowid = '.((int) $did);
1374  $sql .= ' AND traite = 0';
1375  if ($this->db->query($sql)) {
1376  return 0;
1377  } else {
1378  $this->error = $this->db->lasterror();
1379  dol_syslog(get_class($this).'::demande_prelevement_delete Error '.$this->error);
1380  return -1;
1381  }
1382  }
1383 
1384 
1390  public function buildZATCAQRString()
1391  {
1392  global $conf, $mysoc;
1393 
1394  $tmplang = new Translate('', $conf);
1395  $tmplang->setDefaultLang('en_US');
1396  $tmplang->load("main");
1397 
1398  $datestring = dol_print_date($this->date, 'dayhourrfc');
1399  //$pricewithtaxstring = price($this->total_ttc, 0, $tmplang, 0, -1, 2);
1400  //$pricetaxstring = price($this->total_tva, 0, $tmplang, 0, -1, 2);
1401  $pricewithtaxstring = price2num($this->total_ttc, 2, 1);
1402  $pricetaxstring = price2num($this->total_tva, 2, 1);
1403 
1404  /*
1405  $name = implode(unpack("H*", $this->thirdparty->name));
1406  $vatnumber = implode(unpack("H*", $this->thirdparty->tva_intra));
1407  $date = implode(unpack("H*", $datestring));
1408  $pricewithtax = implode(unpack("H*", price2num($pricewithtaxstring, 2)));
1409  $pricetax = implode(unpack("H*", $pricetaxstring));
1410 
1411  //var_dump(strlen($this->thirdparty->name));
1412  //var_dump(str_pad(dechex('9'), 2, '0', STR_PAD_LEFT));
1413  //var_dump($this->thirdparty->name);
1414  //var_dump(implode(unpack("H*", $this->thirdparty->name)));
1415  //var_dump(price($this->total_tva, 0, $tmplang, 0, -1, 2));
1416 
1417  $s = '01'.str_pad(dechex(strlen($this->thirdparty->name)), 2, '0', STR_PAD_LEFT).$name;
1418  $s .= '02'.str_pad(dechex(strlen($this->thirdparty->tva_intra)), 2, '0', STR_PAD_LEFT).$vatnumber;
1419  $s .= '03'.str_pad(dechex(strlen($datestring)), 2, '0', STR_PAD_LEFT).$date;
1420  $s .= '04'.str_pad(dechex(strlen($pricewithtaxstring)), 2, '0', STR_PAD_LEFT).$pricewithtax;
1421  $s .= '05'.str_pad(dechex(strlen($pricetaxstring)), 2, '0', STR_PAD_LEFT).$pricetax;
1422  $s .= ''; // Hash of xml invoice
1423  $s .= ''; // ecda signature
1424  $s .= ''; // ecda public key
1425  $s .= ''; // ecda signature of public key stamp
1426  */
1427 
1428  // Using TLV format
1429  $s = pack('C1', 1).pack('C1', strlen($mysoc->name)).$mysoc->name;
1430  $s .= pack('C1', 2).pack('C1', strlen($mysoc->tva_intra)).$mysoc->tva_intra;
1431  $s .= pack('C1', 3).pack('C1', strlen($datestring)).$datestring;
1432  $s .= pack('C1', 4).pack('C1', strlen($pricewithtaxstring)).$pricewithtaxstring;
1433  $s .= pack('C1', 5).pack('C1', strlen($pricetaxstring)).$pricetaxstring;
1434  $s .= ''; // Hash of xml invoice
1435  $s .= ''; // ecda signature
1436  $s .= ''; // ecda public key
1437  $s .= ''; // ecda signature of public key stamp
1438 
1439  $s = base64_encode($s);
1440 
1441  return $s;
1442  }
1443 
1444 
1450  public function buildSwitzerlandQRString()
1451  {
1452  global $conf, $mysoc;
1453 
1454  $tmplang = new Translate('', $conf);
1455  $tmplang->setDefaultLang('en_US');
1456  $tmplang->load("main");
1457 
1458  $pricewithtaxstring = price2num($this->total_ttc, 2, 1);
1459  $pricetaxstring = price2num($this->total_tva, 2, 1);
1460 
1461  $complementaryinfo = '';
1462  /*
1463  Example: //S1/10/10201409/11/190512/20/1400.000-53/30/106017086/31/180508/32/7.7/40/2:10;0:30
1464  /10/ Numéro de facture – 10201409
1465  /11/ Date de facture – 12.05.2019
1466  /20/ Référence client – 1400.000-53
1467  /30/ Numéro IDE pour la TVA – CHE-106.017.086 TVA
1468  /31/ Date de la prestation pour la comptabilisation de la TVA – 08.05.2018
1469  /32/ Taux de TVA sur le montant total de la facture – 7.7%
1470  /40/ Conditions – 2% d’escompte à 10 jours, paiement net à 30 jours
1471  */
1472  $datestring = dol_print_date($this->date, '%y%m%d');
1473  //$pricewithtaxstring = price($this->total_ttc, 0, $tmplang, 0, -1, 2);
1474  //$pricetaxstring = price($this->total_tva, 0, $tmplang, 0, -1, 2);
1475  $complementaryinfo = '//S1/10/'.str_replace('/', '', $this->ref).'/11/'.$datestring;
1476  if ($this->ref_client) {
1477  $complementaryinfo .= '/20/'.$this->ref_client;
1478  }
1479  if ($this->thirdparty->tva_intra) {
1480  $complementaryinfo .= '/30/'.$this->thirdparty->tva_intra;
1481  }
1482 
1483  include_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
1484  $bankaccount = new Account($this->db);
1485 
1486  // Header
1487  $s = '';
1488  $s .= "SPC\n";
1489  $s .= "0200\n";
1490  $s .= "1\n";
1491  // Info Seller ("Compte / Payable à")
1492  if ($this->fk_account > 0) {
1493  // Bank BAN if country is LI or CH. TODO Add a test to check than IBAN start with CH or LI
1494  $bankaccount->fetch($this->fk_account);
1495  $s .= $bankaccount->iban."\n";
1496  } else {
1497  $s .= "\n";
1498  }
1499  if ($bankaccount->id > 0 && getDolGlobalString('PDF_SWISS_QRCODE_USE_OWNER_OF_ACCOUNT_AS_CREDITOR')) {
1500  // If a bank account is prodived and we ask to use it as creditor, we use the bank address
1501  // 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 ?
1502  $s .= "S\n";
1503  $s .= dol_trunc($bankaccount->proprio, 70, 'right', 'UTF-8', 1)."\n";
1504  $addresslinearray = explode("\n", $bankaccount->owner_address);
1505  $s .= dol_trunc(empty($addresslinearray[1]) ? '' : $addresslinearray[1], 70, 'right', 'UTF-8', 1)."\n"; // address line 1
1506  $s .= dol_trunc(empty($addresslinearray[2]) ? '' : $addresslinearray[2], 70, 'right', 'UTF-8', 1)."\n"; // address line 2
1507  /*$s .= dol_trunc($mysoc->zip, 16, 'right', 'UTF-8', 1)."\n";
1508  $s .= dol_trunc($mysoc->town, 35, 'right', 'UTF-8', 1)."\n";
1509  $s .= dol_trunc($mysoc->country_code, 2, 'right', 'UTF-8', 1)."\n";*/
1510  } else {
1511  $s .= "S\n";
1512  $s .= dol_trunc($mysoc->name, 70, 'right', 'UTF-8', 1)."\n";
1513  $addresslinearray = explode("\n", $mysoc->address);
1514  $s .= dol_trunc(empty($addresslinearray[1]) ? '' : $addresslinearray[1], 70, 'right', 'UTF-8', 1)."\n"; // address line 1
1515  $s .= dol_trunc(empty($addresslinearray[2]) ? '' : $addresslinearray[2], 70, 'right', 'UTF-8', 1)."\n"; // address line 2
1516  $s .= dol_trunc($mysoc->zip, 16, 'right', 'UTF-8', 1)."\n";
1517  $s .= dol_trunc($mysoc->town, 35, 'right', 'UTF-8', 1)."\n";
1518  $s .= dol_trunc($mysoc->country_code, 2, 'right', 'UTF-8', 1)."\n";
1519  }
1520  // Final seller (Ultimate seller) ("Créancier final" = "En faveur de")
1521  $s .= "\n";
1522  $s .= "\n";
1523  $s .= "\n";
1524  $s .= "\n";
1525  $s .= "\n";
1526  $s .= "\n";
1527  $s .= "\n";
1528  // Amount of payment (to do?)
1529  $s .= price($pricewithtaxstring, 0, 'none', 0, 0, 2)."\n";
1530  $s .= ($this->multicurrency_code ? $this->multicurrency_code : $conf->currency)."\n";
1531  // Buyer
1532  $s .= "S\n";
1533  $s .= dol_trunc($this->thirdparty->name, 70, 'right', 'UTF-8', 1)."\n";
1534  $addresslinearray = explode("\n", $this->thirdparty->address);
1535  $s .= dol_trunc(empty($addresslinearray[1]) ? '' : $addresslinearray[1], 70, 'right', 'UTF-8', 1)."\n"; // address line 1
1536  $s .= dol_trunc(empty($addresslinearray[2]) ? '' : $addresslinearray[2], 70, 'right', 'UTF-8', 1)."\n"; // address line 2
1537  $s .= dol_trunc($this->thirdparty->zip, 16, 'right', 'UTF-8', 1)."\n";
1538  $s .= dol_trunc($this->thirdparty->town, 35, 'right', 'UTF-8', 1)."\n";
1539  $s .= dol_trunc($this->thirdparty->country_code, 2, 'right', 'UTF-8', 1)."\n";
1540  // ID of payment
1541  $s .= "NON\n"; // NON or QRR
1542  $s .= "\n"; // QR Code reference if previous field is QRR
1543  // Free text
1544  if ($complementaryinfo) {
1545  $s .= $complementaryinfo."\n";
1546  } else {
1547  $s .= "\n";
1548  }
1549  $s .= "EPD\n";
1550  // More text, complementary info
1551  if ($complementaryinfo) {
1552  $s .= $complementaryinfo."\n";
1553  }
1554  $s .= "\n";
1555  //var_dump($s);exit;
1556  return $s;
1557  }
1558 }
1559 
1560 
1561 
1562 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
1563 
1567 abstract class CommonInvoiceLine extends CommonObjectLine
1568 {
1573  public $label;
1574 
1579  public $ref; // Product ref (deprecated)
1584  public $libelle; // Product label (deprecated)
1585 
1590  public $product_type = 0;
1591 
1596  public $product_ref;
1597 
1602  public $product_label;
1603 
1608  public $product_desc;
1609 
1614  public $qty;
1615 
1620  public $subprice;
1621 
1627  public $price;
1628 
1633  public $fk_product;
1634 
1639  public $vat_src_code;
1640 
1645  public $tva_tx;
1646 
1651  public $localtax1_tx;
1652 
1657  public $localtax2_tx;
1658 
1663  public $localtax1_type;
1664 
1669  public $localtax2_type;
1670 
1675  public $remise_percent;
1676 
1682  public $remise;
1683 
1688  public $total_ht;
1689 
1694  public $total_tva;
1695 
1700  public $total_localtax1;
1701 
1706  public $total_localtax2;
1707 
1712  public $total_ttc;
1713 
1714  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
1715  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
1716 
1717  public $buy_price_ht;
1718  public $buyprice; // For backward compatibility
1719  public $pa_ht; // For backward compatibility
1720 
1721  public $marge_tx;
1722  public $marque_tx;
1723 
1730  public $info_bits = 0;
1731 
1732  public $special_code = 0;
1733 
1734  public $fk_multicurrency;
1735  public $multicurrency_code;
1736  public $multicurrency_subprice;
1737  public $multicurrency_total_ht;
1738  public $multicurrency_total_tva;
1739  public $multicurrency_total_ttc;
1740 
1741  public $fk_user_author;
1742  public $fk_user_modif;
1743 
1744  public $fk_accounting_account;
1745 }
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:1390
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\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\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
CommonInvoice\makeStripeSepaRequest
makeStripeSepaRequest($fuser, $did=0, $type='direct-debit', $sourcetype='facture')
Create a payment order into prelevement_demande then send the payment order to Stripe (for a direct d...
Definition: commoninvoice.class.php:898
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:1369
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:1450
CommonInvoiceLine\$label
$label
Custom label of line.
Definition: commoninvoice.class.php:1573
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:1634
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:1579
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:1567
CommonObject\setPaymentMethods
setPaymentMethods($id)
Change the payments methods.
Definition: commonobject.class.php:2330
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:1584
if
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
Definition: journals_list.php:25