dolibarr  18.0.0-alpha
commande.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2003-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2005-2014 Regis Houssin <regis.houssin@inodbox.com>
5  * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
6  * Copyright (C) 2010-2020 Juanjo Menent <jmenent@2byte.es>
7  * Copyright (C) 2011 Jean Heimburger <jean@tiaris.info>
8  * Copyright (C) 2012-2014 Christophe Battarel <christophe.battarel@altairis.fr>
9  * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
10  * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
11  * Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
12  * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
13  * Copyright (C) 2016-2022 Ferran Marcet <fmarcet@2byte.es>
14  * Copyright (C) 2021-2023 Frédéric France <frederic.france@netlogic.fr>
15  * Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program. If not, see <https://www.gnu.org/licenses/>.
29  */
30 
36 include_once DOL_DOCUMENT_ROOT.'/core/class/commonorder.class.php';
37 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
38 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
39 require_once DOL_DOCUMENT_ROOT.'/margin/lib/margins.lib.php';
40 require_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
41 
42 
46 class Commande extends CommonOrder
47 {
51  public $element = 'commande';
52 
56  public $table_element = 'commande';
57 
61  public $table_element_line = 'commandedet';
62 
66  public $class_element_line = 'OrderLine';
67 
71  public $fk_element = 'fk_commande';
72 
76  public $picto = 'order';
77 
82  public $ismultientitymanaged = 1;
83 
88  public $restrictiononfksoc = 1;
89 
93  protected $table_ref_field = 'ref';
94 
98  public $socid;
99 
103  public $ref_client;
104 
108  public $contactid;
109 
114  public $statut;
115 
119  public $billed;
120 
124  public $brouillon;
125 
129  public $cond_reglement_code;
130 
134  public $deposit_percent;
135 
139  public $fk_account;
140 
144  public $mode_reglement;
145 
149  public $mode_reglement_id;
150 
154  public $mode_reglement_code;
155 
160  public $availability_id;
161 
166  public $availability_code;
167 
172  public $availability;
173 
177  public $demand_reason_id;
178 
182  public $demand_reason_code;
183 
187  public $date;
188 
194  public $date_commande;
195 
201  public $date_livraison;
202 
206  public $delivery_date;
207 
211  public $fk_remise_except;
212 
213  public $remise_percent;
214  public $remise_absolue;
215  public $info_bits;
216  public $rang;
217  public $special_code;
218  public $source; // Order mode. How we received order (by phone, by email, ...)
219 
223  public $warehouse_id;
224 
225  public $extraparams = array();
226 
227  public $linked_objects = array();
228 
232  public $user_author_id;
233 
237  public $user_valid;
238 
242  public $line;
243 
247  public $lines = array();
248 
249  // Multicurrency
253  public $fk_multicurrency;
254 
258  public $multicurrency_code;
259  public $multicurrency_tx;
260  public $multicurrency_total_ht;
261  public $multicurrency_total_tva;
262  public $multicurrency_total_ttc;
263 
267  public $pos_source;
268 
272  public $expeditions;
273 
277  public $online_payment_url;
278 
279 
304  // BEGIN MODULEBUILDER PROPERTIES
308  public $fields = array(
309  'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
310  'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>20, 'index'=>1),
311  'ref' =>array('type'=>'varchar(30)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'showoncombobox'=>1, 'position'=>25),
312  'ref_ext' =>array('type'=>'varchar(255)', 'label'=>'RefExt', 'enabled'=>1, 'visible'=>0, 'position'=>26),
313  'ref_client' =>array('type'=>'varchar(255)', 'label'=>'RefCustomer', 'enabled'=>1, 'visible'=>-1, 'position'=>28),
314  'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>'isModEnabled("societe")', 'visible'=>-1, 'notnull'=>1, 'position'=>20),
315  'fk_projet' =>array('type'=>'integer:Project:projet/class/project.class.php:1:(fk_statut:=:1)', 'label'=>'Project', 'enabled'=>"isModEnabled('project')", 'visible'=>-1, 'position'=>25),
316  'date_commande' =>array('type'=>'date', 'label'=>'Date', 'enabled'=>1, 'visible'=>1, 'position'=>60),
317  'date_valid' =>array('type'=>'datetime', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>62),
318  'date_cloture' =>array('type'=>'datetime', 'label'=>'DateClosing', 'enabled'=>1, 'visible'=>-1, 'position'=>65),
319  'fk_user_valid' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>85),
320  'fk_user_cloture' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserClosing', 'enabled'=>1, 'visible'=>-1, 'position'=>90),
321  'source' =>array('type'=>'smallint(6)', 'label'=>'Source', 'enabled'=>1, 'visible'=>-1, 'position'=>95),
322  //'amount_ht' =>array('type'=>'double(24,8)', 'label'=>'AmountHT', 'enabled'=>1, 'visible'=>-1, 'position'=>105),
323  'remise_percent' =>array('type'=>'double', 'label'=>'RelativeDiscount', 'enabled'=>1, 'visible'=>-1, 'position'=>110),
324  'remise_absolue' =>array('type'=>'double', 'label'=>'CustomerRelativeDiscount', 'enabled'=>1, 'visible'=>-1, 'position'=>115),
325  //'remise' =>array('type'=>'double', 'label'=>'Remise', 'enabled'=>1, 'visible'=>-1, 'position'=>120),
326  'total_tva' =>array('type'=>'double(24,8)', 'label'=>'VAT', 'enabled'=>1, 'visible'=>-1, 'position'=>125, 'isameasure'=>1),
327  'localtax1' =>array('type'=>'double(24,8)', 'label'=>'LocalTax1', 'enabled'=>1, 'visible'=>-1, 'position'=>130, 'isameasure'=>1),
328  'localtax2' =>array('type'=>'double(24,8)', 'label'=>'LocalTax2', 'enabled'=>1, 'visible'=>-1, 'position'=>135, 'isameasure'=>1),
329  'total_ht' =>array('type'=>'double(24,8)', 'label'=>'TotalHT', 'enabled'=>1, 'visible'=>-1, 'position'=>140, 'isameasure'=>1),
330  'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'TotalTTC', 'enabled'=>1, 'visible'=>-1, 'position'=>145, 'isameasure'=>1),
331  'note_private' =>array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>150),
332  'note_public' =>array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>155),
333  'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'PDFTemplate', 'enabled'=>1, 'visible'=>0, 'position'=>160),
334  //'facture' =>array('type'=>'tinyint(4)', 'label'=>'ParentInvoice', 'enabled'=>1, 'visible'=>-1, 'position'=>165),
335  'fk_account' =>array('type'=>'integer', 'label'=>'BankAccount', 'enabled'=>'$conf->banque->enabled', 'visible'=>-1, 'position'=>170),
336  'fk_currency' =>array('type'=>'varchar(3)', 'label'=>'MulticurrencyID', 'enabled'=>1, 'visible'=>-1, 'position'=>175),
337  'fk_cond_reglement' =>array('type'=>'integer', 'label'=>'PaymentTerm', 'enabled'=>1, 'visible'=>-1, 'position'=>180),
338  'deposit_percent' =>array('type'=>'varchar(63)', 'label'=>'DepositPercent', 'enabled'=>1, 'visible'=>-1, 'position'=>181),
339  'fk_mode_reglement' =>array('type'=>'integer', 'label'=>'PaymentMode', 'enabled'=>1, 'visible'=>-1, 'position'=>185),
340  'date_livraison' =>array('type'=>'date', 'label'=>'DateDeliveryPlanned', 'enabled'=>1, 'visible'=>-1, 'position'=>190),
341  'fk_shipping_method' =>array('type'=>'integer', 'label'=>'ShippingMethod', 'enabled'=>1, 'visible'=>-1, 'position'=>195),
342  'fk_warehouse' =>array('type'=>'integer:Entrepot:product/stock/class/entrepot.class.php', 'label'=>'Fk warehouse', 'enabled'=>'$conf->stock->enabled', 'visible'=>-1, 'position'=>200),
343  'fk_availability' =>array('type'=>'integer', 'label'=>'Availability', 'enabled'=>1, 'visible'=>-1, 'position'=>205),
344  'fk_input_reason' =>array('type'=>'integer', 'label'=>'InputReason', 'enabled'=>1, 'visible'=>-1, 'position'=>210),
345  //'fk_delivery_address' =>array('type'=>'integer', 'label'=>'DeliveryAddress', 'enabled'=>1, 'visible'=>-1, 'position'=>215),
346  'extraparams' =>array('type'=>'varchar(255)', 'label'=>'Extraparams', 'enabled'=>1, 'visible'=>-1, 'position'=>225),
347  'fk_incoterms' =>array('type'=>'integer', 'label'=>'IncotermCode', 'enabled'=>'$conf->incoterm->enabled', 'visible'=>-1, 'position'=>230),
348  'location_incoterms' =>array('type'=>'varchar(255)', 'label'=>'IncotermLabel', 'enabled'=>'$conf->incoterm->enabled', 'visible'=>-1, 'position'=>235),
349  'fk_multicurrency' =>array('type'=>'integer', 'label'=>'Fk multicurrency', 'enabled'=>'isModEnabled("multicurrency")', 'visible'=>-1, 'position'=>240),
350  'multicurrency_code' =>array('type'=>'varchar(255)', 'label'=>'MulticurrencyCurrency', 'enabled'=>'isModEnabled("multicurrency")', 'visible'=>-1, 'position'=>245),
351  'multicurrency_tx' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyRate', 'enabled'=>'isModEnabled("multicurrency")', 'visible'=>-1, 'position'=>250, 'isameasure'=>1),
352  'multicurrency_total_ht' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyAmountHT', 'enabled'=>'isModEnabled("multicurrency")', 'visible'=>-1, 'position'=>255, 'isameasure'=>1),
353  'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyAmountVAT', 'enabled'=>'isModEnabled("multicurrency")', 'visible'=>-1, 'position'=>260, 'isameasure'=>1),
354  'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyAmountTTC', 'enabled'=>'isModEnabled("multicurrency")', 'visible'=>-1, 'position'=>265, 'isameasure'=>1),
355  'last_main_doc' =>array('type'=>'varchar(255)', 'label'=>'LastMainDoc', 'enabled'=>1, 'visible'=>-1, 'position'=>270),
356  'module_source' =>array('type'=>'varchar(32)', 'label'=>'POSModule', 'enabled'=>1, 'visible'=>-1, 'position'=>275),
357  'pos_source' =>array('type'=>'varchar(32)', 'label'=>'POSTerminal', 'enabled'=>1, 'visible'=>-1, 'position'=>280),
358  'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-1, 'position'=>300),
359  'fk_user_modif' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>302),
360  'date_creation' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>304),
361  'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>306),
362  'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>400),
363  'fk_statut' =>array('type'=>'smallint(6)', 'label'=>'Status', 'enabled'=>1, 'visible'=>-1, 'position'=>500),
364  );
365  // END MODULEBUILDER PROPERTIES
366 
371 
375  const STATUS_CANCELED = -1;
379  const STATUS_DRAFT = 0;
383  const STATUS_VALIDATED = 1;
388  const STATUS_ACCEPTED = 2; // For backward compatibility. Use key STATUS_SHIPMENTONPROCESS instead.
389 
393  const STATUS_CLOSED = 3;
394 
395 
401  public function __construct($db)
402  {
403  $this->db = $db;
404  }
405 
413  public function getNextNumRef($soc)
414  {
415  global $langs, $conf;
416  $langs->load("order");
417 
418  if (!empty($conf->global->COMMANDE_ADDON)) {
419  $mybool = false;
420 
421  $file = $conf->global->COMMANDE_ADDON.".php";
422  $classname = $conf->global->COMMANDE_ADDON;
423 
424  // Include file with class
425  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
426  foreach ($dirmodels as $reldir) {
427  $dir = dol_buildpath($reldir."core/modules/commande/");
428 
429  // Load file with numbering class (if found)
430  $mybool |= @include_once $dir.$file;
431  }
432 
433  if ($mybool === false) {
434  dol_print_error('', "Failed to include file ".$file);
435  return '';
436  }
437 
438  $obj = new $classname();
439  $numref = $obj->getNextValue($soc, $this);
440 
441  if ($numref != "") {
442  return $numref;
443  } else {
444  $this->error = $obj->error;
445  //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
446  return "";
447  }
448  } else {
449  print $langs->trans("Error")." ".$langs->trans("Error_COMMANDE_ADDON_NotDefined");
450  return "";
451  }
452  }
453 
454 
463  public function valid($user, $idwarehouse = 0, $notrigger = 0)
464  {
465  global $conf, $langs;
466 
467  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
468 
469  $error = 0;
470 
471  // Protection
472  if ($this->statut == self::STATUS_VALIDATED) {
473  dol_syslog(get_class($this)."::valid action abandonned: already validated", LOG_WARNING);
474  return 0;
475  }
476 
477  if (!((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->creer))
478  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->order_advance->validate)))) {
479  $this->error = 'NotEnoughPermissions';
480  dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
481  return -1;
482  }
483 
484  $now = dol_now();
485 
486  $this->db->begin();
487 
488  // Definition du nom de module de numerotation de commande
489  $soc = new Societe($this->db);
490  $soc->fetch($this->socid);
491 
492  // Class of company linked to order
493  $result = $soc->set_as_client();
494 
495  // Define new ref
496  if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
497  $num = $this->getNextNumRef($soc);
498  } else {
499  $num = $this->ref;
500  }
501  $this->newref = dol_sanitizeFileName($num);
502 
503  // Validate
504  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
505  $sql .= " SET ref = '".$this->db->escape($num)."',";
506  $sql .= " fk_statut = ".self::STATUS_VALIDATED.",";
507  $sql .= " date_valid='".$this->db->idate($now)."',";
508  $sql .= " fk_user_valid = ".($user->id > 0 ? (int) $user->id : "null").",";
509  $sql .= " fk_user_modif = ".((int) $user->id);
510  $sql .= " WHERE rowid = ".((int) $this->id);
511 
512  dol_syslog(get_class($this)."::valid", LOG_DEBUG);
513  $resql = $this->db->query($sql);
514  if (!$resql) {
515  dol_print_error($this->db);
516  $this->error = $this->db->lasterror();
517  $error++;
518  }
519 
520  if (!$error) {
521  // If stock is incremented on validate order, we must increment it
522  if ($result >= 0 && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1) {
523  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
524  $langs->load("agenda");
525 
526  // Loop on each line
527  $cpt = count($this->lines);
528  for ($i = 0; $i < $cpt; $i++) {
529  if ($this->lines[$i]->fk_product > 0) {
530  $mouvP = new MouvementStock($this->db);
531  $mouvP->origin = &$this;
532  $mouvP->setOrigin($this->element, $this->id);
533  // We decrement stock of product (and sub-products)
534  $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("OrderValidatedInDolibarr", $num));
535  if ($result < 0) {
536  $error++;
537  $this->error = $mouvP->error;
538  }
539  }
540  if ($error) {
541  break;
542  }
543  }
544  }
545  }
546 
547  if (!$error && !$notrigger) {
548  // Call trigger
549  $result = $this->call_trigger('ORDER_VALIDATE', $user);
550  if ($result < 0) {
551  $error++;
552  }
553  // End call triggers
554  }
555 
556  if (!$error) {
557  $this->oldref = $this->ref;
558 
559  // Rename directory if dir was a temporary ref
560  if (preg_match('/^[\(]?PROV/i', $this->ref)) {
561  // Now we rename also files into index
562  $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'commande/".$this->db->escape($this->newref)."'";
563  $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'commande/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
564  $resql = $this->db->query($sql);
565  if (!$resql) {
566  $error++; $this->error = $this->db->lasterror();
567  }
568 
569  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
570  $oldref = dol_sanitizeFileName($this->ref);
571  $newref = dol_sanitizeFileName($num);
572  $dirsource = $conf->commande->multidir_output[$this->entity].'/'.$oldref;
573  $dirdest = $conf->commande->multidir_output[$this->entity].'/'.$newref;
574  if (!$error && file_exists($dirsource)) {
575  dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
576 
577  if (@rename($dirsource, $dirdest)) {
578  dol_syslog("Rename ok");
579  // Rename docs starting with $oldref with $newref
580  $listoffiles = dol_dir_list($conf->commande->multidir_output[$this->entity].'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
581  foreach ($listoffiles as $fileentry) {
582  $dirsource = $fileentry['name'];
583  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
584  $dirsource = $fileentry['path'].'/'.$dirsource;
585  $dirdest = $fileentry['path'].'/'.$dirdest;
586  @rename($dirsource, $dirdest);
587  }
588  }
589  }
590  }
591  }
592 
593  // Set new ref and current status
594  if (!$error) {
595  $this->ref = $num;
596  $this->statut = self::STATUS_VALIDATED;
597  $this->brouillon = 0;
598  }
599 
600  if (!$error) {
601  $this->db->commit();
602  return 1;
603  } else {
604  $this->db->rollback();
605  return -1;
606  }
607  }
608 
609  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
617  public function setDraft($user, $idwarehouse = -1)
618  {
619  //phpcs:enable
620  global $conf, $langs;
621 
622  $error = 0;
623 
624  // Protection
625  if ($this->statut <= self::STATUS_DRAFT) {
626  return 0;
627  }
628 
629  if (!((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->creer))
630  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->order_advance->validate)))) {
631  $this->error = 'Permission denied';
632  return -1;
633  }
634 
635  dol_syslog(__METHOD__, LOG_DEBUG);
636 
637  $this->db->begin();
638 
639  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
640  $sql .= " SET fk_statut = ".self::STATUS_DRAFT.",";
641  $sql .= " fk_user_modif = ".((int) $user->id);
642  $sql .= " WHERE rowid = ".((int) $this->id);
643 
644  if ($this->db->query($sql)) {
645  if (!$error) {
646  $this->oldcopy = clone $this;
647  }
648 
649  // If stock is decremented on validate order, we must reincrement it
650  if (isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1) {
651  $result = 0;
652 
653  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
654  $langs->load("agenda");
655 
656  $num = count($this->lines);
657  for ($i = 0; $i < $num; $i++) {
658  if ($this->lines[$i]->fk_product > 0) {
659  $mouvP = new MouvementStock($this->db);
660  $mouvP->origin = &$this;
661  $mouvP->setOrigin($this->element, $this->id);
662  // We increment stock of product (and sub-products)
663  $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("OrderBackToDraftInDolibarr", $this->ref));
664  if ($result < 0) {
665  $error++; $this->error = $mouvP->error; break;
666  }
667  }
668  }
669  }
670 
671  if (!$error) {
672  // Call trigger
673  $result = $this->call_trigger('ORDER_UNVALIDATE', $user);
674  if ($result < 0) {
675  $error++;
676  }
677  }
678 
679  if (!$error) {
680  $this->statut = self::STATUS_DRAFT;
681  $this->db->commit();
682  return 1;
683  } else {
684  $this->db->rollback();
685  return -1;
686  }
687  } else {
688  $this->error = $this->db->error();
689  $this->db->rollback();
690  return -1;
691  }
692  }
693 
694 
695  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
703  public function set_reopen($user)
704  {
705  // phpcs:enable
706  $error = 0;
707 
708  if ($this->statut != self::STATUS_CANCELED && $this->statut != self::STATUS_CLOSED) {
709  dol_syslog(get_class($this)."::set_reopen order has not status closed", LOG_WARNING);
710  return 0;
711  }
712 
713  $this->db->begin();
714 
715  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
716  $sql .= ' SET fk_statut='.self::STATUS_VALIDATED.', facture=0,';
717  $sql .= " fk_user_modif = ".((int) $user->id);
718  $sql .= " WHERE rowid = ".((int) $this->id);
719 
720  dol_syslog(get_class($this)."::set_reopen", LOG_DEBUG);
721  $resql = $this->db->query($sql);
722  if ($resql) {
723  // Call trigger
724  $result = $this->call_trigger('ORDER_REOPEN', $user);
725  if ($result < 0) {
726  $error++;
727  }
728  // End call triggers
729  } else {
730  $error++;
731  $this->error = $this->db->lasterror();
732  dol_print_error($this->db);
733  }
734 
735  if (!$error) {
736  $this->statut = self::STATUS_VALIDATED;
737  $this->billed = 0;
738 
739  $this->db->commit();
740  return 1;
741  } else {
742  foreach ($this->errors as $errmsg) {
743  dol_syslog(get_class($this)."::set_reopen ".$errmsg, LOG_ERR);
744  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
745  }
746  $this->db->rollback();
747  return -1 * $error;
748  }
749  }
750 
758  public function cloture($user, $notrigger = 0)
759  {
760  global $conf;
761 
762  $error = 0;
763 
764  $usercanclose = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->creer))
765  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->order_advance->close)));
766 
767  if ($usercanclose) {
768  if ($this->statut == self::STATUS_CLOSED) {
769  return 0;
770  }
771  $this->db->begin();
772 
773  $now = dol_now();
774 
775  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
776  $sql .= ' SET fk_statut = '.self::STATUS_CLOSED.',';
777  $sql .= ' fk_user_cloture = '.((int) $user->id).',';
778  $sql .= " date_cloture = '".$this->db->idate($now)."',";
779  $sql .= " fk_user_modif = ".((int) $user->id);
780  $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > '.self::STATUS_DRAFT;
781 
782  if ($this->db->query($sql)) {
783  if (!$notrigger) {
784  // Call trigger
785  $result = $this->call_trigger('ORDER_CLOSE', $user);
786  if ($result < 0) {
787  $error++;
788  }
789  // End call triggers
790  }
791 
792  if (!$error) {
793  $this->statut = self::STATUS_CLOSED;
794 
795  $this->db->commit();
796  return 1;
797  } else {
798  $this->db->rollback();
799  return -1;
800  }
801  } else {
802  $this->error = $this->db->lasterror();
803 
804  $this->db->rollback();
805  return -1;
806  }
807  }
808  return 0;
809  }
810 
818  public function cancel($idwarehouse = -1)
819  {
820  global $conf, $user, $langs;
821 
822  $error = 0;
823 
824  $this->db->begin();
825 
826  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
827  $sql .= " SET fk_statut = ".self::STATUS_CANCELED.",";
828  $sql .= " fk_user_modif = ".((int) $user->id);
829  $sql .= " WHERE rowid = ".((int) $this->id);
830  $sql .= " AND fk_statut = ".self::STATUS_VALIDATED;
831 
832  dol_syslog(get_class($this)."::cancel", LOG_DEBUG);
833  if ($this->db->query($sql)) {
834  // If stock is decremented on validate order, we must reincrement it
835  if (isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1) {
836  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
837  $langs->load("agenda");
838 
839  $num = count($this->lines);
840  for ($i = 0; $i < $num; $i++) {
841  if ($this->lines[$i]->fk_product > 0) {
842  $mouvP = new MouvementStock($this->db);
843  $mouvP->setOrigin($this->element, $this->id);
844  // We increment stock of product (and sub-products)
845  $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("OrderCanceledInDolibarr", $this->ref)); // price is 0, we don't want WAP to be changed
846  if ($result < 0) {
847  $error++;
848  $this->error = $mouvP->error;
849  break;
850  }
851  }
852  }
853  }
854 
855  if (!$error) {
856  // Call trigger
857  $result = $this->call_trigger('ORDER_CANCEL', $user);
858  if ($result < 0) {
859  $error++;
860  }
861  // End call triggers
862  }
863 
864  if (!$error) {
865  $this->statut = self::STATUS_CANCELED;
866  $this->db->commit();
867  return 1;
868  } else {
869  foreach ($this->errors as $errmsg) {
870  dol_syslog(get_class($this)."::cancel ".$errmsg, LOG_ERR);
871  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
872  }
873  $this->db->rollback();
874  return -1 * $error;
875  }
876  } else {
877  $this->error = $this->db->error();
878  $this->db->rollback();
879  return -1;
880  }
881  }
882 
891  public function create($user, $notrigger = 0)
892  {
893  global $conf, $langs, $mysoc;
894  $error = 0;
895 
896  // Clean parameters
897  $this->brouillon = 1; // set command as draft
898 
899  // Set tmp vars
900  $date = ($this->date_commande ? $this->date_commande : $this->date);
901  $delivery_date = empty($this->delivery_date) ? $this->date_livraison : $this->delivery_date;
902 
903  // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
904  if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) {
905  list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $date);
906  } else {
907  $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
908  }
909  if (empty($this->fk_multicurrency)) {
910  $this->multicurrency_code = $conf->currency;
911  $this->fk_multicurrency = 0;
912  $this->multicurrency_tx = 1;
913  }
914 
915  dol_syslog(get_class($this)."::create user=".$user->id);
916 
917  // Check parameters
918  if (!empty($this->ref)) { // We check that ref is not already used
919  $result = self::isExistingObject($this->element, 0, $this->ref); // Check ref is not yet used
920  if ($result > 0) {
921  $this->error = 'ErrorRefAlreadyExists';
922  dol_syslog(get_class($this)."::create ".$this->error, LOG_WARNING);
923  $this->db->rollback();
924  return -1;
925  }
926  }
927 
928  $soc = new Societe($this->db);
929  $result = $soc->fetch($this->socid);
930  if ($result < 0) {
931  $this->error = "Failed to fetch company";
932  dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
933  return -2;
934  }
935  if (!empty($conf->global->ORDER_REQUIRE_SOURCE) && $this->source < 0) {
936  $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Source"));
937  dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
938  return -1;
939  }
940 
941  $now = dol_now();
942 
943  $this->db->begin();
944 
945  $sql = "INSERT INTO ".MAIN_DB_PREFIX."commande (";
946  $sql .= " ref, fk_soc, date_creation, fk_user_author, fk_projet, date_commande, source, note_private, note_public, ref_ext, ref_client";
947  $sql .= ", model_pdf, fk_cond_reglement, deposit_percent, fk_mode_reglement, fk_account, fk_availability, fk_input_reason, date_livraison, fk_delivery_address";
948  $sql .= ", fk_shipping_method";
949  $sql .= ", fk_warehouse";
950  $sql .= ", remise_absolue, remise_percent";
951  $sql .= ", fk_incoterms, location_incoterms";
952  $sql .= ", entity, module_source, pos_source";
953  $sql .= ", fk_multicurrency";
954  $sql .= ", multicurrency_code";
955  $sql .= ", multicurrency_tx";
956  $sql .= ")";
957  $sql .= " VALUES ('(PROV)', ".((int) $this->socid).", '".$this->db->idate($now)."', ".((int) $user->id);
958  $sql .= ", ".($this->fk_project > 0 ? ((int) $this->fk_project) : "null");
959  $sql .= ", '".$this->db->idate($date)."'";
960  $sql .= ", ".($this->source >= 0 && $this->source != '' ? $this->db->escape($this->source) : 'null');
961  $sql .= ", '".$this->db->escape($this->note_private)."'";
962  $sql .= ", '".$this->db->escape($this->note_public)."'";
963  $sql .= ", ".($this->ref_ext ? "'".$this->db->escape($this->ref_ext)."'" : "null");
964  $sql .= ", ".($this->ref_client ? "'".$this->db->escape($this->ref_client)."'" : "null");
965  $sql .= ", '".$this->db->escape($this->model_pdf)."'";
966  $sql .= ", ".($this->cond_reglement_id > 0 ? ((int) $this->cond_reglement_id) : "null");
967  $sql .= ", ".(!empty($this->deposit_percent) ? "'".$this->db->escape($this->deposit_percent)."'" : "null");
968  $sql .= ", ".($this->mode_reglement_id > 0 ? ((int) $this->mode_reglement_id) : "null");
969  $sql .= ", ".($this->fk_account > 0 ? ((int) $this->fk_account) : 'NULL');
970  $sql .= ", ".($this->availability_id > 0 ? ((int) $this->availability_id) : "null");
971  $sql .= ", ".($this->demand_reason_id > 0 ? ((int) $this->demand_reason_id) : "null");
972  $sql .= ", ".($delivery_date ? "'".$this->db->idate($delivery_date)."'" : "null");
973  $sql .= ", ".($this->fk_delivery_address > 0 ? ((int) $this->fk_delivery_address) : 'NULL');
974  $sql .= ", ".(!empty($this->shipping_method_id) && $this->shipping_method_id > 0 ? ((int) $this->shipping_method_id) : 'NULL');
975  $sql .= ", ".(!empty($this->warehouse_id) && $this->warehouse_id > 0 ? ((int) $this->warehouse_id) : 'NULL');
976  $sql .= ", ".($this->remise_absolue > 0 ? $this->db->escape($this->remise_absolue) : 'NULL');
977  $sql .= ", ".($this->remise_percent > 0 ? $this->db->escape($this->remise_percent) : 0);
978  $sql .= ", ".(int) $this->fk_incoterms;
979  $sql .= ", '".$this->db->escape($this->location_incoterms)."'";
980  $sql .= ", ".setEntity($this);
981  $sql .= ", ".($this->module_source ? "'".$this->db->escape($this->module_source)."'" : "null");
982  $sql .= ", ".($this->pos_source != '' ? "'".$this->db->escape($this->pos_source)."'" : "null");
983  $sql .= ", ".(int) $this->fk_multicurrency;
984  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
985  $sql .= ", ".(float) $this->multicurrency_tx;
986  $sql .= ")";
987 
988  dol_syslog(get_class($this)."::create", LOG_DEBUG);
989  $resql = $this->db->query($sql);
990  if ($resql) {
991  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'commande');
992 
993  if ($this->id) {
994  $fk_parent_line = 0;
995  $num = count($this->lines);
996 
997  /*
998  * Insert products details into db
999  */
1000  for ($i = 0; $i < $num; $i++) {
1001  $line = $this->lines[$i];
1002 
1003  // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
1004  //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object.
1005  if (!is_object($line)) {
1006  $line = (object) $line;
1007  }
1008 
1009  // Reset fk_parent_line for no child products and special product
1010  if (($line->product_type != 9 && empty($line->fk_parent_line)) || $line->product_type == 9) {
1011  $fk_parent_line = 0;
1012  }
1013 
1014  // Complete vat rate with code
1015  $vatrate = $line->tva_tx;
1016  if ($line->vat_src_code && !preg_match('/\(.*\)/', $vatrate)) {
1017  $vatrate .= ' ('.$line->vat_src_code.')';
1018  }
1019 
1020  if (!empty($conf->global->MAIN_CREATEFROM_KEEP_LINE_ORIGIN_INFORMATION)) {
1021  $originid = $line->origin_id;
1022  $origintype = $line->origin;
1023  } else {
1024  $originid = $line->id;
1025  $origintype = $this->element;
1026  }
1027 
1028  // ref_ext
1029  if (empty($line->ref_ext)) {
1030  $line->ref_ext = '';
1031  }
1032 
1033  $result = $this->addline(
1034  $line->desc,
1035  $line->subprice,
1036  $line->qty,
1037  $vatrate,
1038  $line->localtax1_tx,
1039  $line->localtax2_tx,
1040  $line->fk_product,
1041  $line->remise_percent,
1042  $line->info_bits,
1043  $line->fk_remise_except,
1044  'HT',
1045  0,
1046  $line->date_start,
1047  $line->date_end,
1048  $line->product_type,
1049  $line->rang,
1050  $line->special_code,
1051  $fk_parent_line,
1052  $line->fk_fournprice,
1053  $line->pa_ht,
1054  $line->label,
1055  $line->array_options,
1056  $line->fk_unit,
1057  $origintype,
1058  $originid,
1059  0,
1060  $line->ref_ext,
1061  1
1062  );
1063  if ($result < 0) {
1064  if ($result != self::STOCK_NOT_ENOUGH_FOR_ORDER) {
1065  $this->error = $this->db->lasterror();
1066  $this->errors[] = $this->error;
1067  dol_print_error($this->db);
1068  }
1069  $this->db->rollback();
1070  return -1;
1071  }
1072  // Defined the new fk_parent_line
1073  if ($result > 0 && $line->product_type == 9) {
1074  $fk_parent_line = $result;
1075  }
1076  }
1077 
1078  $result = $this->update_price(1, 'auto', 0, $mysoc); // This method is designed to add line from user input so total calculation must be done using 'auto' mode.
1079 
1080  // update ref
1081  $initialref = '(PROV'.$this->id.')';
1082  if (!empty($this->ref)) {
1083  $initialref = $this->ref;
1084  }
1085 
1086  $sql = 'UPDATE '.MAIN_DB_PREFIX."commande SET ref='".$this->db->escape($initialref)."' WHERE rowid=".((int) $this->id);
1087  if ($this->db->query($sql)) {
1088  $this->ref = $initialref;
1089 
1090  if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) { // To use new linkedObjectsIds instead of old linked_objects
1091  $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
1092  }
1093 
1094  // Add object linked
1095  if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects)) {
1096  foreach ($this->linked_objects as $origin => $tmp_origin_id) {
1097  if (is_array($tmp_origin_id)) { // New behaviour, if linked_object can have several links per type, so is something like array('contract'=>array(id1, id2, ...))
1098  foreach ($tmp_origin_id as $origin_id) {
1099  $ret = $this->add_object_linked($origin, $origin_id);
1100  if (!$ret) {
1101  $this->error = $this->db->lasterror();
1102  $error++;
1103  }
1104  }
1105  } else // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
1106  {
1107  $origin_id = $tmp_origin_id;
1108  $ret = $this->add_object_linked($origin, $origin_id);
1109  if (!$ret) {
1110  $this->error = $this->db->lasterror();
1111  $error++;
1112  }
1113  }
1114  }
1115  }
1116 
1117  if (!$error && $this->id && !empty($conf->global->MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN) && !empty($this->origin) && !empty($this->origin_id)) { // Get contact from origin object
1118  $originforcontact = $this->origin;
1119  $originidforcontact = $this->origin_id;
1120  if ($originforcontact == 'shipping') { // shipment and order share the same contacts. If creating from shipment we take data of order
1121  require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
1122  $exp = new Expedition($this->db);
1123  $exp->fetch($this->origin_id);
1124  $exp->fetchObjectLinked();
1125  if (count($exp->linkedObjectsIds['commande']) > 0) {
1126  foreach ($exp->linkedObjectsIds['commande'] as $key => $value) {
1127  $originforcontact = 'commande';
1128  if (is_object($value)) {
1129  $originidforcontact = $value->id;
1130  } else {
1131  $originidforcontact = $value;
1132  }
1133  break; // We take first one
1134  }
1135  }
1136  }
1137 
1138  $sqlcontact = "SELECT ctc.code, ctc.source, ec.fk_socpeople FROM ".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as ctc";
1139  $sqlcontact .= " WHERE element_id = ".((int) $originidforcontact)." AND ec.fk_c_type_contact = ctc.rowid AND ctc.element = '".$this->db->escape($originforcontact)."'";
1140 
1141  $resqlcontact = $this->db->query($sqlcontact);
1142  if ($resqlcontact) {
1143  while ($objcontact = $this->db->fetch_object($resqlcontact)) {
1144  //print $objcontact->code.'-'.$objcontact->source.'-'.$objcontact->fk_socpeople."\n";
1145  $this->add_contact($objcontact->fk_socpeople, $objcontact->code, $objcontact->source); // May failed because of duplicate key or because code of contact type does not exists for new object
1146  }
1147  } else {
1148  dol_print_error($resqlcontact);
1149  }
1150  }
1151 
1152  if (!$error) {
1153  $result = $this->insertExtraFields();
1154  if ($result < 0) {
1155  $error++;
1156  }
1157  }
1158 
1159  if (!$error && !$notrigger) {
1160  // Call trigger
1161  $result = $this->call_trigger('ORDER_CREATE', $user);
1162  if ($result < 0) {
1163  $error++;
1164  }
1165  // End call triggers
1166  }
1167 
1168  if (!$error) {
1169  $this->db->commit();
1170  return $this->id;
1171  } else {
1172  $this->db->rollback();
1173  return -1 * $error;
1174  }
1175  } else {
1176  $this->error = $this->db->lasterror();
1177  $this->db->rollback();
1178  return -1;
1179  }
1180  }
1181 
1182  return 0;
1183  } else {
1184  dol_print_error($this->db);
1185  $this->db->rollback();
1186  return -1;
1187  }
1188  }
1189 
1190 
1198  public function createFromClone(User $user, $socid = 0)
1199  {
1200  global $conf, $user, $hookmanager;
1201 
1202  $error = 0;
1203 
1204  $this->db->begin();
1205 
1206  // get lines so they will be clone
1207  foreach ($this->lines as $line) {
1208  $line->fetch_optionals();
1209  }
1210 
1211  // Load source object
1212  $objFrom = clone $this;
1213 
1214  // Change socid if needed
1215  if (!empty($socid) && $socid != $this->socid) {
1216  $objsoc = new Societe($this->db);
1217 
1218  if ($objsoc->fetch($socid) > 0) {
1219  $this->socid = $objsoc->id;
1220  $this->cond_reglement_id = (!empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0);
1221  $this->deposit_percent = (!empty($objsoc->deposit_percent) ? $objsoc->deposit_percent : null);
1222  $this->mode_reglement_id = (!empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0);
1223  $this->fk_project = 0;
1224  $this->fk_delivery_address = 0;
1225  }
1226 
1227  // TODO Change product price if multi-prices
1228  }
1229 
1230  $this->id = 0;
1231  $this->ref = '';
1232  $this->statut = self::STATUS_DRAFT;
1233 
1234  // Clear fields
1235  $this->user_author_id = $user->id;
1236  $this->user_valid = 0; // deprecated
1237  $this->user_validation_id = 0;
1238  $this->date = dol_now();
1239  $this->date_commande = dol_now();
1240  $this->date_creation = '';
1241  $this->date_validation = '';
1242  if (empty($conf->global->MAIN_KEEP_REF_CUSTOMER_ON_CLONING)) {
1243  $this->ref_client = '';
1244  }
1245 
1246  // Do not clone ref_ext
1247  $num = count($this->lines);
1248  for ($i = 0; $i < $num; $i++) {
1249  $this->lines[$i]->ref_ext = '';
1250  }
1251 
1252  // Create clone
1253  $this->context['createfromclone'] = 'createfromclone';
1254  $result = $this->create($user);
1255  if ($result < 0) {
1256  $error++;
1257  }
1258 
1259  if (!$error) {
1260  // copy internal contacts
1261  if ($this->copy_linked_contact($objFrom, 'internal') < 0) {
1262  $error++;
1263  }
1264  }
1265 
1266  if (!$error) {
1267  // copy external contacts if same company
1268  if ($this->socid == $objFrom->socid) {
1269  if ($this->copy_linked_contact($objFrom, 'external') < 0) {
1270  $error++;
1271  }
1272  }
1273  }
1274 
1275  if (!$error) {
1276  // Hook of thirdparty module
1277  if (is_object($hookmanager)) {
1278  $parameters = array('objFrom'=>$objFrom);
1279  $action = '';
1280  $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1281  if ($reshook < 0) {
1282  $this->setErrorsFromObject($hookmanager);
1283  $error++;
1284  }
1285  }
1286  }
1287 
1288  unset($this->context['createfromclone']);
1289 
1290  // End
1291  if (!$error) {
1292  $this->db->commit();
1293  return $this->id;
1294  } else {
1295  $this->db->rollback();
1296  return -1;
1297  }
1298  }
1299 
1300 
1308  public function createFromProposal($object, User $user)
1309  {
1310  global $conf, $hookmanager;
1311 
1312  dol_include_once('/multicurrency/class/multicurrency.class.php');
1313  dol_include_once('/core/class/extrafields.class.php');
1314 
1315  $error = 0;
1316 
1317 
1318  $this->date_commande = dol_now();
1319  $this->source = 0;
1320 
1321  $num = count($object->lines);
1322  for ($i = 0; $i < $num; $i++) {
1323  $line = new OrderLine($this->db);
1324 
1325  $line->libelle = $object->lines[$i]->libelle;
1326  $line->label = $object->lines[$i]->label;
1327  $line->desc = $object->lines[$i]->desc;
1328  $line->price = $object->lines[$i]->price;
1329  $line->subprice = $object->lines[$i]->subprice;
1330  $line->vat_src_code = $object->lines[$i]->vat_src_code;
1331  $line->tva_tx = $object->lines[$i]->tva_tx;
1332  $line->localtax1_tx = $object->lines[$i]->localtax1_tx;
1333  $line->localtax2_tx = $object->lines[$i]->localtax2_tx;
1334  $line->qty = $object->lines[$i]->qty;
1335  $line->fk_remise_except = $object->lines[$i]->fk_remise_except;
1336  $line->remise_percent = $object->lines[$i]->remise_percent;
1337  $line->fk_product = $object->lines[$i]->fk_product;
1338  $line->info_bits = $object->lines[$i]->info_bits;
1339  $line->product_type = $object->lines[$i]->product_type;
1340  $line->rang = $object->lines[$i]->rang;
1341  $line->special_code = $object->lines[$i]->special_code;
1342  $line->fk_parent_line = $object->lines[$i]->fk_parent_line;
1343  $line->fk_unit = $object->lines[$i]->fk_unit;
1344 
1345  $line->date_start = $object->lines[$i]->date_start;
1346  $line->date_end = $object->lines[$i]->date_end;
1347 
1348  $line->fk_fournprice = $object->lines[$i]->fk_fournprice;
1349  $marginInfos = getMarginInfos($object->lines[$i]->subprice, $object->lines[$i]->remise_percent, $object->lines[$i]->tva_tx, $object->lines[$i]->localtax1_tx, $object->lines[$i]->localtax2_tx, $object->lines[$i]->fk_fournprice, $object->lines[$i]->pa_ht);
1350  $line->pa_ht = $marginInfos[0];
1351  $line->marge_tx = $marginInfos[1];
1352  $line->marque_tx = $marginInfos[2];
1353 
1354  // get extrafields from original line
1355  $object->lines[$i]->fetch_optionals();
1356  foreach ($object->lines[$i]->array_options as $options_key => $value) {
1357  $line->array_options[$options_key] = $value;
1358  }
1359 
1360  $this->lines[$i] = $line;
1361  }
1362 
1363  $this->entity = $object->entity;
1364  $this->socid = $object->socid;
1365  $this->fk_project = $object->fk_project;
1366  $this->cond_reglement_id = $object->cond_reglement_id;
1367  $this->deposit_percent = $object->deposit_percent;
1368  $this->mode_reglement_id = $object->mode_reglement_id;
1369  $this->fk_account = $object->fk_account;
1370  $this->availability_id = $object->availability_id;
1371  $this->demand_reason_id = $object->demand_reason_id;
1372  $this->date_livraison = $object->date_livraison; // deprecated
1373  $this->delivery_date = $object->date_livraison;
1374  $this->shipping_method_id = $object->shipping_method_id;
1375  $this->warehouse_id = $object->warehouse_id;
1376  $this->fk_delivery_address = $object->fk_delivery_address;
1377  $this->contact_id = $object->contact_id;
1378  $this->ref_client = $object->ref_client;
1379 
1380  if (empty($conf->global->MAIN_DISABLE_PROPAGATE_NOTES_FROM_ORIGIN)) {
1381  $this->note_private = $object->note_private;
1382  $this->note_public = $object->note_public;
1383  }
1384 
1385  $this->origin = $object->element;
1386  $this->origin_id = $object->id;
1387 
1388  // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
1389  if (!empty($conf->multicurrency->enabled)) {
1390  if (!empty($object->multicurrency_code)) {
1391  $this->multicurrency_code = $object->multicurrency_code;
1392  }
1393  if (!empty($conf->global->MULTICURRENCY_USE_ORIGIN_TX) && !empty($object->multicurrency_tx)) {
1394  $this->multicurrency_tx = $object->multicurrency_tx;
1395  }
1396 
1397  if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) {
1398  $tmparray = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $this->date_commande);
1399  $this->fk_multicurrency = $tmparray[0];
1400  $this->multicurrency_tx = $tmparray[1];
1401  } else {
1402  $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
1403  }
1404  if (empty($this->fk_multicurrency)) {
1405  $this->multicurrency_code = $conf->currency;
1406  $this->fk_multicurrency = 0;
1407  $this->multicurrency_tx = 1;
1408  }
1409  }
1410 
1411  // get extrafields from original line
1412  $object->fetch_optionals();
1413 
1414  $e = new ExtraFields($this->db);
1415  $element_extrafields = $e->fetch_name_optionals_label($this->table_element);
1416 
1417  foreach ($object->array_options as $options_key => $value) {
1418  if (array_key_exists(str_replace('options_', '', $options_key), $element_extrafields)) {
1419  $this->array_options[$options_key] = $value;
1420  }
1421  }
1422  // Possibility to add external linked objects with hooks
1423  $this->linked_objects[$this->origin] = $this->origin_id;
1424  if (isset($object->other_linked_objects) && is_array($object->other_linked_objects) && !empty($object->other_linked_objects)) {
1425  $this->linked_objects = array_merge($this->linked_objects, $object->other_linked_objects);
1426  }
1427 
1428  $ret = $this->create($user);
1429 
1430  if ($ret > 0) {
1431  // Actions hooked (by external module)
1432  $hookmanager->initHooks(array('orderdao'));
1433 
1434  $parameters = array('objFrom'=>$object);
1435  $action = '';
1436  $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1437  if ($reshook < 0) {
1438  $this->setErrorsFromObject($hookmanager);
1439  $error++;
1440  }
1441 
1442  if (!$error) {
1443  // Validate immediatly the order
1444  if (!empty($conf->global->ORDER_VALID_AFTER_CLOSE_PROPAL)) {
1445  $this->fetch($ret);
1446  $this->valid($user);
1447  }
1448  return $ret;
1449  } else {
1450  return -1;
1451  }
1452  } else {
1453  return -1;
1454  }
1455  }
1456 
1457 
1498  public function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1 = 0, $txlocaltax2 = 0, $fk_product = 0, $remise_percent = 0, $info_bits = 0, $fk_remise_except = 0, $price_base_type = 'HT', $pu_ttc = 0, $date_start = '', $date_end = '', $type = 0, $rang = -1, $special_code = 0, $fk_parent_line = 0, $fk_fournprice = null, $pa_ht = 0, $label = '', $array_options = 0, $fk_unit = null, $origin = '', $origin_id = 0, $pu_ht_devise = 0, $ref_ext = '', $noupdateafterinsertline = 0)
1499  {
1500  global $mysoc, $conf, $langs, $user;
1501 
1502  $logtext = "::addline commandeid=$this->id, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, fk_product=$fk_product, remise_percent=$remise_percent";
1503  $logtext .= ", info_bits=$info_bits, fk_remise_except=$fk_remise_except, price_base_type=$price_base_type, pu_ttc=$pu_ttc, date_start=$date_start";
1504  $logtext .= ", date_end=$date_end, type=$type special_code=$special_code, fk_unit=$fk_unit, origin=$origin, origin_id=$origin_id, pu_ht_devise=$pu_ht_devise, ref_ext=$ref_ext";
1505  dol_syslog(get_class($this).$logtext, LOG_DEBUG);
1506 
1507  if ($this->statut == self::STATUS_DRAFT) {
1508  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1509 
1510  // Clean parameters
1511 
1512  if (empty($remise_percent)) {
1513  $remise_percent = 0;
1514  }
1515  if (empty($qty)) {
1516  $qty = 0;
1517  }
1518  if (empty($info_bits)) {
1519  $info_bits = 0;
1520  }
1521  if (empty($rang)) {
1522  $rang = 0;
1523  }
1524  if (empty($txtva)) {
1525  $txtva = 0;
1526  }
1527  if (empty($txlocaltax1)) {
1528  $txlocaltax1 = 0;
1529  }
1530  if (empty($txlocaltax2)) {
1531  $txlocaltax2 = 0;
1532  }
1533  if (empty($fk_parent_line) || $fk_parent_line < 0) {
1534  $fk_parent_line = 0;
1535  }
1536  if (empty($this->fk_multicurrency)) {
1537  $this->fk_multicurrency = 0;
1538  }
1539  if (empty($ref_ext)) {
1540  $ref_ext = '';
1541  }
1542 
1543  $remise_percent = price2num($remise_percent);
1544  $qty = price2num($qty);
1545  $pu_ht = price2num($pu_ht);
1546  $pu_ht_devise = price2num($pu_ht_devise);
1547  $pu_ttc = price2num($pu_ttc);
1548  $pa_ht = price2num($pa_ht);
1549  if (!preg_match('/\((.*)\)/', $txtva)) {
1550  $txtva = price2num($txtva); // $txtva can have format '5,1' or '5.1' or '5.1(XXX)', we must clean only if '5,1'
1551  }
1552  $txlocaltax1 = price2num($txlocaltax1);
1553  $txlocaltax2 = price2num($txlocaltax2);
1554  if ($price_base_type == 'HT') {
1555  $pu = $pu_ht;
1556  } else {
1557  $pu = $pu_ttc;
1558  }
1559  $label = trim($label);
1560  $desc = trim($desc);
1561 
1562  // Check parameters
1563  if ($type < 0) {
1564  return -1;
1565  }
1566 
1567  if ($date_start && $date_end && $date_start > $date_end) {
1568  $langs->load("errors");
1569  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
1570  return -1;
1571  }
1572 
1573  $this->db->begin();
1574 
1575  $product_type = $type;
1576  if (!empty($fk_product) && $fk_product > 0) {
1577  $product = new Product($this->db);
1578  $result = $product->fetch($fk_product);
1579  $product_type = $product->type;
1580 
1581  if (!empty($conf->global->STOCK_MUST_BE_ENOUGH_FOR_ORDER) && $product_type == 0 && $product->stock_reel < $qty) {
1582  $langs->load("errors");
1583  $this->error = $langs->trans('ErrorStockIsNotEnoughToAddProductOnOrder', $product->ref);
1584  $this->errors[] = $this->error;
1585  dol_syslog(get_class($this)."::addline error=Product ".$product->ref.": ".$this->error, LOG_ERR);
1586  $this->db->rollback();
1588  }
1589  }
1590  // Calcul du total TTC et de la TVA pour la ligne a partir de
1591  // qty, pu, remise_percent et txtva
1592  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1593  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1594 
1595  $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
1596 
1597  // Clean vat code
1598  $reg = array();
1599  $vat_src_code = '';
1600  if (preg_match('/\((.*)\)/', $txtva, $reg)) {
1601  $vat_src_code = $reg[1];
1602  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
1603  }
1604 
1605  $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $product_type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
1606 
1607  /*var_dump($txlocaltax1);
1608  var_dump($txlocaltax2);
1609  var_dump($localtaxes_type);
1610  var_dump($tabprice);
1611  var_dump($tabprice[9]);
1612  var_dump($tabprice[10]);
1613  exit;*/
1614 
1615  $total_ht = $tabprice[0];
1616  $total_tva = $tabprice[1];
1617  $total_ttc = $tabprice[2];
1618  $total_localtax1 = $tabprice[9];
1619  $total_localtax2 = $tabprice[10];
1620  $pu_ht = $tabprice[3];
1621 
1622  // MultiCurrency
1623  $multicurrency_total_ht = $tabprice[16];
1624  $multicurrency_total_tva = $tabprice[17];
1625  $multicurrency_total_ttc = $tabprice[18];
1626  $pu_ht_devise = $tabprice[19];
1627 
1628  // Rang to use
1629  $ranktouse = $rang;
1630  if ($ranktouse == -1) {
1631  $rangmax = $this->line_max($fk_parent_line);
1632  $ranktouse = $rangmax + 1;
1633  }
1634 
1635  // TODO A virer
1636  // Anciens indicateurs: $price, $remise (a ne plus utiliser)
1637  $price = $pu;
1638  $remise = 0;
1639  if ($remise_percent > 0) {
1640  $remise = round(($pu * $remise_percent / 100), 2);
1641  $price = $pu - $remise;
1642  }
1643 
1644  // Insert line
1645  $this->line = new OrderLine($this->db);
1646 
1647  $this->line->context = $this->context;
1648 
1649  $this->line->fk_commande = $this->id;
1650  $this->line->label = $label;
1651  $this->line->desc = $desc;
1652  $this->line->qty = $qty;
1653  $this->line->ref_ext = $ref_ext;
1654 
1655  $this->line->vat_src_code = $vat_src_code;
1656  $this->line->tva_tx = $txtva;
1657  $this->line->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0);
1658  $this->line->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0);
1659  $this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
1660  $this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
1661  $this->line->fk_product = $fk_product;
1662  $this->line->product_type = $product_type;
1663  $this->line->fk_remise_except = $fk_remise_except;
1664  $this->line->remise_percent = $remise_percent;
1665  $this->line->subprice = $pu_ht;
1666  $this->line->rang = $ranktouse;
1667  $this->line->info_bits = $info_bits;
1668  $this->line->total_ht = $total_ht;
1669  $this->line->total_tva = $total_tva;
1670  $this->line->total_localtax1 = $total_localtax1;
1671  $this->line->total_localtax2 = $total_localtax2;
1672  $this->line->total_ttc = $total_ttc;
1673  $this->line->special_code = $special_code;
1674  $this->line->origin = $origin;
1675  $this->line->origin_id = $origin_id;
1676  $this->line->fk_parent_line = $fk_parent_line;
1677  $this->line->fk_unit = $fk_unit;
1678 
1679  $this->line->date_start = $date_start;
1680  $this->line->date_end = $date_end;
1681 
1682  $this->line->fk_fournprice = $fk_fournprice;
1683  $this->line->pa_ht = $pa_ht;
1684 
1685  // Multicurrency
1686  $this->line->fk_multicurrency = $this->fk_multicurrency;
1687  $this->line->multicurrency_code = $this->multicurrency_code;
1688  $this->line->multicurrency_subprice = $pu_ht_devise;
1689  $this->line->multicurrency_total_ht = $multicurrency_total_ht;
1690  $this->line->multicurrency_total_tva = $multicurrency_total_tva;
1691  $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
1692 
1693  // TODO Ne plus utiliser
1694  $this->line->price = $price;
1695 
1696  if (is_array($array_options) && count($array_options) > 0) {
1697  $this->line->array_options = $array_options;
1698  }
1699 
1700  $result = $this->line->insert($user);
1701  if ($result > 0) {
1702  // Reorder if child line
1703  if (!empty($fk_parent_line)) {
1704  $this->line_order(true, 'DESC');
1705  } elseif ($ranktouse > 0 && $ranktouse <= count($this->lines)) { // Update all rank of all other lines
1706  $linecount = count($this->lines);
1707  for ($ii = $ranktouse; $ii <= $linecount; $ii++) {
1708  $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii + 1);
1709  }
1710  }
1711 
1712  // Mise a jour informations denormalisees au niveau de la commande meme
1713  if (empty($noupdateafterinsertline)) {
1714  $result = $this->update_price(1, 'auto', 0, $mysoc); // This method is designed to add line from user input so total calculation must be done using 'auto' mode.
1715  }
1716 
1717  if ($result > 0) {
1718  $this->db->commit();
1719  return $this->line->id;
1720  } else {
1721  $this->db->rollback();
1722  return -1;
1723  }
1724  } else {
1725  $this->error = $this->line->error;
1726  dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR);
1727  $this->db->rollback();
1728  return -2;
1729  }
1730  } else {
1731  dol_syslog(get_class($this)."::addline status of order must be Draft to allow use of ->addline()", LOG_ERR);
1732  return -3;
1733  }
1734  }
1735 
1736 
1737  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1751  public function add_product($idproduct, $qty, $remise_percent = 0.0, $date_start = '', $date_end = '')
1752  {
1753  // phpcs:enable
1754  global $conf, $mysoc;
1755 
1756  if (!$qty) {
1757  $qty = 1;
1758  }
1759 
1760  if ($idproduct > 0) {
1761  $prod = new Product($this->db);
1762  $prod->fetch($idproduct);
1763 
1764  $tva_tx = get_default_tva($mysoc, $this->thirdparty, $prod->id);
1765  $tva_npr = get_default_npr($mysoc, $this->thirdparty, $prod->id);
1766  if (empty($tva_tx)) {
1767  $tva_npr = 0;
1768  }
1769  $vat_src_code = ''; // May be defined into tva_tx
1770 
1771  $localtax1_tx = get_localtax($tva_tx, 1, $this->thirdparty, $mysoc, $tva_npr);
1772  $localtax2_tx = get_localtax($tva_tx, 2, $this->thirdparty, $mysoc, $tva_npr);
1773 
1774  // multiprix
1775  if ($conf->global->PRODUIT_MULTIPRICES && $this->thirdparty->price_level) {
1776  $price = $prod->multiprices[$this->thirdparty->price_level];
1777  } else {
1778  $price = $prod->price;
1779  }
1780 
1781  $line = new OrderLine($this->db);
1782 
1783  $line->context = $this->context;
1784 
1785  $line->fk_product = $idproduct;
1786  $line->desc = $prod->description;
1787  $line->qty = $qty;
1788  $line->subprice = $price;
1789  $line->remise_percent = $remise_percent;
1790  $line->vat_src_code = $vat_src_code;
1791  $line->tva_tx = $tva_tx;
1792  $line->localtax1_tx = $localtax1_tx;
1793  $line->localtax2_tx = $localtax2_tx;
1794  $line->ref = $prod->ref;
1795  $line->libelle = $prod->label;
1796  $line->product_desc = $prod->description;
1797  $line->fk_unit = $prod->fk_unit;
1798 
1799  // Save the start and end date of the line in the object
1800  if ($date_start) {
1801  $line->date_start = $date_start;
1802  }
1803  if ($date_end) {
1804  $line->date_end = $date_end;
1805  }
1806 
1807  $this->lines[] = $line;
1808 
1827  }
1828  }
1829 
1830 
1840  public function fetch($id, $ref = '', $ref_ext = '', $notused = '')
1841  {
1842  // Check parameters
1843  if (empty($id) && empty($ref) && empty($ref_ext)) {
1844  return -1;
1845  }
1846 
1847  $sql = 'SELECT c.rowid, c.entity, c.date_creation, c.ref, c.fk_soc, c.fk_user_author, c.fk_user_valid, c.fk_user_modif, c.fk_statut';
1848  $sql .= ', c.amount_ht, c.total_ht, c.total_ttc, c.total_tva, c.localtax1 as total_localtax1, c.localtax2 as total_localtax2, c.fk_cond_reglement, c.deposit_percent, c.fk_mode_reglement, c.fk_availability, c.fk_input_reason';
1849  $sql .= ', c.fk_account';
1850  $sql .= ', c.date_commande, c.date_valid, c.tms';
1851  $sql .= ', c.date_livraison as delivery_date';
1852  $sql .= ', c.fk_shipping_method';
1853  $sql .= ', c.fk_warehouse';
1854  $sql .= ', c.fk_projet as fk_project, c.remise_percent, c.remise, c.remise_absolue, c.source, c.facture as billed';
1855  $sql .= ', c.note_private, c.note_public, c.ref_client, c.ref_ext, c.model_pdf, c.last_main_doc, c.fk_delivery_address, c.extraparams';
1856  $sql .= ', c.fk_incoterms, c.location_incoterms';
1857  $sql .= ", c.fk_multicurrency, c.multicurrency_code, c.multicurrency_tx, c.multicurrency_total_ht, c.multicurrency_total_tva, c.multicurrency_total_ttc";
1858  $sql .= ", c.module_source, c.pos_source";
1859  $sql .= ", i.libelle as label_incoterms";
1860  $sql .= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
1861  $sql .= ', cr.code as cond_reglement_code, cr.libelle as cond_reglement_libelle, cr.libelle_facture as cond_reglement_libelle_doc';
1862  $sql .= ', ca.code as availability_code, ca.label as availability_label';
1863  $sql .= ', dr.code as demand_reason_code';
1864  $sql .= ' FROM '.MAIN_DB_PREFIX.'commande as c';
1865  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as cr ON c.fk_cond_reglement = cr.rowid';
1866  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON c.fk_mode_reglement = p.id';
1867  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_availability as ca ON c.fk_availability = ca.rowid';
1868  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_input_reason as dr ON c.fk_input_reason = dr.rowid';
1869  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON c.fk_incoterms = i.rowid';
1870 
1871  if ($id) {
1872  $sql .= " WHERE c.rowid=".((int) $id);
1873  } else {
1874  $sql .= " WHERE c.entity IN (".getEntity('commande').")"; // Dont't use entity if you use rowid
1875  }
1876 
1877  if ($ref) {
1878  $sql .= " AND c.ref='".$this->db->escape($ref)."'";
1879  }
1880  if ($ref_ext) {
1881  $sql .= " AND c.ref_ext='".$this->db->escape($ref_ext)."'";
1882  }
1883 
1884  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
1885  $result = $this->db->query($sql);
1886  if ($result) {
1887  $obj = $this->db->fetch_object($result);
1888  if ($obj) {
1889  $this->id = $obj->rowid;
1890  $this->entity = $obj->entity;
1891 
1892  $this->ref = $obj->ref;
1893  $this->ref_client = $obj->ref_client;
1894  $this->ref_customer = $obj->ref_client;
1895  $this->ref_ext = $obj->ref_ext;
1896 
1897  $this->socid = $obj->fk_soc;
1898  $this->thirdparty = null; // Clear if another value was already set by fetch_thirdparty
1899 
1900  $this->fk_project = $obj->fk_project;
1901  $this->project = null; // Clear if another value was already set by fetch_projet
1902 
1903  $this->statut = $obj->fk_statut;
1904  $this->status = $obj->fk_statut;
1905 
1906  $this->user_author_id = $obj->fk_user_author;
1907  $this->user_creation_id = $obj->fk_user_author;
1908  $this->user_validation_id = $obj->fk_user_valid;
1909  $this->user_valid = $obj->fk_user_valid; // deprecated
1910  $this->user_modification_id = $obj->fk_user_modif;
1911  $this->user_modification = $obj->fk_user_modif;
1912  $this->total_ht = $obj->total_ht;
1913  $this->total_tva = $obj->total_tva;
1914  $this->total_localtax1 = $obj->total_localtax1;
1915  $this->total_localtax2 = $obj->total_localtax2;
1916  $this->total_ttc = $obj->total_ttc;
1917  $this->date = $this->db->jdate($obj->date_commande);
1918  $this->date_commande = $this->db->jdate($obj->date_commande);
1919  $this->date_creation = $this->db->jdate($obj->date_creation);
1920  $this->date_validation = $this->db->jdate($obj->date_valid);
1921  $this->date_modification = $this->db->jdate($obj->tms);
1922  $this->remise = $obj->remise;
1923  $this->remise_percent = $obj->remise_percent;
1924  $this->remise_absolue = $obj->remise_absolue;
1925  $this->source = $obj->source;
1926  $this->billed = $obj->billed;
1927  $this->note = $obj->note_private; // deprecated
1928  $this->note_private = $obj->note_private;
1929  $this->note_public = $obj->note_public;
1930  $this->model_pdf = $obj->model_pdf;
1931  $this->modelpdf = $obj->model_pdf; // deprecated
1932  $this->last_main_doc = $obj->last_main_doc;
1933  $this->mode_reglement_id = $obj->fk_mode_reglement;
1934  $this->mode_reglement_code = $obj->mode_reglement_code;
1935  $this->mode_reglement = $obj->mode_reglement_libelle;
1936  $this->cond_reglement_id = $obj->fk_cond_reglement;
1937  $this->cond_reglement_code = $obj->cond_reglement_code;
1938  $this->cond_reglement = $obj->cond_reglement_libelle;
1939  $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc;
1940  $this->deposit_percent = $obj->deposit_percent;
1941  $this->fk_account = $obj->fk_account;
1942  $this->availability_id = $obj->fk_availability;
1943  $this->availability_code = $obj->availability_code;
1944  $this->availability = $obj->availability_label;
1945  $this->demand_reason_id = $obj->fk_input_reason;
1946  $this->demand_reason_code = $obj->demand_reason_code;
1947  $this->date_livraison = $this->db->jdate($obj->delivery_date); // deprecated
1948  $this->delivery_date = $this->db->jdate($obj->delivery_date);
1949  $this->shipping_method_id = ($obj->fk_shipping_method > 0) ? $obj->fk_shipping_method : null;
1950  $this->warehouse_id = ($obj->fk_warehouse > 0) ? $obj->fk_warehouse : null;
1951  $this->fk_delivery_address = $obj->fk_delivery_address;
1952  $this->module_source = $obj->module_source;
1953  $this->pos_source = $obj->pos_source;
1954 
1955  //Incoterms
1956  $this->fk_incoterms = $obj->fk_incoterms;
1957  $this->location_incoterms = $obj->location_incoterms;
1958  $this->label_incoterms = $obj->label_incoterms;
1959 
1960  // Multicurrency
1961  $this->fk_multicurrency = $obj->fk_multicurrency;
1962  $this->multicurrency_code = $obj->multicurrency_code;
1963  $this->multicurrency_tx = $obj->multicurrency_tx;
1964  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
1965  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
1966  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
1967 
1968  $this->extraparams = (array) json_decode($obj->extraparams, true);
1969 
1970  $this->lines = array();
1971 
1972  if ($this->statut == self::STATUS_DRAFT) {
1973  $this->brouillon = 1;
1974  }
1975 
1976  // Retrieve all extrafield
1977  // fetch optionals attributes and labels
1978  $this->fetch_optionals();
1979 
1980  $this->db->free($result);
1981 
1982  // Lines
1983  $result = $this->fetch_lines();
1984  if ($result < 0) {
1985  return -3;
1986  }
1987  return 1;
1988  } else {
1989  $this->error = 'Order with id '.$id.' not found sql='.$sql;
1990  return 0;
1991  }
1992  } else {
1993  $this->error = $this->db->error();
1994  return -1;
1995  }
1996  }
1997 
1998 
1999  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2006  public function insert_discount($idremise)
2007  {
2008  // phpcs:enable
2009  global $langs;
2010 
2011  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2012  include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
2013 
2014  $this->db->begin();
2015 
2016  $remise = new DiscountAbsolute($this->db);
2017  $result = $remise->fetch($idremise);
2018 
2019  if ($result > 0) {
2020  if ($remise->fk_facture) { // Protection against multiple submission
2021  $this->error = $langs->trans("ErrorDiscountAlreadyUsed");
2022  $this->db->rollback();
2023  return -5;
2024  }
2025 
2026  $line = new OrderLine($this->db);
2027 
2028  $line->fk_commande = $this->id;
2029  $line->fk_remise_except = $remise->id;
2030  $line->desc = $remise->description; // Description ligne
2031  $line->vat_src_code = $remise->vat_src_code;
2032  $line->tva_tx = $remise->tva_tx;
2033  $line->subprice = -$remise->amount_ht;
2034  $line->price = -$remise->amount_ht;
2035  $line->fk_product = 0; // Id produit predefini
2036  $line->qty = 1;
2037  $line->remise_percent = 0;
2038  $line->rang = -1;
2039  $line->info_bits = 2;
2040 
2041  $line->total_ht = -$remise->amount_ht;
2042  $line->total_tva = -$remise->amount_tva;
2043  $line->total_ttc = -$remise->amount_ttc;
2044 
2045  $result = $line->insert();
2046  if ($result > 0) {
2047  $result = $this->update_price(1);
2048  if ($result > 0) {
2049  $this->db->commit();
2050  return 1;
2051  } else {
2052  $this->db->rollback();
2053  return -1;
2054  }
2055  } else {
2056  $this->error = $line->error;
2057  $this->errors = $line->errors;
2058  $this->db->rollback();
2059  return -2;
2060  }
2061  } else {
2062  $this->db->rollback();
2063  return -2;
2064  }
2065  }
2066 
2067 
2068  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2076  public function fetch_lines($only_product = 0, $loadalsotranslation = 0)
2077  {
2078  // phpcs:enable
2079  global $langs, $conf;
2080 
2081  $this->lines = array();
2082 
2083  $sql = 'SELECT l.rowid, l.fk_product, l.fk_parent_line, l.product_type, l.fk_commande, l.label as custom_label, l.description, l.price, l.qty, l.vat_src_code, l.tva_tx, l.ref_ext,';
2084  $sql .= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.fk_remise_except, l.remise_percent, l.subprice, l.fk_product_fournisseur_price as fk_fournprice, l.buy_price_ht as pa_ht, l.rang, l.info_bits, l.special_code,';
2085  $sql .= ' l.total_ht, l.total_ttc, l.total_tva, l.total_localtax1, l.total_localtax2, l.date_start, l.date_end,';
2086  $sql .= ' l.fk_unit,';
2087  $sql .= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
2088  $sql .= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label, p.tosell as product_tosell, p.tobuy as product_tobuy, p.tobatch as product_tobatch, p.barcode as product_barcode,';
2089  $sql .= ' p.weight, p.weight_units, p.volume, p.volume_units';
2090  $sql .= ' FROM '.MAIN_DB_PREFIX.'commandedet as l';
2091  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON (p.rowid = l.fk_product)';
2092  $sql .= ' WHERE l.fk_commande = '.((int) $this->id);
2093  if ($only_product) {
2094  $sql .= ' AND p.fk_product_type = 0';
2095  }
2096  $sql .= ' ORDER BY l.rang, l.rowid';
2097 
2098  dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
2099  $result = $this->db->query($sql);
2100  if ($result) {
2101  $num = $this->db->num_rows($result);
2102 
2103  $i = 0;
2104  while ($i < $num) {
2105  $objp = $this->db->fetch_object($result);
2106 
2107  $line = new OrderLine($this->db);
2108 
2109  $line->rowid = $objp->rowid;
2110  $line->id = $objp->rowid;
2111  $line->fk_commande = $objp->fk_commande;
2112  $line->commande_id = $objp->fk_commande;
2113  $line->label = $objp->custom_label;
2114  $line->desc = $objp->description;
2115  $line->description = $objp->description; // Description line
2116  $line->product_type = $objp->product_type;
2117  $line->qty = $objp->qty;
2118  $line->ref_ext = $objp->ref_ext;
2119 
2120  $line->vat_src_code = $objp->vat_src_code;
2121  $line->tva_tx = $objp->tva_tx;
2122  $line->localtax1_tx = $objp->localtax1_tx;
2123  $line->localtax2_tx = $objp->localtax2_tx;
2124  $line->localtax1_type = $objp->localtax1_type;
2125  $line->localtax2_type = $objp->localtax2_type;
2126  $line->total_ht = $objp->total_ht;
2127  $line->total_ttc = $objp->total_ttc;
2128  $line->total_tva = $objp->total_tva;
2129  $line->total_localtax1 = $objp->total_localtax1;
2130  $line->total_localtax2 = $objp->total_localtax2;
2131  $line->subprice = $objp->subprice;
2132  $line->fk_remise_except = $objp->fk_remise_except;
2133  $line->remise_percent = $objp->remise_percent;
2134  $line->price = $objp->price;
2135  $line->fk_product = $objp->fk_product;
2136  $line->fk_fournprice = $objp->fk_fournprice;
2137  $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht);
2138  $line->pa_ht = $marginInfos[0];
2139  $line->marge_tx = $marginInfos[1];
2140  $line->marque_tx = $marginInfos[2];
2141  $line->rang = $objp->rang;
2142  $line->info_bits = $objp->info_bits;
2143  $line->special_code = $objp->special_code;
2144  $line->fk_parent_line = $objp->fk_parent_line;
2145 
2146  $line->ref = $objp->product_ref;
2147  $line->libelle = $objp->product_label;
2148 
2149  $line->product_ref = $objp->product_ref;
2150  $line->product_label = $objp->product_label;
2151  $line->product_tosell = $objp->product_tosell;
2152  $line->product_tobuy = $objp->product_tobuy;
2153  $line->product_desc = $objp->product_desc;
2154  $line->product_tobatch = $objp->product_tobatch;
2155  $line->product_barcode = $objp->product_barcode;
2156 
2157  $line->fk_product_type = $objp->fk_product_type; // Produit ou service
2158  $line->fk_unit = $objp->fk_unit;
2159 
2160  $line->weight = $objp->weight;
2161  $line->weight_units = $objp->weight_units;
2162  $line->volume = $objp->volume;
2163  $line->volume_units = $objp->volume_units;
2164 
2165  $line->date_start = $this->db->jdate($objp->date_start);
2166  $line->date_end = $this->db->jdate($objp->date_end);
2167 
2168  // Multicurrency
2169  $line->fk_multicurrency = $objp->fk_multicurrency;
2170  $line->multicurrency_code = $objp->multicurrency_code;
2171  $line->multicurrency_subprice = $objp->multicurrency_subprice;
2172  $line->multicurrency_total_ht = $objp->multicurrency_total_ht;
2173  $line->multicurrency_total_tva = $objp->multicurrency_total_tva;
2174  $line->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
2175 
2176  $line->fetch_optionals();
2177 
2178  // multilangs
2179  if (getDolGlobalInt('MAIN_MULTILANGS') && !empty($objp->fk_product) && !empty($loadalsotranslation)) {
2180  $tmpproduct = new Product($this->db);
2181  $tmpproduct->fetch($objp->fk_product);
2182  $tmpproduct->getMultiLangs();
2183 
2184  $line->multilangs = $tmpproduct->multilangs;
2185  }
2186 
2187  $this->lines[$i] = $line;
2188 
2189  $i++;
2190  }
2191 
2192  $this->db->free($result);
2193 
2194  return 1;
2195  } else {
2196  $this->error = $this->db->error();
2197  return -3;
2198  }
2199  }
2200 
2201 
2207  public function getNbOfProductsLines()
2208  {
2209  $nb = 0;
2210  foreach ($this->lines as $line) {
2211  if ($line->product_type == 0) {
2212  $nb++;
2213  }
2214  }
2215  return $nb;
2216  }
2217 
2223  public function getNbOfServicesLines()
2224  {
2225  $nb = 0;
2226  foreach ($this->lines as $line) {
2227  if ($line->product_type == 1) {
2228  $nb++;
2229  }
2230  }
2231  return $nb;
2232  }
2233 
2239  public function getNbOfShipments()
2240  {
2241  $nb = 0;
2242 
2243  $sql = 'SELECT COUNT(DISTINCT ed.fk_expedition) as nb';
2244  $sql .= ' FROM '.MAIN_DB_PREFIX.'expeditiondet as ed,';
2245  $sql .= ' '.MAIN_DB_PREFIX.'commandedet as cd';
2246  $sql .= ' WHERE';
2247  $sql .= ' ed.fk_origin_line = cd.rowid';
2248  $sql .= ' AND cd.fk_commande = '.((int) $this->id);
2249  //print $sql;
2250 
2251  dol_syslog(get_class($this)."::getNbOfShipments", LOG_DEBUG);
2252  $resql = $this->db->query($sql);
2253  if ($resql) {
2254  $obj = $this->db->fetch_object($resql);
2255  if ($obj) {
2256  $nb = $obj->nb;
2257  }
2258 
2259  $this->db->free($resql);
2260  return $nb;
2261  } else {
2262  $this->error = $this->db->lasterror();
2263  return -1;
2264  }
2265  }
2266 
2275  public function loadExpeditions($filtre_statut = -1, $fk_product = 0)
2276  {
2277  $this->expeditions = array();
2278 
2279  $sql = 'SELECT cd.rowid, cd.fk_product,';
2280  $sql .= ' sum(ed.qty) as qty';
2281  $sql .= ' FROM '.MAIN_DB_PREFIX.'expeditiondet as ed,';
2282  if ($filtre_statut >= 0) {
2283  $sql .= ' '.MAIN_DB_PREFIX.'expedition as e,';
2284  }
2285  $sql .= ' '.MAIN_DB_PREFIX.'commandedet as cd';
2286  $sql .= ' WHERE';
2287  if ($filtre_statut >= 0) {
2288  $sql .= ' ed.fk_expedition = e.rowid AND';
2289  }
2290  $sql .= ' ed.fk_origin_line = cd.rowid';
2291  $sql .= ' AND cd.fk_commande = '.((int) $this->id);
2292  if ($fk_product > 0) {
2293  $sql .= ' AND cd.fk_product = '.((int) $fk_product);
2294  }
2295  if ($filtre_statut >= 0) {
2296  $sql .= ' AND e.fk_statut >= '.((int) $filtre_statut);
2297  }
2298  $sql .= ' GROUP BY cd.rowid, cd.fk_product';
2299  //print $sql;
2300 
2301  dol_syslog(get_class($this)."::loadExpeditions", LOG_DEBUG);
2302  $resql = $this->db->query($sql);
2303  if ($resql) {
2304  $num = $this->db->num_rows($resql);
2305  $i = 0;
2306  while ($i < $num) {
2307  $obj = $this->db->fetch_object($resql);
2308  $this->expeditions[$obj->rowid] = $obj->qty;
2309  $i++;
2310  }
2311  $this->db->free($resql);
2312  return $num;
2313  } else {
2314  $this->error = $this->db->lasterror();
2315  return -1;
2316  }
2317  }
2318 
2324  public function countNbOfShipments()
2325  {
2326  $sql = 'SELECT count(*)';
2327  $sql .= ' FROM '.MAIN_DB_PREFIX.'expedition as e';
2328  $sql .= ', '.MAIN_DB_PREFIX.'element_element as el';
2329  $sql .= ' WHERE el.fk_source = '.((int) $this->id);
2330  $sql .= " AND el.sourcetype = 'commande'";
2331  $sql .= " AND el.fk_target = e.rowid";
2332  $sql .= " AND el.targettype = 'shipping'";
2333 
2334  $resql = $this->db->query($sql);
2335  if ($resql) {
2336  $row = $this->db->fetch_row($resql);
2337  return $row[0];
2338  } else {
2339  dol_print_error($this->db);
2340  }
2341 
2342  return 0;
2343  }
2344 
2345  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2354  public function stock_array($filtre_statut = self::STATUS_CANCELED)
2355  {
2356  // phpcs:enable
2357  $this->stocks = array();
2358 
2359  // Tableau des id de produit de la commande
2360  $array_of_product = array();
2361 
2362  // Recherche total en stock pour chaque produit
2363  // TODO $array_of_product est défini vide juste au dessus !!
2364  if (count($array_of_product)) {
2365  $sql = "SELECT fk_product, sum(ps.reel) as total";
2366  $sql .= " FROM ".MAIN_DB_PREFIX."product_stock as ps";
2367  $sql .= " WHERE ps.fk_product IN (".$this->db->sanitize(join(',', $array_of_product)).")";
2368  $sql .= ' GROUP BY fk_product';
2369  $resql = $this->db->query($sql);
2370  if ($resql) {
2371  $num = $this->db->num_rows($resql);
2372  $i = 0;
2373  while ($i < $num) {
2374  $obj = $this->db->fetch_object($resql);
2375  $this->stocks[$obj->fk_product] = $obj->total;
2376  $i++;
2377  }
2378  $this->db->free($resql);
2379  }
2380  }
2381  return 0;
2382  }
2383 
2392  public function deleteline($user = null, $lineid = 0, $id = 0)
2393  {
2394  if ($this->statut == self::STATUS_DRAFT) {
2395  $this->db->begin();
2396 
2397  // Delete line
2398  $line = new OrderLine($this->db);
2399 
2400  $line->context = $this->context;
2401 
2402  // Load data
2403  $line->fetch($lineid);
2404 
2405  if ($id > 0 && $line->fk_commande != $id) {
2406  $this->error = 'ErrorLineIDDoesNotMatchWithObjectID';
2407  return -1;
2408  }
2409 
2410  // Memorize previous line for triggers
2411  $staticline = clone $line;
2412  $line->oldline = $staticline;
2413 
2414  if ($line->delete($user) > 0) {
2415  $result = $this->update_price(1);
2416 
2417  if ($result > 0) {
2418  $this->db->commit();
2419  return 1;
2420  } else {
2421  $this->db->rollback();
2422  $this->error = $this->db->lasterror();
2423  return -1;
2424  }
2425  } else {
2426  $this->db->rollback();
2427  $this->error = $line->error;
2428  return -1;
2429  }
2430  } else {
2431  $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
2432  return -1;
2433  }
2434  }
2435 
2436  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2447  public function set_remise($user, $remise, $notrigger = 0)
2448  {
2449  // phpcs:enable
2450  dol_syslog(get_class($this)."::set_remise is deprecated, use setDiscount instead", LOG_NOTICE);
2451  return $this->setDiscount($user, $remise, $notrigger);
2452  }
2453 
2462  public function setDiscount($user, $remise, $notrigger = 0)
2463  {
2464  $remise = trim($remise) ?trim($remise) : 0;
2465 
2466  if ($user->rights->commande->creer) {
2467  $error = 0;
2468 
2469  $this->db->begin();
2470 
2471  $remise = price2num($remise, 2);
2472 
2473  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
2474  $sql .= ' SET remise_percent = '.((float) $remise);
2475  $sql .= ' WHERE rowid = '.((int) $this->id).' AND fk_statut = '.((int) self::STATUS_DRAFT);
2476 
2477  dol_syslog(__METHOD__, LOG_DEBUG);
2478  $resql = $this->db->query($sql);
2479  if (!$resql) {
2480  $this->errors[] = $this->db->error();
2481  $error++;
2482  }
2483 
2484  if (!$error) {
2485  $this->oldcopy = clone $this;
2486  $this->remise_percent = $remise;
2487  $this->update_price(1);
2488  }
2489 
2490  if (!$notrigger && empty($error)) {
2491  // Call trigger
2492  $result = $this->call_trigger('ORDER_MODIFY', $user);
2493  if ($result < 0) {
2494  $error++;
2495  }
2496  // End call triggers
2497  }
2498 
2499  if (!$error) {
2500  $this->db->commit();
2501  return 1;
2502  } else {
2503  foreach ($this->errors as $errmsg) {
2504  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2505  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2506  }
2507  $this->db->rollback();
2508  return -1 * $error;
2509  }
2510  }
2511 
2512  return 0;
2513  }
2514 
2515 
2516  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2525  public function set_remise_absolue($user, $remise, $notrigger = 0)
2526  {
2527  // phpcs:enable
2528  if (empty($remise)) {
2529  $remise = 0;
2530  }
2531 
2532  $remise = price2num($remise);
2533 
2534  if ($user->rights->commande->creer) {
2535  $error = 0;
2536 
2537  $this->db->begin();
2538 
2539  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
2540  $sql .= ' SET remise_absolue = '.((float) $remise);
2541  $sql .= ' WHERE rowid = '.((int) $this->id).' AND fk_statut = '.self::STATUS_DRAFT;
2542 
2543  dol_syslog(__METHOD__, LOG_DEBUG);
2544  $resql = $this->db->query($sql);
2545  if (!$resql) {
2546  $this->errors[] = $this->db->error();
2547  $error++;
2548  }
2549 
2550  if (!$error) {
2551  $this->oldcopy = clone $this;
2552  $this->remise_absolue = $remise;
2553  $this->update_price(1);
2554  }
2555 
2556  if (!$notrigger && empty($error)) {
2557  // Call trigger
2558  $result = $this->call_trigger('ORDER_MODIFY', $user);
2559  if ($result < 0) {
2560  $error++;
2561  }
2562  // End call triggers
2563  }
2564 
2565  if (!$error) {
2566  $this->db->commit();
2567  return 1;
2568  } else {
2569  foreach ($this->errors as $errmsg) {
2570  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2571  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2572  }
2573  $this->db->rollback();
2574  return -1 * $error;
2575  }
2576  }
2577 
2578  return 0;
2579  }
2580 
2581 
2582  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2591  public function set_date($user, $date, $notrigger = 0)
2592  {
2593  // phpcs:enable
2594  if ($user->rights->commande->creer) {
2595  $error = 0;
2596 
2597  $this->db->begin();
2598 
2599  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
2600  $sql .= " SET date_commande = ".($date ? "'".$this->db->idate($date)."'" : 'null');
2601  $sql .= " WHERE rowid = ".((int) $this->id)." AND fk_statut = ".((int) self::STATUS_DRAFT);
2602 
2603  dol_syslog(__METHOD__, LOG_DEBUG);
2604  $resql = $this->db->query($sql);
2605  if (!$resql) {
2606  $this->errors[] = $this->db->error();
2607  $error++;
2608  }
2609 
2610  if (!$error) {
2611  $this->oldcopy = clone $this;
2612  $this->date = $date;
2613  }
2614 
2615  if (!$notrigger && empty($error)) {
2616  // Call trigger
2617  $result = $this->call_trigger('ORDER_MODIFY', $user);
2618  if ($result < 0) {
2619  $error++;
2620  }
2621  // End call triggers
2622  }
2623 
2624  if (!$error) {
2625  $this->db->commit();
2626  return 1;
2627  } else {
2628  foreach ($this->errors as $errmsg) {
2629  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2630  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2631  }
2632  $this->db->rollback();
2633  return -1 * $error;
2634  }
2635  } else {
2636  return -2;
2637  }
2638  }
2639 
2640  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2650  public function set_date_livraison($user, $delivery_date, $notrigger = 0)
2651  {
2652  // phpcs:enable
2653  return $this->setDeliveryDate($user, $delivery_date, $notrigger);
2654  }
2655 
2664  public function setDeliveryDate($user, $delivery_date, $notrigger = 0)
2665  {
2666  if ($user->rights->commande->creer) {
2667  $error = 0;
2668 
2669  $this->db->begin();
2670 
2671  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
2672  $sql .= " SET date_livraison = ".($delivery_date ? "'".$this->db->idate($delivery_date)."'" : 'null');
2673  $sql .= " WHERE rowid = ".((int) $this->id);
2674 
2675  dol_syslog(__METHOD__, LOG_DEBUG);
2676  $resql = $this->db->query($sql);
2677  if (!$resql) {
2678  $this->errors[] = $this->db->error();
2679  $error++;
2680  }
2681 
2682  if (!$error) {
2683  $this->oldcopy = clone $this;
2684  $this->date_livraison = $delivery_date;
2685  $this->delivery_date = $delivery_date;
2686  }
2687 
2688  if (!$notrigger && empty($error)) {
2689  // Call trigger
2690  $result = $this->call_trigger('ORDER_MODIFY', $user);
2691  if ($result < 0) {
2692  $error++;
2693  }
2694  // End call triggers
2695  }
2696 
2697  if (!$error) {
2698  $this->db->commit();
2699  return 1;
2700  } else {
2701  foreach ($this->errors as $errmsg) {
2702  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2703  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2704  }
2705  $this->db->rollback();
2706  return -1 * $error;
2707  }
2708  } else {
2709  return -2;
2710  }
2711  }
2712 
2713  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2727  public function liste_array($shortlist = 0, $draft = 0, $excluser = '', $socid = 0, $limit = 0, $offset = 0, $sortfield = 'c.date_commande', $sortorder = 'DESC')
2728  {
2729  // phpcs:enable
2730  global $user;
2731 
2732  $ga = array();
2733 
2734  $sql = "SELECT s.rowid, s.nom as name, s.client,";
2735  $sql .= " c.rowid as cid, c.ref";
2736  if (empty($user->rights->societe->client->voir) && !$socid) {
2737  $sql .= ", sc.fk_soc, sc.fk_user";
2738  }
2739  $sql .= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande as c";
2740  if (empty($user->rights->societe->client->voir) && !$socid) {
2741  $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
2742  }
2743  $sql .= " WHERE c.entity IN (".getEntity('commande').")";
2744  $sql .= " AND c.fk_soc = s.rowid";
2745  if (empty($user->rights->societe->client->voir) && !$socid) { //restriction
2746  $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
2747  }
2748  if ($socid) {
2749  $sql .= " AND s.rowid = ".((int) $socid);
2750  }
2751  if ($draft) {
2752  $sql .= " AND c.fk_statut = ".self::STATUS_DRAFT;
2753  }
2754  if (is_object($excluser)) {
2755  $sql .= " AND c.fk_user_author <> ".((int) $excluser->id);
2756  }
2757  $sql .= $this->db->order($sortfield, $sortorder);
2758  $sql .= $this->db->plimit($limit, $offset);
2759 
2760  $result = $this->db->query($sql);
2761  if ($result) {
2762  $numc = $this->db->num_rows($result);
2763  if ($numc) {
2764  $i = 0;
2765  while ($i < $numc) {
2766  $obj = $this->db->fetch_object($result);
2767 
2768  if ($shortlist == 1) {
2769  $ga[$obj->cid] = $obj->ref;
2770  } elseif ($shortlist == 2) {
2771  $ga[$obj->cid] = $obj->ref.' ('.$obj->name.')';
2772  } else {
2773  $ga[$i]['id'] = $obj->cid;
2774  $ga[$i]['ref'] = $obj->ref;
2775  $ga[$i]['name'] = $obj->name;
2776  }
2777  $i++;
2778  }
2779  }
2780  return $ga;
2781  } else {
2782  dol_print_error($this->db);
2783  return -1;
2784  }
2785  }
2786 
2794  public function availability($availability_id, $notrigger = 0)
2795  {
2796  global $user;
2797 
2798  dol_syslog('Commande::availability('.$availability_id.')');
2799  if ($this->statut >= self::STATUS_DRAFT) {
2800  $error = 0;
2801 
2802  $this->db->begin();
2803 
2804  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
2805  $sql .= ' SET fk_availability = '.((int) $availability_id);
2806  $sql .= ' WHERE rowid='.((int) $this->id);
2807 
2808  dol_syslog(__METHOD__, LOG_DEBUG);
2809  $resql = $this->db->query($sql);
2810  if (!$resql) {
2811  $this->errors[] = $this->db->error();
2812  $error++;
2813  }
2814 
2815  if (!$error) {
2816  $this->oldcopy = clone $this;
2817  $this->availability_id = $availability_id;
2818  }
2819 
2820  if (!$notrigger && empty($error)) {
2821  // Call trigger
2822  $result = $this->call_trigger('ORDER_MODIFY', $user);
2823  if ($result < 0) {
2824  $error++;
2825  }
2826  // End call triggers
2827  }
2828 
2829  if (!$error) {
2830  $this->db->commit();
2831  return 1;
2832  } else {
2833  foreach ($this->errors as $errmsg) {
2834  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2835  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2836  }
2837  $this->db->rollback();
2838  return -1 * $error;
2839  }
2840  } else {
2841  $error_str = 'Command status do not meet requirement '.$this->statut;
2842  dol_syslog(__METHOD__.$error_str, LOG_ERR);
2843  $this->error = $error_str;
2844  $this->errors[] = $this->error;
2845  return -2;
2846  }
2847  }
2848 
2849  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2857  public function demand_reason($demand_reason_id, $notrigger = 0)
2858  {
2859  // phpcs:enable
2860  global $user;
2861 
2862  dol_syslog('Commande::demand_reason('.$demand_reason_id.')');
2863  if ($this->statut >= self::STATUS_DRAFT) {
2864  $error = 0;
2865 
2866  $this->db->begin();
2867 
2868  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
2869  $sql .= ' SET fk_input_reason = '.((int) $demand_reason_id);
2870  $sql .= ' WHERE rowid='.((int) $this->id);
2871 
2872  dol_syslog(__METHOD__, LOG_DEBUG);
2873  $resql = $this->db->query($sql);
2874  if (!$resql) {
2875  $this->errors[] = $this->db->error();
2876  $error++;
2877  }
2878 
2879  if (!$error) {
2880  $this->oldcopy = clone $this;
2881  $this->demand_reason_id = $demand_reason_id;
2882  }
2883 
2884  if (!$notrigger && empty($error)) {
2885  // Call trigger
2886  $result = $this->call_trigger('ORDER_MODIFY', $user);
2887  if ($result < 0) {
2888  $error++;
2889  }
2890  // End call triggers
2891  }
2892 
2893  if (!$error) {
2894  $this->db->commit();
2895  return 1;
2896  } else {
2897  foreach ($this->errors as $errmsg) {
2898  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2899  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2900  }
2901  $this->db->rollback();
2902  return -1 * $error;
2903  }
2904  } else {
2905  $error_str = 'order status do not meet requirement '.$this->statut;
2906  dol_syslog(__METHOD__.$error_str, LOG_ERR);
2907  $this->error = $error_str;
2908  $this->errors[] = $this->error;
2909  return -2;
2910  }
2911  }
2912 
2913  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2922  public function set_ref_client($user, $ref_client, $notrigger = 0)
2923  {
2924  // phpcs:enable
2925  if ($user->rights->commande->creer) {
2926  $error = 0;
2927 
2928  $this->db->begin();
2929 
2930  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande SET';
2931  $sql .= ' ref_client = '.(empty($ref_client) ? 'NULL' : "'".$this->db->escape($ref_client)."'");
2932  $sql .= ' WHERE rowid = '.((int) $this->id);
2933 
2934  dol_syslog(__METHOD__.' this->id='.$this->id.', ref_client='.$ref_client, LOG_DEBUG);
2935  $resql = $this->db->query($sql);
2936  if (!$resql) {
2937  $this->errors[] = $this->db->error();
2938  $error++;
2939  }
2940 
2941  if (!$error) {
2942  $this->oldcopy = clone $this;
2943  $this->ref_client = $ref_client;
2944  }
2945 
2946  if (!$notrigger && empty($error)) {
2947  // Call trigger
2948  $result = $this->call_trigger('ORDER_MODIFY', $user);
2949  if ($result < 0) {
2950  $error++;
2951  }
2952  // End call triggers
2953  }
2954  if (!$error) {
2955  $this->db->commit();
2956  return 1;
2957  } else {
2958  foreach ($this->errors as $errmsg) {
2959  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2960  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2961  }
2962  $this->db->rollback();
2963  return -1 * $error;
2964  }
2965  } else {
2966  return -1;
2967  }
2968  }
2969 
2977  public function classifyBilled(User $user, $notrigger = 0)
2978  {
2979  $error = 0;
2980 
2981  if ($this->billed) {
2982  return 0;
2983  }
2984 
2985  $this->db->begin();
2986 
2987  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande SET facture = 1';
2988  $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > '.self::STATUS_DRAFT;
2989 
2990  dol_syslog(get_class($this)."::classifyBilled", LOG_DEBUG);
2991  if ($this->db->query($sql)) {
2992  if (!$error) {
2993  $this->oldcopy = clone $this;
2994  $this->billed = 1;
2995  }
2996 
2997  if (!$notrigger && empty($error)) {
2998  // Call trigger
2999  $result = $this->call_trigger('ORDER_CLASSIFY_BILLED', $user);
3000  if ($result < 0) {
3001  $error++;
3002  }
3003  // End call triggers
3004  }
3005 
3006  if (!$error) {
3007  $this->db->commit();
3008  return 1;
3009  } else {
3010  foreach ($this->errors as $errmsg) {
3011  dol_syslog(get_class($this)."::classifyBilled ".$errmsg, LOG_ERR);
3012  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
3013  }
3014  $this->db->rollback();
3015  return -1 * $error;
3016  }
3017  } else {
3018  $this->error = $this->db->error();
3019  $this->db->rollback();
3020  return -1;
3021  }
3022  }
3023 
3031  public function classifyUnBilled(User $user, $notrigger = 0)
3032  {
3033  $error = 0;
3034 
3035  $this->db->begin();
3036 
3037  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande SET facture = 0';
3038  $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > '.self::STATUS_DRAFT;
3039 
3040  dol_syslog(get_class($this)."::classifyUnBilled", LOG_DEBUG);
3041  if ($this->db->query($sql)) {
3042  if (!$error) {
3043  $this->oldcopy = clone $this;
3044  $this->billed = 1;
3045  }
3046 
3047  if (!$notrigger && empty($error)) {
3048  // Call trigger
3049  $result = $this->call_trigger('ORDER_CLASSIFY_UNBILLED', $user);
3050  if ($result < 0) {
3051  $error++;
3052  }
3053  // End call triggers
3054  }
3055 
3056  if (!$error) {
3057  $this->billed = 0;
3058 
3059  $this->db->commit();
3060  return 1;
3061  } else {
3062  foreach ($this->errors as $errmsg) {
3063  dol_syslog(get_class($this)."::classifyUnBilled ".$errmsg, LOG_ERR);
3064  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
3065  }
3066  $this->db->rollback();
3067  return -1 * $error;
3068  }
3069  } else {
3070  $this->error = $this->db->error();
3071  $this->db->rollback();
3072  return -1;
3073  }
3074  }
3075 
3076 
3107  public function updateline($rowid, $desc, $pu, $qty, $remise_percent, $txtva, $txlocaltax1 = 0.0, $txlocaltax2 = 0.0, $price_base_type = 'HT', $info_bits = 0, $date_start = '', $date_end = '', $type = 0, $fk_parent_line = 0, $skip_update_total = 0, $fk_fournprice = null, $pa_ht = 0, $label = '', $special_code = 0, $array_options = 0, $fk_unit = null, $pu_ht_devise = 0, $notrigger = 0, $ref_ext = '', $rang = 0)
3108  {
3109  global $conf, $mysoc, $langs, $user;
3110 
3111  dol_syslog(get_class($this)."::updateline id=$rowid, desc=$desc, pu=$pu, qty=$qty, remise_percent=$remise_percent, txtva=$txtva, txlocaltax1=$txlocaltax1, txlocaltax2=$txlocaltax2, price_base_type=$price_base_type, info_bits=$info_bits, date_start=$date_start, date_end=$date_end, type=$type, fk_parent_line=$fk_parent_line, pa_ht=$pa_ht, special_code=$special_code, ref_ext=$ref_ext");
3112  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
3113 
3114  if ($this->statut == Commande::STATUS_DRAFT) {
3115  // Clean parameters
3116  if (empty($qty)) {
3117  $qty = 0;
3118  }
3119  if (empty($info_bits)) {
3120  $info_bits = 0;
3121  }
3122  if (empty($txtva)) {
3123  $txtva = 0;
3124  }
3125  if (empty($txlocaltax1)) {
3126  $txlocaltax1 = 0;
3127  }
3128  if (empty($txlocaltax2)) {
3129  $txlocaltax2 = 0;
3130  }
3131  if (empty($remise_percent)) {
3132  $remise_percent = 0;
3133  }
3134  if (empty($special_code) || $special_code == 3) {
3135  $special_code = 0;
3136  }
3137  if (empty($ref_ext)) {
3138  $ref_ext = '';
3139  }
3140 
3141  if ($date_start && $date_end && $date_start > $date_end) {
3142  $langs->load("errors");
3143  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
3144  return -1;
3145  }
3146 
3147  $remise_percent = price2num($remise_percent);
3148  $qty = price2num($qty);
3149  $pu = price2num($pu);
3150  $pa_ht = price2num($pa_ht);
3151  $pu_ht_devise = price2num($pu_ht_devise);
3152  if (!preg_match('/\((.*)\)/', $txtva)) {
3153  $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
3154  }
3155  $txlocaltax1 = price2num($txlocaltax1);
3156  $txlocaltax2 = price2num($txlocaltax2);
3157 
3158  $this->db->begin();
3159 
3160  // Calcul du total TTC et de la TVA pour la ligne a partir de
3161  // qty, pu, remise_percent et txtva
3162  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
3163  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
3164 
3165  $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
3166 
3167  // Clean vat code
3168  $vat_src_code = '';
3169  $reg = array();
3170  if (preg_match('/\((.*)\)/', $txtva, $reg)) {
3171  $vat_src_code = $reg[1];
3172  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
3173  }
3174 
3175  $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
3176 
3177  $total_ht = $tabprice[0];
3178  $total_tva = $tabprice[1];
3179  $total_ttc = $tabprice[2];
3180  $total_localtax1 = $tabprice[9];
3181  $total_localtax2 = $tabprice[10];
3182  $pu_ht = $tabprice[3];
3183  $pu_tva = $tabprice[4];
3184  $pu_ttc = $tabprice[5];
3185 
3186  // MultiCurrency
3187  $multicurrency_total_ht = $tabprice[16];
3188  $multicurrency_total_tva = $tabprice[17];
3189  $multicurrency_total_ttc = $tabprice[18];
3190  $pu_ht_devise = $tabprice[19];
3191 
3192  // Anciens indicateurs: $price, $subprice (a ne plus utiliser)
3193  $price = $pu_ht;
3194  if ($price_base_type == 'TTC') {
3195  $subprice = $pu_ttc;
3196  } else {
3197  $subprice = $pu_ht;
3198  }
3199  $remise = 0;
3200  if ($remise_percent > 0) {
3201  $remise = round(($pu * $remise_percent / 100), 2);
3202  $price = ($pu - $remise);
3203  }
3204 
3205  //Fetch current line from the database and then clone the object and set it in $oldline property
3206  $line = new OrderLine($this->db);
3207  $line->fetch($rowid);
3208  $line->fetch_optionals();
3209 
3210  if (!empty($line->fk_product)) {
3211  $product = new Product($this->db);
3212  $result = $product->fetch($line->fk_product);
3213  $product_type = $product->type;
3214 
3215  if (!empty($conf->global->STOCK_MUST_BE_ENOUGH_FOR_ORDER) && $product_type == 0 && $product->stock_reel < $qty) {
3216  $langs->load("errors");
3217  $this->error = $langs->trans('ErrorStockIsNotEnoughToAddProductOnOrder', $product->ref);
3218  $this->errors[] = $this->error;
3219 
3220  dol_syslog(get_class($this)."::addline error=Product ".$product->ref.": ".$this->error, LOG_ERR);
3221 
3222  $this->db->rollback();
3224  }
3225  }
3226 
3227  $staticline = clone $line;
3228 
3229  $line->oldline = $staticline;
3230  $this->line = $line;
3231  $this->line->context = $this->context;
3232  $this->line->rang = $rang;
3233 
3234  // Reorder if fk_parent_line change
3235  if (!empty($fk_parent_line) && !empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line) {
3236  $rangmax = $this->line_max($fk_parent_line);
3237  $this->line->rang = $rangmax + 1;
3238  }
3239 
3240  $this->line->id = $rowid;
3241  $this->line->label = $label;
3242  $this->line->desc = $desc;
3243  $this->line->qty = $qty;
3244  $this->line->ref_ext = $ref_ext;
3245 
3246  $this->line->vat_src_code = $vat_src_code;
3247  $this->line->tva_tx = $txtva;
3248  $this->line->localtax1_tx = $txlocaltax1;
3249  $this->line->localtax2_tx = $txlocaltax2;
3250  $this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
3251  $this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
3252  $this->line->remise_percent = $remise_percent;
3253  $this->line->subprice = $subprice;
3254  $this->line->info_bits = $info_bits;
3255  $this->line->special_code = $special_code;
3256  $this->line->total_ht = $total_ht;
3257  $this->line->total_tva = $total_tva;
3258  $this->line->total_localtax1 = $total_localtax1;
3259  $this->line->total_localtax2 = $total_localtax2;
3260  $this->line->total_ttc = $total_ttc;
3261  $this->line->date_start = $date_start;
3262  $this->line->date_end = $date_end;
3263  $this->line->product_type = $type;
3264  $this->line->fk_parent_line = $fk_parent_line;
3265  $this->line->skip_update_total = $skip_update_total;
3266  $this->line->fk_unit = $fk_unit;
3267 
3268  $this->line->fk_fournprice = $fk_fournprice;
3269  $this->line->pa_ht = $pa_ht;
3270 
3271  // Multicurrency
3272  $this->line->multicurrency_subprice = $pu_ht_devise;
3273  $this->line->multicurrency_total_ht = $multicurrency_total_ht;
3274  $this->line->multicurrency_total_tva = $multicurrency_total_tva;
3275  $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
3276 
3277  // TODO deprecated
3278  $this->line->price = $price;
3279 
3280  if (is_array($array_options) && count($array_options) > 0) {
3281  // We replace values in this->line->array_options only for entries defined into $array_options
3282  foreach ($array_options as $key => $value) {
3283  $this->line->array_options[$key] = $array_options[$key];
3284  }
3285  }
3286 
3287  $result = $this->line->update($user, $notrigger);
3288  if ($result > 0) {
3289  // Reorder if child line
3290  if (!empty($fk_parent_line)) {
3291  $this->line_order(true, 'DESC');
3292  }
3293 
3294  // Mise a jour info denormalisees
3295  $this->update_price(1);
3296 
3297  $this->db->commit();
3298  return $result;
3299  } else {
3300  $this->error = $this->line->error;
3301 
3302  $this->db->rollback();
3303  return -1;
3304  }
3305  } else {
3306  $this->error = get_class($this)."::updateline Order status makes operation forbidden";
3307  $this->errors = array('OrderStatusMakeOperationForbidden');
3308  return -2;
3309  }
3310  }
3311 
3319  public function update(User $user, $notrigger = 0)
3320  {
3321  global $conf;
3322 
3323  $error = 0;
3324 
3325  // Clean parameters
3326  if (isset($this->ref)) {
3327  $this->ref = trim($this->ref);
3328  }
3329  if (isset($this->ref_client)) {
3330  $this->ref_client = trim($this->ref_client);
3331  }
3332  if (isset($this->note) || isset($this->note_private)) {
3333  $this->note_private = (isset($this->note_private) ? trim($this->note_private) : trim($this->note));
3334  }
3335  if (isset($this->note_public)) {
3336  $this->note_public = trim($this->note_public);
3337  }
3338  if (isset($this->model_pdf)) {
3339  $this->model_pdf = trim($this->model_pdf);
3340  }
3341  if (isset($this->import_key)) {
3342  $this->import_key = trim($this->import_key);
3343  }
3344  $delivery_date = empty($this->delivery_date) ? $this->date_livraison : $this->delivery_date;
3345 
3346  // Check parameters
3347  // Put here code to add control on parameters values
3348 
3349  // Update request
3350  $sql = "UPDATE ".MAIN_DB_PREFIX."commande SET";
3351 
3352  $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").",";
3353  $sql .= " ref_client=".(isset($this->ref_client) ? "'".$this->db->escape($this->ref_client)."'" : "null").",";
3354  $sql .= " ref_ext=".(isset($this->ref_ext) ? "'".$this->db->escape($this->ref_ext)."'" : "null").",";
3355  $sql .= " fk_soc=".(isset($this->socid) ? $this->socid : "null").",";
3356  $sql .= " date_commande=".(strval($this->date_commande) != '' ? "'".$this->db->idate($this->date_commande)."'" : 'null').",";
3357  $sql .= " date_valid=".(strval($this->date_validation) != '' ? "'".$this->db->idate($this->date_validation)."'" : 'null').",";
3358  $sql .= " total_tva=".(isset($this->total_tva) ? $this->total_tva : "null").",";
3359  $sql .= " localtax1=".(isset($this->total_localtax1) ? $this->total_localtax1 : "null").",";
3360  $sql .= " localtax2=".(isset($this->total_localtax2) ? $this->total_localtax2 : "null").",";
3361  $sql .= " total_ht=".(isset($this->total_ht) ? $this->total_ht : "null").",";
3362  $sql .= " total_ttc=".(isset($this->total_ttc) ? $this->total_ttc : "null").",";
3363  $sql .= " fk_statut=".(isset($this->statut) ? $this->statut : "null").",";
3364  $sql .= " fk_user_author=".(isset($this->user_author_id) ? $this->user_author_id : "null").",";
3365  $sql .= " fk_user_valid=".((isset($this->user_valid) && $this->user_valid > 0) ? $this->user_valid : "null").",";
3366  $sql .= " fk_projet=".(isset($this->fk_project) ? $this->fk_project : "null").",";
3367  $sql .= " fk_cond_reglement=".(isset($this->cond_reglement_id) ? $this->cond_reglement_id : "null").",";
3368  $sql .= " deposit_percent=".(!empty($this->deposit_percent) ? strval($this->deposit_percent) : "null").",";
3369  $sql .= " fk_mode_reglement=".(isset($this->mode_reglement_id) ? $this->mode_reglement_id : "null").",";
3370  $sql .= " date_livraison=".(strval($this->delivery_date) != '' ? "'".$this->db->idate($this->delivery_date)."'" : 'null').",";
3371  $sql .= " fk_shipping_method=".(isset($this->shipping_method_id) ? $this->shipping_method_id : "null").",";
3372  $sql .= " fk_account=".($this->fk_account > 0 ? $this->fk_account : "null").",";
3373  $sql .= " fk_input_reason=".($this->demand_reason_id > 0 ? $this->demand_reason_id : "null").",";
3374  $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
3375  $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
3376  $sql .= " model_pdf=".(isset($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null").",";
3377  $sql .= " import_key=".(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null");
3378 
3379  $sql .= " WHERE rowid=".((int) $this->id);
3380 
3381  $this->db->begin();
3382 
3383  dol_syslog(get_class($this)."::update", LOG_DEBUG);
3384  $resql = $this->db->query($sql);
3385  if (!$resql) {
3386  $error++; $this->errors[] = "Error ".$this->db->lasterror();
3387  }
3388 
3389  if (!$error) {
3390  $result = $this->insertExtraFields();
3391  if ($result < 0) {
3392  $error++;
3393  }
3394  }
3395 
3396  if (!$error && !$notrigger) {
3397  // Call trigger
3398  $result = $this->call_trigger('ORDER_MODIFY', $user);
3399  if ($result < 0) {
3400  $error++;
3401  }
3402  // End call triggers
3403  }
3404 
3405  // Commit or rollback
3406  if ($error) {
3407  foreach ($this->errors as $errmsg) {
3408  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
3409  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
3410  }
3411  $this->db->rollback();
3412  return -1 * $error;
3413  } else {
3414  $this->db->commit();
3415  return 1;
3416  }
3417  }
3418 
3426  public function delete($user, $notrigger = 0)
3427  {
3428  global $conf, $langs;
3429  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
3430 
3431  $error = 0;
3432 
3433  dol_syslog(get_class($this)."::delete ".$this->id, LOG_DEBUG);
3434 
3435  $this->db->begin();
3436 
3437  if (!$notrigger) {
3438  // Call trigger
3439  $result = $this->call_trigger('ORDER_DELETE', $user);
3440  if ($result < 0) {
3441  $error++;
3442  }
3443  // End call triggers
3444  }
3445 
3446  // Test we can delete
3447  if ($this->countNbOfShipments() != 0) {
3448  $this->errors[] = $langs->trans('SomeShipmentExists');
3449  $error++;
3450  }
3451 
3452  // Delete extrafields of lines and lines
3453  if (!$error && !empty($this->table_element_line)) {
3454  $tabletodelete = $this->table_element_line;
3455  $sqlef = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete."_extrafields WHERE fk_object IN (SELECT rowid FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".((int) $this->id).")";
3456  $sql = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".((int) $this->id);
3457  if (!$this->db->query($sqlef) || !$this->db->query($sql)) {
3458  $error++;
3459  $this->error = $this->db->lasterror();
3460  $this->errors[] = $this->error;
3461  dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
3462  }
3463  }
3464 
3465  if (!$error) {
3466  // Delete linked object
3467  $res = $this->deleteObjectLinked();
3468  if ($res < 0) {
3469  $error++;
3470  }
3471  }
3472 
3473  if (!$error) {
3474  // Delete linked contacts
3475  $res = $this->delete_linked_contact();
3476  if ($res < 0) {
3477  $error++;
3478  }
3479  }
3480 
3481  // Removed extrafields of object
3482  if (!$error) {
3483  $result = $this->deleteExtraFields();
3484  if ($result < 0) {
3485  $error++;
3486  dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
3487  }
3488  }
3489 
3490  // Delete main record
3491  if (!$error) {
3492  $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element." WHERE rowid = ".((int) $this->id);
3493  $res = $this->db->query($sql);
3494  if (!$res) {
3495  $error++;
3496  $this->error = $this->db->lasterror();
3497  $this->errors[] = $this->error;
3498  dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
3499  }
3500  }
3501 
3502  // Delete record into ECM index and physically
3503  if (!$error) {
3504  $res = $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive
3505  if (!$res) {
3506  $error++;
3507  }
3508  }
3509 
3510  if (!$error) {
3511  // We remove directory
3512  $ref = dol_sanitizeFileName($this->ref);
3513  if ($conf->commande->multidir_output[$this->entity] && !empty($this->ref)) {
3514  $dir = $conf->commande->multidir_output[$this->entity]."/".$ref;
3515  $file = $dir."/".$ref.".pdf";
3516  if (file_exists($file)) {
3517  dol_delete_preview($this);
3518 
3519  if (!dol_delete_file($file, 0, 0, 0, $this)) {
3520  $this->error = 'ErrorFailToDeleteFile';
3521  $this->errors[] = $this->error;
3522  $this->db->rollback();
3523  return 0;
3524  }
3525  }
3526  if (file_exists($dir)) {
3527  $res = @dol_delete_dir_recursive($dir);
3528  if (!$res) {
3529  $this->error = 'ErrorFailToDeleteDir';
3530  $this->errors[] = $this->error;
3531  $this->db->rollback();
3532  return 0;
3533  }
3534  }
3535  }
3536  }
3537 
3538  if (!$error) {
3539  dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
3540  $this->db->commit();
3541  return 1;
3542  } else {
3543  $this->db->rollback();
3544  return -1;
3545  }
3546  }
3547 
3548 
3549  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3556  public function load_board($user)
3557  {
3558  // phpcs:enable
3559  global $conf, $langs;
3560 
3561  $clause = " WHERE";
3562 
3563  $sql = "SELECT c.rowid, c.date_creation as datec, c.date_commande, c.date_livraison as delivery_date, c.fk_statut, c.total_ht";
3564  $sql .= " FROM ".MAIN_DB_PREFIX."commande as c";
3565  if (empty($user->rights->societe->client->voir) && !$user->socid) {
3566  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON c.fk_soc = sc.fk_soc";
3567  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
3568  $clause = " AND";
3569  }
3570  $sql .= $clause." c.entity IN (".getEntity('commande').")";
3571  //$sql.= " AND c.fk_statut IN (1,2,3) AND c.facture = 0";
3572  $sql .= " AND ((c.fk_statut IN (".self::STATUS_VALIDATED.",".self::STATUS_SHIPMENTONPROCESS.")) OR (c.fk_statut = ".self::STATUS_CLOSED." AND c.facture = 0))"; // If status is 2 and facture=1, it must be selected
3573  if ($user->socid) {
3574  $sql .= " AND c.fk_soc = ".((int) $user->socid);
3575  }
3576 
3577  $resql = $this->db->query($sql);
3578  if ($resql) {
3579  $response = new WorkboardResponse();
3580  $response->warning_delay = $conf->commande->client->warning_delay / 60 / 60 / 24;
3581  $response->label = $langs->trans("OrdersToProcess");
3582  $response->labelShort = $langs->trans("Opened");
3583  $response->url = DOL_URL_ROOT.'/commande/list.php?search_status=-3&mainmenu=commercial&leftmenu=orders';
3584  $response->img = img_object('', "order");
3585 
3586  $generic_commande = new Commande($this->db);
3587 
3588  while ($obj = $this->db->fetch_object($resql)) {
3589  $response->nbtodo++;
3590  $response->total += $obj->total_ht;
3591 
3592  $generic_commande->statut = $obj->fk_statut;
3593  $generic_commande->date_commande = $this->db->jdate($obj->date_commande);
3594  $generic_commande->date = $this->db->jdate($obj->date_commande);
3595  $generic_commande->date_livraison = $this->db->jdate($obj->delivery_date);
3596  $generic_commande->delivery_date = $this->db->jdate($obj->delivery_date);
3597 
3598  if ($generic_commande->hasDelay()) {
3599  $response->nbtodolate++;
3600  }
3601  }
3602 
3603  return $response;
3604  } else {
3605  $this->error = $this->db->error();
3606  return -1;
3607  }
3608  }
3609 
3615  public function getLabelSource()
3616  {
3617  global $langs;
3618 
3619  $label = $langs->trans('OrderSource'.$this->source);
3620 
3621  if ($label == 'OrderSource') {
3622  return '';
3623  }
3624  return $label;
3625  }
3626 
3633  public function getLibStatut($mode)
3634  {
3635  return $this->LibStatut($this->statut, $this->billed, $mode);
3636  }
3637 
3638  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3648  public function LibStatut($status, $billed, $mode, $donotshowbilled = 0)
3649  {
3650  // phpcs:enable
3651  global $langs, $conf, $hookmanager;
3652 
3653  $billedtext = '';
3654  if (empty($donotshowbilled)) {
3655  $billedtext .= ($billed ? ' - '.$langs->transnoentitiesnoconv("Billed") : '');
3656  }
3657 
3658  $labelTooltip = '';
3659 
3660  if ($status == self::STATUS_CANCELED) {
3661  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderCanceled');
3662  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderCanceledShort');
3663  $statusType = 'status9';
3664  } elseif ($status == self::STATUS_DRAFT) {
3665  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderDraft');
3666  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderDraftShort');
3667  $statusType = 'status0';
3668  } elseif ($status == self::STATUS_VALIDATED) {
3669  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderValidated').$billedtext;
3670  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderValidatedShort').$billedtext;
3671  $statusType = 'status1';
3672  } elseif ($status == self::STATUS_SHIPMENTONPROCESS) {
3673  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderSent').$billedtext;
3674  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderSentShort').$billedtext;
3675  $labelTooltip = $langs->transnoentitiesnoconv("StatusOrderSent");
3676  if (!empty($this->delivery_date)) {
3677  $labelTooltip .= ' - '.$langs->transnoentitiesnoconv("DateDeliveryPlanned").dol_print_date($this->delivery_date, 'day').$billedtext;
3678  }
3679  $statusType = 'status4';
3680  } elseif ($status == self::STATUS_CLOSED && (!$billed && empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) {
3681  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderToBill'); // translated into Delivered
3682  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderToBillShort'); // translated into Delivered
3683  $statusType = 'status4';
3684  } elseif ($status == self::STATUS_CLOSED && ($billed && empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) {
3685  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderProcessed').$billedtext;
3686  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderProcessedShort').$billedtext;
3687  $statusType = 'status6';
3688  } elseif ($status == self::STATUS_CLOSED && (!empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) {
3689  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderDelivered');
3690  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderDeliveredShort');
3691  $statusType = 'status6';
3692  } else {
3693  $labelStatus = $langs->transnoentitiesnoconv('Unknown');
3694  $labelStatusShort = '';
3695  $statusType = '';
3696  $mode = 0;
3697  }
3698 
3699  $parameters = array(
3700  'status' => $status,
3701  'mode' => $mode,
3702  'billed' => $billed,
3703  'donotshowbilled' => $donotshowbilled
3704  );
3705 
3706  $reshook = $hookmanager->executeHooks('LibStatut', $parameters, $this); // Note that $action and $object may have been modified by hook
3707 
3708  if ($reshook > 0) {
3709  return $hookmanager->resPrint;
3710  }
3711 
3712  return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode, '', array('tooltip' => $labelTooltip));
3713  }
3714 
3721  public function getTooltipContentArray($params)
3722  {
3723  global $conf, $langs, $user;
3724 
3725  $datas = [];
3726 
3727  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
3728  return ['optimize' => $langs->trans("Order")];
3729  }
3730 
3731  if ($user->hasRight('commande', 'lire')) {
3732  $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("Order").'</u>';
3733  if (isset($this->statut)) {
3734  $datas[] = ' '.$this->getLibStatut(5);
3735  }
3736  $datas['Ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
3737  $datas['RefCustomer'] = '<br><b>'.$langs->trans('RefCustomer').':</b> '.(empty($this->ref_customer) ? (empty($this->ref_client) ? '' : $this->ref_client) : $this->ref_customer);
3738  if (!empty($this->total_ht)) {
3739  $datas['AmountHT'] = '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
3740  }
3741  if (!empty($this->total_tva)) {
3742  $datas['VAT'] = '<br><b>'.$langs->trans('VAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
3743  }
3744  if (!empty($this->total_ttc)) {
3745  $datas['AmountTTC'] = '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
3746  }
3747  if (!empty($this->date)) {
3748  $datas['Date'] = '<br><b>'.$langs->trans('Date').':</b> '.dol_print_date($this->date, 'day');
3749  }
3750  if (!empty($this->delivery_date)) {
3751  $datas['DeliveryDate'] = '<br><b>'.$langs->trans('DeliveryDate').':</b> '.dol_print_date($this->delivery_date, 'dayhour');
3752  }
3753  }
3754 
3755  return $datas;
3756  }
3757 
3771  public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0, $target = '')
3772  {
3773  global $conf, $langs, $user, $hookmanager;
3774 
3775  if (!empty($conf->dol_no_mouse_hover)) {
3776  $notooltip = 1; // Force disable tooltips
3777  }
3778 
3779  $result = '';
3780 
3781  if (isModEnabled("expedition") && ($option == '1' || $option == '2')) {
3782  $url = DOL_URL_ROOT.'/expedition/shipment.php?id='.$this->id;
3783  } else {
3784  $url = DOL_URL_ROOT.'/commande/card.php?id='.$this->id;
3785  }
3786 
3787  if (!$user->rights->commande->lire) {
3788  $option = 'nolink';
3789  }
3790 
3791  if ($option !== 'nolink') {
3792  // Add param to save lastsearch_values or not
3793  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
3794  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
3795  $add_save_lastsearch_values = 1;
3796  }
3797  if ($add_save_lastsearch_values) {
3798  $url .= '&save_lastsearch_values=1';
3799  }
3800  }
3801 
3802  if ($short) {
3803  return $url;
3804  }
3805  $params = [
3806  'id' => $this->id,
3807  'objecttype' => $this->element,
3808  'option' => $option,
3809  ];
3810  $classfortooltip = 'classfortooltip';
3811  $dataparams = '';
3812  if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
3813  $classfortooltip = 'classforajaxtooltip';
3814  $dataparams = ' data-params='.json_encode($params);
3815  // $label = $langs->trans('Loading');
3816  }
3817 
3818  $label = implode($this->getTooltipContentArray($params));
3819 
3820  $linkclose = '';
3821  if (empty($notooltip) && $user->hasRight('commande', 'lire')) {
3822  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
3823  $label = $langs->trans("Order");
3824  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
3825  }
3826  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
3827  $linkclose .= $dataparams.' class="'.$classfortooltip.'"';
3828 
3829  $target_value = array('_self', '_blank', '_parent', '_top');
3830  if (in_array($target, $target_value)) {
3831  $linkclose .= ' target="'.dol_escape_htmltag($target).'"';
3832  }
3833  }
3834 
3835  $linkstart = '<a href="'.$url.'"';
3836  $linkstart .= $linkclose.'>';
3837  $linkend = '</a>';
3838 
3839  if ($option === 'nolink') {
3840  $linkstart = '';
3841  $linkend = '';
3842  }
3843 
3844  $result .= $linkstart;
3845  if ($withpicto) {
3846  $result .= img_object(($notooltip ? '' : $label), $this->picto, ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : $dataparams.' class="'.(($withpicto != 2) ? 'paddingright ' : '').$classfortooltip.'"'), 0, 0, $notooltip ? 0 : 1);
3847  }
3848  if ($withpicto != 2) {
3849  $result .= $this->ref;
3850  }
3851  $result .= $linkend;
3852 
3853  if ($addlinktonotes) {
3854  $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
3855  if ($txttoshow) {
3856  $notetoshow = $langs->trans("ViewPrivateNote").':<br>'.dol_string_nohtmltag($txttoshow, 1);
3857  $result .= ' <span class="note inline-block">';
3858  $result .= '<a href="'.DOL_URL_ROOT.'/commande/note.php?id='.$this->id.'" class="classfortooltip" title="'.dol_escape_htmltag($notetoshow).'">';
3859  $result .= img_picto('', 'note');
3860  $result .= '</a>';
3861  //$result.=img_picto($langs->trans("ViewNote"),'object_generic');
3862  //$result.='</a>';
3863  $result .= '</span>';
3864  }
3865  }
3866 
3867  global $action;
3868  $hookmanager->initHooks(array($this->element . 'dao'));
3869  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
3870  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3871  if ($reshook > 0) {
3872  $result = $hookmanager->resPrint;
3873  } else {
3874  $result .= $hookmanager->resPrint;
3875  }
3876  return $result;
3877  }
3878 
3879 
3886  public function info($id)
3887  {
3888  $sql = 'SELECT c.rowid, date_creation as datec, tms as datem,';
3889  $sql .= ' date_valid as datev,';
3890  $sql .= ' date_cloture as datecloture,';
3891  $sql .= ' fk_user_author, fk_user_valid, fk_user_cloture';
3892  $sql .= ' FROM '.MAIN_DB_PREFIX.'commande as c';
3893  $sql .= ' WHERE c.rowid = '.((int) $id);
3894  $result = $this->db->query($sql);
3895  if ($result) {
3896  if ($this->db->num_rows($result)) {
3897  $obj = $this->db->fetch_object($result);
3898  $this->id = $obj->rowid;
3899  if ($obj->fk_user_author) {
3900  $this->user_creation_id = $obj->fk_user_author;
3901  }
3902  if ($obj->fk_user_valid) {
3903  $this->user_validation_id = $obj->fk_user_valid;
3904  }
3905  if ($obj->fk_user_cloture) {
3906  $this->user_closing_id = $obj->fk_user_cloture;
3907  }
3908 
3909  $this->date_creation = $this->db->jdate($obj->datec);
3910  $this->date_modification = $this->db->jdate($obj->datem);
3911  $this->date_validation = $this->db->jdate($obj->datev);
3912  $this->date_cloture = $this->db->jdate($obj->datecloture);
3913  }
3914 
3915  $this->db->free($result);
3916  } else {
3917  dol_print_error($this->db);
3918  }
3919  }
3920 
3921 
3929  public function initAsSpecimen()
3930  {
3931  global $conf, $langs;
3932 
3933  dol_syslog(get_class($this)."::initAsSpecimen");
3934 
3935  // Load array of products prodids
3936  $num_prods = 0;
3937  $prodids = array();
3938  $sql = "SELECT rowid";
3939  $sql .= " FROM ".MAIN_DB_PREFIX."product";
3940  $sql .= " WHERE entity IN (".getEntity('product').")";
3941  $sql .= $this->db->plimit(100);
3942 
3943  $resql = $this->db->query($sql);
3944  if ($resql) {
3945  $num_prods = $this->db->num_rows($resql);
3946  $i = 0;
3947  while ($i < $num_prods) {
3948  $i++;
3949  $row = $this->db->fetch_row($resql);
3950  $prodids[$i] = $row[0];
3951  }
3952  }
3953 
3954  // Initialise parametres
3955  $this->id = 0;
3956  $this->ref = 'SPECIMEN';
3957  $this->specimen = 1;
3958  $this->socid = 1;
3959  $this->date = time();
3960  $this->date_lim_reglement = $this->date + 3600 * 24 * 30;
3961  $this->cond_reglement_code = 'RECEP';
3962  $this->mode_reglement_code = 'CHQ';
3963  $this->availability_code = 'DSP';
3964  $this->demand_reason_code = 'SRC_00';
3965 
3966  $this->note_public = 'This is a comment (public)';
3967  $this->note_private = 'This is a comment (private)';
3968 
3969  $this->multicurrency_tx = 1;
3970  $this->multicurrency_code = $conf->currency;
3971 
3972  // Lines
3973  $nbp = 5;
3974  $xnbp = 0;
3975  while ($xnbp < $nbp) {
3976  $line = new OrderLine($this->db);
3977 
3978  $line->desc = $langs->trans("Description")." ".$xnbp;
3979  $line->qty = 1;
3980  $line->subprice = 100;
3981  $line->price = 100;
3982  $line->tva_tx = 20;
3983  if ($xnbp == 2) {
3984  $line->total_ht = 50;
3985  $line->total_ttc = 60;
3986  $line->total_tva = 10;
3987  $line->remise_percent = 50;
3988  } else {
3989  $line->total_ht = 100;
3990  $line->total_ttc = 120;
3991  $line->total_tva = 20;
3992  $line->remise_percent = 0;
3993  }
3994  if ($num_prods > 0) {
3995  $prodid = mt_rand(1, $num_prods);
3996  $line->fk_product = $prodids[$prodid];
3997  $line->product_ref = 'SPECIMEN';
3998  }
3999 
4000  $this->lines[$xnbp] = $line;
4001 
4002  $this->total_ht += $line->total_ht;
4003  $this->total_tva += $line->total_tva;
4004  $this->total_ttc += $line->total_ttc;
4005 
4006  $xnbp++;
4007  }
4008  }
4009 
4010 
4011  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4017  public function load_state_board()
4018  {
4019  // phpcs:enable
4020  global $user;
4021 
4022  $this->nb = array();
4023  $clause = "WHERE";
4024 
4025  $sql = "SELECT count(co.rowid) as nb";
4026  $sql .= " FROM ".MAIN_DB_PREFIX."commande as co";
4027  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON co.fk_soc = s.rowid";
4028  if (empty($user->rights->societe->client->voir) && !$user->socid) {
4029  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
4030  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
4031  $clause = "AND";
4032  }
4033  $sql .= " ".$clause." co.entity IN (".getEntity('commande').")";
4034 
4035  $resql = $this->db->query($sql);
4036  if ($resql) {
4037  while ($obj = $this->db->fetch_object($resql)) {
4038  $this->nb["orders"] = $obj->nb;
4039  }
4040  $this->db->free($resql);
4041  return 1;
4042  } else {
4043  dol_print_error($this->db);
4044  $this->error = $this->db->error();
4045  return -1;
4046  }
4047  }
4048 
4054  public function getLinesArray()
4055  {
4056  return $this->fetch_lines();
4057  }
4058 
4070  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
4071  {
4072  global $conf, $langs;
4073 
4074  $langs->load("orders");
4075  $outputlangs->load("products");
4076 
4077  if (!dol_strlen($modele)) {
4078  $modele = 'einstein';
4079 
4080  if (!empty($this->model_pdf)) {
4081  $modele = $this->model_pdf;
4082  } elseif (!empty($this->modelpdf)) { // deprecated
4083  $modele = $this->modelpdf;
4084  } elseif (!empty($conf->global->COMMANDE_ADDON_PDF)) {
4085  $modele = $conf->global->COMMANDE_ADDON_PDF;
4086  }
4087  }
4088 
4089  $modelpath = "core/modules/commande/doc/";
4090 
4091  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
4092  }
4093 
4094 
4103  public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
4104  {
4105  $tables = array(
4106  'commande'
4107  );
4108 
4109  return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
4110  }
4111 
4120  public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
4121  {
4122  $tables = array(
4123  'commandedet',
4124  );
4125 
4126  return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
4127  }
4128 
4134  public function hasDelay()
4135  {
4136  global $conf;
4137 
4138  if (!($this->statut > Commande::STATUS_DRAFT && $this->statut < Commande::STATUS_CLOSED)) {
4139  return false; // Never late if not inside this status range
4140  }
4141 
4142  $now = dol_now();
4143 
4144  return max($this->date, $this->date_livraison) < ($now - $conf->commande->client->warning_delay);
4145  }
4146 
4152  public function showDelay()
4153  {
4154  global $conf, $langs;
4155 
4156  if (empty($this->date_livraison)) {
4157  $text = $langs->trans("OrderDate").' '.dol_print_date($this->date_commande, 'day');
4158  } else {
4159  $text = $text = $langs->trans("DeliveryDate").' '.dol_print_date($this->date_livraison, 'day');
4160  }
4161  $text .= ' '.($conf->commande->client->warning_delay > 0 ? '+' : '-').' '.round(abs($conf->commande->client->warning_delay) / 3600 / 24, 1).' '.$langs->trans("days").' < '.$langs->trans("Today");
4162 
4163  return $text;
4164  }
4165 }
4166 
4167 
4172 {
4176  public $element = 'commandedet';
4177 
4178  public $table_element = 'commandedet';
4179 
4180  public $oldline;
4181 
4186  public $fk_commande;
4187 
4194  public $commande_id;
4195 
4196  public $fk_parent_line;
4197 
4201  public $fk_facture;
4202 
4206  public $ref_ext;
4207 
4208  public $fk_remise_except;
4209 
4213  public $rang = 0;
4214  public $fk_fournprice;
4215 
4220  public $pa_ht;
4221  public $marge_tx;
4222  public $marque_tx;
4223 
4228  public $remise;
4229 
4230  // Start and end date of the line
4231  public $date_start;
4232  public $date_end;
4233 
4234  public $skip_update_total; // Skip update price total for special lines
4235 
4236 
4242  public function __construct($db)
4243  {
4244  $this->db = $db;
4245  }
4246 
4253  public function fetch($rowid)
4254  {
4255  $sql = 'SELECT cd.rowid, cd.fk_commande, cd.fk_parent_line, cd.fk_product, cd.product_type, cd.label as custom_label, cd.description, cd.price, cd.qty, cd.tva_tx, cd.localtax1_tx, cd.localtax2_tx,';
4256  $sql .= ' cd.remise, cd.remise_percent, cd.fk_remise_except, cd.subprice, cd.ref_ext,';
4257  $sql .= ' cd.info_bits, cd.total_ht, cd.total_tva, cd.total_localtax1, cd.total_localtax2, cd.total_ttc, cd.fk_product_fournisseur_price as fk_fournprice, cd.buy_price_ht as pa_ht, cd.rang, cd.special_code,';
4258  $sql .= ' cd.fk_unit,';
4259  $sql .= ' cd.fk_multicurrency, cd.multicurrency_code, cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc,';
4260  $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc, p.tobatch as product_tobatch,';
4261  $sql .= ' cd.date_start, cd.date_end, cd.vat_src_code';
4262  $sql .= ' FROM '.MAIN_DB_PREFIX.'commandedet as cd';
4263  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON cd.fk_product = p.rowid';
4264  $sql .= ' WHERE cd.rowid = '.((int) $rowid);
4265  $result = $this->db->query($sql);
4266  if ($result) {
4267  $objp = $this->db->fetch_object($result);
4268 
4269  if (!$objp) {
4270  $this->error = 'OrderLine with id '. $rowid .' not found sql='.$sql;
4271  return 0;
4272  }
4273 
4274  $this->rowid = $objp->rowid;
4275  $this->id = $objp->rowid;
4276  $this->fk_commande = $objp->fk_commande;
4277  $this->fk_parent_line = $objp->fk_parent_line;
4278  $this->label = $objp->custom_label;
4279  $this->desc = $objp->description;
4280  $this->qty = $objp->qty;
4281  $this->price = $objp->price;
4282  $this->subprice = $objp->subprice;
4283  $this->ref_ext = $objp->ref_ext;
4284  $this->vat_src_code = $objp->vat_src_code;
4285  $this->tva_tx = $objp->tva_tx;
4286  $this->localtax1_tx = $objp->localtax1_tx;
4287  $this->localtax2_tx = $objp->localtax2_tx;
4288  $this->remise = $objp->remise;
4289  $this->remise_percent = $objp->remise_percent;
4290  $this->fk_remise_except = $objp->fk_remise_except;
4291  $this->fk_product = $objp->fk_product;
4292  $this->product_type = $objp->product_type;
4293  $this->info_bits = $objp->info_bits;
4294  $this->special_code = $objp->special_code;
4295  $this->total_ht = $objp->total_ht;
4296  $this->total_tva = $objp->total_tva;
4297  $this->total_localtax1 = $objp->total_localtax1;
4298  $this->total_localtax2 = $objp->total_localtax2;
4299  $this->total_ttc = $objp->total_ttc;
4300  $this->fk_fournprice = $objp->fk_fournprice;
4301  $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $this->fk_fournprice, $objp->pa_ht);
4302  $this->pa_ht = $marginInfos[0];
4303  $this->marge_tx = $marginInfos[1];
4304  $this->marque_tx = $marginInfos[2];
4305  $this->special_code = $objp->special_code;
4306  $this->rang = $objp->rang;
4307 
4308  $this->ref = $objp->product_ref; // deprecated
4309 
4310  $this->product_ref = $objp->product_ref;
4311  $this->product_label = $objp->product_label;
4312  $this->product_desc = $objp->product_desc;
4313  $this->product_tobatch = $objp->product_tobatch;
4314  $this->fk_unit = $objp->fk_unit;
4315 
4316  $this->date_start = $this->db->jdate($objp->date_start);
4317  $this->date_end = $this->db->jdate($objp->date_end);
4318 
4319  $this->fk_multicurrency = $objp->fk_multicurrency;
4320  $this->multicurrency_code = $objp->multicurrency_code;
4321  $this->multicurrency_subprice = $objp->multicurrency_subprice;
4322  $this->multicurrency_total_ht = $objp->multicurrency_total_ht;
4323  $this->multicurrency_total_tva = $objp->multicurrency_total_tva;
4324  $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
4325 
4326  $this->db->free($result);
4327 
4328  return 1;
4329  } else {
4330  $this->error = $this->db->lasterror();
4331  return -1;
4332  }
4333  }
4334 
4342  public function delete(User $user, $notrigger = 0)
4343  {
4344  global $conf, $langs;
4345 
4346  $error = 0;
4347 
4348  if (empty($this->id) && !empty($this->rowid)) { // For backward compatibility
4349  $this->id = $this->rowid;
4350  }
4351 
4352  // check if order line is not in a shipment line before deleting
4353  $sqlCheckShipmentLine = "SELECT";
4354  $sqlCheckShipmentLine .= " ed.rowid";
4355  $sqlCheckShipmentLine .= " FROM ".MAIN_DB_PREFIX."expeditiondet ed";
4356  $sqlCheckShipmentLine .= " WHERE ed.fk_origin_line = ".((int) $this->id);
4357 
4358  $resqlCheckShipmentLine = $this->db->query($sqlCheckShipmentLine);
4359  if (!$resqlCheckShipmentLine) {
4360  $error++;
4361  $this->error = $this->db->lasterror();
4362  $this->errors[] = $this->error;
4363  } else {
4364  $langs->load('errors');
4365  $num = $this->db->num_rows($resqlCheckShipmentLine);
4366  if ($num > 0) {
4367  $error++;
4368  $objCheckShipmentLine = $this->db->fetch_object($resqlCheckShipmentLine);
4369  $this->error = $langs->trans('ErrorRecordAlreadyExists').' : '.$langs->trans('ShipmentLine').' '.$objCheckShipmentLine->rowid;
4370  $this->errors[] = $this->error;
4371  }
4372  $this->db->free($resqlCheckShipmentLine);
4373  }
4374  if ($error) {
4375  dol_syslog(__METHOD__.'Error ; '.$this->error, LOG_ERR);
4376  return -1;
4377  }
4378 
4379  $this->db->begin();
4380 
4381  $sql = 'DELETE FROM '.MAIN_DB_PREFIX."commandedet WHERE rowid = ".((int) $this->id);
4382 
4383  dol_syslog("OrderLine::delete", LOG_DEBUG);
4384  $resql = $this->db->query($sql);
4385  if ($resql) {
4386  if (!$error && !$notrigger) {
4387  // Call trigger
4388  $result = $this->call_trigger('LINEORDER_DELETE', $user);
4389  if ($result < 0) {
4390  $error++;
4391  }
4392  // End call triggers
4393  }
4394 
4395  // Remove extrafields
4396  if (!$error) {
4397  $result = $this->deleteExtraFields();
4398  if ($result < 0) {
4399  $error++;
4400  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
4401  }
4402  }
4403 
4404  if (!$error) {
4405  $this->db->commit();
4406  return 1;
4407  }
4408 
4409  foreach ($this->errors as $errmsg) {
4410  dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
4411  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
4412  }
4413  $this->db->rollback();
4414  return -1 * $error;
4415  } else {
4416  $this->error = $this->db->lasterror();
4417  return -1;
4418  }
4419  }
4420 
4428  public function insert($user = null, $notrigger = 0)
4429  {
4430  global $langs, $conf;
4431 
4432  $error = 0;
4433 
4434  $pa_ht_isemptystring = (empty($this->pa_ht) && $this->pa_ht == ''); // If true, we can use a default value. If this->pa_ht = '0', we must use '0'.
4435 
4436  dol_syslog(get_class($this)."::insert rang=".$this->rang);
4437 
4438  // Clean parameters
4439  if (empty($this->tva_tx)) {
4440  $this->tva_tx = 0;
4441  }
4442  if (empty($this->localtax1_tx)) {
4443  $this->localtax1_tx = 0;
4444  }
4445  if (empty($this->localtax2_tx)) {
4446  $this->localtax2_tx = 0;
4447  }
4448  if (empty($this->localtax1_type)) {
4449  $this->localtax1_type = 0;
4450  }
4451  if (empty($this->localtax2_type)) {
4452  $this->localtax2_type = 0;
4453  }
4454  if (empty($this->total_localtax1)) {
4455  $this->total_localtax1 = 0;
4456  }
4457  if (empty($this->total_localtax2)) {
4458  $this->total_localtax2 = 0;
4459  }
4460  if (empty($this->rang)) {
4461  $this->rang = 0;
4462  }
4463  if (empty($this->remise_percent)) {
4464  $this->remise_percent = 0;
4465  }
4466  if (empty($this->info_bits)) {
4467  $this->info_bits = 0;
4468  }
4469  if (empty($this->special_code)) {
4470  $this->special_code = 0;
4471  }
4472  if (empty($this->fk_parent_line)) {
4473  $this->fk_parent_line = 0;
4474  }
4475  if (empty($this->pa_ht)) {
4476  $this->pa_ht = 0;
4477  }
4478  if (empty($this->ref_ext)) {
4479  $this->ref_ext = '';
4480  }
4481 
4482  // if buy price not defined, define buyprice as configured in margin admin
4483  if ($this->pa_ht == 0 && $pa_ht_isemptystring) {
4484  $result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product);
4485  if ($result < 0) {
4486  return $result;
4487  } else {
4488  $this->pa_ht = $result;
4489  }
4490  }
4491 
4492  // Check parameters
4493  if ($this->product_type < 0) {
4494  return -1;
4495  }
4496 
4497  $this->db->begin();
4498 
4499  // Insertion dans base de la ligne
4500  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'commandedet';
4501  $sql .= ' (fk_commande, fk_parent_line, label, description, qty, ref_ext,';
4502  $sql .= ' vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
4503  $sql .= ' fk_product, product_type, remise_percent, subprice, price, fk_remise_except,';
4504  $sql .= ' special_code, rang, fk_product_fournisseur_price, buy_price_ht,';
4505  $sql .= ' info_bits, total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, date_start, date_end,';
4506  $sql .= ' fk_unit';
4507  $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
4508  $sql .= ')';
4509  $sql .= " VALUES (".$this->fk_commande.",";
4510  $sql .= " ".($this->fk_parent_line > 0 ? "'".$this->db->escape($this->fk_parent_line)."'" : "null").",";
4511  $sql .= " ".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
4512  $sql .= " '".$this->db->escape($this->desc)."',";
4513  $sql .= " '".price2num($this->qty)."',";
4514  $sql .= " '".$this->db->escape($this->ref_ext)."',";
4515  $sql .= " ".(empty($this->vat_src_code) ? "''" : "'".$this->db->escape($this->vat_src_code)."'").",";
4516  $sql .= " '".price2num($this->tva_tx)."',";
4517  $sql .= " '".price2num($this->localtax1_tx)."',";
4518  $sql .= " '".price2num($this->localtax2_tx)."',";
4519  $sql .= " '".$this->db->escape($this->localtax1_type)."',";
4520  $sql .= " '".$this->db->escape($this->localtax2_type)."',";
4521  $sql .= ' '.((!empty($this->fk_product) && $this->fk_product > 0) ? $this->fk_product : "null").',';
4522  $sql .= " '".$this->db->escape($this->product_type)."',";
4523  $sql .= " '".price2num($this->remise_percent)."',";
4524  $sql .= " ".(price2num($this->subprice) !== '' ?price2num($this->subprice) : "null").",";
4525  $sql .= " ".($this->price != '' ? "'".price2num($this->price)."'" : "null").",";
4526  $sql .= ' '.(!empty($this->fk_remise_except) ? $this->fk_remise_except : "null").',';
4527  $sql .= ' '.((int) $this->special_code).',';
4528  $sql .= ' '.((int) $this->rang).',';
4529  $sql .= ' '.(!empty($this->fk_fournprice) ? $this->fk_fournprice : "null").',';
4530  $sql .= ' '.price2num($this->pa_ht).',';
4531  $sql .= " ".((int) $this->info_bits).",";
4532  $sql .= " ".price2num($this->total_ht, 'MT').",";
4533  $sql .= " ".price2num($this->total_tva, 'MT').",";
4534  $sql .= " ".price2num($this->total_localtax1, 'MT').",";
4535  $sql .= " ".price2num($this->total_localtax2, 'MT').",";
4536  $sql .= " ".price2num($this->total_ttc, 'MT').",";
4537  $sql .= " ".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null").',';
4538  $sql .= " ".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null").',';
4539  $sql .= ' '.(!$this->fk_unit ? 'NULL' : ((int) $this->fk_unit));
4540  $sql .= ", ".(!empty($this->fk_multicurrency) ? ((int) $this->fk_multicurrency) : 'NULL');
4541  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
4542  $sql .= ", ".price2num($this->multicurrency_subprice, 'CU');
4543  $sql .= ", ".price2num($this->multicurrency_total_ht, 'CT');
4544  $sql .= ", ".price2num($this->multicurrency_total_tva, 'CT');
4545  $sql .= ", ".price2num($this->multicurrency_total_ttc, 'CT');
4546  $sql .= ')';
4547 
4548  dol_syslog(get_class($this)."::insert", LOG_DEBUG);
4549  $resql = $this->db->query($sql);
4550  if ($resql) {
4551  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'commandedet');
4552  $this->rowid = $this->id;
4553 
4554  if (!$error) {
4555  $result = $this->insertExtraFields();
4556  if ($result < 0) {
4557  $error++;
4558  }
4559  }
4560 
4561  if (!$error && !$notrigger) {
4562  // Call trigger
4563  $result = $this->call_trigger('LINEORDER_INSERT', $user);
4564  if ($result < 0) {
4565  $error++;
4566  }
4567  // End call triggers
4568  }
4569 
4570  if (!$error) {
4571  $this->db->commit();
4572  return 1;
4573  }
4574 
4575  foreach ($this->errors as $errmsg) {
4576  dol_syslog(get_class($this)."::insert ".$errmsg, LOG_ERR);
4577  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
4578  }
4579  $this->db->rollback();
4580  return -1 * $error;
4581  } else {
4582  $this->error = $this->db->error();
4583  $this->db->rollback();
4584  return -2;
4585  }
4586  }
4587 
4595  public function update(User $user, $notrigger = 0)
4596  {
4597  global $conf, $langs;
4598 
4599  $error = 0;
4600 
4601  $pa_ht_isemptystring = (empty($this->pa_ht) && $this->pa_ht == ''); // If true, we can use a default value. If this->pa_ht = '0', we must use '0'.
4602 
4603  // Clean parameters
4604  if (empty($this->tva_tx)) {
4605  $this->tva_tx = 0;
4606  }
4607  if (empty($this->localtax1_tx)) {
4608  $this->localtax1_tx = 0;
4609  }
4610  if (empty($this->localtax2_tx)) {
4611  $this->localtax2_tx = 0;
4612  }
4613  if (empty($this->localtax1_type)) {
4614  $this->localtax1_type = 0;
4615  }
4616  if (empty($this->localtax2_type)) {
4617  $this->localtax2_type = 0;
4618  }
4619  if (empty($this->qty)) {
4620  $this->qty = 0;
4621  }
4622  if (empty($this->total_localtax1)) {
4623  $this->total_localtax1 = 0;
4624  }
4625  if (empty($this->total_localtax2)) {
4626  $this->total_localtax2 = 0;
4627  }
4628  if (empty($this->marque_tx)) {
4629  $this->marque_tx = 0;
4630  }
4631  if (empty($this->marge_tx)) {
4632  $this->marge_tx = 0;
4633  }
4634  if (empty($this->remise_percent)) {
4635  $this->remise_percent = 0;
4636  }
4637  if (empty($this->remise)) {
4638  $this->remise = 0;
4639  }
4640  if (empty($this->info_bits)) {
4641  $this->info_bits = 0;
4642  }
4643  if (empty($this->special_code)) {
4644  $this->special_code = 0;
4645  }
4646  if (empty($this->product_type)) {
4647  $this->product_type = 0;
4648  }
4649  if (empty($this->fk_parent_line)) {
4650  $this->fk_parent_line = 0;
4651  }
4652  if (empty($this->pa_ht)) {
4653  $this->pa_ht = 0;
4654  }
4655  if (empty($this->ref_ext)) {
4656  $this->ref_ext = '';
4657  }
4658 
4659  // if buy price not defined, define buyprice as configured in margin admin
4660  if ($this->pa_ht == 0 && $pa_ht_isemptystring) {
4661  $result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product);
4662  if ($result < 0) {
4663  return $result;
4664  } else {
4665  $this->pa_ht = $result;
4666  }
4667  }
4668 
4669  $this->db->begin();
4670 
4671  // Mise a jour ligne en base
4672  $sql = "UPDATE ".MAIN_DB_PREFIX."commandedet SET";
4673  $sql .= " description='".$this->db->escape($this->desc)."'";
4674  $sql .= " , label=".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null");
4675  $sql .= " , vat_src_code=".(!empty($this->vat_src_code) ? "'".$this->db->escape($this->vat_src_code)."'" : "''");
4676  $sql .= " , tva_tx=".price2num($this->tva_tx);
4677  $sql .= " , localtax1_tx=".price2num($this->localtax1_tx);
4678  $sql .= " , localtax2_tx=".price2num($this->localtax2_tx);
4679  $sql .= " , localtax1_type='".$this->db->escape($this->localtax1_type)."'";
4680  $sql .= " , localtax2_type='".$this->db->escape($this->localtax2_type)."'";
4681  $sql .= " , qty=".price2num($this->qty);
4682  $sql .= " , ref_ext='".$this->db->escape($this->ref_ext)."'";
4683  $sql .= " , subprice=".price2num($this->subprice);
4684  $sql .= " , remise_percent=".price2num($this->remise_percent);
4685  $sql .= " , price=".price2num($this->price); // TODO A virer
4686  $sql .= " , remise=".price2num($this->remise); // TODO A virer
4687  if (empty($this->skip_update_total)) {
4688  $sql .= " , total_ht=".price2num($this->total_ht);
4689  $sql .= " , total_tva=".price2num($this->total_tva);
4690  $sql .= " , total_ttc=".price2num($this->total_ttc);
4691  $sql .= " , total_localtax1=".price2num($this->total_localtax1);
4692  $sql .= " , total_localtax2=".price2num($this->total_localtax2);
4693  }
4694  $sql .= " , fk_product_fournisseur_price=".(!empty($this->fk_fournprice) ? $this->fk_fournprice : "null");
4695  $sql .= " , buy_price_ht='".price2num($this->pa_ht)."'";
4696  $sql .= " , info_bits=".((int) $this->info_bits);
4697  $sql .= " , special_code=".((int) $this->special_code);
4698  $sql .= " , date_start=".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null");
4699  $sql .= " , date_end=".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null");
4700  $sql .= " , product_type=".$this->product_type;
4701  $sql .= " , fk_parent_line=".(!empty($this->fk_parent_line) ? $this->fk_parent_line : "null");
4702  if (!empty($this->rang)) {
4703  $sql .= ", rang=".((int) $this->rang);
4704  }
4705  $sql .= " , fk_unit=".(!$this->fk_unit ? 'NULL' : $this->fk_unit);
4706 
4707  // Multicurrency
4708  $sql .= " , multicurrency_subprice=".price2num($this->multicurrency_subprice);
4709  $sql .= " , multicurrency_total_ht=".price2num($this->multicurrency_total_ht);
4710  $sql .= " , multicurrency_total_tva=".price2num($this->multicurrency_total_tva);
4711  $sql .= " , multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc);
4712 
4713  $sql .= " WHERE rowid = ".((int) $this->rowid);
4714 
4715  dol_syslog(get_class($this)."::update", LOG_DEBUG);
4716  $resql = $this->db->query($sql);
4717  if ($resql) {
4718  if (!$error) {
4719  $this->id = $this->rowid;
4720  $result = $this->insertExtraFields();
4721  if ($result < 0) {
4722  $error++;
4723  }
4724  }
4725 
4726  if (!$error && !$notrigger) {
4727  // Call trigger
4728  $result = $this->call_trigger('LINEORDER_MODIFY', $user);
4729  if ($result < 0) {
4730  $error++;
4731  }
4732  // End call triggers
4733  }
4734 
4735  if (!$error) {
4736  $this->db->commit();
4737  return 1;
4738  }
4739 
4740  foreach ($this->errors as $errmsg) {
4741  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
4742  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
4743  }
4744  $this->db->rollback();
4745  return -1 * $error;
4746  } else {
4747  $this->error = $this->db->error();
4748  $this->db->rollback();
4749  return -2;
4750  }
4751  }
4752 
4753  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4760  public function update_total()
4761  {
4762  // phpcs:enable
4763  $this->db->begin();
4764 
4765  // Clean parameters
4766  if (empty($this->total_localtax1)) {
4767  $this->total_localtax1 = 0;
4768  }
4769  if (empty($this->total_localtax2)) {
4770  $this->total_localtax2 = 0;
4771  }
4772 
4773  // Mise a jour ligne en base
4774  $sql = "UPDATE ".MAIN_DB_PREFIX."commandedet SET";
4775  $sql .= " total_ht='".price2num($this->total_ht)."'";
4776  $sql .= ",total_tva='".price2num($this->total_tva)."'";
4777  $sql .= ",total_localtax1='".price2num($this->total_localtax1)."'";
4778  $sql .= ",total_localtax2='".price2num($this->total_localtax2)."'";
4779  $sql .= ",total_ttc='".price2num($this->total_ttc)."'";
4780  $sql .= " WHERE rowid = ".((int) $this->rowid);
4781 
4782  dol_syslog("OrderLine::update_total", LOG_DEBUG);
4783 
4784  $resql = $this->db->query($sql);
4785  if ($resql) {
4786  $this->db->commit();
4787  return 1;
4788  } else {
4789  $this->error = $this->db->error();
4790  $this->db->rollback();
4791  return -2;
4792  }
4793  }
4794 }
Commande\valid
valid($user, $idwarehouse=0, $notrigger=0)
Validate order.
Definition: commande.class.php:463
Commande\getNextNumRef
getNextNumRef($soc)
Returns the reference to the following non used Order depending on the active numbering module define...
Definition: commande.class.php:413
Societe
Class to manage third parties objects (customers, suppliers, prospects...)
Definition: societe.class.php:50
getLocalTaxesFromRate
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
Definition: functions.lib.php:6275
db
$conf db
API class for accounts.
Definition: inc.php:41
OrderLine\$remise
$remise
Definition: commande.class.php:4228
dol_escape_htmltag
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields.
Definition: functions.lib.php:1504
Commande\$pos_source
$pos_source
key of pos source ('0', '1', ...)
Definition: commande.class.php:267
Commande\fetch_lines
fetch_lines($only_product=0, $loadalsotranslation=0)
Load array lines.
Definition: commande.class.php:2076
dol_sanitizeFileName
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Definition: functions.lib.php:1236
Commande\generateDocument
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
Definition: commande.class.php:4070
CommonObject\copy_linked_contact
copy_linked_contact($objFrom, $source='internal')
Copy contact from one element to current.
Definition: commonobject.class.php:1271
Expedition
Class to manage shipments.
Definition: expedition.class.php:52
Commande\setDeliveryDate
setDeliveryDate($user, $delivery_date, $notrigger=0)
Set the planned delivery date.
Definition: commande.class.php:2664
Commande\set_remise
set_remise($user, $remise, $notrigger=0)
Applique une remise relative.
Definition: commande.class.php:2447
Commande\showDelay
showDelay()
Show the customer delayed info.
Definition: commande.class.php:4152
dol_delete_dir_recursive
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
Definition: files.lib.php:1412
Commande\countNbOfShipments
countNbOfShipments()
Returns an array with expeditions lines number.
Definition: commande.class.php:2324
DoliDB
Class to manage Dolibarr database access.
Definition: DoliDB.class.php:30
Commande\stock_array
stock_array($filtre_statut=self::STATUS_CANCELED)
Return a array with the pending stock by product.
Definition: commande.class.php:2354
Commande\load_board
load_board($user)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Definition: commande.class.php:3556
OrderLine\__construct
__construct($db)
Constructor.
Definition: commande.class.php:4242
$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
CommonObject\updateRangOfLine
updateRangOfLine($rowid, $rang)
Update position of line (rang)
Definition: commonobject.class.php:3270
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
CommonObject\setErrorsFromObject
setErrorsFromObject($object)
setErrorsFromObject
Definition: commonobject.class.php:679
CommonOrder
Superclass for orders classes.
Definition: commonorder.class.php:31
Commande\STATUS_CLOSED
const STATUS_CLOSED
Closed (Sent, billed or not)
Definition: commande.class.php:393
dol_include_once
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
Definition: functions.lib.php:1043
Commande\createFromProposal
createFromProposal($object, User $user)
Load an object from a proposal and create a new order into database.
Definition: commande.class.php:1308
dol_buildpath
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
Definition: functions.lib.php:1072
dol_dir_list
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:61
Commande\LibStatut
LibStatut($status, $billed, $mode, $donotshowbilled=0)
Return label of status.
Definition: commande.class.php:3648
Commande\set_date
set_date($user, $date, $notrigger=0)
Set the order date.
Definition: commande.class.php:2591
MultiCurrency\getIdFromCode
static getIdFromCode($dbs, $code)
Get id of currency from code.
Definition: multicurrency.class.php:501
Commande\STATUS_SHIPMENTONPROCESS
const STATUS_SHIPMENTONPROCESS
Shipment on process.
Definition: commande.class.php:387
CommonObject\deleteObjectLinked
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='', $f_user=null, $notrigger=0)
Delete all links between an object $this.
Definition: commonobject.class.php:4275
Commande\set_date_livraison
set_date_livraison($user, $delivery_date, $notrigger=0)
Set delivery date.
Definition: commande.class.php:2650
Commande\addline
addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $info_bits=0, $fk_remise_except=0, $price_base_type='HT', $pu_ttc=0, $date_start='', $date_end='', $type=0, $rang=-1, $special_code=0, $fk_parent_line=0, $fk_fournprice=null, $pa_ht=0, $label='', $array_options=0, $fk_unit=null, $origin='', $origin_id=0, $pu_ht_devise=0, $ref_ext='', $noupdateafterinsertline=0)
Add an order line into database (linked to product/service or not)
Definition: commande.class.php:1498
Commande\hasDelay
hasDelay()
Is the sales order delayed?
Definition: commande.class.php:4134
Commande\getNbOfShipments
getNbOfShipments()
Count number of shipments for this order.
Definition: commande.class.php:2239
Commande\STATUS_CANCELED
const STATUS_CANCELED
Canceled status.
Definition: commande.class.php:375
Commande\__construct
__construct($db)
Constructor.
Definition: commande.class.php:401
Commande\$table_ref_field
$table_ref_field
{}
Definition: commande.class.php:93
Commande\getNbOfProductsLines
getNbOfProductsLines()
Return number of line with type product.
Definition: commande.class.php:2207
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5834
Commande\insert_discount
insert_discount($idremise)
Adding line of fixed discount in the order in DB.
Definition: commande.class.php:2006
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
Commande\classifyUnBilled
classifyUnBilled(User $user, $notrigger=0)
Classify the order as not invoiced.
Definition: commande.class.php:3031
WorkboardResponse
Definition: workboardresponse.class.php:24
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:4025
Commande\STATUS_VALIDATED
const STATUS_VALIDATED
Validated status.
Definition: commande.class.php:383
rowid
print *****$script_file(".$version.") pid c cd cd cd description as p label as s rowid
Definition: email_expire_services_to_representatives.php:79
CommonObject\commonGenerateDocument
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
Definition: commonobject.class.php:5460
calcul_price_total
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller='', $localtaxes_array='', $progress=100, $multicurrency_tx=1, $pu_devise=0, $multicurrency_code='')
Calculate totals (net, vat, ...) of a line.
Definition: price.lib.php:86
Commande\cancel
cancel($idwarehouse=-1)
Cancel an order If stock is decremented on order validation, we must reincrement it.
Definition: commande.class.php:818
dol_delete_file
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
Definition: files.lib.php:1261
CommonObject\update_price
update_price($exclspec=0, $roundingadjust='none', $nodatabaseupdate=0, $seller=null)
Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines).
Definition: commonobject.class.php:3582
Commande\deleteline
deleteline($user=null, $lineid=0, $id=0)
Delete an order line.
Definition: commande.class.php:2392
Commande\fetch
fetch($id, $ref='', $ref_ext='', $notused='')
Get object from database.
Definition: commande.class.php:1840
get_default_npr
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.
Definition: functions.lib.php:6613
Commande\loadExpeditions
loadExpeditions($filtre_statut=-1, $fk_product=0)
Load array this->expeditions of lines of shipments with nb of products sent for each order line Note:...
Definition: commande.class.php:2275
getEntity
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
Definition: functions.lib.php:190
OrderLine
Class to manage order lines.
Definition: commande.class.php:4171
Commande\availability
availability($availability_id, $notrigger=0)
Update delivery delay.
Definition: commande.class.php:2794
get_localtax
get_localtax($vatrate, $local, $thirdparty_buyer="", $thirdparty_seller="", $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
Definition: functions.lib.php:6015
MouvementStock
Class to manage stock movements.
Definition: mouvementstock.class.php:31
CommonObject\insertExtraFields
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
Definition: commonobject.class.php:6229
CommonObject\isExistingObject
static isExistingObject($element, $id, $ref='', $ref_ext='')
Check an object id/ref exists If you don't need/want to instantiate object and just need to know if o...
Definition: commonobject.class.php:637
Commande
Class to manage customers orders.
Definition: commande.class.php:46
Commande\getLibStatut
getLibStatut($mode)
Return status label of Order.
Definition: commande.class.php:3633
Commande\add_product
add_product($idproduct, $qty, $remise_percent=0.0, $date_start='', $date_end='')
Add line into array $this->client must be loaded.
Definition: commande.class.php:1751
CommonObject\delete_linked_contact
delete_linked_contact($source='', $code='')
Delete all links between an object $this and all its contacts in llx_element_contact.
Definition: commonobject.class.php:1361
Commande\setDiscount
setDiscount($user, $remise, $notrigger=0)
Set a percentage discount.
Definition: commande.class.php:2462
Commande\update
update(User $user, $notrigger=0)
Update database.
Definition: commande.class.php:3319
CommonObject\defineBuyPrice
defineBuyPrice($unitPrice=0.0, $discountPercent=0.0, $fk_product=0)
Get buy price to use for margin calculation.
Definition: commonobject.class.php:8628
dol_string_nohtmltag
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
Definition: functions.lib.php:6921
CommonObject\commonReplaceProduct
static commonReplaceProduct(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a product id with another one.
Definition: commonobject.class.php:8599
Commande\updateline
updateline($rowid, $desc, $pu, $qty, $remise_percent, $txtva, $txlocaltax1=0.0, $txlocaltax2=0.0, $price_base_type='HT', $info_bits=0, $date_start='', $date_end='', $type=0, $fk_parent_line=0, $skip_update_total=0, $fk_fournprice=null, $pa_ht=0, $label='', $special_code=0, $array_options=0, $fk_unit=null, $pu_ht_devise=0, $notrigger=0, $ref_ext='', $rang=0)
Update a line in database.
Definition: commande.class.php:3107
CommonObject\deleteEcmFiles
deleteEcmFiles($mode=0)
Delete related files of object in database.
Definition: commonobject.class.php:10189
CommonObject\add_contact
add_contact($fk_socpeople, $type_contact, $source='external', $notrigger=0)
Add a link between element $this->element and a contact.
Definition: commonobject.class.php:1162
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
MultiCurrency\getIdAndTxFromCode
static getIdAndTxFromCode($dbs, $code, $date_document='')
Get id and rate of currency from code.
Definition: multicurrency.class.php:526
Commande\getNomUrl
getNomUrl($withpicto=0, $option='', $max=0, $short=0, $notooltip=0, $save_lastsearch_value=-1, $addlinktonotes=0, $target='')
Return clicable link of object (with eventually picto)
Definition: commande.class.php:3771
CommonObject\line_max
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
Definition: commonobject.class.php:3428
Commande\liste_array
liste_array($shortlist=0, $draft=0, $excluser='', $socid=0, $limit=0, $offset=0, $sortfield='c.date_commande', $sortorder='DESC')
Return list of orders (eventuelly filtered on a user) into an array.
Definition: commande.class.php:2727
CommonObject\fetch_optionals
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
Definition: commonobject.class.php:6080
Commande\cloture
cloture($user, $notrigger=0)
Close order.
Definition: commande.class.php:758
Commande\set_ref_client
set_ref_client($user, $ref_client, $notrigger=0)
Set customer ref.
Definition: commande.class.php:2922
dol_strlen
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Definition: functions.lib.php:3888
get_default_tva
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
Definition: functions.lib.php:6499
Commande\STATUS_DRAFT
const STATUS_DRAFT
Draft status.
Definition: commande.class.php:379
Commande\info
info($id)
Charge les informations d'ordre info dans l'objet commande.
Definition: commande.class.php:3886
Commande\set_remise_absolue
set_remise_absolue($user, $remise, $notrigger=0)
Set a fixed amount discount.
Definition: commande.class.php:2525
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:147
Commande\getTooltipContentArray
getTooltipContentArray($params)
getTooltipContentArray
Definition: commande.class.php:3721
OrderLine\insert
insert($user=null, $notrigger=0)
Insert line into database.
Definition: commande.class.php:4428
ref
$object ref
Definition: info.php:78
User
Class to manage Dolibarr users.
Definition: user.class.php:44
Commande\load_state_board
load_state_board()
Charge indicateurs this->nb de tableau de bord.
Definition: commande.class.php:4017
Commande\getLinesArray
getLinesArray()
Create an array of order lines.
Definition: commande.class.php:4054
CommonObject\deleteExtraFields
deleteExtraFields()
Delete all extra fields values for the current object.
Definition: commonobject.class.php:6189
ExtraFields
Class to manage standard extra fields.
Definition: extrafields.class.php:39
Commande\STOCK_NOT_ENOUGH_FOR_ORDER
const STOCK_NOT_ENOUGH_FOR_ORDER
ERR Not enough stock.
Definition: commande.class.php:370
Commande\create
create($user, $notrigger=0)
Create order Note that this->ref can be set or empty.
Definition: commande.class.php:891
OrderLine\update_total
update_total()
Update DB line fields total_xxx Used by migration.
Definition: commande.class.php:4760
Product
Class to manage products or services.
Definition: product.class.php:46
Commande\replaceThirdparty
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
Definition: commande.class.php:4103
getMarginInfos
getMarginInfos($pvht, $remise_percent, $tva_tx, $localtax1_tx, $localtax2_tx, $fk_pa, $paht)
Return an array with margins information of a line.
Definition: margins.lib.php:118
dol_delete_preview
dol_delete_preview($object)
Delete all preview files linked to object instance.
Definition: files.lib.php:1464
CommonObject\add_object_linked
add_object_linked($origin=null, $origin_id=null, $f_user=null, $notrigger=0)
Add an object link into llx_element_element.
Definition: commonobject.class.php:3865
dolGetStatus
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
Definition: functions.lib.php:10767
img_object
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
Definition: functions.lib.php:4361
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2947
Commande\getNbOfServicesLines
getNbOfServicesLines()
Return number of line with type service.
Definition: commande.class.php:2223
Commande\demand_reason
demand_reason($demand_reason_id, $notrigger=0)
Update order demand_reason.
Definition: commande.class.php:2857
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
CommonObject\call_trigger
call_trigger($triggerName, $user)
Call trigger based on this instance.
Definition: commonobject.class.php:5864
Commande\createFromClone
createFromClone(User $user, $socid=0)
Load an object from its id and create a new one in database.
Definition: commande.class.php:1198
Commande\$module_source
$module_source
key of module source when order generated from a dedicated module ('cashdesk', 'takepos',...
Definition: commande.class.php:265
Commande\replaceProduct
static replaceProduct(DoliDB $db, $origin_id, $dest_id)
Function used to replace a product id with another one.
Definition: commande.class.php:4120
CommonOrderLine
Superclass for orders classes.
Definition: commonorder.class.php:79
Commande\setDraft
setDraft($user, $idwarehouse=-1)
Set draft status.
Definition: commande.class.php:617
getDolGlobalInt
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
Definition: functions.lib.php:96
CommonObject\line_order
line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true)
Save a new position (field rang) for details lines.
Definition: commonobject.class.php:3106
OrderLine\fetch
fetch($rowid)
Load line order.
Definition: commande.class.php:4253
CommonObject\commonReplaceThirdparty
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
Definition: commonobject.class.php:8570
Commande\getLabelSource
getLabelSource()
Return source label of order.
Definition: commande.class.php:3615
Commande\set_reopen
set_reopen($user)
Tag the order as validated (opened) Function used when order is reopend after being closed.
Definition: commande.class.php:703
Commande\initAsSpecimen
initAsSpecimen()
Initialise an instance with random values.
Definition: commande.class.php:3929
OrderLine\update
update(User $user, $notrigger=0)
Update the line object into db.
Definition: commande.class.php:4595
Commande\classifyBilled
classifyBilled(User $user, $notrigger=0)
Classify the order as invoiced.
Definition: commande.class.php:2977