dolibarr  16.0.5
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-2022 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 
109  public $ref_int;
110 
114  public $contactid;
115 
120  public $statut;
121 
125  public $billed;
126 
130  public $brouillon;
131 
135  public $cond_reglement_code;
136 
140  public $deposit_percent;
141 
145  public $fk_account;
146 
150  public $mode_reglement;
151 
155  public $mode_reglement_id;
156 
160  public $mode_reglement_code;
161 
166  public $availability_id;
167 
172  public $availability_code;
173 
178  public $availability;
179 
183  public $demand_reason_id;
184 
188  public $demand_reason_code;
189 
193  public $date;
194 
200  public $date_commande;
201 
207  public $date_livraison;
208 
212  public $delivery_date;
213 
217  public $fk_remise_except;
218 
219  public $remise_percent;
220  public $remise_absolue;
221  public $info_bits;
222  public $rang;
223  public $special_code;
224  public $source; // Order mode. How we received order (by phone, by email, ...)
225 
229  public $warehouse_id;
230 
231  public $extraparams = array();
232 
233  public $linked_objects = array();
234 
238  public $user_author_id;
239 
243  public $user_valid;
244 
248  public $lines = array();
249 
250  // Multicurrency
254  public $fk_multicurrency;
255 
259  public $multicurrency_code;
260  public $multicurrency_tx;
261  public $multicurrency_total_ht;
262  public $multicurrency_total_tva;
263  public $multicurrency_total_ttc;
264 
268  public $pos_source;
269 
273  public $expeditions;
274 
278  public $online_payment_url;
279 
280 
305  // BEGIN MODULEBUILDER PROPERTIES
309  public $fields = array(
310  'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
311  'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>20, 'index'=>1),
312  'ref' =>array('type'=>'varchar(30)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'showoncombobox'=>1, 'position'=>25),
313  'ref_ext' =>array('type'=>'varchar(255)', 'label'=>'RefExt', 'enabled'=>1, 'visible'=>0, 'position'=>26),
314  'ref_int' =>array('type'=>'varchar(255)', 'label'=>'RefInt', 'enabled'=>1, 'visible'=>0, 'position'=>27), // deprecated
315  'ref_client' =>array('type'=>'varchar(255)', 'label'=>'RefCustomer', 'enabled'=>1, 'visible'=>-1, 'position'=>28),
316  'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>'$conf->societe->enabled', 'visible'=>-1, 'notnull'=>1, 'position'=>20),
317  'fk_projet' =>array('type'=>'integer:Project:projet/class/project.class.php:1:fk_statut=1', 'label'=>'Project', 'enabled'=>'$conf->project->enabled', 'visible'=>-1, 'position'=>25),
318  'date_commande' =>array('type'=>'date', 'label'=>'Date', 'enabled'=>1, 'visible'=>1, 'position'=>60),
319  'date_valid' =>array('type'=>'datetime', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>62),
320  'date_cloture' =>array('type'=>'datetime', 'label'=>'DateClosing', 'enabled'=>1, 'visible'=>-1, 'position'=>65),
321  'fk_user_valid' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>85),
322  'fk_user_cloture' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserClosing', 'enabled'=>1, 'visible'=>-1, 'position'=>90),
323  'source' =>array('type'=>'smallint(6)', 'label'=>'Source', 'enabled'=>1, 'visible'=>-1, 'position'=>95),
324  //'amount_ht' =>array('type'=>'double(24,8)', 'label'=>'AmountHT', 'enabled'=>1, 'visible'=>-1, 'position'=>105),
325  'remise_percent' =>array('type'=>'double', 'label'=>'RelativeDiscount', 'enabled'=>1, 'visible'=>-1, 'position'=>110),
326  'remise_absolue' =>array('type'=>'double', 'label'=>'CustomerRelativeDiscount', 'enabled'=>1, 'visible'=>-1, 'position'=>115),
327  //'remise' =>array('type'=>'double', 'label'=>'Remise', 'enabled'=>1, 'visible'=>-1, 'position'=>120),
328  'total_tva' =>array('type'=>'double(24,8)', 'label'=>'VAT', 'enabled'=>1, 'visible'=>-1, 'position'=>125, 'isameasure'=>1),
329  'localtax1' =>array('type'=>'double(24,8)', 'label'=>'LocalTax1', 'enabled'=>1, 'visible'=>-1, 'position'=>130, 'isameasure'=>1),
330  'localtax2' =>array('type'=>'double(24,8)', 'label'=>'LocalTax2', 'enabled'=>1, 'visible'=>-1, 'position'=>135, 'isameasure'=>1),
331  'total_ht' =>array('type'=>'double(24,8)', 'label'=>'TotalHT', 'enabled'=>1, 'visible'=>-1, 'position'=>140, 'isameasure'=>1),
332  'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'TotalTTC', 'enabled'=>1, 'visible'=>-1, 'position'=>145, 'isameasure'=>1),
333  'note_private' =>array('type'=>'text', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>150),
334  'note_public' =>array('type'=>'text', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>155),
335  'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'PDFTemplate', 'enabled'=>1, 'visible'=>0, 'position'=>160),
336  //'facture' =>array('type'=>'tinyint(4)', 'label'=>'ParentInvoice', 'enabled'=>1, 'visible'=>-1, 'position'=>165),
337  'fk_account' =>array('type'=>'integer', 'label'=>'BankAccount', 'enabled'=>'$conf->banque->enabled', 'visible'=>-1, 'position'=>170),
338  'fk_currency' =>array('type'=>'varchar(3)', 'label'=>'MulticurrencyID', 'enabled'=>1, 'visible'=>-1, 'position'=>175),
339  'fk_cond_reglement' =>array('type'=>'integer', 'label'=>'PaymentTerm', 'enabled'=>1, 'visible'=>-1, 'position'=>180),
340  'deposit_percent' =>array('type'=>'varchar(63)', 'label'=>'DepositPercent', 'enabled'=>1, 'visible'=>-1, 'position'=>181),
341  'fk_mode_reglement' =>array('type'=>'integer', 'label'=>'PaymentMode', 'enabled'=>1, 'visible'=>-1, 'position'=>185),
342  'date_livraison' =>array('type'=>'date', 'label'=>'DateDeliveryPlanned', 'enabled'=>1, 'visible'=>-1, 'position'=>190),
343  'fk_shipping_method' =>array('type'=>'integer', 'label'=>'ShippingMethod', 'enabled'=>1, 'visible'=>-1, 'position'=>195),
344  'fk_warehouse' =>array('type'=>'integer:Entrepot:product/stock/class/entrepot.class.php', 'label'=>'Fk warehouse', 'enabled'=>'$conf->stock->enabled', 'visible'=>-1, 'position'=>200),
345  'fk_availability' =>array('type'=>'integer', 'label'=>'Availability', 'enabled'=>1, 'visible'=>-1, 'position'=>205),
346  'fk_input_reason' =>array('type'=>'integer', 'label'=>'InputReason', 'enabled'=>1, 'visible'=>-1, 'position'=>210),
347  //'fk_delivery_address' =>array('type'=>'integer', 'label'=>'DeliveryAddress', 'enabled'=>1, 'visible'=>-1, 'position'=>215),
348  'extraparams' =>array('type'=>'varchar(255)', 'label'=>'Extraparams', 'enabled'=>1, 'visible'=>-1, 'position'=>225),
349  'fk_incoterms' =>array('type'=>'integer', 'label'=>'IncotermCode', 'enabled'=>'$conf->incoterm->enabled', 'visible'=>-1, 'position'=>230),
350  'location_incoterms' =>array('type'=>'varchar(255)', 'label'=>'IncotermLabel', 'enabled'=>'$conf->incoterm->enabled', 'visible'=>-1, 'position'=>235),
351  'fk_multicurrency' =>array('type'=>'integer', 'label'=>'Fk multicurrency', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>240),
352  'multicurrency_code' =>array('type'=>'varchar(255)', 'label'=>'MulticurrencyCurrency', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>245),
353  'multicurrency_tx' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyRate', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>250, 'isameasure'=>1),
354  'multicurrency_total_ht' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyAmountHT', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>255, 'isameasure'=>1),
355  'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyAmountVAT', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>260, 'isameasure'=>1),
356  'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyAmountTTC', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>265, 'isameasure'=>1),
357  'last_main_doc' =>array('type'=>'varchar(255)', 'label'=>'LastMainDoc', 'enabled'=>1, 'visible'=>-1, 'position'=>270),
358  'module_source' =>array('type'=>'varchar(32)', 'label'=>'POSModule', 'enabled'=>1, 'visible'=>-1, 'position'=>275),
359  'pos_source' =>array('type'=>'varchar(32)', 'label'=>'POSTerminal', 'enabled'=>1, 'visible'=>-1, 'position'=>280),
360  'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-1, 'position'=>300),
361  'fk_user_modif' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>302),
362  'date_creation' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>304),
363  'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>306),
364  'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>400),
365  'fk_statut' =>array('type'=>'smallint(6)', 'label'=>'Status', 'enabled'=>1, 'visible'=>-1, 'position'=>500),
366  );
367  // END MODULEBUILDER PROPERTIES
368 
373 
377  const STATUS_CANCELED = -1;
381  const STATUS_DRAFT = 0;
385  const STATUS_VALIDATED = 1;
390  const STATUS_ACCEPTED = 2; // For backward compatibility. Use key STATUS_SHIPMENTONPROCESS instead.
391 
395  const STATUS_CLOSED = 3;
396 
397 
403  public function __construct($db)
404  {
405  $this->db = $db;
406  }
407 
415  public function getNextNumRef($soc)
416  {
417  global $langs, $conf;
418  $langs->load("order");
419 
420  if (!empty($conf->global->COMMANDE_ADDON)) {
421  $mybool = false;
422 
423  $file = $conf->global->COMMANDE_ADDON.".php";
424  $classname = $conf->global->COMMANDE_ADDON;
425 
426  // Include file with class
427  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
428  foreach ($dirmodels as $reldir) {
429  $dir = dol_buildpath($reldir."core/modules/commande/");
430 
431  // Load file with numbering class (if found)
432  $mybool |= @include_once $dir.$file;
433  }
434 
435  if ($mybool === false) {
436  dol_print_error('', "Failed to include file ".$file);
437  return '';
438  }
439 
440  $obj = new $classname();
441  $numref = $obj->getNextValue($soc, $this);
442 
443  if ($numref != "") {
444  return $numref;
445  } else {
446  $this->error = $obj->error;
447  //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
448  return "";
449  }
450  } else {
451  print $langs->trans("Error")." ".$langs->trans("Error_COMMANDE_ADDON_NotDefined");
452  return "";
453  }
454  }
455 
456 
465  public function valid($user, $idwarehouse = 0, $notrigger = 0)
466  {
467  global $conf, $langs;
468 
469  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
470 
471  $error = 0;
472 
473  // Protection
474  if ($this->statut == self::STATUS_VALIDATED) {
475  dol_syslog(get_class($this)."::valid action abandonned: already validated", LOG_WARNING);
476  return 0;
477  }
478 
479  if (!((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->creer))
480  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->order_advance->validate)))) {
481  $this->error = 'NotEnoughPermissions';
482  dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
483  return -1;
484  }
485 
486  $now = dol_now();
487 
488  $this->db->begin();
489 
490  // Definition du nom de module de numerotation de commande
491  $soc = new Societe($this->db);
492  $soc->fetch($this->socid);
493 
494  // Class of company linked to order
495  $result = $soc->set_as_client();
496 
497  // Define new ref
498  if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
499  $num = $this->getNextNumRef($soc);
500  } else {
501  $num = $this->ref;
502  }
503  $this->newref = dol_sanitizeFileName($num);
504 
505  // Validate
506  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
507  $sql .= " SET ref = '".$this->db->escape($num)."',";
508  $sql .= " fk_statut = ".self::STATUS_VALIDATED.",";
509  $sql .= " date_valid='".$this->db->idate($now)."',";
510  $sql .= " fk_user_valid = ".($user->id > 0 ? (int) $user->id : "null").",";
511  $sql .= " fk_user_modif = ".((int) $user->id);
512  $sql .= " WHERE rowid = ".((int) $this->id);
513 
514  dol_syslog(get_class($this)."::valid", LOG_DEBUG);
515  $resql = $this->db->query($sql);
516  if (!$resql) {
517  dol_print_error($this->db);
518  $this->error = $this->db->lasterror();
519  $error++;
520  }
521 
522  if (!$error) {
523  // If stock is incremented on validate order, we must increment it
524  if ($result >= 0 && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1) {
525  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
526  $langs->load("agenda");
527 
528  // Loop on each line
529  $cpt = count($this->lines);
530  for ($i = 0; $i < $cpt; $i++) {
531  if ($this->lines[$i]->fk_product > 0) {
532  $mouvP = new MouvementStock($this->db);
533  $mouvP->origin = &$this;
534  $mouvP->setOrigin($this->element, $this->id);
535  // We decrement stock of product (and sub-products)
536  $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("OrderValidatedInDolibarr", $num));
537  if ($result < 0) {
538  $error++;
539  $this->error = $mouvP->error;
540  }
541  }
542  if ($error) {
543  break;
544  }
545  }
546  }
547  }
548 
549  if (!$error && !$notrigger) {
550  // Call trigger
551  $result = $this->call_trigger('ORDER_VALIDATE', $user);
552  if ($result < 0) {
553  $error++;
554  }
555  // End call triggers
556  }
557 
558  if (!$error) {
559  $this->oldref = $this->ref;
560 
561  // Rename directory if dir was a temporary ref
562  if (preg_match('/^[\(]?PROV/i', $this->ref)) {
563  // Now we rename also files into index
564  $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)."'";
565  $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'commande/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
566  $resql = $this->db->query($sql);
567  if (!$resql) {
568  $error++; $this->error = $this->db->lasterror();
569  }
570 
571  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
572  $oldref = dol_sanitizeFileName($this->ref);
573  $newref = dol_sanitizeFileName($num);
574  $dirsource = $conf->commande->multidir_output[$this->entity].'/'.$oldref;
575  $dirdest = $conf->commande->multidir_output[$this->entity].'/'.$newref;
576  if (!$error && file_exists($dirsource)) {
577  dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
578 
579  if (@rename($dirsource, $dirdest)) {
580  dol_syslog("Rename ok");
581  // Rename docs starting with $oldref with $newref
582  $listoffiles = dol_dir_list($conf->commande->multidir_output[$this->entity].'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
583  foreach ($listoffiles as $fileentry) {
584  $dirsource = $fileentry['name'];
585  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
586  $dirsource = $fileentry['path'].'/'.$dirsource;
587  $dirdest = $fileentry['path'].'/'.$dirdest;
588  @rename($dirsource, $dirdest);
589  }
590  }
591  }
592  }
593  }
594 
595  // Set new ref and current status
596  if (!$error) {
597  $this->ref = $num;
598  $this->statut = self::STATUS_VALIDATED;
599  $this->brouillon = 0;
600  }
601 
602  if (!$error) {
603  $this->db->commit();
604  return 1;
605  } else {
606  $this->db->rollback();
607  return -1;
608  }
609  }
610 
611  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
619  public function setDraft($user, $idwarehouse = -1)
620  {
621  //phpcs:enable
622  global $conf, $langs;
623 
624  $error = 0;
625 
626  // Protection
627  if ($this->statut <= self::STATUS_DRAFT) {
628  return 0;
629  }
630 
631  if (!((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->creer))
632  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->order_advance->validate)))) {
633  $this->error = 'Permission denied';
634  return -1;
635  }
636 
637  dol_syslog(__METHOD__, LOG_DEBUG);
638 
639  $this->db->begin();
640 
641  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
642  $sql .= " SET fk_statut = ".self::STATUS_DRAFT.",";
643  $sql .= " fk_user_modif = ".((int) $user->id);
644  $sql .= " WHERE rowid = ".((int) $this->id);
645 
646  if ($this->db->query($sql)) {
647  if (!$error) {
648  $this->oldcopy = clone $this;
649  }
650 
651  // If stock is decremented on validate order, we must reincrement it
652  if (!empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1) {
653  $result = 0;
654 
655  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
656  $langs->load("agenda");
657 
658  $num = count($this->lines);
659  for ($i = 0; $i < $num; $i++) {
660  if ($this->lines[$i]->fk_product > 0) {
661  $mouvP = new MouvementStock($this->db);
662  $mouvP->origin = &$this;
663  $mouvP->setOrigin($this->element, $this->id);
664  // We increment stock of product (and sub-products)
665  $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("OrderBackToDraftInDolibarr", $this->ref));
666  if ($result < 0) {
667  $error++; $this->error = $mouvP->error; break;
668  }
669  }
670  }
671  }
672 
673  if (!$error) {
674  // Call trigger
675  $result = $this->call_trigger('ORDER_UNVALIDATE', $user);
676  if ($result < 0) {
677  $error++;
678  }
679  }
680 
681  if (!$error) {
682  $this->statut = self::STATUS_DRAFT;
683  $this->db->commit();
684  return 1;
685  } else {
686  $this->db->rollback();
687  return -1;
688  }
689  } else {
690  $this->error = $this->db->error();
691  $this->db->rollback();
692  return -1;
693  }
694  }
695 
696 
697  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
705  public function set_reopen($user)
706  {
707  // phpcs:enable
708  $error = 0;
709 
710  if ($this->statut != self::STATUS_CANCELED && $this->statut != self::STATUS_CLOSED) {
711  dol_syslog(get_class($this)."::set_reopen order has not status closed", LOG_WARNING);
712  return 0;
713  }
714 
715  $this->db->begin();
716 
717  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
718  $sql .= ' SET fk_statut='.self::STATUS_VALIDATED.', facture=0,';
719  $sql .= " fk_user_modif = ".((int) $user->id);
720  $sql .= " WHERE rowid = ".((int) $this->id);
721 
722  dol_syslog(get_class($this)."::set_reopen", LOG_DEBUG);
723  $resql = $this->db->query($sql);
724  if ($resql) {
725  // Call trigger
726  $result = $this->call_trigger('ORDER_REOPEN', $user);
727  if ($result < 0) {
728  $error++;
729  }
730  // End call triggers
731  } else {
732  $error++;
733  $this->error = $this->db->lasterror();
734  dol_print_error($this->db);
735  }
736 
737  if (!$error) {
738  $this->statut = self::STATUS_VALIDATED;
739  $this->billed = 0;
740 
741  $this->db->commit();
742  return 1;
743  } else {
744  foreach ($this->errors as $errmsg) {
745  dol_syslog(get_class($this)."::set_reopen ".$errmsg, LOG_ERR);
746  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
747  }
748  $this->db->rollback();
749  return -1 * $error;
750  }
751  }
752 
760  public function cloture($user, $notrigger = 0)
761  {
762  global $conf;
763 
764  $error = 0;
765 
766  $usercanclose = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->creer))
767  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->order_advance->close)));
768 
769  if ($usercanclose) {
770  if ($this->statut == self::STATUS_CLOSED) {
771  return 0;
772  }
773  $this->db->begin();
774 
775  $now = dol_now();
776 
777  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
778  $sql .= ' SET fk_statut = '.self::STATUS_CLOSED.',';
779  $sql .= ' fk_user_cloture = '.((int) $user->id).',';
780  $sql .= " date_cloture = '".$this->db->idate($now)."',";
781  $sql .= " fk_user_modif = ".((int) $user->id);
782  $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > '.self::STATUS_DRAFT;
783 
784  if ($this->db->query($sql)) {
785  if (!$notrigger) {
786  // Call trigger
787  $result = $this->call_trigger('ORDER_CLOSE', $user);
788  if ($result < 0) {
789  $error++;
790  }
791  // End call triggers
792  }
793 
794  if (!$error) {
795  $this->statut = self::STATUS_CLOSED;
796 
797  $this->db->commit();
798  return 1;
799  } else {
800  $this->db->rollback();
801  return -1;
802  }
803  } else {
804  $this->error = $this->db->lasterror();
805 
806  $this->db->rollback();
807  return -1;
808  }
809  }
810  return 0;
811  }
812 
820  public function cancel($idwarehouse = -1)
821  {
822  global $conf, $user, $langs;
823 
824  $error = 0;
825 
826  $this->db->begin();
827 
828  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
829  $sql .= " SET fk_statut = ".self::STATUS_CANCELED.",";
830  $sql .= " fk_user_modif = ".((int) $user->id);
831  $sql .= " WHERE rowid = ".((int) $this->id);
832  $sql .= " AND fk_statut = ".self::STATUS_VALIDATED;
833 
834  dol_syslog(get_class($this)."::cancel", LOG_DEBUG);
835  if ($this->db->query($sql)) {
836  // If stock is decremented on validate order, we must reincrement it
837  if (!empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1) {
838  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
839  $langs->load("agenda");
840 
841  $num = count($this->lines);
842  for ($i = 0; $i < $num; $i++) {
843  if ($this->lines[$i]->fk_product > 0) {
844  $mouvP = new MouvementStock($this->db);
845  $mouvP->setOrigin($this->element, $this->id);
846  // We increment stock of product (and sub-products)
847  $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
848  if ($result < 0) {
849  $error++;
850  $this->error = $mouvP->error;
851  break;
852  }
853  }
854  }
855  }
856 
857  if (!$error) {
858  // Call trigger
859  $result = $this->call_trigger('ORDER_CANCEL', $user);
860  if ($result < 0) {
861  $error++;
862  }
863  // End call triggers
864  }
865 
866  if (!$error) {
867  $this->statut = self::STATUS_CANCELED;
868  $this->db->commit();
869  return 1;
870  } else {
871  foreach ($this->errors as $errmsg) {
872  dol_syslog(get_class($this)."::cancel ".$errmsg, LOG_ERR);
873  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
874  }
875  $this->db->rollback();
876  return -1 * $error;
877  }
878  } else {
879  $this->error = $this->db->error();
880  $this->db->rollback();
881  return -1;
882  }
883  }
884 
893  public function create($user, $notrigger = 0)
894  {
895  global $conf, $langs, $mysoc;
896  $error = 0;
897 
898  // Clean parameters
899  $this->brouillon = 1; // set command as draft
900 
901  // Set tmp vars
902  $date = ($this->date_commande ? $this->date_commande : $this->date);
903  $delivery_date = empty($this->delivery_date) ? $this->date_livraison : $this->delivery_date;
904 
905  // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
906  if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) {
907  list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $date);
908  } else {
909  $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
910  }
911  if (empty($this->fk_multicurrency)) {
912  $this->multicurrency_code = $conf->currency;
913  $this->fk_multicurrency = 0;
914  $this->multicurrency_tx = 1;
915  }
916 
917  dol_syslog(get_class($this)."::create user=".$user->id);
918 
919  // Check parameters
920  if (!empty($this->ref)) { // We check that ref is not already used
921  $result = self::isExistingObject($this->element, 0, $this->ref); // Check ref is not yet used
922  if ($result > 0) {
923  $this->error = 'ErrorRefAlreadyExists';
924  dol_syslog(get_class($this)."::create ".$this->error, LOG_WARNING);
925  $this->db->rollback();
926  return -1;
927  }
928  }
929 
930  $soc = new Societe($this->db);
931  $result = $soc->fetch($this->socid);
932  if ($result < 0) {
933  $this->error = "Failed to fetch company";
934  dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
935  return -2;
936  }
937  if (!empty($conf->global->ORDER_REQUIRE_SOURCE) && $this->source < 0) {
938  $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Source"));
939  dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
940  return -1;
941  }
942 
943  $now = dol_now();
944 
945  $this->db->begin();
946 
947  $sql = "INSERT INTO ".MAIN_DB_PREFIX."commande (";
948  $sql .= " ref, fk_soc, date_creation, fk_user_author, fk_projet, date_commande, source, note_private, note_public, ref_ext, ref_client, ref_int";
949  $sql .= ", model_pdf, fk_cond_reglement, deposit_percent, fk_mode_reglement, fk_account, fk_availability, fk_input_reason, date_livraison, fk_delivery_address";
950  $sql .= ", fk_shipping_method";
951  $sql .= ", fk_warehouse";
952  $sql .= ", remise_absolue, remise_percent";
953  $sql .= ", fk_incoterms, location_incoterms";
954  $sql .= ", entity, module_source, pos_source";
955  $sql .= ", fk_multicurrency";
956  $sql .= ", multicurrency_code";
957  $sql .= ", multicurrency_tx";
958  $sql .= ")";
959  $sql .= " VALUES ('(PROV)', ".((int) $this->socid).", '".$this->db->idate($now)."', ".((int) $user->id);
960  $sql .= ", ".($this->fk_project > 0 ? ((int) $this->fk_project) : "null");
961  $sql .= ", '".$this->db->idate($date)."'";
962  $sql .= ", ".($this->source >= 0 && $this->source != '' ? $this->db->escape($this->source) : 'null');
963  $sql .= ", '".$this->db->escape($this->note_private)."'";
964  $sql .= ", '".$this->db->escape($this->note_public)."'";
965  $sql .= ", ".($this->ref_ext ? "'".$this->db->escape($this->ref_ext)."'" : "null");
966  $sql .= ", ".($this->ref_client ? "'".$this->db->escape($this->ref_client)."'" : "null");
967  $sql .= ", ".($this->ref_int ? "'".$this->db->escape($this->ref_int)."'" : "null");
968  $sql .= ", '".$this->db->escape($this->model_pdf)."'";
969  $sql .= ", ".($this->cond_reglement_id > 0 ? ((int) $this->cond_reglement_id) : "null");
970  $sql .= ", ".(! empty($this->deposit_percent) ? "'".$this->db->escape($this->deposit_percent)."'" : "null");
971  $sql .= ", ".($this->mode_reglement_id > 0 ? ((int) $this->mode_reglement_id) : "null");
972  $sql .= ", ".($this->fk_account > 0 ? ((int) $this->fk_account) : 'NULL');
973  $sql .= ", ".($this->availability_id > 0 ? ((int) $this->availability_id) : "null");
974  $sql .= ", ".($this->demand_reason_id > 0 ? ((int) $this->demand_reason_id) : "null");
975  $sql .= ", ".($delivery_date ? "'".$this->db->idate($delivery_date)."'" : "null");
976  $sql .= ", ".($this->fk_delivery_address > 0 ? ((int) $this->fk_delivery_address) : 'NULL');
977  $sql .= ", ".(!empty($this->shipping_method_id) && $this->shipping_method_id > 0 ? ((int) $this->shipping_method_id) : 'NULL');
978  $sql .= ", ".(!empty($this->warehouse_id) && $this->warehouse_id > 0 ? ((int) $this->warehouse_id) : 'NULL');
979  $sql .= ", ".($this->remise_absolue > 0 ? $this->db->escape($this->remise_absolue) : 'NULL');
980  $sql .= ", ".($this->remise_percent > 0 ? $this->db->escape($this->remise_percent) : 0);
981  $sql .= ", ".(int) $this->fk_incoterms;
982  $sql .= ", '".$this->db->escape($this->location_incoterms)."'";
983  $sql .= ", ".setEntity($this);
984  $sql .= ", ".($this->module_source ? "'".$this->db->escape($this->module_source)."'" : "null");
985  $sql .= ", ".($this->pos_source != '' ? "'".$this->db->escape($this->pos_source)."'" : "null");
986  $sql .= ", ".(int) $this->fk_multicurrency;
987  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
988  $sql .= ", ".(float) $this->multicurrency_tx;
989  $sql .= ")";
990 
991  dol_syslog(get_class($this)."::create", LOG_DEBUG);
992  $resql = $this->db->query($sql);
993  if ($resql) {
994  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'commande');
995 
996  if ($this->id) {
997  $fk_parent_line = 0;
998  $num = count($this->lines);
999 
1000  /*
1001  * Insert products details into db
1002  */
1003  for ($i = 0; $i < $num; $i++) {
1004  $line = $this->lines[$i];
1005 
1006  // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
1007  //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object.
1008  if (!is_object($line)) {
1009  $line = (object) $line;
1010  }
1011 
1012  // Reset fk_parent_line for no child products and special product
1013  if (($line->product_type != 9 && empty($line->fk_parent_line)) || $line->product_type == 9) {
1014  $fk_parent_line = 0;
1015  }
1016 
1017  // Complete vat rate with code
1018  $vatrate = $line->tva_tx;
1019  if ($line->vat_src_code && !preg_match('/\(.*\)/', $vatrate)) {
1020  $vatrate .= ' ('.$line->vat_src_code.')';
1021  }
1022 
1023  if (!empty($conf->global->MAIN_CREATEFROM_KEEP_LINE_ORIGIN_INFORMATION)) {
1024  $originid = $line->origin_id;
1025  $origintype = $line->origin;
1026  } else {
1027  $originid = $line->id;
1028  $origintype = $this->element;
1029  }
1030 
1031  // ref_ext
1032  if (empty($line->ref_ext)) {
1033  $line->ref_ext = '';
1034  }
1035 
1036  $result = $this->addline(
1037  $line->desc,
1038  $line->subprice,
1039  $line->qty,
1040  $vatrate,
1041  $line->localtax1_tx,
1042  $line->localtax2_tx,
1043  $line->fk_product,
1044  $line->remise_percent,
1045  $line->info_bits,
1046  $line->fk_remise_except,
1047  'HT',
1048  0,
1049  $line->date_start,
1050  $line->date_end,
1051  $line->product_type,
1052  $line->rang,
1053  $line->special_code,
1054  $fk_parent_line,
1055  $line->fk_fournprice,
1056  $line->pa_ht,
1057  $line->label,
1058  $line->array_options,
1059  $line->fk_unit,
1060  $origintype,
1061  $originid,
1062  0,
1063  $line->ref_ext,
1064  1
1065  );
1066  if ($result < 0) {
1067  if ($result != self::STOCK_NOT_ENOUGH_FOR_ORDER) {
1068  $this->error = $this->db->lasterror();
1069  $this->errors[] = $this->error;
1070  dol_print_error($this->db);
1071  }
1072  $this->db->rollback();
1073  return -1;
1074  }
1075  // Defined the new fk_parent_line
1076  if ($result > 0 && $line->product_type == 9) {
1077  $fk_parent_line = $result;
1078  }
1079  }
1080 
1081  $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.
1082 
1083  // update ref
1084  $initialref = '(PROV'.$this->id.')';
1085  if (!empty($this->ref)) {
1086  $initialref = $this->ref;
1087  }
1088 
1089  $sql = 'UPDATE '.MAIN_DB_PREFIX."commande SET ref='".$this->db->escape($initialref)."' WHERE rowid=".((int) $this->id);
1090  if ($this->db->query($sql)) {
1091  $this->ref = $initialref;
1092 
1093  if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) { // To use new linkedObjectsIds instead of old linked_objects
1094  $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
1095  }
1096 
1097  // Add object linked
1098  if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects)) {
1099  foreach ($this->linked_objects as $origin => $tmp_origin_id) {
1100  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, ...))
1101  foreach ($tmp_origin_id as $origin_id) {
1102  $ret = $this->add_object_linked($origin, $origin_id);
1103  if (!$ret) {
1104  $this->error = $this->db->lasterror();
1105  $error++;
1106  }
1107  }
1108  } else // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
1109  {
1110  $origin_id = $tmp_origin_id;
1111  $ret = $this->add_object_linked($origin, $origin_id);
1112  if (!$ret) {
1113  $this->error = $this->db->lasterror();
1114  $error++;
1115  }
1116  }
1117  }
1118  }
1119 
1120  if (!$error && $this->id && !empty($conf->global->MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN) && !empty($this->origin) && !empty($this->origin_id)) { // Get contact from origin object
1121  $originforcontact = $this->origin;
1122  $originidforcontact = $this->origin_id;
1123  if ($originforcontact == 'shipping') { // shipment and order share the same contacts. If creating from shipment we take data of order
1124  require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
1125  $exp = new Expedition($this->db);
1126  $exp->fetch($this->origin_id);
1127  $exp->fetchObjectLinked();
1128  if (count($exp->linkedObjectsIds['commande']) > 0) {
1129  foreach ($exp->linkedObjectsIds['commande'] as $key => $value) {
1130  $originforcontact = 'commande';
1131  if (is_object($value)) {
1132  $originidforcontact = $value->id;
1133  } else {
1134  $originidforcontact = $value;
1135  }
1136  break; // We take first one
1137  }
1138  }
1139  }
1140 
1141  $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";
1142  $sqlcontact .= " WHERE element_id = ".((int) $originidforcontact)." AND ec.fk_c_type_contact = ctc.rowid AND ctc.element = '".$this->db->escape($originforcontact)."'";
1143 
1144  $resqlcontact = $this->db->query($sqlcontact);
1145  if ($resqlcontact) {
1146  while ($objcontact = $this->db->fetch_object($resqlcontact)) {
1147  //print $objcontact->code.'-'.$objcontact->source.'-'.$objcontact->fk_socpeople."\n";
1148  $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
1149  }
1150  } else {
1151  dol_print_error($resqlcontact);
1152  }
1153  }
1154 
1155  if (!$error) {
1156  $result = $this->insertExtraFields();
1157  if ($result < 0) {
1158  $error++;
1159  }
1160  }
1161 
1162  if (!$error && !$notrigger) {
1163  // Call trigger
1164  $result = $this->call_trigger('ORDER_CREATE', $user);
1165  if ($result < 0) {
1166  $error++;
1167  }
1168  // End call triggers
1169  }
1170 
1171  if (!$error) {
1172  $this->db->commit();
1173  return $this->id;
1174  } else {
1175  $this->db->rollback();
1176  return -1 * $error;
1177  }
1178  } else {
1179  $this->error = $this->db->lasterror();
1180  $this->db->rollback();
1181  return -1;
1182  }
1183  }
1184  } else {
1185  dol_print_error($this->db);
1186  $this->db->rollback();
1187  return -1;
1188  }
1189  }
1190 
1191 
1199  public function createFromClone(User $user, $socid = 0)
1200  {
1201  global $conf, $user, $hookmanager;
1202 
1203  $error = 0;
1204 
1205  $this->db->begin();
1206 
1207  // get lines so they will be clone
1208  foreach ($this->lines as $line) {
1209  $line->fetch_optionals();
1210  }
1211 
1212  // Load source object
1213  $objFrom = clone $this;
1214 
1215  // Change socid if needed
1216  if (!empty($socid) && $socid != $this->socid) {
1217  $objsoc = new Societe($this->db);
1218 
1219  if ($objsoc->fetch($socid) > 0) {
1220  $this->socid = $objsoc->id;
1221  $this->cond_reglement_id = (!empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0);
1222  $this->deposit_percent = (!empty($objsoc->deposit_percent) ? $objsoc->deposit_percent : null);
1223  $this->mode_reglement_id = (!empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0);
1224  $this->fk_project = 0;
1225  $this->fk_delivery_address = 0;
1226  }
1227 
1228  // TODO Change product price if multi-prices
1229  }
1230 
1231  $this->id = 0;
1232  $this->ref = '';
1233  $this->statut = self::STATUS_DRAFT;
1234 
1235  // Clear fields
1236  $this->user_author_id = $user->id;
1237  $this->user_valid = 0; // deprecated
1238  $this->user_validation_id = 0;
1239  $this->date = dol_now();
1240  $this->date_commande = dol_now();
1241  $this->date_creation = '';
1242  $this->date_validation = '';
1243  if (empty($conf->global->MAIN_KEEP_REF_CUSTOMER_ON_CLONING)) {
1244  $this->ref_client = '';
1245  }
1246 
1247  // Do not clone ref_ext
1248  $num = count($this->lines);
1249  for ($i = 0; $i < $num; $i++) {
1250  $this->lines[$i]->ref_ext = '';
1251  }
1252 
1253  // Create clone
1254  $this->context['createfromclone'] = 'createfromclone';
1255  $result = $this->create($user);
1256  if ($result < 0) {
1257  $error++;
1258  }
1259 
1260  if (!$error) {
1261  // copy internal contacts
1262  if ($this->copy_linked_contact($objFrom, 'internal') < 0) {
1263  $error++;
1264  }
1265  }
1266 
1267  if (!$error) {
1268  // copy external contacts if same company
1269  if ($this->socid == $objFrom->socid) {
1270  if ($this->copy_linked_contact($objFrom, 'external') < 0) {
1271  $error++;
1272  }
1273  }
1274  }
1275 
1276  if (!$error) {
1277  // Hook of thirdparty module
1278  if (is_object($hookmanager)) {
1279  $parameters = array('objFrom'=>$objFrom);
1280  $action = '';
1281  $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1282  if ($reshook < 0) {
1283  $this->errors += $hookmanager->errors;
1284  $this->error = $hookmanager->error;
1285  $error++;
1286  }
1287  }
1288  }
1289 
1290  unset($this->context['createfromclone']);
1291 
1292  // End
1293  if (!$error) {
1294  $this->db->commit();
1295  return $this->id;
1296  } else {
1297  $this->db->rollback();
1298  return -1;
1299  }
1300  }
1301 
1302 
1310  public function createFromProposal($object, User $user)
1311  {
1312  global $conf, $hookmanager;
1313 
1314  dol_include_once('/multicurrency/class/multicurrency.class.php');
1315  dol_include_once('/core/class/extrafields.class.php');
1316 
1317  $error = 0;
1318 
1319 
1320  $this->date_commande = dol_now();
1321  $this->source = 0;
1322 
1323  $num = count($object->lines);
1324  for ($i = 0; $i < $num; $i++) {
1325  $line = new OrderLine($this->db);
1326 
1327  $line->libelle = $object->lines[$i]->libelle;
1328  $line->label = $object->lines[$i]->label;
1329  $line->desc = $object->lines[$i]->desc;
1330  $line->price = $object->lines[$i]->price;
1331  $line->subprice = $object->lines[$i]->subprice;
1332  $line->vat_src_code = $object->lines[$i]->vat_src_code;
1333  $line->tva_tx = $object->lines[$i]->tva_tx;
1334  $line->localtax1_tx = $object->lines[$i]->localtax1_tx;
1335  $line->localtax2_tx = $object->lines[$i]->localtax2_tx;
1336  $line->qty = $object->lines[$i]->qty;
1337  $line->fk_remise_except = $object->lines[$i]->fk_remise_except;
1338  $line->remise_percent = $object->lines[$i]->remise_percent;
1339  $line->fk_product = $object->lines[$i]->fk_product;
1340  $line->info_bits = $object->lines[$i]->info_bits;
1341  $line->product_type = $object->lines[$i]->product_type;
1342  $line->rang = $object->lines[$i]->rang;
1343  $line->special_code = $object->lines[$i]->special_code;
1344  $line->fk_parent_line = $object->lines[$i]->fk_parent_line;
1345  $line->fk_unit = $object->lines[$i]->fk_unit;
1346 
1347  $line->date_start = $object->lines[$i]->date_start;
1348  $line->date_end = $object->lines[$i]->date_end;
1349 
1350  $line->fk_fournprice = $object->lines[$i]->fk_fournprice;
1351  $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);
1352  $line->pa_ht = $marginInfos[0];
1353  $line->marge_tx = $marginInfos[1];
1354  $line->marque_tx = $marginInfos[2];
1355 
1356  $line->origin = $object->element;
1357  $line->origin_id = $object->lines[$i]->id;
1358 
1359  // get extrafields from original line
1360  $object->lines[$i]->fetch_optionals();
1361  foreach ($object->lines[$i]->array_options as $options_key => $value) {
1362  $line->array_options[$options_key] = $value;
1363  }
1364 
1365  $this->lines[$i] = $line;
1366  }
1367 
1368  $this->entity = $object->entity;
1369  $this->socid = $object->socid;
1370  $this->fk_project = $object->fk_project;
1371  $this->cond_reglement_id = $object->cond_reglement_id;
1372  $this->deposit_percent = $object->deposit_percent;
1373  $this->mode_reglement_id = $object->mode_reglement_id;
1374  $this->fk_account = $object->fk_account;
1375  $this->availability_id = $object->availability_id;
1376  $this->demand_reason_id = $object->demand_reason_id;
1377  $this->date_livraison = $object->date_livraison; // deprecated
1378  $this->delivery_date = $object->date_livraison;
1379  $this->shipping_method_id = $object->shipping_method_id;
1380  $this->warehouse_id = $object->warehouse_id;
1381  $this->fk_delivery_address = $object->fk_delivery_address;
1382  $this->contact_id = $object->contact_id;
1383  $this->ref_client = $object->ref_client;
1384 
1385  if (empty($conf->global->MAIN_DISABLE_PROPAGATE_NOTES_FROM_ORIGIN)) {
1386  $this->note_private = $object->note_private;
1387  $this->note_public = $object->note_public;
1388  }
1389 
1390  $this->origin = $object->element;
1391  $this->origin_id = $object->id;
1392 
1393  // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
1394  if (!empty($conf->multicurrency->enabled)) {
1395  if (!empty($object->multicurrency_code)) {
1396  $this->multicurrency_code = $object->multicurrency_code;
1397  }
1398  if (!empty($conf->global->MULTICURRENCY_USE_ORIGIN_TX) && !empty($object->multicurrency_tx)) {
1399  $this->multicurrency_tx = $object->multicurrency_tx;
1400  }
1401 
1402  if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) {
1403  $tmparray = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $this->date_commande);
1404  $this->fk_multicurrency = $tmparray[0];
1405  $this->multicurrency_tx = $tmparray[1];
1406  } else {
1407  $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
1408  }
1409  if (empty($this->fk_multicurrency)) {
1410  $this->multicurrency_code = $conf->currency;
1411  $this->fk_multicurrency = 0;
1412  $this->multicurrency_tx = 1;
1413  }
1414  }
1415 
1416  // get extrafields from original line
1417  $object->fetch_optionals();
1418 
1419  $e = new ExtraFields($this->db);
1420  $element_extrafields = $e->fetch_name_optionals_label($this->table_element);
1421 
1422  foreach ($object->array_options as $options_key => $value) {
1423  if (array_key_exists(str_replace('options_', '', $options_key), $element_extrafields)) {
1424  $this->array_options[$options_key] = $value;
1425  }
1426  }
1427  // Possibility to add external linked objects with hooks
1428  $this->linked_objects[$this->origin] = $this->origin_id;
1429  if (isset($object->other_linked_objects) && is_array($object->other_linked_objects) && !empty($object->other_linked_objects)) {
1430  $this->linked_objects = array_merge($this->linked_objects, $object->other_linked_objects);
1431  }
1432 
1433  $ret = $this->create($user);
1434 
1435  if ($ret > 0) {
1436  // Actions hooked (by external module)
1437  $hookmanager->initHooks(array('orderdao'));
1438 
1439  $parameters = array('objFrom'=>$object);
1440  $action = '';
1441  $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1442  if ($reshook < 0) {
1443  $this->errors += $hookmanager->errors;
1444  $this->error = $hookmanager->error;
1445  $error++;
1446  }
1447 
1448  if (!$error) {
1449  // Validate immediatly the order
1450  if (!empty($conf->global->ORDER_VALID_AFTER_CLOSE_PROPAL)) {
1451  $this->fetch($ret);
1452  $this->valid($user);
1453  }
1454  return $ret;
1455  } else {
1456  return -1;
1457  }
1458  } else {
1459  return -1;
1460  }
1461  }
1462 
1463 
1504  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)
1505  {
1506  global $mysoc, $conf, $langs, $user;
1507 
1508  $logtext = "::addline commandeid=$this->id, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, fk_product=$fk_product, remise_percent=$remise_percent";
1509  $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";
1510  $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";
1511  dol_syslog(get_class($this).$logtext, LOG_DEBUG);
1512 
1513  if ($this->statut == self::STATUS_DRAFT) {
1514  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1515 
1516  // Clean parameters
1517 
1518  if (empty($remise_percent)) {
1519  $remise_percent = 0;
1520  }
1521  if (empty($qty)) {
1522  $qty = 0;
1523  }
1524  if (empty($info_bits)) {
1525  $info_bits = 0;
1526  }
1527  if (empty($rang)) {
1528  $rang = 0;
1529  }
1530  if (empty($txtva)) {
1531  $txtva = 0;
1532  }
1533  if (empty($txlocaltax1)) {
1534  $txlocaltax1 = 0;
1535  }
1536  if (empty($txlocaltax2)) {
1537  $txlocaltax2 = 0;
1538  }
1539  if (empty($fk_parent_line) || $fk_parent_line < 0) {
1540  $fk_parent_line = 0;
1541  }
1542  if (empty($this->fk_multicurrency)) {
1543  $this->fk_multicurrency = 0;
1544  }
1545  if (empty($ref_ext)) {
1546  $ref_ext = '';
1547  }
1548 
1549  $remise_percent = price2num($remise_percent);
1550  $qty = price2num($qty);
1551  $pu_ht = price2num($pu_ht);
1552  $pu_ht_devise = price2num($pu_ht_devise);
1553  $pu_ttc = price2num($pu_ttc);
1554  $pa_ht = price2num($pa_ht);
1555  if (!preg_match('/\((.*)\)/', $txtva)) {
1556  $txtva = price2num($txtva); // $txtva can have format '5,1' or '5.1' or '5.1(XXX)', we must clean only if '5,1'
1557  }
1558  $txlocaltax1 = price2num($txlocaltax1);
1559  $txlocaltax2 = price2num($txlocaltax2);
1560  if ($price_base_type == 'HT') {
1561  $pu = $pu_ht;
1562  } else {
1563  $pu = $pu_ttc;
1564  }
1565  $label = trim($label);
1566  $desc = trim($desc);
1567 
1568  // Check parameters
1569  if ($type < 0) {
1570  return -1;
1571  }
1572 
1573  if ($date_start && $date_end && $date_start > $date_end) {
1574  $langs->load("errors");
1575  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
1576  return -1;
1577  }
1578 
1579  $this->db->begin();
1580 
1581  $product_type = $type;
1582  if (!empty($fk_product) && $fk_product > 0) {
1583  $product = new Product($this->db);
1584  $result = $product->fetch($fk_product);
1585  $product_type = $product->type;
1586 
1587  if (!empty($conf->global->STOCK_MUST_BE_ENOUGH_FOR_ORDER) && $product_type == 0 && $product->stock_reel < $qty) {
1588  $langs->load("errors");
1589  $this->error = $langs->trans('ErrorStockIsNotEnoughToAddProductOnOrder', $product->ref);
1590  $this->errors[] = $this->error;
1591  dol_syslog(get_class($this)."::addline error=Product ".$product->ref.": ".$this->error, LOG_ERR);
1592  $this->db->rollback();
1594  }
1595  }
1596  // Calcul du total TTC et de la TVA pour la ligne a partir de
1597  // qty, pu, remise_percent et txtva
1598  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1599  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1600 
1601  $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
1602 
1603  // Clean vat code
1604  $reg = array();
1605  $vat_src_code = '';
1606  if (preg_match('/\((.*)\)/', $txtva, $reg)) {
1607  $vat_src_code = $reg[1];
1608  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
1609  }
1610 
1611  $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);
1612 
1613  /*var_dump($txlocaltax1);
1614  var_dump($txlocaltax2);
1615  var_dump($localtaxes_type);
1616  var_dump($tabprice);
1617  var_dump($tabprice[9]);
1618  var_dump($tabprice[10]);
1619  exit;*/
1620 
1621  $total_ht = $tabprice[0];
1622  $total_tva = $tabprice[1];
1623  $total_ttc = $tabprice[2];
1624  $total_localtax1 = $tabprice[9];
1625  $total_localtax2 = $tabprice[10];
1626  $pu_ht = $tabprice[3];
1627 
1628  // MultiCurrency
1629  $multicurrency_total_ht = $tabprice[16];
1630  $multicurrency_total_tva = $tabprice[17];
1631  $multicurrency_total_ttc = $tabprice[18];
1632  $pu_ht_devise = $tabprice[19];
1633 
1634  // Rang to use
1635  $ranktouse = $rang;
1636  if ($ranktouse == -1) {
1637  $rangmax = $this->line_max($fk_parent_line);
1638  $ranktouse = $rangmax + 1;
1639  }
1640 
1641  // TODO A virer
1642  // Anciens indicateurs: $price, $remise (a ne plus utiliser)
1643  $price = $pu;
1644  $remise = 0;
1645  if ($remise_percent > 0) {
1646  $remise = round(($pu * $remise_percent / 100), 2);
1647  $price = $pu - $remise;
1648  }
1649 
1650  // Insert line
1651  $this->line = new OrderLine($this->db);
1652 
1653  $this->line->context = $this->context;
1654 
1655  $this->line->fk_commande = $this->id;
1656  $this->line->label = $label;
1657  $this->line->desc = $desc;
1658  $this->line->qty = $qty;
1659  $this->line->ref_ext = $ref_ext;
1660 
1661  $this->line->vat_src_code = $vat_src_code;
1662  $this->line->tva_tx = $txtva;
1663  $this->line->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0);
1664  $this->line->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0);
1665  $this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
1666  $this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
1667  $this->line->fk_product = $fk_product;
1668  $this->line->product_type = $product_type;
1669  $this->line->fk_remise_except = $fk_remise_except;
1670  $this->line->remise_percent = $remise_percent;
1671  $this->line->subprice = $pu_ht;
1672  $this->line->rang = $ranktouse;
1673  $this->line->info_bits = $info_bits;
1674  $this->line->total_ht = $total_ht;
1675  $this->line->total_tva = $total_tva;
1676  $this->line->total_localtax1 = $total_localtax1;
1677  $this->line->total_localtax2 = $total_localtax2;
1678  $this->line->total_ttc = $total_ttc;
1679  $this->line->special_code = $special_code;
1680  $this->line->origin = $origin;
1681  $this->line->origin_id = $origin_id;
1682  $this->line->fk_parent_line = $fk_parent_line;
1683  $this->line->fk_unit = $fk_unit;
1684 
1685  $this->line->date_start = $date_start;
1686  $this->line->date_end = $date_end;
1687 
1688  $this->line->fk_fournprice = $fk_fournprice;
1689  $this->line->pa_ht = $pa_ht;
1690 
1691  // Multicurrency
1692  $this->line->fk_multicurrency = $this->fk_multicurrency;
1693  $this->line->multicurrency_code = $this->multicurrency_code;
1694  $this->line->multicurrency_subprice = $pu_ht_devise;
1695  $this->line->multicurrency_total_ht = $multicurrency_total_ht;
1696  $this->line->multicurrency_total_tva = $multicurrency_total_tva;
1697  $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
1698 
1699  // TODO Ne plus utiliser
1700  $this->line->price = $price;
1701 
1702  if (is_array($array_options) && count($array_options) > 0) {
1703  $this->line->array_options = $array_options;
1704  }
1705 
1706  $result = $this->line->insert($user);
1707  if ($result > 0) {
1708  // Reorder if child line
1709  if (!empty($fk_parent_line)) {
1710  $this->line_order(true, 'DESC');
1711  } elseif ($ranktouse > 0 && $ranktouse <= count($this->lines)) { // Update all rank of all other lines
1712  $linecount = count($this->lines);
1713  for ($ii = $ranktouse; $ii <= $linecount; $ii++) {
1714  $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii + 1);
1715  }
1716  }
1717 
1718  // Mise a jour informations denormalisees au niveau de la commande meme
1719  if (empty($noupdateafterinsertline)) {
1720  $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.
1721  }
1722 
1723  if ($result > 0) {
1724  $this->db->commit();
1725  return $this->line->id;
1726  } else {
1727  $this->db->rollback();
1728  return -1;
1729  }
1730  } else {
1731  $this->error = $this->line->error;
1732  dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR);
1733  $this->db->rollback();
1734  return -2;
1735  }
1736  } else {
1737  dol_syslog(get_class($this)."::addline status of order must be Draft to allow use of ->addline()", LOG_ERR);
1738  return -3;
1739  }
1740  }
1741 
1742 
1743  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1757  public function add_product($idproduct, $qty, $remise_percent = 0.0, $date_start = '', $date_end = '')
1758  {
1759  // phpcs:enable
1760  global $conf, $mysoc;
1761 
1762  if (!$qty) {
1763  $qty = 1;
1764  }
1765 
1766  if ($idproduct > 0) {
1767  $prod = new Product($this->db);
1768  $prod->fetch($idproduct);
1769 
1770  $tva_tx = get_default_tva($mysoc, $this->thirdparty, $prod->id);
1771  $tva_npr = get_default_npr($mysoc, $this->thirdparty, $prod->id);
1772  if (empty($tva_tx)) {
1773  $tva_npr = 0;
1774  }
1775  $vat_src_code = ''; // May be defined into tva_tx
1776 
1777  $localtax1_tx = get_localtax($tva_tx, 1, $this->thirdparty, $mysoc, $tva_npr);
1778  $localtax2_tx = get_localtax($tva_tx, 2, $this->thirdparty, $mysoc, $tva_npr);
1779 
1780  // multiprix
1781  if ($conf->global->PRODUIT_MULTIPRICES && $this->thirdparty->price_level) {
1782  $price = $prod->multiprices[$this->thirdparty->price_level];
1783  } else {
1784  $price = $prod->price;
1785  }
1786 
1787  $line = new OrderLine($this->db);
1788 
1789  $line->context = $this->context;
1790 
1791  $line->fk_product = $idproduct;
1792  $line->desc = $prod->description;
1793  $line->qty = $qty;
1794  $line->subprice = $price;
1795  $line->remise_percent = $remise_percent;
1796  $line->vat_src_code = $vat_src_code;
1797  $line->tva_tx = $tva_tx;
1798  $line->localtax1_tx = $localtax1_tx;
1799  $line->localtax2_tx = $localtax2_tx;
1800  $line->ref = $prod->ref;
1801  $line->libelle = $prod->label;
1802  $line->product_desc = $prod->description;
1803  $line->fk_unit = $prod->fk_unit;
1804 
1805  // Save the start and end date of the line in the object
1806  if ($date_start) {
1807  $line->date_start = $date_start;
1808  }
1809  if ($date_end) {
1810  $line->date_end = $date_end;
1811  }
1812 
1813  $this->lines[] = $line;
1814 
1833  }
1834  }
1835 
1836 
1846  public function fetch($id, $ref = '', $ref_ext = '', $notused = '')
1847  {
1848  // Check parameters
1849  if (empty($id) && empty($ref) && empty($ref_ext)) {
1850  return -1;
1851  }
1852 
1853  $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';
1854  $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';
1855  $sql .= ', c.fk_account';
1856  $sql .= ', c.date_commande, c.date_valid, c.tms';
1857  $sql .= ', c.date_livraison as delivery_date';
1858  $sql .= ', c.fk_shipping_method';
1859  $sql .= ', c.fk_warehouse';
1860  $sql .= ', c.fk_projet as fk_project, c.remise_percent, c.remise, c.remise_absolue, c.source, c.facture as billed';
1861  $sql .= ', c.note_private, c.note_public, c.ref_client, c.ref_ext, c.ref_int, c.model_pdf, c.last_main_doc, c.fk_delivery_address, c.extraparams';
1862  $sql .= ', c.fk_incoterms, c.location_incoterms';
1863  $sql .= ", c.fk_multicurrency, c.multicurrency_code, c.multicurrency_tx, c.multicurrency_total_ht, c.multicurrency_total_tva, c.multicurrency_total_ttc";
1864  $sql .= ", c.module_source, c.pos_source";
1865  $sql .= ", i.libelle as label_incoterms";
1866  $sql .= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
1867  $sql .= ', cr.code as cond_reglement_code, cr.libelle as cond_reglement_libelle, cr.libelle_facture as cond_reglement_libelle_doc';
1868  $sql .= ', ca.code as availability_code, ca.label as availability_label';
1869  $sql .= ', dr.code as demand_reason_code';
1870  $sql .= ' FROM '.MAIN_DB_PREFIX.'commande as c';
1871  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as cr ON c.fk_cond_reglement = cr.rowid';
1872  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON c.fk_mode_reglement = p.id';
1873  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_availability as ca ON c.fk_availability = ca.rowid';
1874  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_input_reason as dr ON c.fk_input_reason = dr.rowid';
1875  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON c.fk_incoterms = i.rowid';
1876 
1877  if ($id) {
1878  $sql .= " WHERE c.rowid=".((int) $id);
1879  } else {
1880  $sql .= " WHERE c.entity IN (".getEntity('commande').")"; // Dont't use entity if you use rowid
1881  }
1882 
1883  if ($ref) {
1884  $sql .= " AND c.ref='".$this->db->escape($ref)."'";
1885  }
1886  if ($ref_ext) {
1887  $sql .= " AND c.ref_ext='".$this->db->escape($ref_ext)."'";
1888  }
1889  if ($notused) {
1890  $sql .= " AND c.ref_int='".$this->db->escape($notused)."'";
1891  }
1892 
1893  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
1894  $result = $this->db->query($sql);
1895  if ($result) {
1896  $obj = $this->db->fetch_object($result);
1897  if ($obj) {
1898  $this->id = $obj->rowid;
1899  $this->entity = $obj->entity;
1900 
1901  $this->ref = $obj->ref;
1902  $this->ref_client = $obj->ref_client;
1903  $this->ref_customer = $obj->ref_client;
1904  $this->ref_ext = $obj->ref_ext;
1905  $this->ref_int = $obj->ref_int;
1906 
1907  $this->socid = $obj->fk_soc;
1908  $this->thirdparty = null; // Clear if another value was already set by fetch_thirdparty
1909 
1910  $this->fk_project = $obj->fk_project;
1911  $this->project = null; // Clear if another value was already set by fetch_projet
1912 
1913  $this->statut = $obj->fk_statut;
1914  $this->status = $obj->fk_statut;
1915 
1916  $this->user_author_id = $obj->fk_user_author;
1917  $this->user_creation_id = $obj->fk_user_author;
1918  $this->user_validation_id = $obj->fk_user_valid;
1919  $this->user_valid = $obj->fk_user_valid; // deprecated
1920  $this->user_modification_id = $obj->fk_user_modif;
1921  $this->user_modification = $obj->fk_user_modif;
1922  $this->total_ht = $obj->total_ht;
1923  $this->total_tva = $obj->total_tva;
1924  $this->total_localtax1 = $obj->total_localtax1;
1925  $this->total_localtax2 = $obj->total_localtax2;
1926  $this->total_ttc = $obj->total_ttc;
1927  $this->date = $this->db->jdate($obj->date_commande);
1928  $this->date_commande = $this->db->jdate($obj->date_commande);
1929  $this->date_creation = $this->db->jdate($obj->date_creation);
1930  $this->date_validation = $this->db->jdate($obj->date_valid);
1931  $this->date_modification = $this->db->jdate($obj->tms);
1932  $this->remise = $obj->remise;
1933  $this->remise_percent = $obj->remise_percent;
1934  $this->remise_absolue = $obj->remise_absolue;
1935  $this->source = $obj->source;
1936  $this->billed = $obj->billed;
1937  $this->note = $obj->note_private; // deprecated
1938  $this->note_private = $obj->note_private;
1939  $this->note_public = $obj->note_public;
1940  $this->model_pdf = $obj->model_pdf;
1941  $this->modelpdf = $obj->model_pdf; // deprecated
1942  $this->last_main_doc = $obj->last_main_doc;
1943  $this->mode_reglement_id = $obj->fk_mode_reglement;
1944  $this->mode_reglement_code = $obj->mode_reglement_code;
1945  $this->mode_reglement = $obj->mode_reglement_libelle;
1946  $this->cond_reglement_id = $obj->fk_cond_reglement;
1947  $this->cond_reglement_code = $obj->cond_reglement_code;
1948  $this->cond_reglement = $obj->cond_reglement_libelle;
1949  $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc;
1950  $this->deposit_percent = $obj->deposit_percent;
1951  $this->fk_account = $obj->fk_account;
1952  $this->availability_id = $obj->fk_availability;
1953  $this->availability_code = $obj->availability_code;
1954  $this->availability = $obj->availability_label;
1955  $this->demand_reason_id = $obj->fk_input_reason;
1956  $this->demand_reason_code = $obj->demand_reason_code;
1957  $this->date_livraison = $this->db->jdate($obj->delivery_date); // deprecated
1958  $this->delivery_date = $this->db->jdate($obj->delivery_date);
1959  $this->shipping_method_id = ($obj->fk_shipping_method > 0) ? $obj->fk_shipping_method : null;
1960  $this->warehouse_id = ($obj->fk_warehouse > 0) ? $obj->fk_warehouse : null;
1961  $this->fk_delivery_address = $obj->fk_delivery_address;
1962  $this->module_source = $obj->module_source;
1963  $this->pos_source = $obj->pos_source;
1964 
1965  //Incoterms
1966  $this->fk_incoterms = $obj->fk_incoterms;
1967  $this->location_incoterms = $obj->location_incoterms;
1968  $this->label_incoterms = $obj->label_incoterms;
1969 
1970  // Multicurrency
1971  $this->fk_multicurrency = $obj->fk_multicurrency;
1972  $this->multicurrency_code = $obj->multicurrency_code;
1973  $this->multicurrency_tx = $obj->multicurrency_tx;
1974  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
1975  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
1976  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
1977 
1978  $this->extraparams = (array) json_decode($obj->extraparams, true);
1979 
1980  $this->lines = array();
1981 
1982  if ($this->statut == self::STATUS_DRAFT) {
1983  $this->brouillon = 1;
1984  }
1985 
1986  // Retrieve all extrafield
1987  // fetch optionals attributes and labels
1988  $this->fetch_optionals();
1989 
1990  $this->db->free($result);
1991 
1992  // Lines
1993  $result = $this->fetch_lines();
1994  if ($result < 0) {
1995  return -3;
1996  }
1997  return 1;
1998  } else {
1999  $this->error = 'Order with id '.$id.' not found sql='.$sql;
2000  return 0;
2001  }
2002  } else {
2003  $this->error = $this->db->error();
2004  return -1;
2005  }
2006  }
2007 
2008 
2009  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2016  public function insert_discount($idremise)
2017  {
2018  // phpcs:enable
2019  global $langs;
2020 
2021  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2022  include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
2023 
2024  $this->db->begin();
2025 
2026  $remise = new DiscountAbsolute($this->db);
2027  $result = $remise->fetch($idremise);
2028 
2029  if ($result > 0) {
2030  if ($remise->fk_facture) { // Protection against multiple submission
2031  $this->error = $langs->trans("ErrorDiscountAlreadyUsed");
2032  $this->db->rollback();
2033  return -5;
2034  }
2035 
2036  $line = new OrderLine($this->db);
2037 
2038  $line->fk_commande = $this->id;
2039  $line->fk_remise_except = $remise->id;
2040  $line->desc = $remise->description; // Description ligne
2041  $line->vat_src_code = $remise->vat_src_code;
2042  $line->tva_tx = $remise->tva_tx;
2043  $line->subprice = -$remise->amount_ht;
2044  $line->price = -$remise->amount_ht;
2045  $line->fk_product = 0; // Id produit predefini
2046  $line->qty = 1;
2047  $line->remise_percent = 0;
2048  $line->rang = -1;
2049  $line->info_bits = 2;
2050 
2051  $line->total_ht = -$remise->amount_ht;
2052  $line->total_tva = -$remise->amount_tva;
2053  $line->total_ttc = -$remise->amount_ttc;
2054 
2055  $result = $line->insert();
2056  if ($result > 0) {
2057  $result = $this->update_price(1);
2058  if ($result > 0) {
2059  $this->db->commit();
2060  return 1;
2061  } else {
2062  $this->db->rollback();
2063  return -1;
2064  }
2065  } else {
2066  $this->error = $line->error;
2067  $this->errors = $line->errors;
2068  $this->db->rollback();
2069  return -2;
2070  }
2071  } else {
2072  $this->db->rollback();
2073  return -2;
2074  }
2075  }
2076 
2077 
2078  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2086  public function fetch_lines($only_product = 0, $loadalsotranslation = 0)
2087  {
2088  // phpcs:enable
2089  global $langs, $conf;
2090 
2091  $this->lines = array();
2092 
2093  $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,';
2094  $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,';
2095  $sql .= ' l.total_ht, l.total_ttc, l.total_tva, l.total_localtax1, l.total_localtax2, l.date_start, l.date_end,';
2096  $sql .= ' l.fk_unit,';
2097  $sql .= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
2098  $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,';
2099  $sql .= ' p.weight, p.weight_units, p.volume, p.volume_units';
2100  $sql .= ' FROM '.MAIN_DB_PREFIX.'commandedet as l';
2101  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON (p.rowid = l.fk_product)';
2102  $sql .= ' WHERE l.fk_commande = '.((int) $this->id);
2103  if ($only_product) {
2104  $sql .= ' AND p.fk_product_type = 0';
2105  }
2106  $sql .= ' ORDER BY l.rang, l.rowid';
2107 
2108  dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
2109  $result = $this->db->query($sql);
2110  if ($result) {
2111  $num = $this->db->num_rows($result);
2112 
2113  $i = 0;
2114  while ($i < $num) {
2115  $objp = $this->db->fetch_object($result);
2116 
2117  $line = new OrderLine($this->db);
2118 
2119  $line->rowid = $objp->rowid;
2120  $line->id = $objp->rowid;
2121  $line->fk_commande = $objp->fk_commande;
2122  $line->commande_id = $objp->fk_commande;
2123  $line->label = $objp->custom_label;
2124  $line->desc = $objp->description;
2125  $line->description = $objp->description; // Description line
2126  $line->product_type = $objp->product_type;
2127  $line->qty = $objp->qty;
2128  $line->ref_ext = $objp->ref_ext;
2129 
2130  $line->vat_src_code = $objp->vat_src_code;
2131  $line->tva_tx = $objp->tva_tx;
2132  $line->localtax1_tx = $objp->localtax1_tx;
2133  $line->localtax2_tx = $objp->localtax2_tx;
2134  $line->localtax1_type = $objp->localtax1_type;
2135  $line->localtax2_type = $objp->localtax2_type;
2136  $line->total_ht = $objp->total_ht;
2137  $line->total_ttc = $objp->total_ttc;
2138  $line->total_tva = $objp->total_tva;
2139  $line->total_localtax1 = $objp->total_localtax1;
2140  $line->total_localtax2 = $objp->total_localtax2;
2141  $line->subprice = $objp->subprice;
2142  $line->fk_remise_except = $objp->fk_remise_except;
2143  $line->remise_percent = $objp->remise_percent;
2144  $line->price = $objp->price;
2145  $line->fk_product = $objp->fk_product;
2146  $line->fk_fournprice = $objp->fk_fournprice;
2147  $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht);
2148  $line->pa_ht = $marginInfos[0];
2149  $line->marge_tx = $marginInfos[1];
2150  $line->marque_tx = $marginInfos[2];
2151  $line->rang = $objp->rang;
2152  $line->info_bits = $objp->info_bits;
2153  $line->special_code = $objp->special_code;
2154  $line->fk_parent_line = $objp->fk_parent_line;
2155 
2156  $line->ref = $objp->product_ref;
2157  $line->libelle = $objp->product_label;
2158 
2159  $line->product_ref = $objp->product_ref;
2160  $line->product_label = $objp->product_label;
2161  $line->product_tosell = $objp->product_tosell;
2162  $line->product_tobuy = $objp->product_tobuy;
2163  $line->product_desc = $objp->product_desc;
2164  $line->product_tobatch = $objp->product_tobatch;
2165  $line->product_barcode = $objp->product_barcode;
2166 
2167  $line->fk_product_type = $objp->fk_product_type; // Produit ou service
2168  $line->fk_unit = $objp->fk_unit;
2169 
2170  $line->weight = $objp->weight;
2171  $line->weight_units = $objp->weight_units;
2172  $line->volume = $objp->volume;
2173  $line->volume_units = $objp->volume_units;
2174 
2175  $line->date_start = $this->db->jdate($objp->date_start);
2176  $line->date_end = $this->db->jdate($objp->date_end);
2177 
2178  // Multicurrency
2179  $line->fk_multicurrency = $objp->fk_multicurrency;
2180  $line->multicurrency_code = $objp->multicurrency_code;
2181  $line->multicurrency_subprice = $objp->multicurrency_subprice;
2182  $line->multicurrency_total_ht = $objp->multicurrency_total_ht;
2183  $line->multicurrency_total_tva = $objp->multicurrency_total_tva;
2184  $line->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
2185 
2186  $line->fetch_optionals();
2187 
2188  // multilangs
2189  if (!empty($conf->global->MAIN_MULTILANGS) && !empty($objp->fk_product) && !empty($loadalsotranslation)) {
2190  $tmpproduct = new Product($this->db);
2191  $tmpproduct->fetch($objp->fk_product);
2192  $tmpproduct->getMultiLangs();
2193 
2194  $line->multilangs = $tmpproduct->multilangs;
2195  }
2196 
2197  $this->lines[$i] = $line;
2198 
2199  $i++;
2200  }
2201 
2202  $this->db->free($result);
2203 
2204  return 1;
2205  } else {
2206  $this->error = $this->db->error();
2207  return -3;
2208  }
2209  }
2210 
2211 
2217  public function getNbOfProductsLines()
2218  {
2219  $nb = 0;
2220  foreach ($this->lines as $line) {
2221  if ($line->product_type == 0) {
2222  $nb++;
2223  }
2224  }
2225  return $nb;
2226  }
2227 
2233  public function getNbOfServicesLines()
2234  {
2235  $nb = 0;
2236  foreach ($this->lines as $line) {
2237  if ($line->product_type == 1) {
2238  $nb++;
2239  }
2240  }
2241  return $nb;
2242  }
2243 
2249  public function getNbOfShipments()
2250  {
2251  $nb = 0;
2252 
2253  $sql = 'SELECT COUNT(DISTINCT ed.fk_expedition) as nb';
2254  $sql .= ' FROM '.MAIN_DB_PREFIX.'expeditiondet as ed,';
2255  $sql .= ' '.MAIN_DB_PREFIX.'commandedet as cd';
2256  $sql .= ' WHERE';
2257  $sql .= ' ed.fk_origin_line = cd.rowid';
2258  $sql .= ' AND cd.fk_commande = '.((int) $this->id);
2259  //print $sql;
2260 
2261  dol_syslog(get_class($this)."::getNbOfShipments", LOG_DEBUG);
2262  $resql = $this->db->query($sql);
2263  if ($resql) {
2264  $obj = $this->db->fetch_object($resql);
2265  if ($obj) {
2266  $nb = $obj->nb;
2267  }
2268 
2269  $this->db->free($resql);
2270  return $nb;
2271  } else {
2272  $this->error = $this->db->lasterror();
2273  return -1;
2274  }
2275  }
2276 
2285  public function loadExpeditions($filtre_statut = -1, $fk_product = 0)
2286  {
2287  $this->expeditions = array();
2288 
2289  $sql = 'SELECT cd.rowid, cd.fk_product,';
2290  $sql .= ' sum(ed.qty) as qty';
2291  $sql .= ' FROM '.MAIN_DB_PREFIX.'expeditiondet as ed,';
2292  if ($filtre_statut >= 0) {
2293  $sql .= ' '.MAIN_DB_PREFIX.'expedition as e,';
2294  }
2295  $sql .= ' '.MAIN_DB_PREFIX.'commandedet as cd';
2296  $sql .= ' WHERE';
2297  if ($filtre_statut >= 0) {
2298  $sql .= ' ed.fk_expedition = e.rowid AND';
2299  }
2300  $sql .= ' ed.fk_origin_line = cd.rowid';
2301  $sql .= ' AND cd.fk_commande = '.((int) $this->id);
2302  if ($fk_product > 0) {
2303  $sql .= ' AND cd.fk_product = '.((int) $fk_product);
2304  }
2305  if ($filtre_statut >= 0) {
2306  $sql .= ' AND e.fk_statut >= '.((int) $filtre_statut);
2307  }
2308  $sql .= ' GROUP BY cd.rowid, cd.fk_product';
2309  //print $sql;
2310 
2311  dol_syslog(get_class($this)."::loadExpeditions", LOG_DEBUG);
2312  $resql = $this->db->query($sql);
2313  if ($resql) {
2314  $num = $this->db->num_rows($resql);
2315  $i = 0;
2316  while ($i < $num) {
2317  $obj = $this->db->fetch_object($resql);
2318  $this->expeditions[$obj->rowid] = $obj->qty;
2319  $i++;
2320  }
2321  $this->db->free($resql);
2322  return $num;
2323  } else {
2324  $this->error = $this->db->lasterror();
2325  return -1;
2326  }
2327  }
2328 
2329  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2337  public function nb_expedition()
2338  {
2339  // phpcs:enable
2340  $sql = 'SELECT count(*)';
2341  $sql .= ' FROM '.MAIN_DB_PREFIX.'expedition as e';
2342  $sql .= ', '.MAIN_DB_PREFIX.'element_element as el';
2343  $sql .= ' WHERE el.fk_source = '.((int) $this->id);
2344  $sql .= " AND el.sourcetype = 'commande'";
2345  $sql .= " AND el.fk_target = e.rowid";
2346  $sql .= " AND el.targettype = 'shipping'";
2347 
2348  $resql = $this->db->query($sql);
2349  if ($resql) {
2350  $row = $this->db->fetch_row($resql);
2351  return $row[0];
2352  } else {
2353  dol_print_error($this->db);
2354  }
2355  }
2356 
2357  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2366  public function stock_array($filtre_statut = self::STATUS_CANCELED)
2367  {
2368  // phpcs:enable
2369  $this->stocks = array();
2370 
2371  // Tableau des id de produit de la commande
2372  $array_of_product = array();
2373 
2374  // Recherche total en stock pour chaque produit
2375  // TODO $array_of_product est défini vide juste au dessus !!
2376  if (count($array_of_product)) {
2377  $sql = "SELECT fk_product, sum(ps.reel) as total";
2378  $sql .= " FROM ".MAIN_DB_PREFIX."product_stock as ps";
2379  $sql .= " WHERE ps.fk_product IN (".$this->db->sanitize(join(',', $array_of_product)).")";
2380  $sql .= ' GROUP BY fk_product';
2381  $resql = $this->db->query($sql);
2382  if ($resql) {
2383  $num = $this->db->num_rows($resql);
2384  $i = 0;
2385  while ($i < $num) {
2386  $obj = $this->db->fetch_object($resql);
2387  $this->stocks[$obj->fk_product] = $obj->total;
2388  $i++;
2389  }
2390  $this->db->free($resql);
2391  }
2392  }
2393  return 0;
2394  }
2395 
2403  public function deleteline($user = null, $lineid = 0)
2404  {
2405  if ($this->statut == self::STATUS_DRAFT) {
2406  $this->db->begin();
2407 
2408  $sql = "SELECT fk_product, qty";
2409  $sql .= " FROM ".MAIN_DB_PREFIX."commandedet";
2410  $sql .= " WHERE rowid = ".((int) $lineid);
2411 
2412  $result = $this->db->query($sql);
2413  if ($result) {
2414  $obj = $this->db->fetch_object($result);
2415 
2416  if ($obj) {
2417  $product = new Product($this->db);
2418  $product->id = $obj->fk_product;
2419 
2420  // Delete line
2421  $line = new OrderLine($this->db);
2422 
2423  // For triggers
2424  $line->fetch($lineid);
2425 
2426  // Memorize previous line for triggers
2427  $staticline = clone $line;
2428  $line->oldline = $staticline;
2429 
2430  if ($line->delete($user) > 0) {
2431  $result = $this->update_price(1);
2432 
2433  if ($result > 0) {
2434  $this->db->commit();
2435  return 1;
2436  } else {
2437  $this->db->rollback();
2438  $this->error = $this->db->lasterror();
2439  return -1;
2440  }
2441  } else {
2442  $this->db->rollback();
2443  $this->error = $line->error;
2444  return -1;
2445  }
2446  } else {
2447  $this->db->rollback();
2448  return 0;
2449  }
2450  } else {
2451  $this->db->rollback();
2452  $this->error = $this->db->lasterror();
2453  return -1;
2454  }
2455  } else {
2456  $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
2457  return -1;
2458  }
2459  }
2460 
2461  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2472  public function set_remise($user, $remise, $notrigger = 0)
2473  {
2474  // phpcs:enable
2475  dol_syslog(get_class($this)."::set_remise is deprecated, use setDiscount instead", LOG_NOTICE);
2476  return $this->setDiscount($user, $remise, $notrigger);
2477  }
2478 
2487  public function setDiscount($user, $remise, $notrigger = 0)
2488  {
2489  $remise = trim($remise) ?trim($remise) : 0;
2490 
2491  if ($user->rights->commande->creer) {
2492  $error = 0;
2493 
2494  $this->db->begin();
2495 
2496  $remise = price2num($remise, 2);
2497 
2498  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
2499  $sql .= ' SET remise_percent = '.((float) $remise);
2500  $sql .= ' WHERE rowid = '.((int) $this->id).' AND fk_statut = '.((int) self::STATUS_DRAFT);
2501 
2502  dol_syslog(__METHOD__, LOG_DEBUG);
2503  $resql = $this->db->query($sql);
2504  if (!$resql) {
2505  $this->errors[] = $this->db->error();
2506  $error++;
2507  }
2508 
2509  if (!$error) {
2510  $this->oldcopy = clone $this;
2511  $this->remise_percent = $remise;
2512  $this->update_price(1);
2513  }
2514 
2515  if (!$notrigger && empty($error)) {
2516  // Call trigger
2517  $result = $this->call_trigger('ORDER_MODIFY', $user);
2518  if ($result < 0) {
2519  $error++;
2520  }
2521  // End call triggers
2522  }
2523 
2524  if (!$error) {
2525  $this->db->commit();
2526  return 1;
2527  } else {
2528  foreach ($this->errors as $errmsg) {
2529  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2530  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2531  }
2532  $this->db->rollback();
2533  return -1 * $error;
2534  }
2535  }
2536  }
2537 
2538 
2539  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2548  public function set_remise_absolue($user, $remise, $notrigger = 0)
2549  {
2550  // phpcs:enable
2551  if (empty($remise)) {
2552  $remise = 0;
2553  }
2554 
2555  $remise = price2num($remise);
2556 
2557  if ($user->rights->commande->creer) {
2558  $error = 0;
2559 
2560  $this->db->begin();
2561 
2562  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
2563  $sql .= ' SET remise_absolue = '.((float) $remise);
2564  $sql .= ' WHERE rowid = '.((int) $this->id).' AND fk_statut = '.self::STATUS_DRAFT;
2565 
2566  dol_syslog(__METHOD__, LOG_DEBUG);
2567  $resql = $this->db->query($sql);
2568  if (!$resql) {
2569  $this->errors[] = $this->db->error();
2570  $error++;
2571  }
2572 
2573  if (!$error) {
2574  $this->oldcopy = clone $this;
2575  $this->remise_absolue = $remise;
2576  $this->update_price(1);
2577  }
2578 
2579  if (!$notrigger && empty($error)) {
2580  // Call trigger
2581  $result = $this->call_trigger('ORDER_MODIFY', $user);
2582  if ($result < 0) {
2583  $error++;
2584  }
2585  // End call triggers
2586  }
2587 
2588  if (!$error) {
2589  $this->db->commit();
2590  return 1;
2591  } else {
2592  foreach ($this->errors as $errmsg) {
2593  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2594  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2595  }
2596  $this->db->rollback();
2597  return -1 * $error;
2598  }
2599  }
2600  }
2601 
2602 
2603  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2612  public function set_date($user, $date, $notrigger = 0)
2613  {
2614  // phpcs:enable
2615  if ($user->rights->commande->creer) {
2616  $error = 0;
2617 
2618  $this->db->begin();
2619 
2620  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
2621  $sql .= " SET date_commande = ".($date ? "'".$this->db->idate($date)."'" : 'null');
2622  $sql .= " WHERE rowid = ".((int) $this->id)." AND fk_statut = ".((int) self::STATUS_DRAFT);
2623 
2624  dol_syslog(__METHOD__, LOG_DEBUG);
2625  $resql = $this->db->query($sql);
2626  if (!$resql) {
2627  $this->errors[] = $this->db->error();
2628  $error++;
2629  }
2630 
2631  if (!$error) {
2632  $this->oldcopy = clone $this;
2633  $this->date = $date;
2634  }
2635 
2636  if (!$notrigger && empty($error)) {
2637  // Call trigger
2638  $result = $this->call_trigger('ORDER_MODIFY', $user);
2639  if ($result < 0) {
2640  $error++;
2641  }
2642  // End call triggers
2643  }
2644 
2645  if (!$error) {
2646  $this->db->commit();
2647  return 1;
2648  } else {
2649  foreach ($this->errors as $errmsg) {
2650  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2651  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2652  }
2653  $this->db->rollback();
2654  return -1 * $error;
2655  }
2656  } else {
2657  return -2;
2658  }
2659  }
2660 
2661  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2671  public function set_date_livraison($user, $delivery_date, $notrigger = 0)
2672  {
2673  // phpcs:enable
2674  return $this->setDeliveryDate($user, $delivery_date, $notrigger);
2675  }
2676 
2685  public function setDeliveryDate($user, $delivery_date, $notrigger = 0)
2686  {
2687  if ($user->rights->commande->creer) {
2688  $error = 0;
2689 
2690  $this->db->begin();
2691 
2692  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
2693  $sql .= " SET date_livraison = ".($delivery_date ? "'".$this->db->idate($delivery_date)."'" : 'null');
2694  $sql .= " WHERE rowid = ".((int) $this->id);
2695 
2696  dol_syslog(__METHOD__, LOG_DEBUG);
2697  $resql = $this->db->query($sql);
2698  if (!$resql) {
2699  $this->errors[] = $this->db->error();
2700  $error++;
2701  }
2702 
2703  if (!$error) {
2704  $this->oldcopy = clone $this;
2705  $this->date_livraison = $delivery_date;
2706  $this->delivery_date = $delivery_date;
2707  }
2708 
2709  if (!$notrigger && empty($error)) {
2710  // Call trigger
2711  $result = $this->call_trigger('ORDER_MODIFY', $user);
2712  if ($result < 0) {
2713  $error++;
2714  }
2715  // End call triggers
2716  }
2717 
2718  if (!$error) {
2719  $this->db->commit();
2720  return 1;
2721  } else {
2722  foreach ($this->errors as $errmsg) {
2723  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2724  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2725  }
2726  $this->db->rollback();
2727  return -1 * $error;
2728  }
2729  } else {
2730  return -2;
2731  }
2732  }
2733 
2734  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2748  public function liste_array($shortlist = 0, $draft = 0, $excluser = '', $socid = 0, $limit = 0, $offset = 0, $sortfield = 'c.date_commande', $sortorder = 'DESC')
2749  {
2750  // phpcs:enable
2751  global $user;
2752 
2753  $ga = array();
2754 
2755  $sql = "SELECT s.rowid, s.nom as name, s.client,";
2756  $sql .= " c.rowid as cid, c.ref";
2757  if (empty($user->rights->societe->client->voir) && !$socid) {
2758  $sql .= ", sc.fk_soc, sc.fk_user";
2759  }
2760  $sql .= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande as c";
2761  if (empty($user->rights->societe->client->voir) && !$socid) {
2762  $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
2763  }
2764  $sql .= " WHERE c.entity IN (".getEntity('commande').")";
2765  $sql .= " AND c.fk_soc = s.rowid";
2766  if (empty($user->rights->societe->client->voir) && !$socid) { //restriction
2767  $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
2768  }
2769  if ($socid) {
2770  $sql .= " AND s.rowid = ".((int) $socid);
2771  }
2772  if ($draft) {
2773  $sql .= " AND c.fk_statut = ".self::STATUS_DRAFT;
2774  }
2775  if (is_object($excluser)) {
2776  $sql .= " AND c.fk_user_author <> ".((int) $excluser->id);
2777  }
2778  $sql .= $this->db->order($sortfield, $sortorder);
2779  $sql .= $this->db->plimit($limit, $offset);
2780 
2781  $result = $this->db->query($sql);
2782  if ($result) {
2783  $numc = $this->db->num_rows($result);
2784  if ($numc) {
2785  $i = 0;
2786  while ($i < $numc) {
2787  $obj = $this->db->fetch_object($result);
2788 
2789  if ($shortlist == 1) {
2790  $ga[$obj->cid] = $obj->ref;
2791  } elseif ($shortlist == 2) {
2792  $ga[$obj->cid] = $obj->ref.' ('.$obj->name.')';
2793  } else {
2794  $ga[$i]['id'] = $obj->cid;
2795  $ga[$i]['ref'] = $obj->ref;
2796  $ga[$i]['name'] = $obj->name;
2797  }
2798  $i++;
2799  }
2800  }
2801  return $ga;
2802  } else {
2803  dol_print_error($this->db);
2804  return -1;
2805  }
2806  }
2807 
2815  public function availability($availability_id, $notrigger = 0)
2816  {
2817  global $user;
2818 
2819  dol_syslog('Commande::availability('.$availability_id.')');
2820  if ($this->statut >= self::STATUS_DRAFT) {
2821  $error = 0;
2822 
2823  $this->db->begin();
2824 
2825  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
2826  $sql .= ' SET fk_availability = '.((int) $availability_id);
2827  $sql .= ' WHERE rowid='.((int) $this->id);
2828 
2829  dol_syslog(__METHOD__, LOG_DEBUG);
2830  $resql = $this->db->query($sql);
2831  if (!$resql) {
2832  $this->errors[] = $this->db->error();
2833  $error++;
2834  }
2835 
2836  if (!$error) {
2837  $this->oldcopy = clone $this;
2838  $this->availability_id = $availability_id;
2839  }
2840 
2841  if (!$notrigger && empty($error)) {
2842  // Call trigger
2843  $result = $this->call_trigger('ORDER_MODIFY', $user);
2844  if ($result < 0) {
2845  $error++;
2846  }
2847  // End call triggers
2848  }
2849 
2850  if (!$error) {
2851  $this->db->commit();
2852  return 1;
2853  } else {
2854  foreach ($this->errors as $errmsg) {
2855  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2856  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2857  }
2858  $this->db->rollback();
2859  return -1 * $error;
2860  }
2861  } else {
2862  $error_str = 'Command status do not meet requirement '.$this->statut;
2863  dol_syslog(__METHOD__.$error_str, LOG_ERR);
2864  $this->error = $error_str;
2865  $this->errors[] = $this->error;
2866  return -2;
2867  }
2868  }
2869 
2870  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2878  public function demand_reason($demand_reason_id, $notrigger = 0)
2879  {
2880  // phpcs:enable
2881  global $user;
2882 
2883  dol_syslog('Commande::demand_reason('.$demand_reason_id.')');
2884  if ($this->statut >= self::STATUS_DRAFT) {
2885  $error = 0;
2886 
2887  $this->db->begin();
2888 
2889  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
2890  $sql .= ' SET fk_input_reason = '.((int) $demand_reason_id);
2891  $sql .= ' WHERE rowid='.((int) $this->id);
2892 
2893  dol_syslog(__METHOD__, LOG_DEBUG);
2894  $resql = $this->db->query($sql);
2895  if (!$resql) {
2896  $this->errors[] = $this->db->error();
2897  $error++;
2898  }
2899 
2900  if (!$error) {
2901  $this->oldcopy = clone $this;
2902  $this->demand_reason_id = $demand_reason_id;
2903  }
2904 
2905  if (!$notrigger && empty($error)) {
2906  // Call trigger
2907  $result = $this->call_trigger('ORDER_MODIFY', $user);
2908  if ($result < 0) {
2909  $error++;
2910  }
2911  // End call triggers
2912  }
2913 
2914  if (!$error) {
2915  $this->db->commit();
2916  return 1;
2917  } else {
2918  foreach ($this->errors as $errmsg) {
2919  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2920  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2921  }
2922  $this->db->rollback();
2923  return -1 * $error;
2924  }
2925  } else {
2926  $error_str = 'order status do not meet requirement '.$this->statut;
2927  dol_syslog(__METHOD__.$error_str, LOG_ERR);
2928  $this->error = $error_str;
2929  $this->errors[] = $this->error;
2930  return -2;
2931  }
2932  }
2933 
2934  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2943  public function set_ref_client($user, $ref_client, $notrigger = 0)
2944  {
2945  // phpcs:enable
2946  if ($user->rights->commande->creer) {
2947  $error = 0;
2948 
2949  $this->db->begin();
2950 
2951  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande SET';
2952  $sql .= ' ref_client = '.(empty($ref_client) ? 'NULL' : "'".$this->db->escape($ref_client)."'");
2953  $sql .= ' WHERE rowid = '.((int) $this->id);
2954 
2955  dol_syslog(__METHOD__.' this->id='.$this->id.', ref_client='.$ref_client, LOG_DEBUG);
2956  $resql = $this->db->query($sql);
2957  if (!$resql) {
2958  $this->errors[] = $this->db->error();
2959  $error++;
2960  }
2961 
2962  if (!$error) {
2963  $this->oldcopy = clone $this;
2964  $this->ref_client = $ref_client;
2965  }
2966 
2967  if (!$notrigger && empty($error)) {
2968  // Call trigger
2969  $result = $this->call_trigger('ORDER_MODIFY', $user);
2970  if ($result < 0) {
2971  $error++;
2972  }
2973  // End call triggers
2974  }
2975  if (!$error) {
2976  $this->db->commit();
2977  return 1;
2978  } else {
2979  foreach ($this->errors as $errmsg) {
2980  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2981  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2982  }
2983  $this->db->rollback();
2984  return -1 * $error;
2985  }
2986  } else {
2987  return -1;
2988  }
2989  }
2990 
2998  public function classifyBilled(User $user, $notrigger = 0)
2999  {
3000  $error = 0;
3001 
3002  if ($this->billed) {
3003  return 0;
3004  }
3005 
3006  $this->db->begin();
3007 
3008  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande SET facture = 1';
3009  $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > '.self::STATUS_DRAFT;
3010 
3011  dol_syslog(get_class($this)."::classifyBilled", LOG_DEBUG);
3012  if ($this->db->query($sql)) {
3013  if (!$error) {
3014  $this->oldcopy = clone $this;
3015  $this->billed = 1;
3016  }
3017 
3018  if (!$notrigger && empty($error)) {
3019  // Call trigger
3020  $result = $this->call_trigger('ORDER_CLASSIFY_BILLED', $user);
3021  if ($result < 0) {
3022  $error++;
3023  }
3024  // End call triggers
3025  }
3026 
3027  if (!$error) {
3028  $this->db->commit();
3029  return 1;
3030  } else {
3031  foreach ($this->errors as $errmsg) {
3032  dol_syslog(get_class($this)."::classifyBilled ".$errmsg, LOG_ERR);
3033  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
3034  }
3035  $this->db->rollback();
3036  return -1 * $error;
3037  }
3038  } else {
3039  $this->error = $this->db->error();
3040  $this->db->rollback();
3041  return -1;
3042  }
3043  }
3044 
3052  public function classifyUnBilled(User $user, $notrigger = 0)
3053  {
3054  $error = 0;
3055 
3056  $this->db->begin();
3057 
3058  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande SET facture = 0';
3059  $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > '.self::STATUS_DRAFT;
3060 
3061  dol_syslog(get_class($this)."::classifyUnBilled", LOG_DEBUG);
3062  if ($this->db->query($sql)) {
3063  if (!$error) {
3064  $this->oldcopy = clone $this;
3065  $this->billed = 1;
3066  }
3067 
3068  if (!$notrigger && empty($error)) {
3069  // Call trigger
3070  $result = $this->call_trigger('ORDER_CLASSIFY_UNBILLED', $user);
3071  if ($result < 0) {
3072  $error++;
3073  }
3074  // End call triggers
3075  }
3076 
3077  if (!$error) {
3078  $this->billed = 0;
3079 
3080  $this->db->commit();
3081  return 1;
3082  } else {
3083  foreach ($this->errors as $errmsg) {
3084  dol_syslog(get_class($this)."::classifyUnBilled ".$errmsg, LOG_ERR);
3085  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
3086  }
3087  $this->db->rollback();
3088  return -1 * $error;
3089  }
3090  } else {
3091  $this->error = $this->db->error();
3092  $this->db->rollback();
3093  return -1;
3094  }
3095  }
3096 
3097 
3128  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)
3129  {
3130  global $conf, $mysoc, $langs, $user;
3131 
3132  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");
3133  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
3134 
3135  if ($this->statut == Commande::STATUS_DRAFT) {
3136  // Clean parameters
3137  if (empty($qty)) {
3138  $qty = 0;
3139  }
3140  if (empty($info_bits)) {
3141  $info_bits = 0;
3142  }
3143  if (empty($txtva)) {
3144  $txtva = 0;
3145  }
3146  if (empty($txlocaltax1)) {
3147  $txlocaltax1 = 0;
3148  }
3149  if (empty($txlocaltax2)) {
3150  $txlocaltax2 = 0;
3151  }
3152  if (empty($remise_percent)) {
3153  $remise_percent = 0;
3154  }
3155  if (empty($special_code) || $special_code == 3) {
3156  $special_code = 0;
3157  }
3158  if (empty($ref_ext)) {
3159  $ref_ext = '';
3160  }
3161 
3162  if ($date_start && $date_end && $date_start > $date_end) {
3163  $langs->load("errors");
3164  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
3165  return -1;
3166  }
3167 
3168  $remise_percent = price2num($remise_percent);
3169  $qty = price2num($qty);
3170  $pu = price2num($pu);
3171  $pa_ht = price2num($pa_ht);
3172  $pu_ht_devise = price2num($pu_ht_devise);
3173  if (!preg_match('/\((.*)\)/', $txtva)) {
3174  $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
3175  }
3176  $txlocaltax1 = price2num($txlocaltax1);
3177  $txlocaltax2 = price2num($txlocaltax2);
3178 
3179  $this->db->begin();
3180 
3181  // Calcul du total TTC et de la TVA pour la ligne a partir de
3182  // qty, pu, remise_percent et txtva
3183  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
3184  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
3185 
3186  $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
3187 
3188  // Clean vat code
3189  $vat_src_code = '';
3190  $reg = array();
3191  if (preg_match('/\((.*)\)/', $txtva, $reg)) {
3192  $vat_src_code = $reg[1];
3193  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
3194  }
3195 
3196  $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);
3197 
3198  $total_ht = $tabprice[0];
3199  $total_tva = $tabprice[1];
3200  $total_ttc = $tabprice[2];
3201  $total_localtax1 = $tabprice[9];
3202  $total_localtax2 = $tabprice[10];
3203  $pu_ht = $tabprice[3];
3204  $pu_tva = $tabprice[4];
3205  $pu_ttc = $tabprice[5];
3206 
3207  // MultiCurrency
3208  $multicurrency_total_ht = $tabprice[16];
3209  $multicurrency_total_tva = $tabprice[17];
3210  $multicurrency_total_ttc = $tabprice[18];
3211  $pu_ht_devise = $tabprice[19];
3212 
3213  // Anciens indicateurs: $price, $subprice (a ne plus utiliser)
3214  $price = $pu_ht;
3215  if ($price_base_type == 'TTC') {
3216  $subprice = $pu_ttc;
3217  } else {
3218  $subprice = $pu_ht;
3219  }
3220  $remise = 0;
3221  if ($remise_percent > 0) {
3222  $remise = round(($pu * $remise_percent / 100), 2);
3223  $price = ($pu - $remise);
3224  }
3225 
3226  //Fetch current line from the database and then clone the object and set it in $oldline property
3227  $line = new OrderLine($this->db);
3228  $line->fetch($rowid);
3229  $line->fetch_optionals();
3230 
3231  if (!empty($line->fk_product)) {
3232  $product = new Product($this->db);
3233  $result = $product->fetch($line->fk_product);
3234  $product_type = $product->type;
3235 
3236  if (!empty($conf->global->STOCK_MUST_BE_ENOUGH_FOR_ORDER) && $product_type == 0 && $product->stock_reel < $qty) {
3237  $langs->load("errors");
3238  $this->error = $langs->trans('ErrorStockIsNotEnoughToAddProductOnOrder', $product->ref);
3239  $this->errors[] = $this->error;
3240 
3241  dol_syslog(get_class($this)."::addline error=Product ".$product->ref.": ".$this->error, LOG_ERR);
3242 
3243  $this->db->rollback();
3245  }
3246  }
3247 
3248  $staticline = clone $line;
3249 
3250  $line->oldline = $staticline;
3251  $this->line = $line;
3252  $this->line->context = $this->context;
3253  $this->line->rang = $rang;
3254 
3255  // Reorder if fk_parent_line change
3256  if (!empty($fk_parent_line) && !empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line) {
3257  $rangmax = $this->line_max($fk_parent_line);
3258  $this->line->rang = $rangmax + 1;
3259  }
3260 
3261  $this->line->id = $rowid;
3262  $this->line->label = $label;
3263  $this->line->desc = $desc;
3264  $this->line->qty = $qty;
3265  $this->line->ref_ext = $ref_ext;
3266 
3267  $this->line->vat_src_code = $vat_src_code;
3268  $this->line->tva_tx = $txtva;
3269  $this->line->localtax1_tx = $txlocaltax1;
3270  $this->line->localtax2_tx = $txlocaltax2;
3271  $this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
3272  $this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
3273  $this->line->remise_percent = $remise_percent;
3274  $this->line->subprice = $subprice;
3275  $this->line->info_bits = $info_bits;
3276  $this->line->special_code = $special_code;
3277  $this->line->total_ht = $total_ht;
3278  $this->line->total_tva = $total_tva;
3279  $this->line->total_localtax1 = $total_localtax1;
3280  $this->line->total_localtax2 = $total_localtax2;
3281  $this->line->total_ttc = $total_ttc;
3282  $this->line->date_start = $date_start;
3283  $this->line->date_end = $date_end;
3284  $this->line->product_type = $type;
3285  $this->line->fk_parent_line = $fk_parent_line;
3286  $this->line->skip_update_total = $skip_update_total;
3287  $this->line->fk_unit = $fk_unit;
3288 
3289  $this->line->fk_fournprice = $fk_fournprice;
3290  $this->line->pa_ht = $pa_ht;
3291 
3292  // Multicurrency
3293  $this->line->multicurrency_subprice = $pu_ht_devise;
3294  $this->line->multicurrency_total_ht = $multicurrency_total_ht;
3295  $this->line->multicurrency_total_tva = $multicurrency_total_tva;
3296  $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
3297 
3298  // TODO deprecated
3299  $this->line->price = $price;
3300 
3301  if (is_array($array_options) && count($array_options) > 0) {
3302  // We replace values in this->line->array_options only for entries defined into $array_options
3303  foreach ($array_options as $key => $value) {
3304  $this->line->array_options[$key] = $array_options[$key];
3305  }
3306  }
3307 
3308  $result = $this->line->update($user, $notrigger);
3309  if ($result > 0) {
3310  // Reorder if child line
3311  if (!empty($fk_parent_line)) {
3312  $this->line_order(true, 'DESC');
3313  }
3314 
3315  // Mise a jour info denormalisees
3316  $this->update_price(1, 'auto');
3317 
3318  $this->db->commit();
3319  return $result;
3320  } else {
3321  $this->error = $this->line->error;
3322 
3323  $this->db->rollback();
3324  return -1;
3325  }
3326  } else {
3327  $this->error = get_class($this)."::updateline Order status makes operation forbidden";
3328  $this->errors = array('OrderStatusMakeOperationForbidden');
3329  return -2;
3330  }
3331  }
3332 
3340  public function update(User $user, $notrigger = 0)
3341  {
3342  global $conf;
3343 
3344  $error = 0;
3345 
3346  // Clean parameters
3347  if (isset($this->ref)) {
3348  $this->ref = trim($this->ref);
3349  }
3350  if (isset($this->ref_client)) {
3351  $this->ref_client = trim($this->ref_client);
3352  }
3353  if (isset($this->note) || isset($this->note_private)) {
3354  $this->note_private = (isset($this->note_private) ? trim($this->note_private) : trim($this->note));
3355  }
3356  if (isset($this->note_public)) {
3357  $this->note_public = trim($this->note_public);
3358  }
3359  if (isset($this->model_pdf)) {
3360  $this->model_pdf = trim($this->model_pdf);
3361  }
3362  if (isset($this->import_key)) {
3363  $this->import_key = trim($this->import_key);
3364  }
3365  $delivery_date = empty($this->delivery_date) ? $this->date_livraison : $this->delivery_date;
3366 
3367  // Check parameters
3368  // Put here code to add control on parameters values
3369 
3370  // Update request
3371  $sql = "UPDATE ".MAIN_DB_PREFIX."commande SET";
3372 
3373  $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").",";
3374  $sql .= " ref_client=".(isset($this->ref_client) ? "'".$this->db->escape($this->ref_client)."'" : "null").",";
3375  $sql .= " ref_ext=".(isset($this->ref_ext) ? "'".$this->db->escape($this->ref_ext)."'" : "null").",";
3376  $sql .= " fk_soc=".(isset($this->socid) ? $this->socid : "null").",";
3377  $sql .= " date_commande=".(strval($this->date_commande) != '' ? "'".$this->db->idate($this->date_commande)."'" : 'null').",";
3378  $sql .= " date_valid=".(strval($this->date_validation) != '' ? "'".$this->db->idate($this->date_validation)."'" : 'null').",";
3379  $sql .= " total_tva=".(isset($this->total_tva) ? $this->total_tva : "null").",";
3380  $sql .= " localtax1=".(isset($this->total_localtax1) ? $this->total_localtax1 : "null").",";
3381  $sql .= " localtax2=".(isset($this->total_localtax2) ? $this->total_localtax2 : "null").",";
3382  $sql .= " total_ht=".(isset($this->total_ht) ? $this->total_ht : "null").",";
3383  $sql .= " total_ttc=".(isset($this->total_ttc) ? $this->total_ttc : "null").",";
3384  $sql .= " fk_statut=".(isset($this->statut) ? $this->statut : "null").",";
3385  $sql .= " fk_user_author=".(isset($this->user_author_id) ? $this->user_author_id : "null").",";
3386  $sql .= " fk_user_valid=".((isset($this->user_valid) && $this->user_valid > 0) ? $this->user_valid : "null").",";
3387  $sql .= " fk_projet=".(isset($this->fk_project) ? $this->fk_project : "null").",";
3388  $sql .= " fk_cond_reglement=".(isset($this->cond_reglement_id) ? $this->cond_reglement_id : "null").",";
3389  $sql .= " deposit_percent=".(! empty($this->deposit_percent) ? strval($this->deposit_percent) : "null").",";
3390  $sql .= " fk_mode_reglement=".(isset($this->mode_reglement_id) ? $this->mode_reglement_id : "null").",";
3391  $sql .= " date_livraison=".(strval($this->delivery_date) != '' ? "'".$this->db->idate($this->delivery_date)."'" : 'null').",";
3392  $sql .= " fk_shipping_method=".(isset($this->shipping_method_id) ? $this->shipping_method_id : "null").",";
3393  $sql .= " fk_account=".($this->fk_account > 0 ? $this->fk_account : "null").",";
3394  $sql .= " fk_input_reason=".($this->demand_reason_id > 0 ? $this->demand_reason_id : "null").",";
3395  $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
3396  $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
3397  $sql .= " model_pdf=".(isset($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null").",";
3398  $sql .= " import_key=".(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null")."";
3399 
3400  $sql .= " WHERE rowid=".((int) $this->id);
3401 
3402  $this->db->begin();
3403 
3404  dol_syslog(get_class($this)."::update", LOG_DEBUG);
3405  $resql = $this->db->query($sql);
3406  if (!$resql) {
3407  $error++; $this->errors[] = "Error ".$this->db->lasterror();
3408  }
3409 
3410  if (!$error) {
3411  $result = $this->insertExtraFields();
3412  if ($result < 0) {
3413  $error++;
3414  }
3415  }
3416 
3417  if (!$error && !$notrigger) {
3418  // Call trigger
3419  $result = $this->call_trigger('ORDER_MODIFY', $user);
3420  if ($result < 0) {
3421  $error++;
3422  }
3423  // End call triggers
3424  }
3425 
3426  // Commit or rollback
3427  if ($error) {
3428  foreach ($this->errors as $errmsg) {
3429  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
3430  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
3431  }
3432  $this->db->rollback();
3433  return -1 * $error;
3434  } else {
3435  $this->db->commit();
3436  return 1;
3437  }
3438  }
3439 
3447  public function delete($user, $notrigger = 0)
3448  {
3449  global $conf, $langs;
3450  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
3451 
3452  $error = 0;
3453 
3454  dol_syslog(get_class($this)."::delete ".$this->id, LOG_DEBUG);
3455 
3456  $this->db->begin();
3457 
3458  if (!$notrigger) {
3459  // Call trigger
3460  $result = $this->call_trigger('ORDER_DELETE', $user);
3461  if ($result < 0) {
3462  $error++;
3463  }
3464  // End call triggers
3465  }
3466 
3467  // Test we can delete
3468  if ($this->nb_expedition() != 0) {
3469  $this->errors[] = $langs->trans('SomeShipmentExists');
3470  $error++;
3471  }
3472 
3473  // Delete extrafields of lines and lines
3474  if (!$error && !empty($this->table_element_line)) {
3475  $tabletodelete = $this->table_element_line;
3476  $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).")";
3477  $sql = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".((int) $this->id);
3478  if (!$this->db->query($sqlef) || !$this->db->query($sql)) {
3479  $error++;
3480  $this->error = $this->db->lasterror();
3481  $this->errors[] = $this->error;
3482  dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
3483  }
3484  }
3485 
3486  if (!$error) {
3487  // Delete linked object
3488  $res = $this->deleteObjectLinked();
3489  if ($res < 0) {
3490  $error++;
3491  }
3492  }
3493 
3494  if (!$error) {
3495  // Delete linked contacts
3496  $res = $this->delete_linked_contact();
3497  if ($res < 0) {
3498  $error++;
3499  }
3500  }
3501 
3502  // Removed extrafields of object
3503  if (!$error) {
3504  $result = $this->deleteExtraFields();
3505  if ($result < 0) {
3506  $error++;
3507  dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
3508  }
3509  }
3510 
3511  // Delete main record
3512  if (!$error) {
3513  $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element." WHERE rowid = ".((int) $this->id);
3514  $res = $this->db->query($sql);
3515  if (!$res) {
3516  $error++;
3517  $this->error = $this->db->lasterror();
3518  $this->errors[] = $this->error;
3519  dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
3520  }
3521  }
3522 
3523  // Delete record into ECM index and physically
3524  if (!$error) {
3525  $res = $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive
3526  if (!$res) {
3527  $error++;
3528  }
3529  }
3530 
3531  if (!$error) {
3532  // We remove directory
3533  $ref = dol_sanitizeFileName($this->ref);
3534  if ($conf->commande->multidir_output[$this->entity] && !empty($this->ref)) {
3535  $dir = $conf->commande->multidir_output[$this->entity]."/".$ref;
3536  $file = $dir."/".$ref.".pdf";
3537  if (file_exists($file)) {
3538  dol_delete_preview($this);
3539 
3540  if (!dol_delete_file($file, 0, 0, 0, $this)) {
3541  $this->error = 'ErrorFailToDeleteFile';
3542  $this->errors[] = $this->error;
3543  $this->db->rollback();
3544  return 0;
3545  }
3546  }
3547  if (file_exists($dir)) {
3548  $res = @dol_delete_dir_recursive($dir);
3549  if (!$res) {
3550  $this->error = 'ErrorFailToDeleteDir';
3551  $this->errors[] = $this->error;
3552  $this->db->rollback();
3553  return 0;
3554  }
3555  }
3556  }
3557  }
3558 
3559  if (!$error) {
3560  dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
3561  $this->db->commit();
3562  return 1;
3563  } else {
3564  $this->db->rollback();
3565  return -1;
3566  }
3567  }
3568 
3569 
3570  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3577  public function load_board($user)
3578  {
3579  // phpcs:enable
3580  global $conf, $langs;
3581 
3582  $clause = " WHERE";
3583 
3584  $sql = "SELECT c.rowid, c.date_creation as datec, c.date_commande, c.date_livraison as delivery_date, c.fk_statut, c.total_ht";
3585  $sql .= " FROM ".MAIN_DB_PREFIX."commande as c";
3586  if (empty($user->rights->societe->client->voir) && !$user->socid) {
3587  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON c.fk_soc = sc.fk_soc";
3588  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
3589  $clause = " AND";
3590  }
3591  $sql .= $clause." c.entity IN (".getEntity('commande').")";
3592  //$sql.= " AND c.fk_statut IN (1,2,3) AND c.facture = 0";
3593  $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
3594  if ($user->socid) {
3595  $sql .= " AND c.fk_soc = ".((int) $user->socid);
3596  }
3597 
3598  $resql = $this->db->query($sql);
3599  if ($resql) {
3600  $response = new WorkboardResponse();
3601  $response->warning_delay = $conf->commande->client->warning_delay / 60 / 60 / 24;
3602  $response->label = $langs->trans("OrdersToProcess");
3603  $response->labelShort = $langs->trans("Opened");
3604  $response->url = DOL_URL_ROOT.'/commande/list.php?search_status=-3&mainmenu=commercial&leftmenu=orders';
3605  $response->img = img_object('', "order");
3606 
3607  $generic_commande = new Commande($this->db);
3608 
3609  while ($obj = $this->db->fetch_object($resql)) {
3610  $response->nbtodo++;
3611  $response->total += $obj->total_ht;
3612 
3613  $generic_commande->statut = $obj->fk_statut;
3614  $generic_commande->date_commande = $this->db->jdate($obj->date_commande);
3615  $generic_commande->date = $this->db->jdate($obj->date_commande);
3616  $generic_commande->date_livraison = $this->db->jdate($obj->delivery_date);
3617  $generic_commande->delivery_date = $this->db->jdate($obj->delivery_date);
3618 
3619  if ($generic_commande->hasDelay()) {
3620  $response->nbtodolate++;
3621  }
3622  }
3623 
3624  return $response;
3625  } else {
3626  $this->error = $this->db->error();
3627  return -1;
3628  }
3629  }
3630 
3636  public function getLabelSource()
3637  {
3638  global $langs;
3639 
3640  $label = $langs->trans('OrderSource'.$this->source);
3641 
3642  if ($label == 'OrderSource') {
3643  return '';
3644  }
3645  return $label;
3646  }
3647 
3654  public function getLibStatut($mode)
3655  {
3656  return $this->LibStatut($this->statut, $this->billed, $mode);
3657  }
3658 
3659  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3669  public function LibStatut($status, $billed, $mode, $donotshowbilled = 0)
3670  {
3671  // phpcs:enable
3672  global $langs, $conf;
3673 
3674  $billedtext = '';
3675  if (empty($donotshowbilled)) {
3676  $billedtext .= ($billed ? ' - '.$langs->transnoentitiesnoconv("Billed") : '');
3677  }
3678 
3679  $labelTooltip = '';
3680 
3681  if ($status == self::STATUS_CANCELED) {
3682  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderCanceled');
3683  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderCanceledShort');
3684  $statusType = 'status9';
3685  } elseif ($status == self::STATUS_DRAFT) {
3686  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderDraft');
3687  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderDraftShort');
3688  $statusType = 'status0';
3689  } elseif ($status == self::STATUS_VALIDATED) {
3690  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderValidated').$billedtext;
3691  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderValidatedShort').$billedtext;
3692  $statusType = 'status1';
3693  } elseif ($status == self::STATUS_SHIPMENTONPROCESS) {
3694  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderSent').$billedtext;
3695  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderSentShort').$billedtext;
3696  $labelTooltip = $langs->transnoentitiesnoconv("StatusOrderSent").' - '.$langs->transnoentitiesnoconv("DateDeliveryPlanned").dol_print_date($this->date_livraison).$billedtext;
3697  $statusType = 'status4';
3698  } elseif ($status == self::STATUS_CLOSED && (!$billed && empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) {
3699  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderToBill');
3700  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderToBillShort');
3701  $statusType = 'status4';
3702  } elseif ($status == self::STATUS_CLOSED && ($billed && empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) {
3703  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderProcessed').$billedtext;
3704  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderProcessedShort').$billedtext;
3705  $statusType = 'status6';
3706  } elseif ($status == self::STATUS_CLOSED && (!empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) {
3707  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderDelivered');
3708  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderDeliveredShort');
3709  $statusType = 'status6';
3710  } else {
3711  $labelStatus = $langs->transnoentitiesnoconv('Unknown');
3712  $labelStatusShort = '';
3713  $statusType = '';
3714  $mode = 0;
3715  }
3716 
3717  return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode, '', array('tooltip' => $labelTooltip));
3718  }
3719 
3720 
3734  public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0, $target = '')
3735  {
3736  global $conf, $langs, $user, $hookmanager;
3737 
3738  if (!empty($conf->dol_no_mouse_hover)) {
3739  $notooltip = 1; // Force disable tooltips
3740  }
3741 
3742  $result = '';
3743 
3744  if (!empty($conf->expedition->enabled) && ($option == '1' || $option == '2')) {
3745  $url = DOL_URL_ROOT.'/expedition/shipment.php?id='.$this->id;
3746  } else {
3747  $url = DOL_URL_ROOT.'/commande/card.php?id='.$this->id;
3748  }
3749 
3750  if (!$user->rights->commande->lire) {
3751  $option = 'nolink';
3752  }
3753 
3754  if ($option !== 'nolink') {
3755  // Add param to save lastsearch_values or not
3756  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
3757  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
3758  $add_save_lastsearch_values = 1;
3759  }
3760  if ($add_save_lastsearch_values) {
3761  $url .= '&save_lastsearch_values=1';
3762  }
3763  }
3764 
3765  if ($short) {
3766  return $url;
3767  }
3768 
3769  $label = '';
3770 
3771  if ($user->rights->commande->lire) {
3772  $label = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("Order").'</u>';
3773  if (isset($this->statut)) {
3774  $label .= ' '.$this->getLibStatut(5);
3775  }
3776  $label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
3777  $label .= '<br><b>'.$langs->trans('RefCustomer').':</b> '.(empty($this->ref_customer) ? (empty($this->ref_client) ? '' : $this->ref_client) : $this->ref_customer);
3778  if (!empty($this->total_ht)) {
3779  $label .= '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
3780  }
3781  if (!empty($this->total_tva)) {
3782  $label .= '<br><b>'.$langs->trans('VAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
3783  }
3784  if (!empty($this->total_ttc)) {
3785  $label .= '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
3786  }
3787  if (!empty($this->date)) {
3788  $label .= '<br><b>'.$langs->trans('Date').':</b> '.dol_print_date($this->date, 'day');
3789  }
3790  if (!empty($this->delivery_date)) {
3791  $label .= '<br><b>'.$langs->trans('DeliveryDate').':</b> '.dol_print_date($this->delivery_date, 'dayhour');
3792  }
3793  }
3794 
3795  $linkclose = '';
3796  if (empty($notooltip) && $user->rights->commande->lire) {
3797  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
3798  $label = $langs->trans("Order");
3799  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
3800  }
3801  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
3802  $linkclose .= ' class="classfortooltip"';
3803 
3804  $target_value=array('_self', '_blank', '_parent', '_top');
3805  if (in_array($target, $target_value)) {
3806  $linkclose .= ' target="'.dol_escape_htmltag($target).'"';
3807  }
3808  }
3809 
3810  $linkstart = '<a href="'.$url.'"';
3811  $linkstart .= $linkclose.'>';
3812  $linkend = '</a>';
3813 
3814  if ($option === 'nolink') {
3815  $linkstart = '';
3816  $linkend = '';
3817  }
3818 
3819  $result .= $linkstart;
3820  if ($withpicto) {
3821  $result .= img_object(($notooltip ? '' : $label), $this->picto, ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
3822  }
3823  if ($withpicto != 2) {
3824  $result .= $this->ref;
3825  }
3826  $result .= $linkend;
3827 
3828  if ($addlinktonotes) {
3829  $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
3830  if ($txttoshow) {
3831  $notetoshow = $langs->trans("ViewPrivateNote").':<br>'.dol_string_nohtmltag($txttoshow, 1);
3832  $result .= ' <span class="note inline-block">';
3833  $result .= '<a href="'.DOL_URL_ROOT.'/commande/note.php?id='.$this->id.'" class="classfortooltip" title="'.dol_escape_htmltag($notetoshow).'">';
3834  $result .= img_picto('', 'note');
3835  $result .= '</a>';
3836  //$result.=img_picto($langs->trans("ViewNote"),'object_generic');
3837  //$result.='</a>';
3838  $result .= '</span>';
3839  }
3840  }
3841 
3842  global $action;
3843  $hookmanager->initHooks(array($this->element . 'dao'));
3844  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
3845  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3846  if ($reshook > 0) {
3847  $result = $hookmanager->resPrint;
3848  } else {
3849  $result .= $hookmanager->resPrint;
3850  }
3851  return $result;
3852  }
3853 
3854 
3861  public function info($id)
3862  {
3863  $sql = 'SELECT c.rowid, date_creation as datec, tms as datem,';
3864  $sql .= ' date_valid as datev,';
3865  $sql .= ' date_cloture as datecloture,';
3866  $sql .= ' fk_user_author, fk_user_valid, fk_user_cloture';
3867  $sql .= ' FROM '.MAIN_DB_PREFIX.'commande as c';
3868  $sql .= ' WHERE c.rowid = '.((int) $id);
3869  $result = $this->db->query($sql);
3870  if ($result) {
3871  if ($this->db->num_rows($result)) {
3872  $obj = $this->db->fetch_object($result);
3873  $this->id = $obj->rowid;
3874  if ($obj->fk_user_author) {
3875  $this->user_creation_id = $obj->fk_user_author;
3876  }
3877  if ($obj->fk_user_valid) {
3878  $this->user_validation_id = $obj->fk_user_valid;
3879  }
3880  if ($obj->fk_user_cloture) {
3881  $this->user_closing_id = $obj->fk_user_cloture;
3882  }
3883 
3884  $this->date_creation = $this->db->jdate($obj->datec);
3885  $this->date_modification = $this->db->jdate($obj->datem);
3886  $this->date_validation = $this->db->jdate($obj->datev);
3887  $this->date_cloture = $this->db->jdate($obj->datecloture);
3888  }
3889 
3890  $this->db->free($result);
3891  } else {
3892  dol_print_error($this->db);
3893  }
3894  }
3895 
3896 
3904  public function initAsSpecimen()
3905  {
3906  global $conf, $langs;
3907 
3908  dol_syslog(get_class($this)."::initAsSpecimen");
3909 
3910  // Load array of products prodids
3911  $num_prods = 0;
3912  $prodids = array();
3913  $sql = "SELECT rowid";
3914  $sql .= " FROM ".MAIN_DB_PREFIX."product";
3915  $sql .= " WHERE entity IN (".getEntity('product').")";
3916  $sql .= $this->db->plimit(100);
3917 
3918  $resql = $this->db->query($sql);
3919  if ($resql) {
3920  $num_prods = $this->db->num_rows($resql);
3921  $i = 0;
3922  while ($i < $num_prods) {
3923  $i++;
3924  $row = $this->db->fetch_row($resql);
3925  $prodids[$i] = $row[0];
3926  }
3927  }
3928 
3929  // Initialise parametres
3930  $this->id = 0;
3931  $this->ref = 'SPECIMEN';
3932  $this->specimen = 1;
3933  $this->socid = 1;
3934  $this->date = time();
3935  $this->date_lim_reglement = $this->date + 3600 * 24 * 30;
3936  $this->cond_reglement_code = 'RECEP';
3937  $this->mode_reglement_code = 'CHQ';
3938  $this->availability_code = 'DSP';
3939  $this->demand_reason_code = 'SRC_00';
3940 
3941  $this->note_public = 'This is a comment (public)';
3942  $this->note_private = 'This is a comment (private)';
3943 
3944  $this->multicurrency_tx = 1;
3945  $this->multicurrency_code = $conf->currency;
3946 
3947  // Lines
3948  $nbp = 5;
3949  $xnbp = 0;
3950  while ($xnbp < $nbp) {
3951  $line = new OrderLine($this->db);
3952 
3953  $line->desc = $langs->trans("Description")." ".$xnbp;
3954  $line->qty = 1;
3955  $line->subprice = 100;
3956  $line->price = 100;
3957  $line->tva_tx = 20;
3958  if ($xnbp == 2) {
3959  $line->total_ht = 50;
3960  $line->total_ttc = 60;
3961  $line->total_tva = 10;
3962  $line->remise_percent = 50;
3963  } else {
3964  $line->total_ht = 100;
3965  $line->total_ttc = 120;
3966  $line->total_tva = 20;
3967  $line->remise_percent = 0;
3968  }
3969  if ($num_prods > 0) {
3970  $prodid = mt_rand(1, $num_prods);
3971  $line->fk_product = $prodids[$prodid];
3972  $line->product_ref = 'SPECIMEN';
3973  }
3974 
3975  $this->lines[$xnbp] = $line;
3976 
3977  $this->total_ht += $line->total_ht;
3978  $this->total_tva += $line->total_tva;
3979  $this->total_ttc += $line->total_ttc;
3980 
3981  $xnbp++;
3982  }
3983  }
3984 
3985 
3986  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3992  public function load_state_board()
3993  {
3994  // phpcs:enable
3995  global $user;
3996 
3997  $this->nb = array();
3998  $clause = "WHERE";
3999 
4000  $sql = "SELECT count(co.rowid) as nb";
4001  $sql .= " FROM ".MAIN_DB_PREFIX."commande as co";
4002  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON co.fk_soc = s.rowid";
4003  if (empty($user->rights->societe->client->voir) && !$user->socid) {
4004  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
4005  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
4006  $clause = "AND";
4007  }
4008  $sql .= " ".$clause." co.entity IN (".getEntity('commande').")";
4009 
4010  $resql = $this->db->query($sql);
4011  if ($resql) {
4012  while ($obj = $this->db->fetch_object($resql)) {
4013  $this->nb["orders"] = $obj->nb;
4014  }
4015  $this->db->free($resql);
4016  return 1;
4017  } else {
4018  dol_print_error($this->db);
4019  $this->error = $this->db->error();
4020  return -1;
4021  }
4022  }
4023 
4029  public function getLinesArray()
4030  {
4031  return $this->fetch_lines();
4032  }
4033 
4045  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
4046  {
4047  global $conf, $langs;
4048 
4049  $langs->load("orders");
4050  $outputlangs->load("products");
4051 
4052  if (!dol_strlen($modele)) {
4053  $modele = 'einstein';
4054 
4055  if (!empty($this->model_pdf)) {
4056  $modele = $this->model_pdf;
4057  } elseif (!empty($this->modelpdf)) { // deprecated
4058  $modele = $this->modelpdf;
4059  } elseif (!empty($conf->global->COMMANDE_ADDON_PDF)) {
4060  $modele = $conf->global->COMMANDE_ADDON_PDF;
4061  }
4062  }
4063 
4064  $modelpath = "core/modules/commande/doc/";
4065 
4066  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
4067  }
4068 
4069 
4078  public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
4079  {
4080  $tables = array(
4081  'commande'
4082  );
4083 
4084  return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
4085  }
4086 
4095  public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
4096  {
4097  $tables = array(
4098  'commandedet',
4099  );
4100 
4101  return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
4102  }
4103 
4109  public function hasDelay()
4110  {
4111  global $conf;
4112 
4113  if (!($this->statut > Commande::STATUS_DRAFT && $this->statut < Commande::STATUS_CLOSED)) {
4114  return false; // Never late if not inside this status range
4115  }
4116 
4117  $now = dol_now();
4118 
4119  return max($this->date, $this->date_livraison) < ($now - $conf->commande->client->warning_delay);
4120  }
4121 
4127  public function showDelay()
4128  {
4129  global $conf, $langs;
4130 
4131  if (empty($this->date_livraison)) {
4132  $text = $langs->trans("OrderDate").' '.dol_print_date($this->date_commande, 'day');
4133  } else {
4134  $text = $text = $langs->trans("DeliveryDate").' '.dol_print_date($this->date_livraison, 'day');
4135  }
4136  $text .= ' '.($conf->commande->client->warning_delay > 0 ? '+' : '-').' '.round(abs($conf->commande->client->warning_delay) / 3600 / 24, 1).' '.$langs->trans("days").' < '.$langs->trans("Today");
4137 
4138  return $text;
4139  }
4140 }
4141 
4142 
4147 {
4151  public $element = 'commandedet';
4152 
4153  public $table_element = 'commandedet';
4154 
4155  public $oldline;
4156 
4161  public $fk_commande;
4162 
4169  public $commande_id;
4170 
4171  public $fk_parent_line;
4172 
4176  public $fk_facture;
4177 
4181  public $ref_ext;
4182 
4183  public $fk_remise_except;
4184 
4188  public $rang = 0;
4189  public $fk_fournprice;
4190 
4195  public $pa_ht;
4196  public $marge_tx;
4197  public $marque_tx;
4198 
4203  public $remise;
4204 
4205  // Start and end date of the line
4206  public $date_start;
4207  public $date_end;
4208 
4209  public $skip_update_total; // Skip update price total for special lines
4210 
4211 
4217  public function __construct($db)
4218  {
4219  $this->db = $db;
4220  }
4221 
4228  public function fetch($rowid)
4229  {
4230  $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,';
4231  $sql .= ' cd.remise, cd.remise_percent, cd.fk_remise_except, cd.subprice, cd.ref_ext,';
4232  $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,';
4233  $sql .= ' cd.fk_unit,';
4234  $sql .= ' cd.fk_multicurrency, cd.multicurrency_code, cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc,';
4235  $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc, p.tobatch as product_tobatch,';
4236  $sql .= ' cd.date_start, cd.date_end, cd.vat_src_code';
4237  $sql .= ' FROM '.MAIN_DB_PREFIX.'commandedet as cd';
4238  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON cd.fk_product = p.rowid';
4239  $sql .= ' WHERE cd.rowid = '.((int) $rowid);
4240  $result = $this->db->query($sql);
4241  if ($result) {
4242  $objp = $this->db->fetch_object($result);
4243  $this->rowid = $objp->rowid;
4244  $this->id = $objp->rowid;
4245  $this->fk_commande = $objp->fk_commande;
4246  $this->fk_parent_line = $objp->fk_parent_line;
4247  $this->label = $objp->custom_label;
4248  $this->desc = $objp->description;
4249  $this->qty = $objp->qty;
4250  $this->price = $objp->price;
4251  $this->subprice = $objp->subprice;
4252  $this->ref_ext = $objp->ref_ext;
4253  $this->vat_src_code = $objp->vat_src_code;
4254  $this->tva_tx = $objp->tva_tx;
4255  $this->localtax1_tx = $objp->localtax1_tx;
4256  $this->localtax2_tx = $objp->localtax2_tx;
4257  $this->remise = $objp->remise;
4258  $this->remise_percent = $objp->remise_percent;
4259  $this->fk_remise_except = $objp->fk_remise_except;
4260  $this->fk_product = $objp->fk_product;
4261  $this->product_type = $objp->product_type;
4262  $this->info_bits = $objp->info_bits;
4263  $this->special_code = $objp->special_code;
4264  $this->total_ht = $objp->total_ht;
4265  $this->total_tva = $objp->total_tva;
4266  $this->total_localtax1 = $objp->total_localtax1;
4267  $this->total_localtax2 = $objp->total_localtax2;
4268  $this->total_ttc = $objp->total_ttc;
4269  $this->fk_fournprice = $objp->fk_fournprice;
4270  $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $this->fk_fournprice, $objp->pa_ht);
4271  $this->pa_ht = $marginInfos[0];
4272  $this->marge_tx = $marginInfos[1];
4273  $this->marque_tx = $marginInfos[2];
4274  $this->special_code = $objp->special_code;
4275  $this->rang = $objp->rang;
4276 
4277  $this->ref = $objp->product_ref; // deprecated
4278 
4279  $this->product_ref = $objp->product_ref;
4280  $this->product_label = $objp->product_label;
4281  $this->product_desc = $objp->product_desc;
4282  $this->product_tobatch = $objp->product_tobatch;
4283  $this->fk_unit = $objp->fk_unit;
4284 
4285  $this->date_start = $this->db->jdate($objp->date_start);
4286  $this->date_end = $this->db->jdate($objp->date_end);
4287 
4288  $this->fk_multicurrency = $objp->fk_multicurrency;
4289  $this->multicurrency_code = $objp->multicurrency_code;
4290  $this->multicurrency_subprice = $objp->multicurrency_subprice;
4291  $this->multicurrency_total_ht = $objp->multicurrency_total_ht;
4292  $this->multicurrency_total_tva = $objp->multicurrency_total_tva;
4293  $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
4294 
4295  $this->db->free($result);
4296 
4297  return 1;
4298  } else {
4299  $this->error = $this->db->lasterror();
4300  return -1;
4301  }
4302  }
4303 
4311  public function delete(User $user, $notrigger = 0)
4312  {
4313  global $conf, $langs;
4314 
4315  $error = 0;
4316 
4317  if (empty($this->id) && !empty($this->rowid)) { // For backward compatibility
4318  $this->id = $this->rowid;
4319  }
4320 
4321  // check if order line is not in a shipment line before deleting
4322  $sqlCheckShipmentLine = "SELECT";
4323  $sqlCheckShipmentLine .= " ed.rowid";
4324  $sqlCheckShipmentLine .= " FROM ".MAIN_DB_PREFIX."expeditiondet ed";
4325  $sqlCheckShipmentLine .= " WHERE ed.fk_origin_line = ".((int) $this->id);
4326 
4327  $resqlCheckShipmentLine = $this->db->query($sqlCheckShipmentLine);
4328  if (!$resqlCheckShipmentLine) {
4329  $error++;
4330  $this->error = $this->db->lasterror();
4331  $this->errors[] = $this->error;
4332  } else {
4333  $langs->load('errors');
4334  $num = $this->db->num_rows($resqlCheckShipmentLine);
4335  if ($num > 0) {
4336  $error++;
4337  $objCheckShipmentLine = $this->db->fetch_object($resqlCheckShipmentLine);
4338  $this->error = $langs->trans('ErrorRecordAlreadyExists').' : '.$langs->trans('ShipmentLine').' '.$objCheckShipmentLine->rowid;
4339  $this->errors[] = $this->error;
4340  }
4341  $this->db->free($resqlCheckShipmentLine);
4342  }
4343  if ($error) {
4344  dol_syslog(__METHOD__.'Error ; '.$this->error, LOG_ERR);
4345  return -1;
4346  }
4347 
4348  $this->db->begin();
4349 
4350  $sql = 'DELETE FROM '.MAIN_DB_PREFIX."commandedet WHERE rowid = ".((int) $this->id);
4351 
4352  dol_syslog("OrderLine::delete", LOG_DEBUG);
4353  $resql = $this->db->query($sql);
4354  if ($resql) {
4355  // Remove extrafields
4356  if (!$error) {
4357  $this->id = $this->rowid;
4358  $result = $this->deleteExtraFields();
4359  if ($result < 0) {
4360  $error++;
4361  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
4362  }
4363  }
4364 
4365  if (!$error && !$notrigger) {
4366  // Call trigger
4367  $result = $this->call_trigger('LINEORDER_DELETE', $user);
4368  if ($result < 0) {
4369  $error++;
4370  }
4371  // End call triggers
4372  }
4373 
4374  if (!$error) {
4375  $this->db->commit();
4376  return 1;
4377  }
4378 
4379  foreach ($this->errors as $errmsg) {
4380  dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
4381  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
4382  }
4383  $this->db->rollback();
4384  return -1 * $error;
4385  } else {
4386  $this->error = $this->db->lasterror();
4387  return -1;
4388  }
4389  }
4390 
4398  public function insert($user = null, $notrigger = 0)
4399  {
4400  global $langs, $conf;
4401 
4402  $error = 0;
4403 
4404  $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'.
4405 
4406  dol_syslog(get_class($this)."::insert rang=".$this->rang);
4407 
4408  // Clean parameters
4409  if (empty($this->tva_tx)) {
4410  $this->tva_tx = 0;
4411  }
4412  if (empty($this->localtax1_tx)) {
4413  $this->localtax1_tx = 0;
4414  }
4415  if (empty($this->localtax2_tx)) {
4416  $this->localtax2_tx = 0;
4417  }
4418  if (empty($this->localtax1_type)) {
4419  $this->localtax1_type = 0;
4420  }
4421  if (empty($this->localtax2_type)) {
4422  $this->localtax2_type = 0;
4423  }
4424  if (empty($this->total_localtax1)) {
4425  $this->total_localtax1 = 0;
4426  }
4427  if (empty($this->total_localtax2)) {
4428  $this->total_localtax2 = 0;
4429  }
4430  if (empty($this->rang)) {
4431  $this->rang = 0;
4432  }
4433  if (empty($this->remise_percent)) {
4434  $this->remise_percent = 0;
4435  }
4436  if (empty($this->info_bits)) {
4437  $this->info_bits = 0;
4438  }
4439  if (empty($this->special_code)) {
4440  $this->special_code = 0;
4441  }
4442  if (empty($this->fk_parent_line)) {
4443  $this->fk_parent_line = 0;
4444  }
4445  if (empty($this->pa_ht)) {
4446  $this->pa_ht = 0;
4447  }
4448  if (empty($this->ref_ext)) {
4449  $this->ref_ext = '';
4450  }
4451 
4452  // if buy price not defined, define buyprice as configured in margin admin
4453  if ($this->pa_ht == 0 && $pa_ht_isemptystring) {
4454  $result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product);
4455  if ($result < 0) {
4456  return $result;
4457  } else {
4458  $this->pa_ht = $result;
4459  }
4460  }
4461 
4462  // Check parameters
4463  if ($this->product_type < 0) {
4464  return -1;
4465  }
4466 
4467  $this->db->begin();
4468 
4469  // Insertion dans base de la ligne
4470  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'commandedet';
4471  $sql .= ' (fk_commande, fk_parent_line, label, description, qty, ref_ext,';
4472  $sql .= ' vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
4473  $sql .= ' fk_product, product_type, remise_percent, subprice, price, fk_remise_except,';
4474  $sql .= ' special_code, rang, fk_product_fournisseur_price, buy_price_ht,';
4475  $sql .= ' info_bits, total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, date_start, date_end,';
4476  $sql .= ' fk_unit';
4477  $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
4478  $sql .= ')';
4479  $sql .= " VALUES (".$this->fk_commande.",";
4480  $sql .= " ".($this->fk_parent_line > 0 ? "'".$this->db->escape($this->fk_parent_line)."'" : "null").",";
4481  $sql .= " ".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
4482  $sql .= " '".$this->db->escape($this->desc)."',";
4483  $sql .= " '".price2num($this->qty)."',";
4484  $sql .= " '".$this->db->escape($this->ref_ext)."',";
4485  $sql .= " ".(empty($this->vat_src_code) ? "''" : "'".$this->db->escape($this->vat_src_code)."'").",";
4486  $sql .= " '".price2num($this->tva_tx)."',";
4487  $sql .= " '".price2num($this->localtax1_tx)."',";
4488  $sql .= " '".price2num($this->localtax2_tx)."',";
4489  $sql .= " '".$this->db->escape($this->localtax1_type)."',";
4490  $sql .= " '".$this->db->escape($this->localtax2_type)."',";
4491  $sql .= ' '.((!empty($this->fk_product) && $this->fk_product > 0) ? $this->fk_product : "null").',';
4492  $sql .= " '".$this->db->escape($this->product_type)."',";
4493  $sql .= " '".price2num($this->remise_percent)."',";
4494  $sql .= " ".(price2num($this->subprice) !== '' ?price2num($this->subprice) : "null").",";
4495  $sql .= " ".($this->price != '' ? "'".price2num($this->price)."'" : "null").",";
4496  $sql .= ' '.(!empty($this->fk_remise_except) ? $this->fk_remise_except : "null").',';
4497  $sql .= ' '.((int) $this->special_code).',';
4498  $sql .= ' '.((int) $this->rang).',';
4499  $sql .= ' '.(!empty($this->fk_fournprice) ? $this->fk_fournprice : "null").',';
4500  $sql .= ' '.price2num($this->pa_ht).',';
4501  $sql .= " ".((int) $this->info_bits).",";
4502  $sql .= " ".price2num($this->total_ht, 'MT').",";
4503  $sql .= " ".price2num($this->total_tva, 'MT').",";
4504  $sql .= " ".price2num($this->total_localtax1, 'MT').",";
4505  $sql .= " ".price2num($this->total_localtax2, 'MT').",";
4506  $sql .= " ".price2num($this->total_ttc, 'MT').",";
4507  $sql .= " ".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null").',';
4508  $sql .= " ".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null").',';
4509  $sql .= ' '.(!$this->fk_unit ? 'NULL' : ((int) $this->fk_unit));
4510  $sql .= ", ".(!empty($this->fk_multicurrency) ? ((int) $this->fk_multicurrency) : 'NULL');
4511  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
4512  $sql .= ", ".price2num($this->multicurrency_subprice, 'CU');
4513  $sql .= ", ".price2num($this->multicurrency_total_ht, 'CT');
4514  $sql .= ", ".price2num($this->multicurrency_total_tva, 'CT');
4515  $sql .= ", ".price2num($this->multicurrency_total_ttc, 'CT');
4516  $sql .= ')';
4517 
4518  dol_syslog(get_class($this)."::insert", LOG_DEBUG);
4519  $resql = $this->db->query($sql);
4520  if ($resql) {
4521  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'commandedet');
4522  $this->rowid = $this->id;
4523 
4524  if (!$error) {
4525  $result = $this->insertExtraFields();
4526  if ($result < 0) {
4527  $error++;
4528  }
4529  }
4530 
4531  if (!$error && !$notrigger) {
4532  // Call trigger
4533  $result = $this->call_trigger('LINEORDER_INSERT', $user);
4534  if ($result < 0) {
4535  $error++;
4536  }
4537  // End call triggers
4538  }
4539 
4540  if (!$error) {
4541  $this->db->commit();
4542  return 1;
4543  }
4544 
4545  foreach ($this->errors as $errmsg) {
4546  dol_syslog(get_class($this)."::insert ".$errmsg, LOG_ERR);
4547  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
4548  }
4549  $this->db->rollback();
4550  return -1 * $error;
4551  } else {
4552  $this->error = $this->db->error();
4553  $this->db->rollback();
4554  return -2;
4555  }
4556  }
4557 
4565  public function update(User $user, $notrigger = 0)
4566  {
4567  global $conf, $langs;
4568 
4569  $error = 0;
4570 
4571  $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'.
4572 
4573  // Clean parameters
4574  if (empty($this->tva_tx)) {
4575  $this->tva_tx = 0;
4576  }
4577  if (empty($this->localtax1_tx)) {
4578  $this->localtax1_tx = 0;
4579  }
4580  if (empty($this->localtax2_tx)) {
4581  $this->localtax2_tx = 0;
4582  }
4583  if (empty($this->localtax1_type)) {
4584  $this->localtax1_type = 0;
4585  }
4586  if (empty($this->localtax2_type)) {
4587  $this->localtax2_type = 0;
4588  }
4589  if (empty($this->qty)) {
4590  $this->qty = 0;
4591  }
4592  if (empty($this->total_localtax1)) {
4593  $this->total_localtax1 = 0;
4594  }
4595  if (empty($this->total_localtax2)) {
4596  $this->total_localtax2 = 0;
4597  }
4598  if (empty($this->marque_tx)) {
4599  $this->marque_tx = 0;
4600  }
4601  if (empty($this->marge_tx)) {
4602  $this->marge_tx = 0;
4603  }
4604  if (empty($this->remise_percent)) {
4605  $this->remise_percent = 0;
4606  }
4607  if (empty($this->remise)) {
4608  $this->remise = 0;
4609  }
4610  if (empty($this->info_bits)) {
4611  $this->info_bits = 0;
4612  }
4613  if (empty($this->special_code)) {
4614  $this->special_code = 0;
4615  }
4616  if (empty($this->product_type)) {
4617  $this->product_type = 0;
4618  }
4619  if (empty($this->fk_parent_line)) {
4620  $this->fk_parent_line = 0;
4621  }
4622  if (empty($this->pa_ht)) {
4623  $this->pa_ht = 0;
4624  }
4625  if (empty($this->ref_ext)) {
4626  $this->ref_ext = '';
4627  }
4628 
4629  // if buy price not defined, define buyprice as configured in margin admin
4630  if ($this->pa_ht == 0 && $pa_ht_isemptystring) {
4631  $result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product);
4632  if ($result < 0) {
4633  return $result;
4634  } else {
4635  $this->pa_ht = $result;
4636  }
4637  }
4638 
4639  $this->db->begin();
4640 
4641  // Mise a jour ligne en base
4642  $sql = "UPDATE ".MAIN_DB_PREFIX."commandedet SET";
4643  $sql .= " description='".$this->db->escape($this->desc)."'";
4644  $sql .= " , label=".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null");
4645  $sql .= " , vat_src_code=".(!empty($this->vat_src_code) ? "'".$this->db->escape($this->vat_src_code)."'" : "''");
4646  $sql .= " , tva_tx=".price2num($this->tva_tx);
4647  $sql .= " , localtax1_tx=".price2num($this->localtax1_tx);
4648  $sql .= " , localtax2_tx=".price2num($this->localtax2_tx);
4649  $sql .= " , localtax1_type='".$this->db->escape($this->localtax1_type)."'";
4650  $sql .= " , localtax2_type='".$this->db->escape($this->localtax2_type)."'";
4651  $sql .= " , qty=".price2num($this->qty);
4652  $sql .= " , ref_ext='".$this->db->escape($this->ref_ext)."'";
4653  $sql .= " , subprice=".price2num($this->subprice)."";
4654  $sql .= " , remise_percent=".price2num($this->remise_percent)."";
4655  $sql .= " , price=".price2num($this->price).""; // TODO A virer
4656  $sql .= " , remise=".price2num($this->remise).""; // TODO A virer
4657  if (empty($this->skip_update_total)) {
4658  $sql .= " , total_ht=".price2num($this->total_ht)."";
4659  $sql .= " , total_tva=".price2num($this->total_tva)."";
4660  $sql .= " , total_ttc=".price2num($this->total_ttc)."";
4661  $sql .= " , total_localtax1=".price2num($this->total_localtax1);
4662  $sql .= " , total_localtax2=".price2num($this->total_localtax2);
4663  }
4664  $sql .= " , fk_product_fournisseur_price=".(!empty($this->fk_fournprice) ? $this->fk_fournprice : "null");
4665  $sql .= " , buy_price_ht='".price2num($this->pa_ht)."'";
4666  $sql .= " , info_bits=".((int) $this->info_bits);
4667  $sql .= " , special_code=".((int) $this->special_code);
4668  $sql .= " , date_start=".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null");
4669  $sql .= " , date_end=".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null");
4670  $sql .= " , product_type=".$this->product_type;
4671  $sql .= " , fk_parent_line=".(!empty($this->fk_parent_line) ? $this->fk_parent_line : "null");
4672  if (!empty($this->rang)) {
4673  $sql .= ", rang=".((int) $this->rang);
4674  }
4675  $sql .= " , fk_unit=".(!$this->fk_unit ? 'NULL' : $this->fk_unit);
4676 
4677  // Multicurrency
4678  $sql .= " , multicurrency_subprice=".price2num($this->multicurrency_subprice)."";
4679  $sql .= " , multicurrency_total_ht=".price2num($this->multicurrency_total_ht)."";
4680  $sql .= " , multicurrency_total_tva=".price2num($this->multicurrency_total_tva)."";
4681  $sql .= " , multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc)."";
4682 
4683  $sql .= " WHERE rowid = ".((int) $this->rowid);
4684 
4685  dol_syslog(get_class($this)."::update", LOG_DEBUG);
4686  $resql = $this->db->query($sql);
4687  if ($resql) {
4688  if (!$error) {
4689  $this->id = $this->rowid;
4690  $result = $this->insertExtraFields();
4691  if ($result < 0) {
4692  $error++;
4693  }
4694  }
4695 
4696  if (!$error && !$notrigger) {
4697  // Call trigger
4698  $result = $this->call_trigger('LINEORDER_MODIFY', $user);
4699  if ($result < 0) {
4700  $error++;
4701  }
4702  // End call triggers
4703  }
4704 
4705  if (!$error) {
4706  $this->db->commit();
4707  return 1;
4708  }
4709 
4710  foreach ($this->errors as $errmsg) {
4711  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
4712  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
4713  }
4714  $this->db->rollback();
4715  return -1 * $error;
4716  } else {
4717  $this->error = $this->db->error();
4718  $this->db->rollback();
4719  return -2;
4720  }
4721  }
4722 
4723  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4730  public function update_total()
4731  {
4732  // phpcs:enable
4733  $this->db->begin();
4734 
4735  // Clean parameters
4736  if (empty($this->total_localtax1)) {
4737  $this->total_localtax1 = 0;
4738  }
4739  if (empty($this->total_localtax2)) {
4740  $this->total_localtax2 = 0;
4741  }
4742 
4743  // Mise a jour ligne en base
4744  $sql = "UPDATE ".MAIN_DB_PREFIX."commandedet SET";
4745  $sql .= " total_ht='".price2num($this->total_ht)."'";
4746  $sql .= ",total_tva='".price2num($this->total_tva)."'";
4747  $sql .= ",total_localtax1='".price2num($this->total_localtax1)."'";
4748  $sql .= ",total_localtax2='".price2num($this->total_localtax2)."'";
4749  $sql .= ",total_ttc='".price2num($this->total_ttc)."'";
4750  $sql .= " WHERE rowid = ".((int) $this->rowid);
4751 
4752  dol_syslog("OrderLine::update_total", LOG_DEBUG);
4753 
4754  $resql = $this->db->query($sql);
4755  if ($resql) {
4756  $this->db->commit();
4757  return 1;
4758  } else {
4759  $this->error = $this->db->error();
4760  $this->db->rollback();
4761  return -2;
4762  }
4763  }
4764 }
Commande\valid
valid($user, $idwarehouse=0, $notrigger=0)
Validate order.
Definition: commande.class.php:465
Commande\getNextNumRef
getNextNumRef($soc)
Returns the reference to the following non used Order depending on the active numbering module define...
Definition: commande.class.php:415
Societe
Class to manage third parties objects (customers, suppliers, prospects...)
Definition: societe.class.php:48
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:6097
db
$conf db
API class for accounts.
Definition: inc.php:41
OrderLine\$remise
$remise
Definition: commande.class.php:4203
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:1468
Commande\$pos_source
$pos_source
key of pos source ('0', '1', ...)
Definition: commande.class.php:268
Commande\fetch_lines
fetch_lines($only_product=0, $loadalsotranslation=0)
Load array lines.
Definition: commande.class.php:2086
dol_sanitizeFileName
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Definition: functions.lib.php:1226
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:4045
CommonObject\copy_linked_contact
copy_linked_contact($objFrom, $source='internal')
Copy contact from one element to current.
Definition: commonobject.class.php:1217
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:2685
Commande\set_remise
set_remise($user, $remise, $notrigger=0)
Applique une remise relative.
Definition: commande.class.php:2472
Commande\showDelay
showDelay()
Show the customer delayed info.
Definition: commande.class.php:4127
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:1383
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:2366
Commande\load_board
load_board($user)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Definition: commande.class.php:3577
OrderLine\__construct
__construct($db)
Constructor.
Definition: commande.class.php:4217
CommonObject\updateRangOfLine
updateRangOfLine($rowid, $rang)
Update position of line (rang)
Definition: commonobject.class.php:3219
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:4844
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:395
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:1033
Commande\createFromProposal
createFromProposal($object, User $user)
Load an object from a proposal and create a new order into database.
Definition: commande.class.php:1310
dol_buildpath
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
Definition: functions.lib.php:1062
Commande\LibStatut
LibStatut($status, $billed, $mode, $donotshowbilled=0)
Return label of status.
Definition: commande.class.php:3669
Commande\set_date
set_date($user, $date, $notrigger=0)
Set the order date.
Definition: commande.class.php:2612
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:389
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:4228
Commande\set_date_livraison
set_date_livraison($user, $delivery_date, $notrigger=0)
Set delivery date.
Definition: commande.class.php:2671
ref
$object ref
Definition: info.php:77
CommonObject\commonReplaceProduct
static commonReplaceProduct(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a product id with another one.
Definition: commonobject.class.php:8376
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:1504
Commande\nb_expedition
nb_expedition()
Returns a array with expeditions lines number.
Definition: commande.class.php:2337
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
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)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:60
Commande\hasDelay
hasDelay()
Is the customer order delayed?
Definition: commande.class.php:4109
Commande\getNbOfShipments
getNbOfShipments()
Count number of shipments for this order.
Definition: commande.class.php:2249
Commande\STATUS_CANCELED
const STATUS_CANCELED
Canceled status.
Definition: commande.class.php:377
Commande\__construct
__construct($db)
Constructor.
Definition: commande.class.php:403
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:2217
Commande\deleteline
deleteline($user=null, $lineid=0)
Delete an order line.
Definition: commande.class.php:2403
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5661
Commande\insert_discount
insert_discount($idremise)
Adding line of fixed discount in the order in DB.
Definition: commande.class.php:2016
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:2514
Commande\classifyUnBilled
classifyUnBilled(User $user, $notrigger=0)
Classify the order as not invoiced.
Definition: commande.class.php:3052
WorkboardResponse
Definition: workboardresponse.class.php:25
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:3880
Commande\STATUS_VALIDATED
const STATUS_VALIDATED
Validated status.
Definition: commande.class.php:385
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:5406
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:820
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:1231
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:3525
Commande\replaceThirdparty
static replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
Definition: commande.class.php:4078
Commande\fetch
fetch($id, $ref='', $ref_ext='', $notused='')
Get object from database.
Definition: commande.class.php:1846
get_default_npr
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Fonction qui renvoie si tva doit etre tva percue recuperable.
Definition: functions.lib.php:6405
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:2285
getEntity
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
Definition: functions.lib.php:148
OrderLine
Class to manage order lines.
Definition: commande.class.php:4146
Commande\availability
availability($availability_id, $notrigger=0)
Update delivery delay.
Definition: commande.class.php:2815
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:5837
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:6156
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:617
Commande
Class to manage customers orders.
Definition: commande.class.php:46
Commande\getLibStatut
getLibStatut($mode)
Return status label of Order.
Definition: commande.class.php:3654
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:1757
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:1319
Commande\setDiscount
setDiscount($user, $remise, $notrigger=0)
Set a percentage discount.
Definition: commande.class.php:2487
Commande\update
update(User $user, $notrigger=0)
Update database.
Definition: commande.class.php:3340
CommonObject\defineBuyPrice
defineBuyPrice($unitPrice=0.0, $discountPercent=0.0, $fk_product=0)
Get buy price to use for margin calculation.
Definition: commonobject.class.php:8405
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:6694
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:3128
CommonObject\deleteEcmFiles
deleteEcmFiles($mode=0)
Delete related files of object in database.
Definition: commonobject.class.php:9966
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:1108
CommonObject\commonReplaceThirdparty
static commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
Definition: commonobject.class.php:8347
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1603
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:3734
CommonObject\line_max
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
Definition: commonobject.class.php:3373
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:2748
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:6007
Commande\cloture
cloture($user, $notrigger=0)
Close order.
Definition: commande.class.php:760
Commande\set_ref_client
set_ref_client($user, $ref_client, $notrigger=0)
Set customer ref.
Definition: commande.class.php:2943
dol_strlen
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Definition: functions.lib.php:3747
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:6304
Commande\STATUS_DRAFT
const STATUS_DRAFT
Draft status.
Definition: commande.class.php:381
Commande\info
info($id)
Charge les informations d'ordre info dans l'objet commande.
Definition: commande.class.php:3861
Commande\set_remise_absolue
set_remise_absolue($user, $remise, $notrigger=0)
Set a fixed amount discount.
Definition: commande.class.php:2548
OrderLine\insert
insert($user=null, $notrigger=0)
Insert line into database.
Definition: commande.class.php:4398
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:3992
Commande\getLinesArray
getLinesArray()
Create an array of order lines.
Definition: commande.class.php:4029
CommonObject\deleteExtraFields
deleteExtraFields()
Delete all extra fields values for the current object.
Definition: commonobject.class.php:6116
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:372
Commande\create
create($user, $notrigger=0)
Create order Note that this->ref can be set or empty.
Definition: commande.class.php:893
OrderLine\update_total
update_total()
Update DB line fields total_xxx Used by migration.
Definition: commande.class.php:4730
Product
Class to manage products or services.
Definition: product.class.php:46
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:117
dol_delete_preview
dol_delete_preview($object)
Delete all preview files linked to object instance.
Definition: files.lib.php:1435
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:3818
dolGetStatus
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
Definition: functions.lib.php:10338
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:4211
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2845
$resql
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->rights->fournisseur->facture->lire)||(isModEnabled('supplier_invoice') && $user->rights->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->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:742
Commande\getNbOfServicesLines
getNbOfServicesLines()
Return number of line with type service.
Definition: commande.class.php:2233
Commande\demand_reason
demand_reason($demand_reason_id, $notrigger=0)
Update order demand_reason.
Definition: commande.class.php:2878
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:5541
CommonObject\call_trigger
call_trigger($triggerName, $user)
Call trigger based on this instance.
Definition: commonobject.class.php:5791
Commande\createFromClone
createFromClone(User $user, $socid=0)
Load an object from its id and create a new one in database.
Definition: commande.class.php:1199
Commande\$module_source
$module_source
key of module source when order generated from a dedicated module ('cashdesk', 'takepos',...
Definition: commande.class.php:266
Commande\replaceProduct
static replaceProduct(DoliDB $db, $origin_id, $dest_id)
Function used to replace a product id with another one.
Definition: commande.class.php:4095
CommonOrderLine
Superclass for orders classes.
Definition: commonorder.class.php:39
Commande\setDraft
setDraft($user, $idwarehouse=-1)
Set draft status.
Definition: commande.class.php:619
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:3055
OrderLine\fetch
fetch($rowid)
Load line order.
Definition: commande.class.php:4228
Commande\getLabelSource
getLabelSource()
Return source label of order.
Definition: commande.class.php:3636
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:705
Commande\initAsSpecimen
initAsSpecimen()
Initialise an instance with random values.
Definition: commande.class.php:3904
OrderLine\update
update(User $user, $notrigger=0)
Update the line object into db.
Definition: commande.class.php:4565
Commande\classifyBilled
classifyBilled(User $user, $notrigger=0)
Classify the order as invoiced.
Definition: commande.class.php:2998