dolibarr  19.0.0-dev
commande.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2003-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2005-2014 Regis Houssin <regis.houssin@inodbox.com>
5  * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
6  * Copyright (C) 2010-2020 Juanjo Menent <jmenent@2byte.es>
7  * Copyright (C) 2011 Jean Heimburger <jean@tiaris.info>
8  * Copyright (C) 2012-2014 Christophe Battarel <christophe.battarel@altairis.fr>
9  * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
10  * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
11  * Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
12  * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
13  * Copyright (C) 2016-2022 Ferran Marcet <fmarcet@2byte.es>
14  * Copyright (C) 2021-2023 Frédéric France <frederic.france@netlogic.fr>
15  * Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program. If not, see <https://www.gnu.org/licenses/>.
29  */
30 
36 include_once DOL_DOCUMENT_ROOT.'/core/class/commonorder.class.php';
37 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
38 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
39 require_once DOL_DOCUMENT_ROOT.'/margin/lib/margins.lib.php';
40 require_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
41 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
42 
43 
47 class Commande extends CommonOrder
48 {
52  public $element = 'commande';
53 
57  public $table_element = 'commande';
58 
62  public $table_element_line = 'commandedet';
63 
67  public $class_element_line = 'OrderLine';
68 
72  public $fk_element = 'fk_commande';
73 
77  public $picto = 'order';
78 
83  public $ismultientitymanaged = 1;
84 
89  public $restrictiononfksoc = 1;
90 
94  protected $table_ref_field = 'ref';
95 
99  public $socid;
100 
104  public $ref_client;
105 
109  public $ref_customer;
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 $cond_reglement_doc;
141 
145  public $deposit_percent;
146 
150  public $fk_account;
151 
155  public $mode_reglement;
156 
160  public $mode_reglement_id;
161 
165  public $mode_reglement_code;
166 
171  public $availability_id;
172 
177  public $availability_code;
178 
183  public $availability;
184 
188  public $demand_reason_id;
189 
193  public $demand_reason_code;
194 
198  public $date;
199 
205  public $date_commande;
206 
212  public $date_livraison;
213 
217  public $delivery_date;
218 
222  public $fk_remise_except;
223 
228 
229  public $remise_absolue;
230  public $info_bits;
231  public $rang;
232  public $special_code;
233  public $source; // Order mode. How we received order (by phone, by email, ...)
234 
238  public $warehouse_id;
239 
240  public $extraparams = array();
241 
242  public $linked_objects = array();
243 
247  public $user_author_id;
248 
252  public $user_valid;
253 
257  public $line;
258 
262  public $lines = array();
263 
264  // Multicurrency
268  public $fk_multicurrency;
269 
273  public $multicurrency_code;
274  public $multicurrency_tx;
275  public $multicurrency_total_ht;
276  public $multicurrency_total_tva;
277  public $multicurrency_total_ttc;
278 
282  public $pos_source;
283 
287  public $expeditions;
288 
292  public $online_payment_url;
293 
294 
319  // BEGIN MODULEBUILDER PROPERTIES
323  public $fields = array(
324  'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
325  'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>20, 'index'=>1),
326  'ref' =>array('type'=>'varchar(30)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'showoncombobox'=>1, 'position'=>25),
327  'ref_ext' =>array('type'=>'varchar(255)', 'label'=>'RefExt', 'enabled'=>1, 'visible'=>0, 'position'=>26),
328  'ref_client' =>array('type'=>'varchar(255)', 'label'=>'RefCustomer', 'enabled'=>1, 'visible'=>-1, 'position'=>28),
329  'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>'isModEnabled("societe")', 'visible'=>-1, 'notnull'=>1, 'position'=>20),
330  'fk_projet' =>array('type'=>'integer:Project:projet/class/project.class.php:1:(fk_statut:=:1)', 'label'=>'Project', 'enabled'=>"isModEnabled('project')", 'visible'=>-1, 'position'=>25),
331  'date_commande' =>array('type'=>'date', 'label'=>'Date', 'enabled'=>1, 'visible'=>1, 'position'=>60),
332  'date_valid' =>array('type'=>'datetime', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>62),
333  'date_cloture' =>array('type'=>'datetime', 'label'=>'DateClosing', 'enabled'=>1, 'visible'=>-1, 'position'=>65),
334  'fk_user_valid' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>85),
335  'fk_user_cloture' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserClosing', 'enabled'=>1, 'visible'=>-1, 'position'=>90),
336  'source' =>array('type'=>'smallint(6)', 'label'=>'Source', 'enabled'=>1, 'visible'=>-1, 'position'=>95),
337  //'amount_ht' =>array('type'=>'double(24,8)', 'label'=>'AmountHT', 'enabled'=>1, 'visible'=>-1, 'position'=>105),
338  //'remise_percent' =>array('type'=>'double', 'label'=>'RelativeDiscount', 'enabled'=>1, 'visible'=>-1, 'position'=>110),
339  'remise_absolue' =>array('type'=>'double', 'label'=>'CustomerRelativeDiscount', 'enabled'=>1, 'visible'=>-1, 'position'=>115),
340  //'remise' =>array('type'=>'double', 'label'=>'Remise', 'enabled'=>1, 'visible'=>-1, 'position'=>120),
341  'total_tva' =>array('type'=>'double(24,8)', 'label'=>'VAT', 'enabled'=>1, 'visible'=>-1, 'position'=>125, 'isameasure'=>1),
342  'localtax1' =>array('type'=>'double(24,8)', 'label'=>'LocalTax1', 'enabled'=>1, 'visible'=>-1, 'position'=>130, 'isameasure'=>1),
343  'localtax2' =>array('type'=>'double(24,8)', 'label'=>'LocalTax2', 'enabled'=>1, 'visible'=>-1, 'position'=>135, 'isameasure'=>1),
344  'total_ht' =>array('type'=>'double(24,8)', 'label'=>'TotalHT', 'enabled'=>1, 'visible'=>-1, 'position'=>140, 'isameasure'=>1),
345  'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'TotalTTC', 'enabled'=>1, 'visible'=>-1, 'position'=>145, 'isameasure'=>1),
346  'note_private' =>array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>150),
347  'note_public' =>array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>155),
348  'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'PDFTemplate', 'enabled'=>1, 'visible'=>0, 'position'=>160),
349  //'facture' =>array('type'=>'tinyint(4)', 'label'=>'ParentInvoice', 'enabled'=>1, 'visible'=>-1, 'position'=>165),
350  'fk_account' =>array('type'=>'integer', 'label'=>'BankAccount', 'enabled'=>'isModEnabled("banque")', 'visible'=>-1, 'position'=>170),
351  'fk_currency' =>array('type'=>'varchar(3)', 'label'=>'MulticurrencyID', 'enabled'=>1, 'visible'=>-1, 'position'=>175),
352  'fk_cond_reglement' =>array('type'=>'integer', 'label'=>'PaymentTerm', 'enabled'=>1, 'visible'=>-1, 'position'=>180),
353  'deposit_percent' =>array('type'=>'varchar(63)', 'label'=>'DepositPercent', 'enabled'=>1, 'visible'=>-1, 'position'=>181),
354  'fk_mode_reglement' =>array('type'=>'integer', 'label'=>'PaymentMode', 'enabled'=>1, 'visible'=>-1, 'position'=>185),
355  'date_livraison' =>array('type'=>'date', 'label'=>'DateDeliveryPlanned', 'enabled'=>1, 'visible'=>-1, 'position'=>190),
356  'fk_shipping_method' =>array('type'=>'integer', 'label'=>'ShippingMethod', 'enabled'=>1, 'visible'=>-1, 'position'=>195),
357  'fk_warehouse' =>array('type'=>'integer:Entrepot:product/stock/class/entrepot.class.php', 'label'=>'Fk warehouse', 'enabled'=>'isModEnabled("stock")', 'visible'=>-1, 'position'=>200),
358  'fk_availability' =>array('type'=>'integer', 'label'=>'Availability', 'enabled'=>1, 'visible'=>-1, 'position'=>205),
359  'fk_input_reason' =>array('type'=>'integer', 'label'=>'InputReason', 'enabled'=>1, 'visible'=>-1, 'position'=>210),
360  //'fk_delivery_address' =>array('type'=>'integer', 'label'=>'DeliveryAddress', 'enabled'=>1, 'visible'=>-1, 'position'=>215),
361  'extraparams' =>array('type'=>'varchar(255)', 'label'=>'Extraparams', 'enabled'=>1, 'visible'=>-1, 'position'=>225),
362  'fk_incoterms' =>array('type'=>'integer', 'label'=>'IncotermCode', 'enabled'=>'$conf->incoterm->enabled', 'visible'=>-1, 'position'=>230),
363  'location_incoterms' =>array('type'=>'varchar(255)', 'label'=>'IncotermLabel', 'enabled'=>'$conf->incoterm->enabled', 'visible'=>-1, 'position'=>235),
364  'fk_multicurrency' =>array('type'=>'integer', 'label'=>'Fk multicurrency', 'enabled'=>'isModEnabled("multicurrency")', 'visible'=>-1, 'position'=>240),
365  'multicurrency_code' =>array('type'=>'varchar(255)', 'label'=>'MulticurrencyCurrency', 'enabled'=>'isModEnabled("multicurrency")', 'visible'=>-1, 'position'=>245),
366  'multicurrency_tx' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyRate', 'enabled'=>'isModEnabled("multicurrency")', 'visible'=>-1, 'position'=>250, 'isameasure'=>1),
367  'multicurrency_total_ht' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyAmountHT', 'enabled'=>'isModEnabled("multicurrency")', 'visible'=>-1, 'position'=>255, 'isameasure'=>1),
368  'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyAmountVAT', 'enabled'=>'isModEnabled("multicurrency")', 'visible'=>-1, 'position'=>260, 'isameasure'=>1),
369  'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyAmountTTC', 'enabled'=>'isModEnabled("multicurrency")', 'visible'=>-1, 'position'=>265, 'isameasure'=>1),
370  'last_main_doc' =>array('type'=>'varchar(255)', 'label'=>'LastMainDoc', 'enabled'=>1, 'visible'=>-1, 'position'=>270),
371  'module_source' =>array('type'=>'varchar(32)', 'label'=>'POSModule', 'enabled'=>1, 'visible'=>-1, 'position'=>275),
372  'pos_source' =>array('type'=>'varchar(32)', 'label'=>'POSTerminal', 'enabled'=>1, 'visible'=>-1, 'position'=>280),
373  'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-1, 'position'=>300),
374  'fk_user_modif' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>302),
375  'date_creation' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>304),
376  'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>306),
377  'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>400),
378  'fk_statut' =>array('type'=>'smallint(6)', 'label'=>'Status', 'enabled'=>1, 'visible'=>-1, 'position'=>500),
379  );
380  // END MODULEBUILDER PROPERTIES
381 
386 
390  const STATUS_CANCELED = -1;
394  const STATUS_DRAFT = 0;
398  const STATUS_VALIDATED = 1;
403  const STATUS_ACCEPTED = 2; // For backward compatibility. Use key STATUS_SHIPMENTONPROCESS instead.
404 
408  const STATUS_CLOSED = 3;
409 
410 
416  public function __construct($db)
417  {
418  $this->db = $db;
419  }
420 
428  public function getNextNumRef($soc)
429  {
430  global $langs, $conf;
431  $langs->load("order");
432 
433  if (!empty($conf->global->COMMANDE_ADDON)) {
434  $mybool = false;
435 
436  $file = $conf->global->COMMANDE_ADDON.".php";
437  $classname = $conf->global->COMMANDE_ADDON;
438 
439  // Include file with class
440  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
441  foreach ($dirmodels as $reldir) {
442  $dir = dol_buildpath($reldir."core/modules/commande/");
443 
444  // Load file with numbering class (if found)
445  $mybool |= @include_once $dir.$file;
446  }
447 
448  if ($mybool === false) {
449  dol_print_error('', "Failed to include file ".$file);
450  return '';
451  }
452 
453  $obj = new $classname();
454  $numref = $obj->getNextValue($soc, $this);
455 
456  if ($numref != "") {
457  return $numref;
458  } else {
459  $this->error = $obj->error;
460  //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
461  return "";
462  }
463  } else {
464  print $langs->trans("Error")." ".$langs->trans("Error_COMMANDE_ADDON_NotDefined");
465  return "";
466  }
467  }
468 
469 
478  public function valid($user, $idwarehouse = 0, $notrigger = 0)
479  {
480  global $conf, $langs;
481 
482  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
483 
484  $error = 0;
485 
486  // Protection
487  if ($this->statut == self::STATUS_VALIDATED) {
488  dol_syslog(get_class($this)."::valid action abandonned: already validated", LOG_WARNING);
489  return 0;
490  }
491 
492  if (!((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->creer))
493  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->order_advance->validate)))) {
494  $this->error = 'NotEnoughPermissions';
495  dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
496  return -1;
497  }
498 
499  $now = dol_now();
500 
501  $this->db->begin();
502 
503  // Definition du nom de module de numerotation de commande
504  $soc = new Societe($this->db);
505  $soc->fetch($this->socid);
506 
507  // Class of company linked to order
508  $result = $soc->set_as_client();
509 
510  // Define new ref
511  if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
512  $num = $this->getNextNumRef($soc);
513  } else {
514  $num = $this->ref;
515  }
516  $this->newref = dol_sanitizeFileName($num);
517 
518  // Validate
519  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
520  $sql .= " SET ref = '".$this->db->escape($num)."',";
521  $sql .= " fk_statut = ".self::STATUS_VALIDATED.",";
522  $sql .= " date_valid='".$this->db->idate($now)."',";
523  $sql .= " fk_user_valid = ".($user->id > 0 ? (int) $user->id : "null").",";
524  $sql .= " fk_user_modif = ".((int) $user->id);
525  $sql .= " WHERE rowid = ".((int) $this->id);
526 
527  dol_syslog(get_class($this)."::valid", LOG_DEBUG);
528  $resql = $this->db->query($sql);
529  if (!$resql) {
530  dol_print_error($this->db);
531  $this->error = $this->db->lasterror();
532  $error++;
533  }
534 
535  if (!$error) {
536  // If stock is incremented on validate order, we must increment it
537  if ($result >= 0 && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1) {
538  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
539  $langs->load("agenda");
540 
541  // Loop on each line
542  $cpt = count($this->lines);
543  for ($i = 0; $i < $cpt; $i++) {
544  if ($this->lines[$i]->fk_product > 0) {
545  $mouvP = new MouvementStock($this->db);
546  $mouvP->origin = &$this;
547  $mouvP->setOrigin($this->element, $this->id);
548  // We decrement stock of product (and sub-products)
549  $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("OrderValidatedInDolibarr", $num));
550  if ($result < 0) {
551  $error++;
552  $this->error = $mouvP->error;
553  }
554  }
555  if ($error) {
556  break;
557  }
558  }
559  }
560  }
561 
562  if (!$error && !$notrigger) {
563  // Call trigger
564  $result = $this->call_trigger('ORDER_VALIDATE', $user);
565  if ($result < 0) {
566  $error++;
567  }
568  // End call triggers
569  }
570 
571  if (!$error) {
572  $this->oldref = $this->ref;
573 
574  // Rename directory if dir was a temporary ref
575  if (preg_match('/^[\(]?PROV/i', $this->ref)) {
576  // Now we rename also files into index
577  $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)."'";
578  $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'commande/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
579  $resql = $this->db->query($sql);
580  if (!$resql) {
581  $error++; $this->error = $this->db->lasterror();
582  }
583 
584  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
585  $oldref = dol_sanitizeFileName($this->ref);
586  $newref = dol_sanitizeFileName($num);
587  $dirsource = $conf->commande->multidir_output[$this->entity].'/'.$oldref;
588  $dirdest = $conf->commande->multidir_output[$this->entity].'/'.$newref;
589  if (!$error && file_exists($dirsource)) {
590  dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
591 
592  if (@rename($dirsource, $dirdest)) {
593  dol_syslog("Rename ok");
594  // Rename docs starting with $oldref with $newref
595  $listoffiles = dol_dir_list($conf->commande->multidir_output[$this->entity].'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
596  foreach ($listoffiles as $fileentry) {
597  $dirsource = $fileentry['name'];
598  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
599  $dirsource = $fileentry['path'].'/'.$dirsource;
600  $dirdest = $fileentry['path'].'/'.$dirdest;
601  @rename($dirsource, $dirdest);
602  }
603  }
604  }
605  }
606  }
607 
608  // Set new ref and current status
609  if (!$error) {
610  $this->ref = $num;
611  $this->statut = self::STATUS_VALIDATED;
612  $this->brouillon = 0;
613  }
614 
615  if (!$error) {
616  $this->db->commit();
617  return 1;
618  } else {
619  $this->db->rollback();
620  return -1;
621  }
622  }
623 
624  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
632  public function setDraft($user, $idwarehouse = -1)
633  {
634  //phpcs:enable
635  global $conf, $langs;
636 
637  $error = 0;
638 
639  // Protection
640  if ($this->statut <= self::STATUS_DRAFT) {
641  return 0;
642  }
643 
644  if (!((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->creer))
645  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->order_advance->validate)))) {
646  $this->error = 'Permission denied';
647  return -1;
648  }
649 
650  dol_syslog(__METHOD__, LOG_DEBUG);
651 
652  $this->db->begin();
653 
654  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
655  $sql .= " SET fk_statut = ".self::STATUS_DRAFT.",";
656  $sql .= " fk_user_modif = ".((int) $user->id);
657  $sql .= " WHERE rowid = ".((int) $this->id);
658 
659  if ($this->db->query($sql)) {
660  if (!$error) {
661  $this->oldcopy = clone $this;
662  }
663 
664  // If stock is decremented on validate order, we must reincrement it
665  if (isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1) {
666  $result = 0;
667 
668  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
669  $langs->load("agenda");
670 
671  $num = count($this->lines);
672  for ($i = 0; $i < $num; $i++) {
673  if ($this->lines[$i]->fk_product > 0) {
674  $mouvP = new MouvementStock($this->db);
675  $mouvP->origin = &$this;
676  $mouvP->setOrigin($this->element, $this->id);
677  // We increment stock of product (and sub-products)
678  $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("OrderBackToDraftInDolibarr", $this->ref));
679  if ($result < 0) {
680  $error++; $this->error = $mouvP->error; break;
681  }
682  }
683  }
684  }
685 
686  if (!$error) {
687  // Call trigger
688  $result = $this->call_trigger('ORDER_UNVALIDATE', $user);
689  if ($result < 0) {
690  $error++;
691  }
692  }
693 
694  if (!$error) {
695  $this->statut = self::STATUS_DRAFT;
696  $this->db->commit();
697  return 1;
698  } else {
699  $this->db->rollback();
700  return -1;
701  }
702  } else {
703  $this->error = $this->db->error();
704  $this->db->rollback();
705  return -1;
706  }
707  }
708 
709 
710  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
718  public function set_reopen($user)
719  {
720  // phpcs:enable
721  $error = 0;
722 
723  if ($this->statut != self::STATUS_CANCELED && $this->statut != self::STATUS_CLOSED) {
724  dol_syslog(get_class($this)."::set_reopen order has not status closed", LOG_WARNING);
725  return 0;
726  }
727 
728  $this->db->begin();
729 
730  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
731  $sql .= ' SET fk_statut='.self::STATUS_VALIDATED.', facture=0,';
732  $sql .= " fk_user_modif = ".((int) $user->id);
733  $sql .= " WHERE rowid = ".((int) $this->id);
734 
735  dol_syslog(get_class($this)."::set_reopen", LOG_DEBUG);
736  $resql = $this->db->query($sql);
737  if ($resql) {
738  // Call trigger
739  $result = $this->call_trigger('ORDER_REOPEN', $user);
740  if ($result < 0) {
741  $error++;
742  }
743  // End call triggers
744  } else {
745  $error++;
746  $this->error = $this->db->lasterror();
747  dol_print_error($this->db);
748  }
749 
750  if (!$error) {
751  $this->statut = self::STATUS_VALIDATED;
752  $this->billed = 0;
753 
754  $this->db->commit();
755  return 1;
756  } else {
757  foreach ($this->errors as $errmsg) {
758  dol_syslog(get_class($this)."::set_reopen ".$errmsg, LOG_ERR);
759  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
760  }
761  $this->db->rollback();
762  return -1 * $error;
763  }
764  }
765 
773  public function cloture($user, $notrigger = 0)
774  {
775  global $conf;
776 
777  $error = 0;
778 
779  $usercanclose = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->creer))
780  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->order_advance->close)));
781 
782  if ($usercanclose) {
783  if ($this->statut == self::STATUS_CLOSED) {
784  return 0;
785  }
786  $this->db->begin();
787 
788  $now = dol_now();
789 
790  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
791  $sql .= ' SET fk_statut = '.self::STATUS_CLOSED.',';
792  $sql .= ' fk_user_cloture = '.((int) $user->id).',';
793  $sql .= " date_cloture = '".$this->db->idate($now)."',";
794  $sql .= " fk_user_modif = ".((int) $user->id);
795  $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > '.self::STATUS_DRAFT;
796 
797  if ($this->db->query($sql)) {
798  if (!$notrigger) {
799  // Call trigger
800  $result = $this->call_trigger('ORDER_CLOSE', $user);
801  if ($result < 0) {
802  $error++;
803  }
804  // End call triggers
805  }
806 
807  if (!$error) {
808  $this->statut = self::STATUS_CLOSED;
809 
810  $this->db->commit();
811  return 1;
812  } else {
813  $this->db->rollback();
814  return -1;
815  }
816  } else {
817  $this->error = $this->db->lasterror();
818 
819  $this->db->rollback();
820  return -1;
821  }
822  }
823  return 0;
824  }
825 
833  public function cancel($idwarehouse = -1)
834  {
835  global $conf, $user, $langs;
836 
837  $error = 0;
838 
839  $this->db->begin();
840 
841  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
842  $sql .= " SET fk_statut = ".self::STATUS_CANCELED.",";
843  $sql .= " fk_user_modif = ".((int) $user->id);
844  $sql .= " WHERE rowid = ".((int) $this->id);
845  $sql .= " AND fk_statut = ".self::STATUS_VALIDATED;
846 
847  dol_syslog(get_class($this)."::cancel", LOG_DEBUG);
848  if ($this->db->query($sql)) {
849  // If stock is decremented on validate order, we must reincrement it
850  if (isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1) {
851  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
852  $langs->load("agenda");
853 
854  $num = count($this->lines);
855  for ($i = 0; $i < $num; $i++) {
856  if ($this->lines[$i]->fk_product > 0) {
857  $mouvP = new MouvementStock($this->db);
858  $mouvP->setOrigin($this->element, $this->id);
859  // We increment stock of product (and sub-products)
860  $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
861  if ($result < 0) {
862  $error++;
863  $this->error = $mouvP->error;
864  break;
865  }
866  }
867  }
868  }
869 
870  if (!$error) {
871  // Call trigger
872  $result = $this->call_trigger('ORDER_CANCEL', $user);
873  if ($result < 0) {
874  $error++;
875  }
876  // End call triggers
877  }
878 
879  if (!$error) {
880  $this->statut = self::STATUS_CANCELED;
881  $this->db->commit();
882  return 1;
883  } else {
884  foreach ($this->errors as $errmsg) {
885  dol_syslog(get_class($this)."::cancel ".$errmsg, LOG_ERR);
886  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
887  }
888  $this->db->rollback();
889  return -1 * $error;
890  }
891  } else {
892  $this->error = $this->db->error();
893  $this->db->rollback();
894  return -1;
895  }
896  }
897 
906  public function create($user, $notrigger = 0)
907  {
908  global $conf, $langs, $mysoc;
909  $error = 0;
910 
911  // Clean parameters
912  $this->brouillon = 1; // set command as draft
913 
914  // Set tmp vars
915  $date = ($this->date_commande ? $this->date_commande : $this->date);
916  $delivery_date = empty($this->delivery_date) ? $this->date_livraison : $this->delivery_date;
917 
918  // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
919  if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) {
920  list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $date);
921  } else {
922  $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
923  }
924  if (empty($this->fk_multicurrency)) {
925  $this->multicurrency_code = $conf->currency;
926  $this->fk_multicurrency = 0;
927  $this->multicurrency_tx = 1;
928  }
929 
930  dol_syslog(get_class($this)."::create user=".$user->id);
931 
932  // Check parameters
933  if (!empty($this->ref)) { // We check that ref is not already used
934  $result = self::isExistingObject($this->element, 0, $this->ref); // Check ref is not yet used
935  if ($result > 0) {
936  $this->error = 'ErrorRefAlreadyExists';
937  dol_syslog(get_class($this)."::create ".$this->error, LOG_WARNING);
938  $this->db->rollback();
939  return -1;
940  }
941  }
942 
943  $soc = new Societe($this->db);
944  $result = $soc->fetch($this->socid);
945  if ($result < 0) {
946  $this->error = "Failed to fetch company";
947  dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
948  return -2;
949  }
950  if (!empty($conf->global->ORDER_REQUIRE_SOURCE) && $this->source < 0) {
951  $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Source"));
952  dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
953  return -1;
954  }
955 
956  $now = dol_now();
957 
958  $this->db->begin();
959 
960  $sql = "INSERT INTO ".MAIN_DB_PREFIX."commande (";
961  $sql .= " ref, fk_soc, date_creation, fk_user_author, fk_projet, date_commande, source, note_private, note_public, ref_ext, ref_client";
962  $sql .= ", model_pdf, fk_cond_reglement, deposit_percent, fk_mode_reglement, fk_account, fk_availability, fk_input_reason, date_livraison, fk_delivery_address";
963  $sql .= ", fk_shipping_method";
964  $sql .= ", fk_warehouse";
965  $sql .= ", remise_absolue, remise_percent";
966  $sql .= ", fk_incoterms, location_incoterms";
967  $sql .= ", entity, module_source, pos_source";
968  $sql .= ", fk_multicurrency";
969  $sql .= ", multicurrency_code";
970  $sql .= ", multicurrency_tx";
971  $sql .= ")";
972  $sql .= " VALUES ('(PROV)', ".((int) $this->socid).", '".$this->db->idate($now)."', ".((int) $user->id);
973  $sql .= ", ".($this->fk_project > 0 ? ((int) $this->fk_project) : "null");
974  $sql .= ", '".$this->db->idate($date)."'";
975  $sql .= ", ".($this->source >= 0 && $this->source != '' ? $this->db->escape($this->source) : 'null');
976  $sql .= ", '".$this->db->escape($this->note_private)."'";
977  $sql .= ", '".$this->db->escape($this->note_public)."'";
978  $sql .= ", ".($this->ref_ext ? "'".$this->db->escape($this->ref_ext)."'" : "null");
979  $sql .= ", ".($this->ref_client ? "'".$this->db->escape($this->ref_client)."'" : "null");
980  $sql .= ", '".$this->db->escape($this->model_pdf)."'";
981  $sql .= ", ".($this->cond_reglement_id > 0 ? ((int) $this->cond_reglement_id) : "null");
982  $sql .= ", ".(!empty($this->deposit_percent) ? "'".$this->db->escape($this->deposit_percent)."'" : "null");
983  $sql .= ", ".($this->mode_reglement_id > 0 ? ((int) $this->mode_reglement_id) : "null");
984  $sql .= ", ".($this->fk_account > 0 ? ((int) $this->fk_account) : 'NULL');
985  $sql .= ", ".($this->availability_id > 0 ? ((int) $this->availability_id) : "null");
986  $sql .= ", ".($this->demand_reason_id > 0 ? ((int) $this->demand_reason_id) : "null");
987  $sql .= ", ".($delivery_date ? "'".$this->db->idate($delivery_date)."'" : "null");
988  $sql .= ", ".($this->fk_delivery_address > 0 ? ((int) $this->fk_delivery_address) : 'NULL');
989  $sql .= ", ".(!empty($this->shipping_method_id) && $this->shipping_method_id > 0 ? ((int) $this->shipping_method_id) : 'NULL');
990  $sql .= ", ".(!empty($this->warehouse_id) && $this->warehouse_id > 0 ? ((int) $this->warehouse_id) : 'NULL');
991  $sql .= ", ".($this->remise_absolue > 0 ? $this->db->escape($this->remise_absolue) : 'NULL');
992  $sql .= ", ".($this->remise_percent > 0 ? $this->db->escape($this->remise_percent) : 0); // TODO deprecated
993  $sql .= ", ".(int) $this->fk_incoterms;
994  $sql .= ", '".$this->db->escape($this->location_incoterms)."'";
995  $sql .= ", ".setEntity($this);
996  $sql .= ", ".($this->module_source ? "'".$this->db->escape($this->module_source)."'" : "null");
997  $sql .= ", ".($this->pos_source != '' ? "'".$this->db->escape($this->pos_source)."'" : "null");
998  $sql .= ", ".(int) $this->fk_multicurrency;
999  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
1000  $sql .= ", ".(float) $this->multicurrency_tx;
1001  $sql .= ")";
1002 
1003  dol_syslog(get_class($this)."::create", LOG_DEBUG);
1004  $resql = $this->db->query($sql);
1005  if ($resql) {
1006  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'commande');
1007 
1008  if ($this->id) {
1009  $fk_parent_line = 0;
1010  $num = count($this->lines);
1011 
1012  /*
1013  * Insert products details into db
1014  */
1015  for ($i = 0; $i < $num; $i++) {
1016  $line = $this->lines[$i];
1017 
1018  // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
1019  //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object.
1020  if (!is_object($line)) {
1021  $line = (object) $line;
1022  }
1023 
1024  // Reset fk_parent_line for no child products and special product
1025  if (($line->product_type != 9 && empty($line->fk_parent_line)) || $line->product_type == 9) {
1026  $fk_parent_line = 0;
1027  }
1028 
1029  // Complete vat rate with code
1030  $vatrate = $line->tva_tx;
1031  if ($line->vat_src_code && !preg_match('/\(.*\)/', $vatrate)) {
1032  $vatrate .= ' ('.$line->vat_src_code.')';
1033  }
1034 
1035  if (!empty($conf->global->MAIN_CREATEFROM_KEEP_LINE_ORIGIN_INFORMATION)) {
1036  $originid = $line->origin_id;
1037  $origintype = $line->origin;
1038  } else {
1039  $originid = $line->id;
1040  $origintype = $this->element;
1041  }
1042 
1043  // ref_ext
1044  if (empty($line->ref_ext)) {
1045  $line->ref_ext = '';
1046  }
1047 
1048  $result = $this->addline(
1049  $line->desc,
1050  $line->subprice,
1051  $line->qty,
1052  $vatrate,
1053  $line->localtax1_tx,
1054  $line->localtax2_tx,
1055  $line->fk_product,
1056  $line->remise_percent,
1057  $line->info_bits,
1058  $line->fk_remise_except,
1059  'HT',
1060  0,
1061  $line->date_start,
1062  $line->date_end,
1063  $line->product_type,
1064  $line->rang,
1065  $line->special_code,
1066  $fk_parent_line,
1067  $line->fk_fournprice,
1068  $line->pa_ht,
1069  $line->label,
1070  $line->array_options,
1071  $line->fk_unit,
1072  $origintype,
1073  $originid,
1074  0,
1075  $line->ref_ext,
1076  1
1077  );
1078  if ($result < 0) {
1079  if ($result != self::STOCK_NOT_ENOUGH_FOR_ORDER) {
1080  $this->error = $this->db->lasterror();
1081  $this->errors[] = $this->error;
1082  dol_print_error($this->db);
1083  }
1084  $this->db->rollback();
1085  return -1;
1086  }
1087  // Defined the new fk_parent_line
1088  if ($result > 0 && $line->product_type == 9) {
1089  $fk_parent_line = $result;
1090  }
1091  }
1092 
1093  $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.
1094 
1095  // update ref
1096  $initialref = '(PROV'.$this->id.')';
1097  if (!empty($this->ref)) {
1098  $initialref = $this->ref;
1099  }
1100 
1101  $sql = 'UPDATE '.MAIN_DB_PREFIX."commande SET ref='".$this->db->escape($initialref)."' WHERE rowid=".((int) $this->id);
1102  if ($this->db->query($sql)) {
1103  $this->ref = $initialref;
1104 
1105  if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) { // To use new linkedObjectsIds instead of old linked_objects
1106  $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
1107  }
1108 
1109  // Add object linked
1110  if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects)) {
1111  foreach ($this->linked_objects as $origin => $tmp_origin_id) {
1112  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, ...))
1113  foreach ($tmp_origin_id as $origin_id) {
1114  $ret = $this->add_object_linked($origin, $origin_id);
1115  if (!$ret) {
1116  $this->error = $this->db->lasterror();
1117  $error++;
1118  }
1119  }
1120  } else // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
1121  {
1122  $origin_id = $tmp_origin_id;
1123  $ret = $this->add_object_linked($origin, $origin_id);
1124  if (!$ret) {
1125  $this->error = $this->db->lasterror();
1126  $error++;
1127  }
1128  }
1129  }
1130  }
1131 
1132  if (!$error && $this->id && !empty($conf->global->MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN) && !empty($this->origin) && !empty($this->origin_id)) { // Get contact from origin object
1133  $originforcontact = $this->origin;
1134  $originidforcontact = $this->origin_id;
1135  if ($originforcontact == 'shipping') { // shipment and order share the same contacts. If creating from shipment we take data of order
1136  require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
1137  $exp = new Expedition($this->db);
1138  $exp->fetch($this->origin_id);
1139  $exp->fetchObjectLinked();
1140  if (count($exp->linkedObjectsIds['commande']) > 0) {
1141  foreach ($exp->linkedObjectsIds['commande'] as $key => $value) {
1142  $originforcontact = 'commande';
1143  if (is_object($value)) {
1144  $originidforcontact = $value->id;
1145  } else {
1146  $originidforcontact = $value;
1147  }
1148  break; // We take first one
1149  }
1150  }
1151  }
1152 
1153  $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";
1154  $sqlcontact .= " WHERE element_id = ".((int) $originidforcontact)." AND ec.fk_c_type_contact = ctc.rowid AND ctc.element = '".$this->db->escape($originforcontact)."'";
1155 
1156  $resqlcontact = $this->db->query($sqlcontact);
1157  if ($resqlcontact) {
1158  while ($objcontact = $this->db->fetch_object($resqlcontact)) {
1159  //print $objcontact->code.'-'.$objcontact->source.'-'.$objcontact->fk_socpeople."\n";
1160  $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
1161  }
1162  } else {
1163  dol_print_error($resqlcontact);
1164  }
1165  }
1166 
1167  if (!$error) {
1168  $result = $this->insertExtraFields();
1169  if ($result < 0) {
1170  $error++;
1171  }
1172  }
1173 
1174  if (!$error && !$notrigger) {
1175  // Call trigger
1176  $result = $this->call_trigger('ORDER_CREATE', $user);
1177  if ($result < 0) {
1178  $error++;
1179  }
1180  // End call triggers
1181  }
1182 
1183  if (!$error) {
1184  $this->db->commit();
1185  return $this->id;
1186  } else {
1187  $this->db->rollback();
1188  return -1 * $error;
1189  }
1190  } else {
1191  $this->error = $this->db->lasterror();
1192  $this->db->rollback();
1193  return -1;
1194  }
1195  }
1196 
1197  return 0;
1198  } else {
1199  dol_print_error($this->db);
1200  $this->db->rollback();
1201  return -1;
1202  }
1203  }
1204 
1205 
1213  public function createFromClone(User $user, $socid = 0)
1214  {
1215  global $conf, $user, $hookmanager;
1216 
1217  $error = 0;
1218 
1219  $this->db->begin();
1220 
1221  // get lines so they will be clone
1222  foreach ($this->lines as $line) {
1223  $line->fetch_optionals();
1224  }
1225 
1226  // Load source object
1227  $objFrom = clone $this;
1228 
1229  // Change socid if needed
1230  if (!empty($socid) && $socid != $this->socid) {
1231  $objsoc = new Societe($this->db);
1232 
1233  if ($objsoc->fetch($socid) > 0) {
1234  $this->socid = $objsoc->id;
1235  $this->cond_reglement_id = (!empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0);
1236  $this->deposit_percent = (!empty($objsoc->deposit_percent) ? $objsoc->deposit_percent : null);
1237  $this->mode_reglement_id = (!empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0);
1238  $this->fk_project = 0;
1239  $this->fk_delivery_address = 0;
1240  }
1241 
1242  // TODO Change product price if multi-prices
1243  }
1244 
1245  $this->id = 0;
1246  $this->ref = '';
1247  $this->statut = self::STATUS_DRAFT;
1248 
1249  // Clear fields
1250  $this->user_author_id = $user->id;
1251  $this->user_valid = 0; // deprecated
1252  $this->user_validation_id = 0;
1253  $this->date = dol_now();
1254  $this->date_commande = dol_now();
1255  $this->date_creation = '';
1256  $this->date_validation = '';
1257  if (empty($conf->global->MAIN_KEEP_REF_CUSTOMER_ON_CLONING)) {
1258  $this->ref_client = '';
1259  $this->ref_customer = '';
1260  }
1261 
1262  // Do not clone ref_ext
1263  $num = count($this->lines);
1264  for ($i = 0; $i < $num; $i++) {
1265  $this->lines[$i]->ref_ext = '';
1266  }
1267 
1268  // Create clone
1269  $this->context['createfromclone'] = 'createfromclone';
1270  $result = $this->create($user);
1271  if ($result < 0) {
1272  $error++;
1273  }
1274 
1275  if (!$error) {
1276  // copy internal contacts
1277  if ($this->copy_linked_contact($objFrom, 'internal') < 0) {
1278  $error++;
1279  }
1280  }
1281 
1282  if (!$error) {
1283  // copy external contacts if same company
1284  if ($this->socid == $objFrom->socid) {
1285  if ($this->copy_linked_contact($objFrom, 'external') < 0) {
1286  $error++;
1287  }
1288  }
1289  }
1290 
1291  if (!$error) {
1292  // Hook of thirdparty module
1293  if (is_object($hookmanager)) {
1294  $parameters = array('objFrom'=>$objFrom);
1295  $action = '';
1296  $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1297  if ($reshook < 0) {
1298  $this->setErrorsFromObject($hookmanager);
1299  $error++;
1300  }
1301  }
1302  }
1303 
1304  unset($this->context['createfromclone']);
1305 
1306  // End
1307  if (!$error) {
1308  $this->db->commit();
1309  return $this->id;
1310  } else {
1311  $this->db->rollback();
1312  return -1;
1313  }
1314  }
1315 
1316 
1324  public function createFromProposal($object, User $user)
1325  {
1326  global $conf, $hookmanager;
1327 
1328  dol_include_once('/multicurrency/class/multicurrency.class.php');
1329  dol_include_once('/core/class/extrafields.class.php');
1330 
1331  $error = 0;
1332 
1333 
1334  $this->date_commande = dol_now();
1335  $this->source = 0;
1336 
1337  $num = count($object->lines);
1338  for ($i = 0; $i < $num; $i++) {
1339  $line = new OrderLine($this->db);
1340 
1341  $line->libelle = $object->lines[$i]->libelle;
1342  $line->label = $object->lines[$i]->label;
1343  $line->desc = $object->lines[$i]->desc;
1344  $line->price = $object->lines[$i]->price;
1345  $line->subprice = $object->lines[$i]->subprice;
1346  $line->vat_src_code = $object->lines[$i]->vat_src_code;
1347  $line->tva_tx = $object->lines[$i]->tva_tx;
1348  $line->localtax1_tx = $object->lines[$i]->localtax1_tx;
1349  $line->localtax2_tx = $object->lines[$i]->localtax2_tx;
1350  $line->qty = $object->lines[$i]->qty;
1351  $line->fk_remise_except = $object->lines[$i]->fk_remise_except;
1352  $line->remise_percent = $object->lines[$i]->remise_percent;
1353  $line->fk_product = $object->lines[$i]->fk_product;
1354  $line->info_bits = $object->lines[$i]->info_bits;
1355  $line->product_type = $object->lines[$i]->product_type;
1356  $line->rang = $object->lines[$i]->rang;
1357  $line->special_code = $object->lines[$i]->special_code;
1358  $line->fk_parent_line = $object->lines[$i]->fk_parent_line;
1359  $line->fk_unit = $object->lines[$i]->fk_unit;
1360 
1361  $line->date_start = $object->lines[$i]->date_start;
1362  $line->date_end = $object->lines[$i]->date_end;
1363 
1364  $line->fk_fournprice = $object->lines[$i]->fk_fournprice;
1365  $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);
1366  $line->pa_ht = $marginInfos[0];
1367  $line->marge_tx = $marginInfos[1];
1368  $line->marque_tx = $marginInfos[2];
1369 
1370  $line->origin = $object->element;
1371  $line->origin_id = $object->lines[$i]->id;
1372 
1373  // get extrafields from original line
1374  $object->lines[$i]->fetch_optionals();
1375  foreach ($object->lines[$i]->array_options as $options_key => $value) {
1376  $line->array_options[$options_key] = $value;
1377  }
1378 
1379  $this->lines[$i] = $line;
1380  }
1381 
1382  $this->entity = $object->entity;
1383  $this->socid = $object->socid;
1384  $this->fk_project = $object->fk_project;
1385  $this->cond_reglement_id = $object->cond_reglement_id;
1386  $this->deposit_percent = $object->deposit_percent;
1387  $this->mode_reglement_id = $object->mode_reglement_id;
1388  $this->fk_account = $object->fk_account;
1389  $this->availability_id = $object->availability_id;
1390  $this->demand_reason_id = $object->demand_reason_id;
1391  $this->date_livraison = $object->date_livraison; // deprecated
1392  $this->delivery_date = $object->date_livraison;
1393  $this->shipping_method_id = $object->shipping_method_id;
1394  $this->warehouse_id = $object->warehouse_id;
1395  $this->fk_delivery_address = $object->fk_delivery_address;
1396  $this->contact_id = $object->contact_id;
1397  $this->ref_client = $object->ref_client;
1398  $this->ref_customer = $object->ref_client;
1399 
1400  if (empty($conf->global->MAIN_DISABLE_PROPAGATE_NOTES_FROM_ORIGIN)) {
1401  $this->note_private = $object->note_private;
1402  $this->note_public = $object->note_public;
1403  }
1404 
1405  $this->origin = $object->element;
1406  $this->origin_id = $object->id;
1407 
1408  // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
1409  if (!empty($conf->multicurrency->enabled)) {
1410  if (!empty($object->multicurrency_code)) {
1411  $this->multicurrency_code = $object->multicurrency_code;
1412  }
1413  if (!empty($conf->global->MULTICURRENCY_USE_ORIGIN_TX) && !empty($object->multicurrency_tx)) {
1414  $this->multicurrency_tx = $object->multicurrency_tx;
1415  }
1416 
1417  if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) {
1418  $tmparray = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $this->date_commande);
1419  $this->fk_multicurrency = $tmparray[0];
1420  $this->multicurrency_tx = $tmparray[1];
1421  } else {
1422  $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
1423  }
1424  if (empty($this->fk_multicurrency)) {
1425  $this->multicurrency_code = $conf->currency;
1426  $this->fk_multicurrency = 0;
1427  $this->multicurrency_tx = 1;
1428  }
1429  }
1430 
1431  // get extrafields from original line
1432  $object->fetch_optionals();
1433 
1434  $e = new ExtraFields($this->db);
1435  $element_extrafields = $e->fetch_name_optionals_label($this->table_element);
1436 
1437  foreach ($object->array_options as $options_key => $value) {
1438  if (array_key_exists(str_replace('options_', '', $options_key), $element_extrafields)) {
1439  $this->array_options[$options_key] = $value;
1440  }
1441  }
1442  // Possibility to add external linked objects with hooks
1443  $this->linked_objects[$this->origin] = $this->origin_id;
1444  if (isset($object->other_linked_objects) && is_array($object->other_linked_objects) && !empty($object->other_linked_objects)) {
1445  $this->linked_objects = array_merge($this->linked_objects, $object->other_linked_objects);
1446  }
1447 
1448  $ret = $this->create($user);
1449 
1450  if ($ret > 0) {
1451  // Actions hooked (by external module)
1452  $hookmanager->initHooks(array('orderdao'));
1453 
1454  $parameters = array('objFrom'=>$object);
1455  $action = '';
1456  $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1457  if ($reshook < 0) {
1458  $this->setErrorsFromObject($hookmanager);
1459  $error++;
1460  }
1461 
1462  if (!$error) {
1463  // Validate immediatly the order
1464  if (!empty($conf->global->ORDER_VALID_AFTER_CLOSE_PROPAL)) {
1465  $this->fetch($ret);
1466  $this->valid($user);
1467  }
1468  return $ret;
1469  } else {
1470  return -1;
1471  }
1472  } else {
1473  return -1;
1474  }
1475  }
1476 
1477 
1518  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)
1519  {
1520  global $mysoc, $conf, $langs, $user;
1521 
1522  $logtext = "::addline commandeid=$this->id, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, fk_product=$fk_product, remise_percent=$remise_percent";
1523  $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";
1524  $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";
1525  dol_syslog(get_class($this).$logtext, LOG_DEBUG);
1526 
1527  if ($this->statut == self::STATUS_DRAFT) {
1528  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1529 
1530  // Clean parameters
1531 
1532  if (empty($remise_percent)) {
1533  $remise_percent = 0;
1534  }
1535  if (empty($qty)) {
1536  $qty = 0;
1537  }
1538  if (empty($info_bits)) {
1539  $info_bits = 0;
1540  }
1541  if (empty($rang)) {
1542  $rang = 0;
1543  }
1544  if (empty($txtva)) {
1545  $txtva = 0;
1546  }
1547  if (empty($txlocaltax1)) {
1548  $txlocaltax1 = 0;
1549  }
1550  if (empty($txlocaltax2)) {
1551  $txlocaltax2 = 0;
1552  }
1553  if (empty($fk_parent_line) || $fk_parent_line < 0) {
1554  $fk_parent_line = 0;
1555  }
1556  if (empty($this->fk_multicurrency)) {
1557  $this->fk_multicurrency = 0;
1558  }
1559  if (empty($ref_ext)) {
1560  $ref_ext = '';
1561  }
1562 
1564  $qty = price2num($qty);
1565  $pu_ht = price2num($pu_ht);
1566  $pu_ht_devise = price2num($pu_ht_devise);
1567  $pu_ttc = price2num($pu_ttc);
1568  $pa_ht = price2num($pa_ht);
1569  if (!preg_match('/\((.*)\)/', $txtva)) {
1570  $txtva = price2num($txtva); // $txtva can have format '5,1' or '5.1' or '5.1(XXX)', we must clean only if '5,1'
1571  }
1572  $txlocaltax1 = price2num($txlocaltax1);
1573  $txlocaltax2 = price2num($txlocaltax2);
1574  if ($price_base_type == 'HT') {
1575  $pu = $pu_ht;
1576  } else {
1577  $pu = $pu_ttc;
1578  }
1579  $label = trim($label);
1580  $desc = trim($desc);
1581 
1582  // Check parameters
1583  if ($type < 0) {
1584  return -1;
1585  }
1586 
1587  if ($date_start && $date_end && $date_start > $date_end) {
1588  $langs->load("errors");
1589  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
1590  return -1;
1591  }
1592 
1593  $this->db->begin();
1594 
1595  $product_type = $type;
1596  if (!empty($fk_product) && $fk_product > 0) {
1597  $product = new Product($this->db);
1598  $result = $product->fetch($fk_product);
1599  $product_type = $product->type;
1600 
1601  if (!empty($conf->global->STOCK_MUST_BE_ENOUGH_FOR_ORDER) && $product_type == 0 && $product->stock_reel < $qty) {
1602  $langs->load("errors");
1603  $this->error = $langs->trans('ErrorStockIsNotEnoughToAddProductOnOrder', $product->ref);
1604  $this->errors[] = $this->error;
1605  dol_syslog(get_class($this)."::addline error=Product ".$product->ref.": ".$this->error, LOG_ERR);
1606  $this->db->rollback();
1608  }
1609  }
1610  // Calcul du total TTC et de la TVA pour la ligne a partir de
1611  // qty, pu, remise_percent et txtva
1612  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1613  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1614 
1615  $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
1616 
1617  // Clean vat code
1618  $reg = array();
1619  $vat_src_code = '';
1620  if (preg_match('/\((.*)\)/', $txtva, $reg)) {
1621  $vat_src_code = $reg[1];
1622  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
1623  }
1624 
1625  $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);
1626 
1627  /*var_dump($txlocaltax1);
1628  var_dump($txlocaltax2);
1629  var_dump($localtaxes_type);
1630  var_dump($tabprice);
1631  var_dump($tabprice[9]);
1632  var_dump($tabprice[10]);
1633  exit;*/
1634 
1635  $total_ht = $tabprice[0];
1636  $total_tva = $tabprice[1];
1637  $total_ttc = $tabprice[2];
1638  $total_localtax1 = $tabprice[9];
1639  $total_localtax2 = $tabprice[10];
1640  $pu_ht = $tabprice[3];
1641 
1642  // MultiCurrency
1643  $multicurrency_total_ht = $tabprice[16];
1644  $multicurrency_total_tva = $tabprice[17];
1645  $multicurrency_total_ttc = $tabprice[18];
1646  $pu_ht_devise = $tabprice[19];
1647 
1648  // Rang to use
1649  $ranktouse = $rang;
1650  if ($ranktouse == -1) {
1651  $rangmax = $this->line_max($fk_parent_line);
1652  $ranktouse = $rangmax + 1;
1653  }
1654 
1655  // TODO A virer
1656  // Anciens indicateurs: $price, $remise (a ne plus utiliser)
1657  $price = $pu;
1658  $remise = 0;
1659  if ($remise_percent > 0) {
1660  $remise = round(($pu * $remise_percent / 100), 2);
1661  $price = $pu - $remise;
1662  }
1663 
1664  // Insert line
1665  $this->line = new OrderLine($this->db);
1666 
1667  $this->line->context = $this->context;
1668 
1669  $this->line->fk_commande = $this->id;
1670  $this->line->label = $label;
1671  $this->line->desc = $desc;
1672  $this->line->qty = $qty;
1673  $this->line->ref_ext = $ref_ext;
1674 
1675  $this->line->vat_src_code = $vat_src_code;
1676  $this->line->tva_tx = $txtva;
1677  $this->line->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0);
1678  $this->line->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0);
1679  $this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
1680  $this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
1681  $this->line->fk_product = $fk_product;
1682  $this->line->product_type = $product_type;
1683  $this->line->fk_remise_except = $fk_remise_except;
1684  $this->line->remise_percent = $remise_percent;
1685  $this->line->subprice = $pu_ht;
1686  $this->line->rang = $ranktouse;
1687  $this->line->info_bits = $info_bits;
1688  $this->line->total_ht = $total_ht;
1689  $this->line->total_tva = $total_tva;
1690  $this->line->total_localtax1 = $total_localtax1;
1691  $this->line->total_localtax2 = $total_localtax2;
1692  $this->line->total_ttc = $total_ttc;
1693  $this->line->special_code = $special_code;
1694  $this->line->origin = $origin;
1695  $this->line->origin_id = $origin_id;
1696  $this->line->fk_parent_line = $fk_parent_line;
1697  $this->line->fk_unit = $fk_unit;
1698 
1699  $this->line->date_start = $date_start;
1700  $this->line->date_end = $date_end;
1701 
1702  $this->line->fk_fournprice = $fk_fournprice;
1703  $this->line->pa_ht = $pa_ht;
1704 
1705  // Multicurrency
1706  $this->line->fk_multicurrency = $this->fk_multicurrency;
1707  $this->line->multicurrency_code = $this->multicurrency_code;
1708  $this->line->multicurrency_subprice = $pu_ht_devise;
1709  $this->line->multicurrency_total_ht = $multicurrency_total_ht;
1710  $this->line->multicurrency_total_tva = $multicurrency_total_tva;
1711  $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
1712 
1713  // TODO Ne plus utiliser
1714  $this->line->price = $price;
1715 
1716  if (is_array($array_options) && count($array_options) > 0) {
1717  $this->line->array_options = $array_options;
1718  }
1719 
1720  $result = $this->line->insert($user);
1721  if ($result > 0) {
1722  // Reorder if child line
1723  if (!empty($fk_parent_line)) {
1724  $this->line_order(true, 'DESC');
1725  } elseif ($ranktouse > 0 && $ranktouse <= count($this->lines)) { // Update all rank of all other lines
1726  $linecount = count($this->lines);
1727  for ($ii = $ranktouse; $ii <= $linecount; $ii++) {
1728  $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii + 1);
1729  }
1730  }
1731 
1732  // Mise a jour informations denormalisees au niveau de la commande meme
1733  if (empty($noupdateafterinsertline)) {
1734  $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.
1735  }
1736 
1737  if ($result > 0) {
1738  $this->db->commit();
1739  return $this->line->id;
1740  } else {
1741  $this->db->rollback();
1742  return -1;
1743  }
1744  } else {
1745  $this->error = $this->line->error;
1746  dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR);
1747  $this->db->rollback();
1748  return -2;
1749  }
1750  } else {
1751  dol_syslog(get_class($this)."::addline status of order must be Draft to allow use of ->addline()", LOG_ERR);
1752  return -3;
1753  }
1754  }
1755 
1756 
1757  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1771  public function add_product($idproduct, $qty, $remise_percent = 0.0, $date_start = '', $date_end = '')
1772  {
1773  // phpcs:enable
1774  global $conf, $mysoc;
1775 
1776  if (!$qty) {
1777  $qty = 1;
1778  }
1779 
1780  if ($idproduct > 0) {
1781  $prod = new Product($this->db);
1782  $prod->fetch($idproduct);
1783 
1784  $tva_tx = get_default_tva($mysoc, $this->thirdparty, $prod->id);
1785  $tva_npr = get_default_npr($mysoc, $this->thirdparty, $prod->id);
1786  if (empty($tva_tx)) {
1787  $tva_npr = 0;
1788  }
1789  $vat_src_code = ''; // May be defined into tva_tx
1790 
1791  $localtax1_tx = get_localtax($tva_tx, 1, $this->thirdparty, $mysoc, $tva_npr);
1792  $localtax2_tx = get_localtax($tva_tx, 2, $this->thirdparty, $mysoc, $tva_npr);
1793 
1794  // multiprix
1795  if ($conf->global->PRODUIT_MULTIPRICES && $this->thirdparty->price_level) {
1796  $price = $prod->multiprices[$this->thirdparty->price_level];
1797  } else {
1798  $price = $prod->price;
1799  }
1800 
1801  $line = new OrderLine($this->db);
1802 
1803  $line->context = $this->context;
1804 
1805  $line->fk_product = $idproduct;
1806  $line->desc = $prod->description;
1807  $line->qty = $qty;
1808  $line->subprice = $price;
1809  $line->remise_percent = $remise_percent;
1810  $line->vat_src_code = $vat_src_code;
1811  $line->tva_tx = $tva_tx;
1812  $line->localtax1_tx = $localtax1_tx;
1813  $line->localtax2_tx = $localtax2_tx;
1814  $line->ref = $prod->ref;
1815  $line->libelle = $prod->label;
1816  $line->product_desc = $prod->description;
1817  $line->fk_unit = $prod->fk_unit;
1818 
1819  // Save the start and end date of the line in the object
1820  if ($date_start) {
1821  $line->date_start = $date_start;
1822  }
1823  if ($date_end) {
1824  $line->date_end = $date_end;
1825  }
1826 
1827  $this->lines[] = $line;
1828 
1847  }
1848  }
1849 
1850 
1860  public function fetch($id, $ref = '', $ref_ext = '', $notused = '')
1861  {
1862  // Check parameters
1863  if (empty($id) && empty($ref) && empty($ref_ext)) {
1864  return -1;
1865  }
1866 
1867  $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';
1868  $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';
1869  $sql .= ', c.fk_account';
1870  $sql .= ', c.date_commande, c.date_valid, c.tms';
1871  $sql .= ', c.date_livraison as delivery_date';
1872  $sql .= ', c.fk_shipping_method';
1873  $sql .= ', c.fk_warehouse';
1874  $sql .= ', c.fk_projet as fk_project, c.remise_percent, c.remise, c.remise_absolue, c.source, c.facture as billed';
1875  $sql .= ', c.note_private, c.note_public, c.ref_client, c.ref_ext, c.model_pdf, c.last_main_doc, c.fk_delivery_address, c.extraparams';
1876  $sql .= ', c.fk_incoterms, c.location_incoterms';
1877  $sql .= ", c.fk_multicurrency, c.multicurrency_code, c.multicurrency_tx, c.multicurrency_total_ht, c.multicurrency_total_tva, c.multicurrency_total_ttc";
1878  $sql .= ", c.module_source, c.pos_source";
1879  $sql .= ", i.libelle as label_incoterms";
1880  $sql .= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
1881  $sql .= ', cr.code as cond_reglement_code, cr.libelle as cond_reglement_libelle, cr.libelle_facture as cond_reglement_libelle_doc';
1882  $sql .= ', ca.code as availability_code, ca.label as availability_label';
1883  $sql .= ', dr.code as demand_reason_code';
1884  $sql .= ' FROM '.MAIN_DB_PREFIX.'commande as c';
1885  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as cr ON c.fk_cond_reglement = cr.rowid';
1886  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON c.fk_mode_reglement = p.id';
1887  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_availability as ca ON c.fk_availability = ca.rowid';
1888  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_input_reason as dr ON c.fk_input_reason = dr.rowid';
1889  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON c.fk_incoterms = i.rowid';
1890 
1891  if ($id) {
1892  $sql .= " WHERE c.rowid=".((int) $id);
1893  } else {
1894  $sql .= " WHERE c.entity IN (".getEntity('commande').")"; // Dont't use entity if you use rowid
1895  }
1896 
1897  if ($ref) {
1898  $sql .= " AND c.ref='".$this->db->escape($ref)."'";
1899  }
1900  if ($ref_ext) {
1901  $sql .= " AND c.ref_ext='".$this->db->escape($ref_ext)."'";
1902  }
1903 
1904  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
1905  $result = $this->db->query($sql);
1906  if ($result) {
1907  $obj = $this->db->fetch_object($result);
1908  if ($obj) {
1909  $this->id = $obj->rowid;
1910  $this->entity = $obj->entity;
1911 
1912  $this->ref = $obj->ref;
1913  $this->ref_client = $obj->ref_client;
1914  $this->ref_customer = $obj->ref_client;
1915  $this->ref_ext = $obj->ref_ext;
1916 
1917  $this->socid = $obj->fk_soc;
1918  $this->thirdparty = null; // Clear if another value was already set by fetch_thirdparty
1919 
1920  $this->fk_project = $obj->fk_project;
1921  $this->project = null; // Clear if another value was already set by fetch_projet
1922 
1923  $this->statut = $obj->fk_statut;
1924  $this->status = $obj->fk_statut;
1925 
1926  $this->user_author_id = $obj->fk_user_author;
1927  $this->user_creation_id = $obj->fk_user_author;
1928  $this->user_validation_id = $obj->fk_user_valid;
1929  $this->user_valid = $obj->fk_user_valid; // deprecated
1930  $this->user_modification_id = $obj->fk_user_modif;
1931  $this->user_modification = $obj->fk_user_modif;
1932  $this->total_ht = $obj->total_ht;
1933  $this->total_tva = $obj->total_tva;
1934  $this->total_localtax1 = $obj->total_localtax1;
1935  $this->total_localtax2 = $obj->total_localtax2;
1936  $this->total_ttc = $obj->total_ttc;
1937  $this->date = $this->db->jdate($obj->date_commande);
1938  $this->date_commande = $this->db->jdate($obj->date_commande);
1939  $this->date_creation = $this->db->jdate($obj->date_creation);
1940  $this->date_validation = $this->db->jdate($obj->date_valid);
1941  $this->date_modification = $this->db->jdate($obj->tms);
1942  $this->remise = $obj->remise;
1943  $this->remise_percent = $obj->remise_percent; // TODO deprecated
1944  $this->remise_absolue = $obj->remise_absolue;
1945  $this->source = $obj->source;
1946  $this->billed = $obj->billed;
1947  $this->note = $obj->note_private; // deprecated
1948  $this->note_private = $obj->note_private;
1949  $this->note_public = $obj->note_public;
1950  $this->model_pdf = $obj->model_pdf;
1951  $this->modelpdf = $obj->model_pdf; // deprecated
1952  $this->last_main_doc = $obj->last_main_doc;
1953  $this->mode_reglement_id = $obj->fk_mode_reglement;
1954  $this->mode_reglement_code = $obj->mode_reglement_code;
1955  $this->mode_reglement = $obj->mode_reglement_libelle;
1956  $this->cond_reglement_id = $obj->fk_cond_reglement;
1957  $this->cond_reglement_code = $obj->cond_reglement_code;
1958  $this->cond_reglement = $obj->cond_reglement_libelle;
1959  $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc;
1960  $this->deposit_percent = $obj->deposit_percent;
1961  $this->fk_account = $obj->fk_account;
1962  $this->availability_id = $obj->fk_availability;
1963  $this->availability_code = $obj->availability_code;
1964  $this->availability = $obj->availability_label;
1965  $this->demand_reason_id = $obj->fk_input_reason;
1966  $this->demand_reason_code = $obj->demand_reason_code;
1967  $this->date_livraison = $this->db->jdate($obj->delivery_date); // deprecated
1968  $this->delivery_date = $this->db->jdate($obj->delivery_date);
1969  $this->shipping_method_id = ($obj->fk_shipping_method > 0) ? $obj->fk_shipping_method : null;
1970  $this->warehouse_id = ($obj->fk_warehouse > 0) ? $obj->fk_warehouse : null;
1971  $this->fk_delivery_address = $obj->fk_delivery_address;
1972  $this->module_source = $obj->module_source;
1973  $this->pos_source = $obj->pos_source;
1974 
1975  //Incoterms
1976  $this->fk_incoterms = $obj->fk_incoterms;
1977  $this->location_incoterms = $obj->location_incoterms;
1978  $this->label_incoterms = $obj->label_incoterms;
1979 
1980  // Multicurrency
1981  $this->fk_multicurrency = $obj->fk_multicurrency;
1982  $this->multicurrency_code = $obj->multicurrency_code;
1983  $this->multicurrency_tx = $obj->multicurrency_tx;
1984  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
1985  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
1986  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
1987 
1988  $this->extraparams = !empty($obj->extraparams) ? (array) json_decode($obj->extraparams, true) : array();
1989 
1990  $this->lines = array();
1991 
1992  if ($this->statut == self::STATUS_DRAFT) {
1993  $this->brouillon = 1;
1994  }
1995 
1996  // Retrieve all extrafield
1997  // fetch optionals attributes and labels
1998  $this->fetch_optionals();
1999 
2000  $this->db->free($result);
2001 
2002  // Lines
2003  $result = $this->fetch_lines();
2004  if ($result < 0) {
2005  return -3;
2006  }
2007  return 1;
2008  } else {
2009  $this->error = 'Order with id '.$id.' not found sql='.$sql;
2010  return 0;
2011  }
2012  } else {
2013  $this->error = $this->db->error();
2014  return -1;
2015  }
2016  }
2017 
2018 
2019  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2026  public function insert_discount($idremise)
2027  {
2028  // phpcs:enable
2029  global $langs;
2030 
2031  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2032  include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
2033 
2034  $this->db->begin();
2035 
2036  $remise = new DiscountAbsolute($this->db);
2037  $result = $remise->fetch($idremise);
2038 
2039  if ($result > 0) {
2040  if ($remise->fk_facture) { // Protection against multiple submission
2041  $this->error = $langs->trans("ErrorDiscountAlreadyUsed");
2042  $this->db->rollback();
2043  return -5;
2044  }
2045 
2046  $line = new OrderLine($this->db);
2047 
2048  $line->fk_commande = $this->id;
2049  $line->fk_remise_except = $remise->id;
2050  $line->desc = $remise->description; // Description ligne
2051  $line->vat_src_code = $remise->vat_src_code;
2052  $line->tva_tx = $remise->tva_tx;
2053  $line->subprice = -$remise->amount_ht;
2054  $line->price = -$remise->amount_ht;
2055  $line->fk_product = 0; // Id produit predefini
2056  $line->qty = 1;
2057  $line->remise_percent = 0;
2058  $line->rang = -1;
2059  $line->info_bits = 2;
2060 
2061  $line->total_ht = -$remise->amount_ht;
2062  $line->total_tva = -$remise->amount_tva;
2063  $line->total_ttc = -$remise->amount_ttc;
2064 
2065  $result = $line->insert();
2066  if ($result > 0) {
2067  $result = $this->update_price(1);
2068  if ($result > 0) {
2069  $this->db->commit();
2070  return 1;
2071  } else {
2072  $this->db->rollback();
2073  return -1;
2074  }
2075  } else {
2076  $this->error = $line->error;
2077  $this->errors = $line->errors;
2078  $this->db->rollback();
2079  return -2;
2080  }
2081  } else {
2082  $this->db->rollback();
2083  return -2;
2084  }
2085  }
2086 
2087 
2088  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2096  public function fetch_lines($only_product = 0, $loadalsotranslation = 0)
2097  {
2098  // phpcs:enable
2099  global $langs, $conf;
2100 
2101  $this->lines = array();
2102 
2103  $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,';
2104  $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,';
2105  $sql .= ' l.total_ht, l.total_ttc, l.total_tva, l.total_localtax1, l.total_localtax2, l.date_start, l.date_end,';
2106  $sql .= ' l.fk_unit,';
2107  $sql .= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
2108  $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,';
2109  $sql .= ' p.weight, p.weight_units, p.volume, p.volume_units';
2110  $sql .= ' FROM '.MAIN_DB_PREFIX.'commandedet as l';
2111  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON (p.rowid = l.fk_product)';
2112  $sql .= ' WHERE l.fk_commande = '.((int) $this->id);
2113  if ($only_product) {
2114  $sql .= ' AND p.fk_product_type = 0';
2115  }
2116  $sql .= ' ORDER BY l.rang, l.rowid';
2117 
2118  dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
2119  $result = $this->db->query($sql);
2120  if ($result) {
2121  $num = $this->db->num_rows($result);
2122 
2123  $i = 0;
2124  while ($i < $num) {
2125  $objp = $this->db->fetch_object($result);
2126 
2127  $line = new OrderLine($this->db);
2128 
2129  $line->rowid = $objp->rowid;
2130  $line->id = $objp->rowid;
2131  $line->fk_commande = $objp->fk_commande;
2132  $line->commande_id = $objp->fk_commande;
2133  $line->label = $objp->custom_label;
2134  $line->desc = $objp->description;
2135  $line->description = $objp->description; // Description line
2136  $line->product_type = $objp->product_type;
2137  $line->qty = $objp->qty;
2138  $line->ref_ext = $objp->ref_ext;
2139 
2140  $line->vat_src_code = $objp->vat_src_code;
2141  $line->tva_tx = $objp->tva_tx;
2142  $line->localtax1_tx = $objp->localtax1_tx;
2143  $line->localtax2_tx = $objp->localtax2_tx;
2144  $line->localtax1_type = $objp->localtax1_type;
2145  $line->localtax2_type = $objp->localtax2_type;
2146  $line->total_ht = $objp->total_ht;
2147  $line->total_ttc = $objp->total_ttc;
2148  $line->total_tva = $objp->total_tva;
2149  $line->total_localtax1 = $objp->total_localtax1;
2150  $line->total_localtax2 = $objp->total_localtax2;
2151  $line->subprice = $objp->subprice;
2152  $line->fk_remise_except = $objp->fk_remise_except;
2153  $line->remise_percent = $objp->remise_percent;
2154  $line->price = $objp->price;
2155  $line->fk_product = $objp->fk_product;
2156  $line->fk_fournprice = $objp->fk_fournprice;
2157  $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht);
2158  $line->pa_ht = $marginInfos[0];
2159  $line->marge_tx = $marginInfos[1];
2160  $line->marque_tx = $marginInfos[2];
2161  $line->rang = $objp->rang;
2162  $line->info_bits = $objp->info_bits;
2163  $line->special_code = $objp->special_code;
2164  $line->fk_parent_line = $objp->fk_parent_line;
2165 
2166  $line->ref = $objp->product_ref;
2167  $line->libelle = $objp->product_label;
2168 
2169  $line->product_ref = $objp->product_ref;
2170  $line->product_label = $objp->product_label;
2171  $line->product_tosell = $objp->product_tosell;
2172  $line->product_tobuy = $objp->product_tobuy;
2173  $line->product_desc = $objp->product_desc;
2174  $line->product_tobatch = $objp->product_tobatch;
2175  $line->product_barcode = $objp->product_barcode;
2176 
2177  $line->fk_product_type = $objp->fk_product_type; // Produit ou service
2178  $line->fk_unit = $objp->fk_unit;
2179 
2180  $line->weight = $objp->weight;
2181  $line->weight_units = $objp->weight_units;
2182  $line->volume = $objp->volume;
2183  $line->volume_units = $objp->volume_units;
2184 
2185  $line->date_start = $this->db->jdate($objp->date_start);
2186  $line->date_end = $this->db->jdate($objp->date_end);
2187 
2188  // Multicurrency
2189  $line->fk_multicurrency = $objp->fk_multicurrency;
2190  $line->multicurrency_code = $objp->multicurrency_code;
2191  $line->multicurrency_subprice = $objp->multicurrency_subprice;
2192  $line->multicurrency_total_ht = $objp->multicurrency_total_ht;
2193  $line->multicurrency_total_tva = $objp->multicurrency_total_tva;
2194  $line->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
2195 
2196  $line->fetch_optionals();
2197 
2198  // multilangs
2199  if (getDolGlobalInt('MAIN_MULTILANGS') && !empty($objp->fk_product) && !empty($loadalsotranslation)) {
2200  $tmpproduct = new Product($this->db);
2201  $tmpproduct->fetch($objp->fk_product);
2202  $tmpproduct->getMultiLangs();
2203 
2204  $line->multilangs = $tmpproduct->multilangs;
2205  }
2206 
2207  $this->lines[$i] = $line;
2208 
2209  $i++;
2210  }
2211 
2212  $this->db->free($result);
2213 
2214  return 1;
2215  } else {
2216  $this->error = $this->db->error();
2217  return -3;
2218  }
2219  }
2220 
2221 
2227  public function getNbOfProductsLines()
2228  {
2229  $nb = 0;
2230  foreach ($this->lines as $line) {
2231  if ($line->product_type == 0) {
2232  $nb++;
2233  }
2234  }
2235  return $nb;
2236  }
2237 
2243  public function getNbOfServicesLines()
2244  {
2245  $nb = 0;
2246  foreach ($this->lines as $line) {
2247  if ($line->product_type == 1) {
2248  $nb++;
2249  }
2250  }
2251  return $nb;
2252  }
2253 
2259  public function getNbOfShipments()
2260  {
2261  $nb = 0;
2262 
2263  $sql = 'SELECT COUNT(DISTINCT ed.fk_expedition) as nb';
2264  $sql .= ' FROM '.MAIN_DB_PREFIX.'expeditiondet as ed,';
2265  $sql .= ' '.MAIN_DB_PREFIX.'commandedet as cd';
2266  $sql .= ' WHERE';
2267  $sql .= ' ed.fk_origin_line = cd.rowid';
2268  $sql .= ' AND cd.fk_commande = '.((int) $this->id);
2269  //print $sql;
2270 
2271  dol_syslog(get_class($this)."::getNbOfShipments", LOG_DEBUG);
2272  $resql = $this->db->query($sql);
2273  if ($resql) {
2274  $obj = $this->db->fetch_object($resql);
2275  if ($obj) {
2276  $nb = $obj->nb;
2277  }
2278 
2279  $this->db->free($resql);
2280  return $nb;
2281  } else {
2282  $this->error = $this->db->lasterror();
2283  return -1;
2284  }
2285  }
2286 
2295  public function loadExpeditions($filtre_statut = -1, $fk_product = 0)
2296  {
2297  $this->expeditions = array();
2298 
2299  $sql = 'SELECT cd.rowid, cd.fk_product,';
2300  $sql .= ' sum(ed.qty) as qty';
2301  $sql .= ' FROM '.MAIN_DB_PREFIX.'expeditiondet as ed,';
2302  if ($filtre_statut >= 0) {
2303  $sql .= ' '.MAIN_DB_PREFIX.'expedition as e,';
2304  }
2305  $sql .= ' '.MAIN_DB_PREFIX.'commandedet as cd';
2306  $sql .= ' WHERE';
2307  if ($filtre_statut >= 0) {
2308  $sql .= ' ed.fk_expedition = e.rowid AND';
2309  }
2310  $sql .= ' ed.fk_origin_line = cd.rowid';
2311  $sql .= ' AND cd.fk_commande = '.((int) $this->id);
2312  if ($fk_product > 0) {
2313  $sql .= ' AND cd.fk_product = '.((int) $fk_product);
2314  }
2315  if ($filtre_statut >= 0) {
2316  $sql .= ' AND e.fk_statut >= '.((int) $filtre_statut);
2317  }
2318  $sql .= ' GROUP BY cd.rowid, cd.fk_product';
2319  //print $sql;
2320 
2321  dol_syslog(get_class($this)."::loadExpeditions", LOG_DEBUG);
2322  $resql = $this->db->query($sql);
2323  if ($resql) {
2324  $num = $this->db->num_rows($resql);
2325  $i = 0;
2326  while ($i < $num) {
2327  $obj = $this->db->fetch_object($resql);
2328  $this->expeditions[$obj->rowid] = $obj->qty;
2329  $i++;
2330  }
2331  $this->db->free($resql);
2332  return $num;
2333  } else {
2334  $this->error = $this->db->lasterror();
2335  return -1;
2336  }
2337  }
2338 
2344  public function countNbOfShipments()
2345  {
2346  $sql = 'SELECT count(*)';
2347  $sql .= ' FROM '.MAIN_DB_PREFIX.'expedition as e';
2348  $sql .= ', '.MAIN_DB_PREFIX.'element_element as el';
2349  $sql .= ' WHERE el.fk_source = '.((int) $this->id);
2350  $sql .= " AND el.sourcetype = 'commande'";
2351  $sql .= " AND el.fk_target = e.rowid";
2352  $sql .= " AND el.targettype = 'shipping'";
2353 
2354  $resql = $this->db->query($sql);
2355  if ($resql) {
2356  $row = $this->db->fetch_row($resql);
2357  return $row[0];
2358  } else {
2359  dol_print_error($this->db);
2360  }
2361 
2362  return 0;
2363  }
2364 
2365  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2374  public function stock_array($filtre_statut = self::STATUS_CANCELED)
2375  {
2376  // phpcs:enable
2377  $this->stocks = array();
2378 
2379  // Tableau des id de produit de la commande
2380  $array_of_product = array();
2381 
2382  // Recherche total en stock pour chaque produit
2383  // TODO $array_of_product est défini vide juste au dessus !!
2384  if (count($array_of_product)) {
2385  $sql = "SELECT fk_product, sum(ps.reel) as total";
2386  $sql .= " FROM ".MAIN_DB_PREFIX."product_stock as ps";
2387  $sql .= " WHERE ps.fk_product IN (".$this->db->sanitize(join(',', $array_of_product)).")";
2388  $sql .= ' GROUP BY fk_product';
2389  $resql = $this->db->query($sql);
2390  if ($resql) {
2391  $num = $this->db->num_rows($resql);
2392  $i = 0;
2393  while ($i < $num) {
2394  $obj = $this->db->fetch_object($resql);
2395  $this->stocks[$obj->fk_product] = $obj->total;
2396  $i++;
2397  }
2398  $this->db->free($resql);
2399  }
2400  }
2401  return 0;
2402  }
2403 
2412  public function deleteline($user = null, $lineid = 0, $id = 0)
2413  {
2414  if ($this->statut == self::STATUS_DRAFT) {
2415  $this->db->begin();
2416 
2417  // Delete line
2418  $line = new OrderLine($this->db);
2419 
2420  $line->context = $this->context;
2421 
2422  // Load data
2423  $line->fetch($lineid);
2424 
2425  if ($id > 0 && $line->fk_commande != $id) {
2426  $this->error = 'ErrorLineIDDoesNotMatchWithObjectID';
2427  return -1;
2428  }
2429 
2430  // Memorize previous line for triggers
2431  $staticline = clone $line;
2432  $line->oldline = $staticline;
2433 
2434  if ($line->delete($user) > 0) {
2435  $result = $this->update_price(1);
2436 
2437  if ($result > 0) {
2438  $this->db->commit();
2439  return 1;
2440  } else {
2441  $this->db->rollback();
2442  $this->error = $this->db->lasterror();
2443  return -1;
2444  }
2445  } else {
2446  $this->db->rollback();
2447  $this->error = $line->error;
2448  return -1;
2449  }
2450  } else {
2451  $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
2452  return -1;
2453  }
2454  }
2455 
2456  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2467  public function set_remise($user, $remise, $notrigger = 0)
2468  {
2469  // phpcs:enable
2470  dol_syslog(get_class($this)."::set_remise is deprecated, use setDiscount instead", LOG_NOTICE);
2471  return $this->setDiscount($user, $remise, $notrigger);
2472  }
2473 
2483  public function setDiscount($user, $remise, $notrigger = 0)
2484  {
2485  $remise = trim($remise) ?trim($remise) : 0;
2486 
2487  if ($user->hasRight('commande', 'creer')) {
2488  $error = 0;
2489 
2490  $this->db->begin();
2491 
2492  $remise = price2num($remise, 2);
2493 
2494  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
2495  $sql .= ' SET remise_percent = '.((float) $remise);
2496  $sql .= ' WHERE rowid = '.((int) $this->id).' AND fk_statut = '.((int) self::STATUS_DRAFT);
2497 
2498  dol_syslog(__METHOD__, LOG_DEBUG);
2499  $resql = $this->db->query($sql);
2500  if (!$resql) {
2501  $this->errors[] = $this->db->error();
2502  $error++;
2503  }
2504 
2505  if (!$error) {
2506  $this->oldcopy = clone $this;
2507  $this->remise_percent = $remise;
2508  $this->update_price(1);
2509  }
2510 
2511  if (!$notrigger && empty($error)) {
2512  // Call trigger
2513  $result = $this->call_trigger('ORDER_MODIFY', $user);
2514  if ($result < 0) {
2515  $error++;
2516  }
2517  // End call triggers
2518  }
2519 
2520  if (!$error) {
2521  $this->db->commit();
2522  return 1;
2523  } else {
2524  foreach ($this->errors as $errmsg) {
2525  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2526  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2527  }
2528  $this->db->rollback();
2529  return -1 * $error;
2530  }
2531  }
2532 
2533  return 0;
2534  }
2535 
2536 
2537  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2546  public function set_remise_absolue($user, $remise, $notrigger = 0)
2547  {
2548  // phpcs:enable
2549  if (empty($remise)) {
2550  $remise = 0;
2551  }
2552 
2553  $remise = price2num($remise);
2554 
2555  if ($user->hasRight('commande', 'creer')) {
2556  $error = 0;
2557 
2558  $this->db->begin();
2559 
2560  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
2561  $sql .= ' SET remise_absolue = '.((float) $remise);
2562  $sql .= ' WHERE rowid = '.((int) $this->id).' AND fk_statut = '.self::STATUS_DRAFT;
2563 
2564  dol_syslog(__METHOD__, LOG_DEBUG);
2565  $resql = $this->db->query($sql);
2566  if (!$resql) {
2567  $this->errors[] = $this->db->error();
2568  $error++;
2569  }
2570 
2571  if (!$error) {
2572  $this->oldcopy = clone $this;
2573  $this->remise_absolue = $remise;
2574  $this->update_price(1);
2575  }
2576 
2577  if (!$notrigger && empty($error)) {
2578  // Call trigger
2579  $result = $this->call_trigger('ORDER_MODIFY', $user);
2580  if ($result < 0) {
2581  $error++;
2582  }
2583  // End call triggers
2584  }
2585 
2586  if (!$error) {
2587  $this->db->commit();
2588  return 1;
2589  } else {
2590  foreach ($this->errors as $errmsg) {
2591  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2592  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2593  }
2594  $this->db->rollback();
2595  return -1 * $error;
2596  }
2597  }
2598 
2599  return 0;
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->hasRight('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->hasRight('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->hasRight('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  $this->ref_customer = $ref_client;
2966  }
2967 
2968  if (!$notrigger && empty($error)) {
2969  // Call trigger
2970  $result = $this->call_trigger('ORDER_MODIFY', $user);
2971  if ($result < 0) {
2972  $error++;
2973  }
2974  // End call triggers
2975  }
2976  if (!$error) {
2977  $this->db->commit();
2978  return 1;
2979  } else {
2980  foreach ($this->errors as $errmsg) {
2981  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2982  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2983  }
2984  $this->db->rollback();
2985  return -1 * $error;
2986  }
2987  } else {
2988  return -1;
2989  }
2990  }
2991 
2999  public function classifyBilled(User $user, $notrigger = 0)
3000  {
3001  $error = 0;
3002 
3003  if ($this->billed) {
3004  return 0;
3005  }
3006 
3007  $this->db->begin();
3008 
3009  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande SET facture = 1';
3010  $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > '.self::STATUS_DRAFT;
3011 
3012  dol_syslog(get_class($this)."::classifyBilled", LOG_DEBUG);
3013  if ($this->db->query($sql)) {
3014  if (!$error) {
3015  $this->oldcopy = clone $this;
3016  $this->billed = 1;
3017  }
3018 
3019  if (!$notrigger && empty($error)) {
3020  // Call trigger
3021  $result = $this->call_trigger('ORDER_CLASSIFY_BILLED', $user);
3022  if ($result < 0) {
3023  $error++;
3024  }
3025  // End call triggers
3026  }
3027 
3028  if (!$error) {
3029  $this->db->commit();
3030  return 1;
3031  } else {
3032  foreach ($this->errors as $errmsg) {
3033  dol_syslog(get_class($this)."::classifyBilled ".$errmsg, LOG_ERR);
3034  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
3035  }
3036  $this->db->rollback();
3037  return -1 * $error;
3038  }
3039  } else {
3040  $this->error = $this->db->error();
3041  $this->db->rollback();
3042  return -1;
3043  }
3044  }
3045 
3053  public function classifyUnBilled(User $user, $notrigger = 0)
3054  {
3055  $error = 0;
3056 
3057  $this->db->begin();
3058 
3059  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande SET facture = 0';
3060  $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > '.self::STATUS_DRAFT;
3061 
3062  dol_syslog(get_class($this)."::classifyUnBilled", LOG_DEBUG);
3063  if ($this->db->query($sql)) {
3064  if (!$error) {
3065  $this->oldcopy = clone $this;
3066  $this->billed = 1;
3067  }
3068 
3069  if (!$notrigger && empty($error)) {
3070  // Call trigger
3071  $result = $this->call_trigger('ORDER_CLASSIFY_UNBILLED', $user);
3072  if ($result < 0) {
3073  $error++;
3074  }
3075  // End call triggers
3076  }
3077 
3078  if (!$error) {
3079  $this->billed = 0;
3080 
3081  $this->db->commit();
3082  return 1;
3083  } else {
3084  foreach ($this->errors as $errmsg) {
3085  dol_syslog(get_class($this)."::classifyUnBilled ".$errmsg, LOG_ERR);
3086  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
3087  }
3088  $this->db->rollback();
3089  return -1 * $error;
3090  }
3091  } else {
3092  $this->error = $this->db->error();
3093  $this->db->rollback();
3094  return -1;
3095  }
3096  }
3097 
3098 
3129  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)
3130  {
3131  global $conf, $mysoc, $langs, $user;
3132 
3133  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");
3134  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
3135 
3136  if ($this->statut == Commande::STATUS_DRAFT) {
3137  // Clean parameters
3138  if (empty($qty)) {
3139  $qty = 0;
3140  }
3141  if (empty($info_bits)) {
3142  $info_bits = 0;
3143  }
3144  if (empty($txtva)) {
3145  $txtva = 0;
3146  }
3147  if (empty($txlocaltax1)) {
3148  $txlocaltax1 = 0;
3149  }
3150  if (empty($txlocaltax2)) {
3151  $txlocaltax2 = 0;
3152  }
3153  if (empty($remise_percent)) {
3154  $remise_percent = 0;
3155  }
3156  if (empty($special_code) || $special_code == 3) {
3157  $special_code = 0;
3158  }
3159  if (empty($ref_ext)) {
3160  $ref_ext = '';
3161  }
3162 
3163  if ($date_start && $date_end && $date_start > $date_end) {
3164  $langs->load("errors");
3165  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
3166  return -1;
3167  }
3168 
3170  $qty = price2num($qty);
3171  $pu = price2num($pu);
3172  $pa_ht = price2num($pa_ht);
3173  $pu_ht_devise = price2num($pu_ht_devise);
3174  if (!preg_match('/\((.*)\)/', $txtva)) {
3175  $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
3176  }
3177  $txlocaltax1 = price2num($txlocaltax1);
3178  $txlocaltax2 = price2num($txlocaltax2);
3179 
3180  $this->db->begin();
3181 
3182  // Calcul du total TTC et de la TVA pour la ligne a partir de
3183  // qty, pu, remise_percent et txtva
3184  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
3185  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
3186 
3187  $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
3188 
3189  // Clean vat code
3190  $vat_src_code = '';
3191  $reg = array();
3192  if (preg_match('/\((.*)\)/', $txtva, $reg)) {
3193  $vat_src_code = $reg[1];
3194  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
3195  }
3196 
3197  $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);
3198 
3199  $total_ht = $tabprice[0];
3200  $total_tva = $tabprice[1];
3201  $total_ttc = $tabprice[2];
3202  $total_localtax1 = $tabprice[9];
3203  $total_localtax2 = $tabprice[10];
3204  $pu_ht = $tabprice[3];
3205  $pu_tva = $tabprice[4];
3206  $pu_ttc = $tabprice[5];
3207 
3208  // MultiCurrency
3209  $multicurrency_total_ht = $tabprice[16];
3210  $multicurrency_total_tva = $tabprice[17];
3211  $multicurrency_total_ttc = $tabprice[18];
3212  $pu_ht_devise = $tabprice[19];
3213 
3214  // Anciens indicateurs: $price, $subprice (a ne plus utiliser)
3215  $price = $pu_ht;
3216  if ($price_base_type == 'TTC') {
3217  $subprice = $pu_ttc;
3218  } else {
3219  $subprice = $pu_ht;
3220  }
3221  $remise = 0;
3222  if ($remise_percent > 0) {
3223  $remise = round(($pu * $remise_percent / 100), 2);
3224  $price = ($pu - $remise);
3225  }
3226 
3227  //Fetch current line from the database and then clone the object and set it in $oldline property
3228  $line = new OrderLine($this->db);
3229  $line->fetch($rowid);
3230  $line->fetch_optionals();
3231 
3232  if (!empty($line->fk_product)) {
3233  $product = new Product($this->db);
3234  $result = $product->fetch($line->fk_product);
3235  $product_type = $product->type;
3236 
3237  if (!empty($conf->global->STOCK_MUST_BE_ENOUGH_FOR_ORDER) && $product_type == 0 && $product->stock_reel < $qty) {
3238  $langs->load("errors");
3239  $this->error = $langs->trans('ErrorStockIsNotEnoughToAddProductOnOrder', $product->ref);
3240  $this->errors[] = $this->error;
3241 
3242  dol_syslog(get_class($this)."::addline error=Product ".$product->ref.": ".$this->error, LOG_ERR);
3243 
3244  $this->db->rollback();
3246  }
3247  }
3248 
3249  $staticline = clone $line;
3250 
3251  $line->oldline = $staticline;
3252  $this->line = $line;
3253  $this->line->context = $this->context;
3254  $this->line->rang = $rang;
3255 
3256  // Reorder if fk_parent_line change
3257  if (!empty($fk_parent_line) && !empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line) {
3258  $rangmax = $this->line_max($fk_parent_line);
3259  $this->line->rang = $rangmax + 1;
3260  }
3261 
3262  $this->line->id = $rowid;
3263  $this->line->label = $label;
3264  $this->line->desc = $desc;
3265  $this->line->qty = $qty;
3266  $this->line->ref_ext = $ref_ext;
3267 
3268  $this->line->vat_src_code = $vat_src_code;
3269  $this->line->tva_tx = $txtva;
3270  $this->line->localtax1_tx = $txlocaltax1;
3271  $this->line->localtax2_tx = $txlocaltax2;
3272  $this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
3273  $this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
3274  $this->line->remise_percent = $remise_percent;
3275  $this->line->subprice = $subprice;
3276  $this->line->info_bits = $info_bits;
3277  $this->line->special_code = $special_code;
3278  $this->line->total_ht = $total_ht;
3279  $this->line->total_tva = $total_tva;
3280  $this->line->total_localtax1 = $total_localtax1;
3281  $this->line->total_localtax2 = $total_localtax2;
3282  $this->line->total_ttc = $total_ttc;
3283  $this->line->date_start = $date_start;
3284  $this->line->date_end = $date_end;
3285  $this->line->product_type = $type;
3286  $this->line->fk_parent_line = $fk_parent_line;
3287  $this->line->skip_update_total = $skip_update_total;
3288  $this->line->fk_unit = $fk_unit;
3289 
3290  $this->line->fk_fournprice = $fk_fournprice;
3291  $this->line->pa_ht = $pa_ht;
3292 
3293  // Multicurrency
3294  $this->line->multicurrency_subprice = $pu_ht_devise;
3295  $this->line->multicurrency_total_ht = $multicurrency_total_ht;
3296  $this->line->multicurrency_total_tva = $multicurrency_total_tva;
3297  $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
3298 
3299  // TODO deprecated
3300  $this->line->price = $price;
3301 
3302  if (is_array($array_options) && count($array_options) > 0) {
3303  // We replace values in this->line->array_options only for entries defined into $array_options
3304  foreach ($array_options as $key => $value) {
3305  $this->line->array_options[$key] = $array_options[$key];
3306  }
3307  }
3308 
3309  $result = $this->line->update($user, $notrigger);
3310  if ($result > 0) {
3311  // Reorder if child line
3312  if (!empty($fk_parent_line)) {
3313  $this->line_order(true, 'DESC');
3314  }
3315 
3316  // Mise a jour info denormalisees
3317  $this->update_price(1, 'auto');
3318 
3319  $this->db->commit();
3320  return $result;
3321  } else {
3322  $this->error = $this->line->error;
3323 
3324  $this->db->rollback();
3325  return -1;
3326  }
3327  } else {
3328  $this->error = get_class($this)."::updateline Order status makes operation forbidden";
3329  $this->errors = array('OrderStatusMakeOperationForbidden');
3330  return -2;
3331  }
3332  }
3333 
3341  public function update(User $user, $notrigger = 0)
3342  {
3343  global $conf;
3344 
3345  $error = 0;
3346 
3347  // Clean parameters
3348  if (isset($this->ref)) {
3349  $this->ref = trim($this->ref);
3350  }
3351  if (isset($this->ref_client)) {
3352  $this->ref_client = trim($this->ref_client);
3353  }
3354  if (isset($this->ref_customer)) {
3355  $this->ref_customer = trim($this->ref_customer);
3356  }
3357  if (isset($this->note) || isset($this->note_private)) {
3358  $this->note_private = (isset($this->note_private) ? trim($this->note_private) : trim($this->note));
3359  }
3360  if (isset($this->note_public)) {
3361  $this->note_public = trim($this->note_public);
3362  }
3363  if (isset($this->model_pdf)) {
3364  $this->model_pdf = trim($this->model_pdf);
3365  }
3366  if (isset($this->import_key)) {
3367  $this->import_key = trim($this->import_key);
3368  }
3369  $delivery_date = empty($this->delivery_date) ? $this->date_livraison : $this->delivery_date;
3370 
3371  // Check parameters
3372  // Put here code to add control on parameters values
3373 
3374  // Update request
3375  $sql = "UPDATE ".MAIN_DB_PREFIX."commande SET";
3376 
3377  $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").",";
3378  $sql .= " ref_client=".(isset($this->ref_client) ? "'".$this->db->escape($this->ref_client)."'" : "null").",";
3379  $sql .= " ref_ext=".(isset($this->ref_ext) ? "'".$this->db->escape($this->ref_ext)."'" : "null").",";
3380  $sql .= " fk_soc=".(isset($this->socid) ? $this->socid : "null").",";
3381  $sql .= " date_commande=".(strval($this->date_commande) != '' ? "'".$this->db->idate($this->date_commande)."'" : 'null').",";
3382  $sql .= " date_valid=".(strval($this->date_validation) != '' ? "'".$this->db->idate($this->date_validation)."'" : 'null').",";
3383  $sql .= " total_tva=".(isset($this->total_tva) ? $this->total_tva : "null").",";
3384  $sql .= " localtax1=".(isset($this->total_localtax1) ? $this->total_localtax1 : "null").",";
3385  $sql .= " localtax2=".(isset($this->total_localtax2) ? $this->total_localtax2 : "null").",";
3386  $sql .= " total_ht=".(isset($this->total_ht) ? $this->total_ht : "null").",";
3387  $sql .= " total_ttc=".(isset($this->total_ttc) ? $this->total_ttc : "null").",";
3388  $sql .= " fk_statut=".(isset($this->statut) ? $this->statut : "null").",";
3389  $sql .= " fk_user_author=".(isset($this->user_author_id) ? $this->user_author_id : "null").",";
3390  $sql .= " fk_user_valid=".((isset($this->user_valid) && $this->user_valid > 0) ? $this->user_valid : "null").",";
3391  $sql .= " fk_projet=".(isset($this->fk_project) ? $this->fk_project : "null").",";
3392  $sql .= " fk_cond_reglement=".(isset($this->cond_reglement_id) ? $this->cond_reglement_id : "null").",";
3393  $sql .= " deposit_percent=".(!empty($this->deposit_percent) ? strval($this->deposit_percent) : "null").",";
3394  $sql .= " fk_mode_reglement=".(isset($this->mode_reglement_id) ? $this->mode_reglement_id : "null").",";
3395  $sql .= " date_livraison=".(strval($this->delivery_date) != '' ? "'".$this->db->idate($this->delivery_date)."'" : 'null').",";
3396  $sql .= " fk_shipping_method=".(isset($this->shipping_method_id) ? $this->shipping_method_id : "null").",";
3397  $sql .= " fk_account=".($this->fk_account > 0 ? $this->fk_account : "null").",";
3398  $sql .= " fk_input_reason=".($this->demand_reason_id > 0 ? $this->demand_reason_id : "null").",";
3399  $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
3400  $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
3401  $sql .= " model_pdf=".(isset($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null").",";
3402  $sql .= " import_key=".(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null");
3403 
3404  $sql .= " WHERE rowid=".((int) $this->id);
3405 
3406  $this->db->begin();
3407 
3408  dol_syslog(get_class($this)."::update", LOG_DEBUG);
3409  $resql = $this->db->query($sql);
3410  if (!$resql) {
3411  $error++; $this->errors[] = "Error ".$this->db->lasterror();
3412  }
3413 
3414  if (!$error) {
3415  $result = $this->insertExtraFields();
3416  if ($result < 0) {
3417  $error++;
3418  }
3419  }
3420 
3421  if (!$error && !$notrigger) {
3422  // Call trigger
3423  $result = $this->call_trigger('ORDER_MODIFY', $user);
3424  if ($result < 0) {
3425  $error++;
3426  }
3427  // End call triggers
3428  }
3429 
3430  // Commit or rollback
3431  if ($error) {
3432  foreach ($this->errors as $errmsg) {
3433  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
3434  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
3435  }
3436  $this->db->rollback();
3437  return -1 * $error;
3438  } else {
3439  $this->db->commit();
3440  return 1;
3441  }
3442  }
3443 
3451  public function delete($user, $notrigger = 0)
3452  {
3453  global $conf, $langs;
3454  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
3455 
3456  $error = 0;
3457 
3458  dol_syslog(get_class($this)."::delete ".$this->id, LOG_DEBUG);
3459 
3460  $this->db->begin();
3461 
3462  if (!$notrigger) {
3463  // Call trigger
3464  $result = $this->call_trigger('ORDER_DELETE', $user);
3465  if ($result < 0) {
3466  $error++;
3467  }
3468  // End call triggers
3469  }
3470 
3471  // Test we can delete
3472  if ($this->countNbOfShipments() != 0) {
3473  $this->errors[] = $langs->trans('SomeShipmentExists');
3474  $error++;
3475  }
3476 
3477  // Delete extrafields of lines and lines
3478  if (!$error && !empty($this->table_element_line)) {
3479  $tabletodelete = $this->table_element_line;
3480  $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).")";
3481  $sql = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".((int) $this->id);
3482  if (!$this->db->query($sqlef) || !$this->db->query($sql)) {
3483  $error++;
3484  $this->error = $this->db->lasterror();
3485  $this->errors[] = $this->error;
3486  dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
3487  }
3488  }
3489 
3490  if (!$error) {
3491  // Delete linked object
3492  $res = $this->deleteObjectLinked();
3493  if ($res < 0) {
3494  $error++;
3495  }
3496  }
3497 
3498  if (!$error) {
3499  // Delete linked contacts
3500  $res = $this->delete_linked_contact();
3501  if ($res < 0) {
3502  $error++;
3503  }
3504  }
3505 
3506  // Removed extrafields of object
3507  if (!$error) {
3508  $result = $this->deleteExtraFields();
3509  if ($result < 0) {
3510  $error++;
3511  dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
3512  }
3513  }
3514 
3515  // Delete main record
3516  if (!$error) {
3517  $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element." WHERE rowid = ".((int) $this->id);
3518  $res = $this->db->query($sql);
3519  if (!$res) {
3520  $error++;
3521  $this->error = $this->db->lasterror();
3522  $this->errors[] = $this->error;
3523  dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
3524  }
3525  }
3526 
3527  // Delete record into ECM index and physically
3528  if (!$error) {
3529  $res = $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive
3530  if (!$res) {
3531  $error++;
3532  }
3533  }
3534 
3535  if (!$error) {
3536  // We remove directory
3537  $ref = dol_sanitizeFileName($this->ref);
3538  if ($conf->commande->multidir_output[$this->entity] && !empty($this->ref)) {
3539  $dir = $conf->commande->multidir_output[$this->entity]."/".$ref;
3540  $file = $dir."/".$ref.".pdf";
3541  if (file_exists($file)) {
3542  dol_delete_preview($this);
3543 
3544  if (!dol_delete_file($file, 0, 0, 0, $this)) {
3545  $this->error = 'ErrorFailToDeleteFile';
3546  $this->errors[] = $this->error;
3547  $this->db->rollback();
3548  return 0;
3549  }
3550  }
3551  if (file_exists($dir)) {
3552  $res = @dol_delete_dir_recursive($dir);
3553  if (!$res) {
3554  $this->error = 'ErrorFailToDeleteDir';
3555  $this->errors[] = $this->error;
3556  $this->db->rollback();
3557  return 0;
3558  }
3559  }
3560  }
3561  }
3562 
3563  if (!$error) {
3564  dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
3565  $this->db->commit();
3566  return 1;
3567  } else {
3568  $this->db->rollback();
3569  return -1;
3570  }
3571  }
3572 
3573 
3574  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3582  public function load_board($user, $mode)
3583  {
3584  // phpcs:enable
3585  global $conf, $langs;
3586 
3587  $clause = " WHERE";
3588 
3589  $sql = "SELECT c.rowid, c.date_creation as datec, c.date_commande, c.date_livraison as delivery_date, c.fk_statut, c.total_ht";
3590  $sql .= " FROM ".MAIN_DB_PREFIX."commande as c";
3591  if (empty($user->rights->societe->client->voir) && !$user->socid) {
3592  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON c.fk_soc = sc.fk_soc";
3593  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
3594  $clause = " AND";
3595  }
3596  $sql .= $clause." c.entity IN (".getEntity('commande').")";
3597  //$sql.= " AND c.fk_statut IN (1,2,3) AND c.facture = 0";
3598  if ($mode == 'toship') {
3599  // An order to ship is an open order (validated or in progress)
3600  $sql .= " AND c.fk_statut IN (" . self::STATUS_VALIDATED . "," . self::STATUS_SHIPMENTONPROCESS . ")";
3601  }
3602  if ($mode == 'tobill') {
3603  // An order to bill is an order not already billed
3604  $sql .= " AND c.fk_statut IN (" . self::STATUS_VALIDATED . "," . self::STATUS_SHIPMENTONPROCESS . ", " . self::STATUS_CLOSED . ") AND c.facture = 0";
3605  }
3606  if ($mode == 'shippedtobill') {
3607  // An order shipped and to bill is a delivered order not already billed
3608  $sql .= " AND c.fk_statut IN (" . self::STATUS_CLOSED . ") AND c.facture = 0";
3609  }
3610  if ($user->socid) {
3611  $sql .= " AND c.fk_soc = ".((int) $user->socid);
3612  }
3613 
3614  $resql = $this->db->query($sql);
3615  if ($resql) {
3616  $delay_warning = 0;
3617  $label = $labelShort = $url = '';
3618  if ($mode == 'toship') {
3619  $delay_warning = $conf->commande->client->warning_delay / 60 / 60 / 24;
3620  $url = DOL_URL_ROOT.'/commande/list.php?search_status=-2&mainmenu=commercial&leftmenu=orders';
3621  $label = $langs->transnoentitiesnoconv("OrdersToProcess");
3622  $labelShort = $langs->transnoentitiesnoconv("Opened");
3623  }
3624  if ($mode == 'tobill') {
3625  $url = DOL_URL_ROOT.'/commande/list.php?search_status=-3&search_billed=0&mainmenu=commercial&leftmenu=orders';
3626  $label = $langs->trans("OrdersToBill"); // We set here bill but may be billed or ordered
3627  $labelShort = $langs->trans("ToBill");
3628  }
3629  if ($mode == 'shippedtobill') {
3630  $url = DOL_URL_ROOT.'/commande/list.php?search_status=3&search_billed=0&mainmenu=commercial&leftmenu=orders';
3631  $label = $langs->trans("OrdersToBill"); // We set here bill but may be billed or ordered
3632  $labelShort = $langs->trans("StatusOrderDelivered").' '.$langs->trans("and").' '.$langs->trans("ToBill");
3633  }
3634 
3635  $response = new WorkboardResponse();
3636  $response->warning_delay = $delay_warning;
3637  $response->label = $label;
3638  $response->labelShort = $labelShort;
3639  $response->url = $url;
3640  $response->img = img_object('', "order");
3641 
3642  $generic_commande = new Commande($this->db);
3643 
3644  while ($obj = $this->db->fetch_object($resql)) {
3645  $response->nbtodo++;
3646  $response->total += $obj->total_ht;
3647 
3648  $generic_commande->statut = $obj->fk_statut;
3649  $generic_commande->date_commande = $this->db->jdate($obj->date_commande);
3650  $generic_commande->date = $this->db->jdate($obj->date_commande);
3651  $generic_commande->date_livraison = $this->db->jdate($obj->delivery_date);
3652  $generic_commande->delivery_date = $this->db->jdate($obj->delivery_date);
3653 
3654  if ($mode == 'toship' && $generic_commande->hasDelay()) {
3655  $response->nbtodolate++;
3656  }
3657  }
3658 
3659  return $response;
3660  } else {
3661  $this->error = $this->db->error();
3662  return -1;
3663  }
3664  }
3665 
3671  public function getLabelSource()
3672  {
3673  global $langs;
3674 
3675  $label = $langs->trans('OrderSource'.$this->source);
3676 
3677  if ($label == 'OrderSource') {
3678  return '';
3679  }
3680  return $label;
3681  }
3682 
3689  public function getLibStatut($mode)
3690  {
3691  return $this->LibStatut($this->statut, $this->billed, $mode);
3692  }
3693 
3694  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3704  public function LibStatut($status, $billed, $mode, $donotshowbilled = 0)
3705  {
3706  // phpcs:enable
3707  global $langs, $conf, $hookmanager;
3708 
3709  $billedtext = '';
3710  if (empty($donotshowbilled)) {
3711  $billedtext .= ($billed ? ' - '.$langs->transnoentitiesnoconv("Billed") : '');
3712  }
3713 
3714  $labelTooltip = '';
3715 
3716  if ($status == self::STATUS_CANCELED) {
3717  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderCanceled');
3718  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderCanceledShort');
3719  $statusType = 'status9';
3720  } elseif ($status == self::STATUS_DRAFT) {
3721  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderDraft');
3722  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderDraftShort');
3723  $statusType = 'status0';
3724  } elseif ($status == self::STATUS_VALIDATED) {
3725  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderValidated').$billedtext;
3726  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderValidatedShort').$billedtext;
3727  $statusType = 'status1';
3728  } elseif ($status == self::STATUS_SHIPMENTONPROCESS) {
3729  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderSent').$billedtext;
3730  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderSentShort').$billedtext;
3731  $labelTooltip = $langs->transnoentitiesnoconv("StatusOrderSent");
3732  if (!empty($this->delivery_date)) {
3733  $labelTooltip .= ' - '.$langs->transnoentitiesnoconv("DateDeliveryPlanned").dol_print_date($this->delivery_date, 'day').$billedtext;
3734  }
3735  $statusType = 'status4';
3736  } elseif ($status == self::STATUS_CLOSED && (!$billed && empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) {
3737  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderToBill'); // translated into Delivered
3738  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderToBillShort'); // translated into Delivered
3739  $statusType = 'status4';
3740  } elseif ($status == self::STATUS_CLOSED && ($billed && empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) {
3741  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderProcessed').$billedtext;
3742  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderProcessedShort').$billedtext;
3743  $statusType = 'status6';
3744  } elseif ($status == self::STATUS_CLOSED && (!empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) {
3745  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderDelivered');
3746  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderDeliveredShort');
3747  $statusType = 'status6';
3748  } else {
3749  $labelStatus = $langs->transnoentitiesnoconv('Unknown');
3750  $labelStatusShort = '';
3751  $statusType = '';
3752  $mode = 0;
3753  }
3754 
3755  $parameters = array(
3756  'status' => $status,
3757  'mode' => $mode,
3758  'billed' => $billed,
3759  'donotshowbilled' => $donotshowbilled
3760  );
3761 
3762  $reshook = $hookmanager->executeHooks('LibStatut', $parameters, $this); // Note that $action and $object may have been modified by hook
3763 
3764  if ($reshook > 0) {
3765  return $hookmanager->resPrint;
3766  }
3767 
3768  return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode, '', array('tooltip' => $labelTooltip));
3769  }
3770 
3777  public function getTooltipContentArray($params)
3778  {
3779  global $conf, $langs, $user;
3780 
3781  $langs->load('orders');
3782  $datas = [];
3783  $nofetch = !empty($params['nofetch']);
3784 
3785  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
3786  return ['optimize' => $langs->trans("Order")];
3787  }
3788 
3789  if ($user->hasRight('commande', 'lire')) {
3790  $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("Order").'</u>';
3791  if (isset($this->statut)) {
3792  $datas['status'] = ' '.$this->getLibStatut(5);
3793  }
3794  $datas['Ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
3795  if (!$nofetch) {
3796  $langs->load('companies');
3797  if (empty($this->thirdparty)) {
3798  $this->fetch_thirdparty();
3799  }
3800  $datas['customer'] = '<br><b>'.$langs->trans('Customer').':</b> '.$this->thirdparty->getNomUrl(1, '', 0, 1);
3801  }
3802  $datas['RefCustomer'] = '<br><b>'.$langs->trans('RefCustomer').':</b> '.(empty($this->ref_customer) ? (empty($this->ref_client) ? '' : $this->ref_client) : $this->ref_customer);
3803  if (!$nofetch) {
3804  $langs->load('project');
3805  if (empty($this->project)) {
3806  $res = $this->fetch_project();
3807  if ($res > 0) {
3808  $datas['project'] = '<br><b>'.$langs->trans('Project').':</b> '.$this->project->getNomUrl(1, '', 0, 1);
3809  }
3810  }
3811  }
3812  if (!empty($this->total_ht)) {
3813  $datas['AmountHT'] = '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
3814  }
3815  if (!empty($this->total_tva)) {
3816  $datas['VAT'] = '<br><b>'.$langs->trans('VAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
3817  }
3818  if (!empty($this->total_ttc)) {
3819  $datas['AmountTTC'] = '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
3820  }
3821  if (!empty($this->date)) {
3822  $datas['Date'] = '<br><b>'.$langs->trans('Date').':</b> '.dol_print_date($this->date, 'day');
3823  }
3824  if (!empty($this->delivery_date)) {
3825  $datas['DeliveryDate'] = '<br><b>'.$langs->trans('DeliveryDate').':</b> '.dol_print_date($this->delivery_date, 'dayhour');
3826  }
3827  }
3828 
3829  return $datas;
3830  }
3831 
3845  public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0, $target = '')
3846  {
3847  global $conf, $langs, $user, $hookmanager;
3848 
3849  if (!empty($conf->dol_no_mouse_hover)) {
3850  $notooltip = 1; // Force disable tooltips
3851  }
3852 
3853  $result = '';
3854 
3855  if (isModEnabled("expedition") && ($option == '1' || $option == '2')) {
3856  $url = DOL_URL_ROOT.'/expedition/shipment.php?id='.$this->id;
3857  } else {
3858  $url = DOL_URL_ROOT.'/commande/card.php?id='.$this->id;
3859  }
3860 
3861  if (!$user->rights->commande->lire) {
3862  $option = 'nolink';
3863  }
3864 
3865  if ($option !== 'nolink') {
3866  // Add param to save lastsearch_values or not
3867  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
3868  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
3869  $add_save_lastsearch_values = 1;
3870  }
3871  if ($add_save_lastsearch_values) {
3872  $url .= '&save_lastsearch_values=1';
3873  }
3874  }
3875 
3876  if ($short) {
3877  return $url;
3878  }
3879  $params = [
3880  'id' => $this->id,
3881  'objecttype' => $this->element,
3882  'option' => $option,
3883  'nofetch' => 1,
3884  ];
3885  $classfortooltip = 'classfortooltip';
3886  $dataparams = '';
3887  if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
3888  $classfortooltip = 'classforajaxtooltip';
3889  $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
3890  $label = '';
3891  } else {
3892  $label = implode($this->getTooltipContentArray($params));
3893  }
3894 
3895  $linkclose = '';
3896  if (empty($notooltip) && $user->hasRight('commande', 'lire')) {
3897  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
3898  $label = $langs->trans("Order");
3899  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
3900  }
3901  $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
3902  $linkclose .= $dataparams.' class="'.$classfortooltip.'"';
3903 
3904  $target_value = array('_self', '_blank', '_parent', '_top');
3905  if (in_array($target, $target_value)) {
3906  $linkclose .= ' target="'.dol_escape_htmltag($target).'"';
3907  }
3908  }
3909 
3910  $linkstart = '<a href="'.$url.'"';
3911  $linkstart .= $linkclose.'>';
3912  $linkend = '</a>';
3913 
3914  if ($option === 'nolink') {
3915  $linkstart = '';
3916  $linkend = '';
3917  }
3918 
3919  $result .= $linkstart;
3920  if ($withpicto) {
3921  $result .= img_object(($notooltip ? '' : $label), $this->picto, (($withpicto != 2) ? 'class="paddingright"' : ''), 0, 0, $notooltip ? 0 : 1);
3922  }
3923  if ($withpicto != 2) {
3924  $result .= $this->ref;
3925  }
3926  $result .= $linkend;
3927 
3928  if ($addlinktonotes) {
3929  $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
3930  if ($txttoshow) {
3931  $notetoshow = $langs->trans("ViewPrivateNote").':<br>'.dol_string_nohtmltag($txttoshow, 1);
3932  $result .= ' <span class="note inline-block">';
3933  $result .= '<a href="'.DOL_URL_ROOT.'/commande/note.php?id='.$this->id.'" class="classfortooltip" title="'.dol_escape_htmltag($notetoshow).'">';
3934  $result .= img_picto('', 'note');
3935  $result .= '</a>';
3936  //$result.=img_picto($langs->trans("ViewNote"),'object_generic');
3937  //$result.='</a>';
3938  $result .= '</span>';
3939  }
3940  }
3941 
3942  global $action;
3943  $hookmanager->initHooks(array($this->element . 'dao'));
3944  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
3945  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3946  if ($reshook > 0) {
3947  $result = $hookmanager->resPrint;
3948  } else {
3949  $result .= $hookmanager->resPrint;
3950  }
3951  return $result;
3952  }
3953 
3954 
3961  public function info($id)
3962  {
3963  $sql = 'SELECT c.rowid, date_creation as datec, tms as datem,';
3964  $sql .= ' date_valid as datev,';
3965  $sql .= ' date_cloture as datecloture,';
3966  $sql .= ' fk_user_author, fk_user_valid, fk_user_cloture';
3967  $sql .= ' FROM '.MAIN_DB_PREFIX.'commande as c';
3968  $sql .= ' WHERE c.rowid = '.((int) $id);
3969  $result = $this->db->query($sql);
3970  if ($result) {
3971  if ($this->db->num_rows($result)) {
3972  $obj = $this->db->fetch_object($result);
3973  $this->id = $obj->rowid;
3974  if ($obj->fk_user_author) {
3975  $this->user_creation_id = $obj->fk_user_author;
3976  }
3977  if ($obj->fk_user_valid) {
3978  $this->user_validation_id = $obj->fk_user_valid;
3979  }
3980  if ($obj->fk_user_cloture) {
3981  $this->user_closing_id = $obj->fk_user_cloture;
3982  }
3983 
3984  $this->date_creation = $this->db->jdate($obj->datec);
3985  $this->date_modification = $this->db->jdate($obj->datem);
3986  $this->date_validation = $this->db->jdate($obj->datev);
3987  $this->date_cloture = $this->db->jdate($obj->datecloture);
3988  }
3989 
3990  $this->db->free($result);
3991  } else {
3992  dol_print_error($this->db);
3993  }
3994  }
3995 
3996 
4004  public function initAsSpecimen()
4005  {
4006  global $conf, $langs;
4007 
4008  dol_syslog(get_class($this)."::initAsSpecimen");
4009 
4010  // Load array of products prodids
4011  $num_prods = 0;
4012  $prodids = array();
4013  $sql = "SELECT rowid";
4014  $sql .= " FROM ".MAIN_DB_PREFIX."product";
4015  $sql .= " WHERE entity IN (".getEntity('product').")";
4016  $sql .= $this->db->plimit(100);
4017 
4018  $resql = $this->db->query($sql);
4019  if ($resql) {
4020  $num_prods = $this->db->num_rows($resql);
4021  $i = 0;
4022  while ($i < $num_prods) {
4023  $i++;
4024  $row = $this->db->fetch_row($resql);
4025  $prodids[$i] = $row[0];
4026  }
4027  }
4028 
4029  // Initialise parametres
4030  $this->id = 0;
4031  $this->ref = 'SPECIMEN';
4032  $this->specimen = 1;
4033  $this->entity = $conf->entity;
4034  $this->socid = 1;
4035  $this->date = time();
4036  $this->date_lim_reglement = $this->date + 3600 * 24 * 30;
4037  $this->cond_reglement_code = 'RECEP';
4038  $this->mode_reglement_code = 'CHQ';
4039  $this->availability_code = 'DSP';
4040  $this->demand_reason_code = 'SRC_00';
4041 
4042  $this->note_public = 'This is a comment (public)';
4043  $this->note_private = 'This is a comment (private)';
4044 
4045  $this->multicurrency_tx = 1;
4046  $this->multicurrency_code = $conf->currency;
4047 
4048  // Lines
4049  $nbp = 5;
4050  $xnbp = 0;
4051  while ($xnbp < $nbp) {
4052  $line = new OrderLine($this->db);
4053 
4054  $line->desc = $langs->trans("Description")." ".$xnbp;
4055  $line->qty = 1;
4056  $line->subprice = 100;
4057  $line->price = 100;
4058  $line->tva_tx = 20;
4059  if ($xnbp == 2) {
4060  $line->total_ht = 50;
4061  $line->total_ttc = 60;
4062  $line->total_tva = 10;
4063  $line->remise_percent = 50;
4064  } else {
4065  $line->total_ht = 100;
4066  $line->total_ttc = 120;
4067  $line->total_tva = 20;
4068  $line->remise_percent = 0;
4069  }
4070  if ($num_prods > 0) {
4071  $prodid = mt_rand(1, $num_prods);
4072  $line->fk_product = $prodids[$prodid];
4073  $line->product_ref = 'SPECIMEN';
4074  }
4075 
4076  $this->lines[$xnbp] = $line;
4077 
4078  $this->total_ht += $line->total_ht;
4079  $this->total_tva += $line->total_tva;
4080  $this->total_ttc += $line->total_ttc;
4081 
4082  $xnbp++;
4083  }
4084  }
4085 
4086 
4087  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4093  public function load_state_board()
4094  {
4095  // phpcs:enable
4096  global $user;
4097 
4098  $this->nb = array();
4099  $clause = "WHERE";
4100 
4101  $sql = "SELECT count(co.rowid) as nb";
4102  $sql .= " FROM ".MAIN_DB_PREFIX."commande as co";
4103  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON co.fk_soc = s.rowid";
4104  if (empty($user->rights->societe->client->voir) && !$user->socid) {
4105  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
4106  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
4107  $clause = "AND";
4108  }
4109  $sql .= " ".$clause." co.entity IN (".getEntity('commande').")";
4110 
4111  $resql = $this->db->query($sql);
4112  if ($resql) {
4113  while ($obj = $this->db->fetch_object($resql)) {
4114  $this->nb["orders"] = $obj->nb;
4115  }
4116  $this->db->free($resql);
4117  return 1;
4118  } else {
4119  dol_print_error($this->db);
4120  $this->error = $this->db->error();
4121  return -1;
4122  }
4123  }
4124 
4130  public function getLinesArray()
4131  {
4132  return $this->fetch_lines();
4133  }
4134 
4146  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
4147  {
4148  global $conf, $langs;
4149 
4150  $langs->load("orders");
4151  $outputlangs->load("products");
4152 
4153  if (!dol_strlen($modele)) {
4154  $modele = 'einstein';
4155 
4156  if (!empty($this->model_pdf)) {
4157  $modele = $this->model_pdf;
4158  } elseif (!empty($this->modelpdf)) { // deprecated
4159  $modele = $this->modelpdf;
4160  } elseif (!empty($conf->global->COMMANDE_ADDON_PDF)) {
4161  $modele = $conf->global->COMMANDE_ADDON_PDF;
4162  }
4163  }
4164 
4165  $modelpath = "core/modules/commande/doc/";
4166 
4167  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
4168  }
4169 
4170 
4179  public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
4180  {
4181  $tables = array(
4182  'commande'
4183  );
4184 
4185  return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
4186  }
4187 
4196  public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
4197  {
4198  $tables = array(
4199  'commandedet',
4200  );
4201 
4202  return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
4203  }
4204 
4210  public function hasDelay()
4211  {
4212  global $conf;
4213 
4214  if (!($this->statut > Commande::STATUS_DRAFT && $this->statut < Commande::STATUS_CLOSED)) {
4215  return false; // Never late if not inside this status range
4216  }
4217 
4218  $now = dol_now();
4219 
4220  return max($this->date, $this->delivery_date) < ($now - $conf->commande->client->warning_delay);
4221  }
4222 
4228  public function showDelay()
4229  {
4230  global $conf, $langs;
4231 
4232  if (empty($this->delivery_date)) {
4233  $text = $langs->trans("OrderDate").' '.dol_print_date($this->date_commande, 'day');
4234  } else {
4235  $text = $text = $langs->trans("DeliveryDate").' '.dol_print_date($this->date_livraison, 'day');
4236  }
4237  $text .= ' '.($conf->commande->client->warning_delay > 0 ? '+' : '-').' '.round(abs($conf->commande->client->warning_delay) / 3600 / 24, 1).' '.$langs->trans("days").' < '.$langs->trans("Today");
4238 
4239  return $text;
4240  }
4241 }
4242 
4243 
4248 {
4252  public $element = 'commandedet';
4253 
4254  public $table_element = 'commandedet';
4255 
4256  public $oldline;
4257 
4262  public $fk_commande;
4263 
4270  public $commande_id;
4271 
4272  public $fk_parent_line;
4273 
4277  public $fk_facture;
4278 
4282  public $ref_ext;
4283 
4284  public $fk_remise_except;
4285 
4289  public $rang = 0;
4290  public $fk_fournprice;
4291 
4296  public $pa_ht;
4297  public $marge_tx;
4298  public $marque_tx;
4299 
4304  public $remise;
4305 
4306  // Start and end date of the line
4307  public $date_start;
4308  public $date_end;
4309 
4310  public $skip_update_total; // Skip update price total for special lines
4311 
4312 
4318  public function __construct($db)
4319  {
4320  $this->db = $db;
4321  }
4322 
4329  public function fetch($rowid)
4330  {
4331  $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,';
4332  $sql .= ' cd.remise, cd.remise_percent, cd.fk_remise_except, cd.subprice, cd.ref_ext,';
4333  $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,';
4334  $sql .= ' cd.fk_unit,';
4335  $sql .= ' cd.fk_multicurrency, cd.multicurrency_code, cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc,';
4336  $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc, p.tobatch as product_tobatch,';
4337  $sql .= ' cd.date_start, cd.date_end, cd.vat_src_code';
4338  $sql .= ' FROM '.MAIN_DB_PREFIX.'commandedet as cd';
4339  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON cd.fk_product = p.rowid';
4340  $sql .= ' WHERE cd.rowid = '.((int) $rowid);
4341  $result = $this->db->query($sql);
4342  if ($result) {
4343  $objp = $this->db->fetch_object($result);
4344 
4345  if (!$objp) {
4346  $this->error = 'OrderLine with id '. $rowid .' not found sql='.$sql;
4347  return 0;
4348  }
4349 
4350  $this->rowid = $objp->rowid;
4351  $this->id = $objp->rowid;
4352  $this->fk_commande = $objp->fk_commande;
4353  $this->fk_parent_line = $objp->fk_parent_line;
4354  $this->label = $objp->custom_label;
4355  $this->desc = $objp->description;
4356  $this->qty = $objp->qty;
4357  $this->price = $objp->price;
4358  $this->subprice = $objp->subprice;
4359  $this->ref_ext = $objp->ref_ext;
4360  $this->vat_src_code = $objp->vat_src_code;
4361  $this->tva_tx = $objp->tva_tx;
4362  $this->localtax1_tx = $objp->localtax1_tx;
4363  $this->localtax2_tx = $objp->localtax2_tx;
4364  $this->remise = $objp->remise;
4365  $this->remise_percent = $objp->remise_percent;
4366  $this->fk_remise_except = $objp->fk_remise_except;
4367  $this->fk_product = $objp->fk_product;
4368  $this->product_type = $objp->product_type;
4369  $this->info_bits = $objp->info_bits;
4370  $this->special_code = $objp->special_code;
4371  $this->total_ht = $objp->total_ht;
4372  $this->total_tva = $objp->total_tva;
4373  $this->total_localtax1 = $objp->total_localtax1;
4374  $this->total_localtax2 = $objp->total_localtax2;
4375  $this->total_ttc = $objp->total_ttc;
4376  $this->fk_fournprice = $objp->fk_fournprice;
4377  $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $this->fk_fournprice, $objp->pa_ht);
4378  $this->pa_ht = $marginInfos[0];
4379  $this->marge_tx = $marginInfos[1];
4380  $this->marque_tx = $marginInfos[2];
4381  $this->special_code = $objp->special_code;
4382  $this->rang = $objp->rang;
4383 
4384  $this->ref = $objp->product_ref; // deprecated
4385 
4386  $this->product_ref = $objp->product_ref;
4387  $this->product_label = $objp->product_label;
4388  $this->product_desc = $objp->product_desc;
4389  $this->product_tobatch = $objp->product_tobatch;
4390  $this->fk_unit = $objp->fk_unit;
4391 
4392  $this->date_start = $this->db->jdate($objp->date_start);
4393  $this->date_end = $this->db->jdate($objp->date_end);
4394 
4395  $this->fk_multicurrency = $objp->fk_multicurrency;
4396  $this->multicurrency_code = $objp->multicurrency_code;
4397  $this->multicurrency_subprice = $objp->multicurrency_subprice;
4398  $this->multicurrency_total_ht = $objp->multicurrency_total_ht;
4399  $this->multicurrency_total_tva = $objp->multicurrency_total_tva;
4400  $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
4401 
4402  $this->db->free($result);
4403 
4404  return 1;
4405  } else {
4406  $this->error = $this->db->lasterror();
4407  return -1;
4408  }
4409  }
4410 
4418  public function delete(User $user, $notrigger = 0)
4419  {
4420  global $conf, $langs;
4421 
4422  $error = 0;
4423 
4424  if (empty($this->id) && !empty($this->rowid)) { // For backward compatibility
4425  $this->id = $this->rowid;
4426  }
4427 
4428  // check if order line is not in a shipment line before deleting
4429  $sqlCheckShipmentLine = "SELECT";
4430  $sqlCheckShipmentLine .= " ed.rowid";
4431  $sqlCheckShipmentLine .= " FROM ".MAIN_DB_PREFIX."expeditiondet ed";
4432  $sqlCheckShipmentLine .= " WHERE ed.fk_origin_line = ".((int) $this->id);
4433 
4434  $resqlCheckShipmentLine = $this->db->query($sqlCheckShipmentLine);
4435  if (!$resqlCheckShipmentLine) {
4436  $error++;
4437  $this->error = $this->db->lasterror();
4438  $this->errors[] = $this->error;
4439  } else {
4440  $langs->load('errors');
4441  $num = $this->db->num_rows($resqlCheckShipmentLine);
4442  if ($num > 0) {
4443  $error++;
4444  $objCheckShipmentLine = $this->db->fetch_object($resqlCheckShipmentLine);
4445  $this->error = $langs->trans('ErrorRecordAlreadyExists').' : '.$langs->trans('ShipmentLine').' '.$objCheckShipmentLine->rowid;
4446  $this->errors[] = $this->error;
4447  }
4448  $this->db->free($resqlCheckShipmentLine);
4449  }
4450  if ($error) {
4451  dol_syslog(__METHOD__.'Error ; '.$this->error, LOG_ERR);
4452  return -1;
4453  }
4454 
4455  $this->db->begin();
4456 
4457  $sql = 'DELETE FROM '.MAIN_DB_PREFIX."commandedet WHERE rowid = ".((int) $this->id);
4458 
4459  dol_syslog("OrderLine::delete", LOG_DEBUG);
4460  $resql = $this->db->query($sql);
4461  if ($resql) {
4462  if (!$error && !$notrigger) {
4463  // Call trigger
4464  $result = $this->call_trigger('LINEORDER_DELETE', $user);
4465  if ($result < 0) {
4466  $error++;
4467  }
4468  // End call triggers
4469  }
4470 
4471  // Remove extrafields
4472  if (!$error) {
4473  $result = $this->deleteExtraFields();
4474  if ($result < 0) {
4475  $error++;
4476  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
4477  }
4478  }
4479 
4480  if (!$error) {
4481  $this->db->commit();
4482  return 1;
4483  }
4484 
4485  foreach ($this->errors as $errmsg) {
4486  dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
4487  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
4488  }
4489  $this->db->rollback();
4490  return -1 * $error;
4491  } else {
4492  $this->error = $this->db->lasterror();
4493  return -1;
4494  }
4495  }
4496 
4504  public function insert($user = null, $notrigger = 0)
4505  {
4506  global $langs, $conf;
4507 
4508  $error = 0;
4509 
4510  $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'.
4511 
4512  dol_syslog(get_class($this)."::insert rang=".$this->rang);
4513 
4514  // Clean parameters
4515  if (empty($this->tva_tx)) {
4516  $this->tva_tx = 0;
4517  }
4518  if (empty($this->localtax1_tx)) {
4519  $this->localtax1_tx = 0;
4520  }
4521  if (empty($this->localtax2_tx)) {
4522  $this->localtax2_tx = 0;
4523  }
4524  if (empty($this->localtax1_type)) {
4525  $this->localtax1_type = 0;
4526  }
4527  if (empty($this->localtax2_type)) {
4528  $this->localtax2_type = 0;
4529  }
4530  if (empty($this->total_localtax1)) {
4531  $this->total_localtax1 = 0;
4532  }
4533  if (empty($this->total_localtax2)) {
4534  $this->total_localtax2 = 0;
4535  }
4536  if (empty($this->rang)) {
4537  $this->rang = 0;
4538  }
4539  if (empty($this->remise_percent)) {
4540  $this->remise_percent = 0;
4541  }
4542  if (empty($this->info_bits)) {
4543  $this->info_bits = 0;
4544  }
4545  if (empty($this->special_code)) {
4546  $this->special_code = 0;
4547  }
4548  if (empty($this->fk_parent_line)) {
4549  $this->fk_parent_line = 0;
4550  }
4551  if (empty($this->pa_ht)) {
4552  $this->pa_ht = 0;
4553  }
4554  if (empty($this->ref_ext)) {
4555  $this->ref_ext = '';
4556  }
4557 
4558  // if buy price not defined, define buyprice as configured in margin admin
4559  if ($this->pa_ht == 0 && $pa_ht_isemptystring) {
4560  $result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product);
4561  if ($result < 0) {
4562  return $result;
4563  } else {
4564  $this->pa_ht = $result;
4565  }
4566  }
4567 
4568  // Check parameters
4569  if ($this->product_type < 0) {
4570  return -1;
4571  }
4572 
4573  $this->db->begin();
4574 
4575  // Insertion dans base de la ligne
4576  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'commandedet';
4577  $sql .= ' (fk_commande, fk_parent_line, label, description, qty, ref_ext,';
4578  $sql .= ' vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
4579  $sql .= ' fk_product, product_type, remise_percent, subprice, price, fk_remise_except,';
4580  $sql .= ' special_code, rang, fk_product_fournisseur_price, buy_price_ht,';
4581  $sql .= ' info_bits, total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, date_start, date_end,';
4582  $sql .= ' fk_unit';
4583  $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
4584  $sql .= ')';
4585  $sql .= " VALUES (".$this->fk_commande.",";
4586  $sql .= " ".($this->fk_parent_line > 0 ? "'".$this->db->escape($this->fk_parent_line)."'" : "null").",";
4587  $sql .= " ".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
4588  $sql .= " '".$this->db->escape($this->desc)."',";
4589  $sql .= " '".price2num($this->qty)."',";
4590  $sql .= " '".$this->db->escape($this->ref_ext)."',";
4591  $sql .= " ".(empty($this->vat_src_code) ? "''" : "'".$this->db->escape($this->vat_src_code)."'").",";
4592  $sql .= " '".price2num($this->tva_tx)."',";
4593  $sql .= " '".price2num($this->localtax1_tx)."',";
4594  $sql .= " '".price2num($this->localtax2_tx)."',";
4595  $sql .= " '".$this->db->escape($this->localtax1_type)."',";
4596  $sql .= " '".$this->db->escape($this->localtax2_type)."',";
4597  $sql .= ' '.((!empty($this->fk_product) && $this->fk_product > 0) ? $this->fk_product : "null").',';
4598  $sql .= " '".$this->db->escape($this->product_type)."',";
4599  $sql .= " '".price2num($this->remise_percent)."',";
4600  $sql .= " ".(price2num($this->subprice) !== '' ?price2num($this->subprice) : "null").",";
4601  $sql .= " ".($this->price != '' ? "'".price2num($this->price)."'" : "null").",";
4602  $sql .= ' '.(!empty($this->fk_remise_except) ? $this->fk_remise_except : "null").',';
4603  $sql .= ' '.((int) $this->special_code).',';
4604  $sql .= ' '.((int) $this->rang).',';
4605  $sql .= ' '.(!empty($this->fk_fournprice) ? $this->fk_fournprice : "null").',';
4606  $sql .= ' '.price2num($this->pa_ht).',';
4607  $sql .= " ".((int) $this->info_bits).",";
4608  $sql .= " ".price2num($this->total_ht, 'MT').",";
4609  $sql .= " ".price2num($this->total_tva, 'MT').",";
4610  $sql .= " ".price2num($this->total_localtax1, 'MT').",";
4611  $sql .= " ".price2num($this->total_localtax2, 'MT').",";
4612  $sql .= " ".price2num($this->total_ttc, 'MT').",";
4613  $sql .= " ".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null").',';
4614  $sql .= " ".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null").',';
4615  $sql .= ' '.(!$this->fk_unit ? 'NULL' : ((int) $this->fk_unit));
4616  $sql .= ", ".(!empty($this->fk_multicurrency) ? ((int) $this->fk_multicurrency) : 'NULL');
4617  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
4618  $sql .= ", ".price2num($this->multicurrency_subprice, 'CU');
4619  $sql .= ", ".price2num($this->multicurrency_total_ht, 'CT');
4620  $sql .= ", ".price2num($this->multicurrency_total_tva, 'CT');
4621  $sql .= ", ".price2num($this->multicurrency_total_ttc, 'CT');
4622  $sql .= ')';
4623 
4624  dol_syslog(get_class($this)."::insert", LOG_DEBUG);
4625  $resql = $this->db->query($sql);
4626  if ($resql) {
4627  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'commandedet');
4628  $this->rowid = $this->id;
4629 
4630  if (!$error) {
4631  $result = $this->insertExtraFields();
4632  if ($result < 0) {
4633  $error++;
4634  }
4635  }
4636 
4637  if (!$error && !$notrigger) {
4638  // Call trigger
4639  $result = $this->call_trigger('LINEORDER_INSERT', $user);
4640  if ($result < 0) {
4641  $error++;
4642  }
4643  // End call triggers
4644  }
4645 
4646  if (!$error) {
4647  $this->db->commit();
4648  return 1;
4649  }
4650 
4651  foreach ($this->errors as $errmsg) {
4652  dol_syslog(get_class($this)."::insert ".$errmsg, LOG_ERR);
4653  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
4654  }
4655  $this->db->rollback();
4656  return -1 * $error;
4657  } else {
4658  $this->error = $this->db->error();
4659  $this->db->rollback();
4660  return -2;
4661  }
4662  }
4663 
4671  public function update(User $user, $notrigger = 0)
4672  {
4673  global $conf, $langs;
4674 
4675  $error = 0;
4676 
4677  $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'.
4678 
4679  // Clean parameters
4680  if (empty($this->tva_tx)) {
4681  $this->tva_tx = 0;
4682  }
4683  if (empty($this->localtax1_tx)) {
4684  $this->localtax1_tx = 0;
4685  }
4686  if (empty($this->localtax2_tx)) {
4687  $this->localtax2_tx = 0;
4688  }
4689  if (empty($this->localtax1_type)) {
4690  $this->localtax1_type = 0;
4691  }
4692  if (empty($this->localtax2_type)) {
4693  $this->localtax2_type = 0;
4694  }
4695  if (empty($this->qty)) {
4696  $this->qty = 0;
4697  }
4698  if (empty($this->total_localtax1)) {
4699  $this->total_localtax1 = 0;
4700  }
4701  if (empty($this->total_localtax2)) {
4702  $this->total_localtax2 = 0;
4703  }
4704  if (empty($this->marque_tx)) {
4705  $this->marque_tx = 0;
4706  }
4707  if (empty($this->marge_tx)) {
4708  $this->marge_tx = 0;
4709  }
4710  if (empty($this->remise_percent)) {
4711  $this->remise_percent = 0;
4712  }
4713  if (empty($this->remise)) {
4714  $this->remise = 0;
4715  }
4716  if (empty($this->info_bits)) {
4717  $this->info_bits = 0;
4718  }
4719  if (empty($this->special_code)) {
4720  $this->special_code = 0;
4721  }
4722  if (empty($this->product_type)) {
4723  $this->product_type = 0;
4724  }
4725  if (empty($this->fk_parent_line)) {
4726  $this->fk_parent_line = 0;
4727  }
4728  if (empty($this->pa_ht)) {
4729  $this->pa_ht = 0;
4730  }
4731  if (empty($this->ref_ext)) {
4732  $this->ref_ext = '';
4733  }
4734 
4735  // if buy price not defined, define buyprice as configured in margin admin
4736  if ($this->pa_ht == 0 && $pa_ht_isemptystring) {
4737  $result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product);
4738  if ($result < 0) {
4739  return $result;
4740  } else {
4741  $this->pa_ht = $result;
4742  }
4743  }
4744 
4745  $this->db->begin();
4746 
4747  // Mise a jour ligne en base
4748  $sql = "UPDATE ".MAIN_DB_PREFIX."commandedet SET";
4749  $sql .= " description='".$this->db->escape($this->desc)."'";
4750  $sql .= " , label=".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null");
4751  $sql .= " , vat_src_code=".(!empty($this->vat_src_code) ? "'".$this->db->escape($this->vat_src_code)."'" : "''");
4752  $sql .= " , tva_tx=".price2num($this->tva_tx);
4753  $sql .= " , localtax1_tx=".price2num($this->localtax1_tx);
4754  $sql .= " , localtax2_tx=".price2num($this->localtax2_tx);
4755  $sql .= " , localtax1_type='".$this->db->escape($this->localtax1_type)."'";
4756  $sql .= " , localtax2_type='".$this->db->escape($this->localtax2_type)."'";
4757  $sql .= " , qty=".price2num($this->qty);
4758  $sql .= " , ref_ext='".$this->db->escape($this->ref_ext)."'";
4759  $sql .= " , subprice=".price2num($this->subprice);
4760  $sql .= " , remise_percent=".price2num($this->remise_percent);
4761  $sql .= " , price=".price2num($this->price); // TODO A virer
4762  $sql .= " , remise=".price2num($this->remise); // TODO A virer
4763  if (empty($this->skip_update_total)) {
4764  $sql .= " , total_ht=".price2num($this->total_ht);
4765  $sql .= " , total_tva=".price2num($this->total_tva);
4766  $sql .= " , total_ttc=".price2num($this->total_ttc);
4767  $sql .= " , total_localtax1=".price2num($this->total_localtax1);
4768  $sql .= " , total_localtax2=".price2num($this->total_localtax2);
4769  }
4770  $sql .= " , fk_product_fournisseur_price=".(!empty($this->fk_fournprice) ? $this->fk_fournprice : "null");
4771  $sql .= " , buy_price_ht='".price2num($this->pa_ht)."'";
4772  $sql .= " , info_bits=".((int) $this->info_bits);
4773  $sql .= " , special_code=".((int) $this->special_code);
4774  $sql .= " , date_start=".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null");
4775  $sql .= " , date_end=".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null");
4776  $sql .= " , product_type=".$this->product_type;
4777  $sql .= " , fk_parent_line=".(!empty($this->fk_parent_line) ? $this->fk_parent_line : "null");
4778  if (!empty($this->rang)) {
4779  $sql .= ", rang=".((int) $this->rang);
4780  }
4781  $sql .= " , fk_unit=".(!$this->fk_unit ? 'NULL' : $this->fk_unit);
4782 
4783  // Multicurrency
4784  $sql .= " , multicurrency_subprice=".price2num($this->multicurrency_subprice);
4785  $sql .= " , multicurrency_total_ht=".price2num($this->multicurrency_total_ht);
4786  $sql .= " , multicurrency_total_tva=".price2num($this->multicurrency_total_tva);
4787  $sql .= " , multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc);
4788 
4789  $sql .= " WHERE rowid = ".((int) $this->rowid);
4790 
4791  dol_syslog(get_class($this)."::update", LOG_DEBUG);
4792  $resql = $this->db->query($sql);
4793  if ($resql) {
4794  if (!$error) {
4795  $this->id = $this->rowid;
4796  $result = $this->insertExtraFields();
4797  if ($result < 0) {
4798  $error++;
4799  }
4800  }
4801 
4802  if (!$error && !$notrigger) {
4803  // Call trigger
4804  $result = $this->call_trigger('LINEORDER_MODIFY', $user);
4805  if ($result < 0) {
4806  $error++;
4807  }
4808  // End call triggers
4809  }
4810 
4811  if (!$error) {
4812  $this->db->commit();
4813  return 1;
4814  }
4815 
4816  foreach ($this->errors as $errmsg) {
4817  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
4818  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
4819  }
4820  $this->db->rollback();
4821  return -1 * $error;
4822  } else {
4823  $this->error = $this->db->error();
4824  $this->db->rollback();
4825  return -2;
4826  }
4827  }
4828 
4829  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4836  public function update_total()
4837  {
4838  // phpcs:enable
4839  $this->db->begin();
4840 
4841  // Clean parameters
4842  if (empty($this->total_localtax1)) {
4843  $this->total_localtax1 = 0;
4844  }
4845  if (empty($this->total_localtax2)) {
4846  $this->total_localtax2 = 0;
4847  }
4848 
4849  // Mise a jour ligne en base
4850  $sql = "UPDATE ".MAIN_DB_PREFIX."commandedet SET";
4851  $sql .= " total_ht='".price2num($this->total_ht)."'";
4852  $sql .= ",total_tva='".price2num($this->total_tva)."'";
4853  $sql .= ",total_localtax1='".price2num($this->total_localtax1)."'";
4854  $sql .= ",total_localtax2='".price2num($this->total_localtax2)."'";
4855  $sql .= ",total_ttc='".price2num($this->total_ttc)."'";
4856  $sql .= " WHERE rowid = ".((int) $this->rowid);
4857 
4858  dol_syslog("OrderLine::update_total", LOG_DEBUG);
4859 
4860  $resql = $this->db->query($sql);
4861  if ($resql) {
4862  $this->db->commit();
4863  return 1;
4864  } else {
4865  $this->error = $this->db->error();
4866  $this->db->rollback();
4867  return -2;
4868  }
4869  }
4870 }
Commande\valid
valid($user, $idwarehouse=0, $notrigger=0)
Validate order.
Definition: commande.class.php:478
Commande\getNextNumRef
getNextNumRef($soc)
Returns the reference to the following non used Order depending on the active numbering module define...
Definition: commande.class.php:428
Societe
Class to manage third parties objects (customers, suppliers, prospects...)
Definition: societe.class.php:51
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:6398
Commande\$remise_percent
$remise_percent
Definition: commande.class.php:227
OrderLine\$remise
$remise
Definition: commande.class.php:4304
Commande\$pos_source
$pos_source
key of pos source ('0', '1', ...)
Definition: commande.class.php:282
Commande\fetch_lines
fetch_lines($only_product=0, $loadalsotranslation=0)
Load array lines.
Definition: commande.class.php:2096
dol_sanitizeFileName
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Definition: functions.lib.php:1323
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:4146
CommonObject\copy_linked_contact
copy_linked_contact($objFrom, $source='internal')
Copy contact from one element to current.
Definition: commonobject.class.php:1132
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:2467
Commande\showDelay
showDelay()
Show the customer delayed info.
Definition: commande.class.php:4228
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:1485
Commande\countNbOfShipments
countNbOfShipments()
Returns an array with expeditions lines number.
Definition: commande.class.php:2344
DoliDB
Class to manage Dolibarr database access.
Definition: DoliDB.class.php:30
dol_escape_htmltag
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
Definition: functions.lib.php:1600
Commande\stock_array
stock_array($filtre_statut=self::STATUS_CANCELED)
Return a array with the pending stock by product.
Definition: commande.class.php:2374
OrderLine\__construct
__construct($db)
Constructor.
Definition: commande.class.php:4318
CommonObject\updateRangOfLine
updateRangOfLine($rowid, $rang)
Update position of line (rang)
Definition: commonobject.class.php:3179
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:5107
CommonObject\setErrorsFromObject
setErrorsFromObject($object)
setErrorsFromObject
Definition: commonobject.class.php:743
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:408
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:1129
Commande\createFromProposal
createFromProposal($object, User $user)
Load an object from a proposal and create a new order into database.
Definition: commande.class.php:1324
dol_buildpath
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
Definition: functions.lib.php:1158
dol_dir_list
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:62
Commande\LibStatut
LibStatut($status, $billed, $mode, $donotshowbilled=0)
Return label of status.
Definition: commande.class.php:3704
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:503
Commande\STATUS_SHIPMENTONPROCESS
const STATUS_SHIPMENTONPROCESS
Shipment on process.
Definition: commande.class.php:402
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:4190
Commande\set_date_livraison
set_date_livraison($user, $delivery_date, $notrigger=0)
Set delivery date.
Definition: commande.class.php:2671
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:1518
CommonObject\fetch_project
fetch_project()
Load the project with id $this->fk_project into this->project.
Definition: commonobject.class.php:1763
Commande\hasDelay
hasDelay()
Is the sales order delayed?
Definition: commande.class.php:4210
Commande\getNbOfShipments
getNbOfShipments()
Count number of shipments for this order.
Definition: commande.class.php:2259
Commande\STATUS_CANCELED
const STATUS_CANCELED
Canceled status.
Definition: commande.class.php:390
Commande\__construct
__construct($db)
Constructor.
Definition: commande.class.php:416
Commande\$table_ref_field
$table_ref_field
{}
Definition: commande.class.php:94
Commande\getNbOfProductsLines
getNbOfProductsLines()
Return number of line with type product.
Definition: commande.class.php:2227
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5955
Commande\insert_discount
insert_discount($idremise)
Adding line of fixed discount in the order in DB.
Definition: commande.class.php:2026
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2675
Commande\classifyUnBilled
classifyUnBilled(User $user, $notrigger=0)
Classify the order as not invoiced.
Definition: commande.class.php:3053
CommonObject\fetch_thirdparty
fetch_thirdparty($force_thirdparty_id=0)
Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty.
Definition: commonobject.class.php:1646
WorkboardResponse
Definition: workboardresponse.class.php:24
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:4135
Commande\load_board
load_board($user, $mode)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Definition: commande.class.php:3582
Commande\STATUS_VALIDATED
const STATUS_VALIDATED
Validated status.
Definition: commande.class.php:398
rowid
print *****$script_file(".$version.") pid c cd cd cd description as p label as s rowid
Definition: email_expire_services_to_representatives.php:79
CommonObject\commonGenerateDocument
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
Definition: commonobject.class.php:5381
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:833
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:1334
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:3491
Commande\deleteline
deleteline($user=null, $lineid=0, $id=0)
Delete an order line.
Definition: commande.class.php:2412
Commande\fetch
fetch($id, $ref='', $ref_ext='', $notused='')
Get object from database.
Definition: commande.class.php:1860
get_default_npr
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.
Definition: functions.lib.php:6738
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:2295
getEntity
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
Definition: functions.lib.php:266
OrderLine
Class to manage order lines.
Definition: commande.class.php:4247
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:6136
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:6157
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:701
Commande
Class to manage customers orders.
Definition: commande.class.php:47
Commande\getLibStatut
getLibStatut($mode)
Return status label of Order.
Definition: commande.class.php:3689
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:1771
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:1222
Commande\setDiscount
setDiscount($user, $remise, $notrigger=0)
Set a percentage discount.
Definition: commande.class.php:2483
Commande\update
update(User $user, $notrigger=0)
Update database.
Definition: commande.class.php:3341
CommonObject\defineBuyPrice
defineBuyPrice($unitPrice=0.0, $discountPercent=0.0, $fk_product=0)
Get buy price to use for margin calculation.
Definition: commonobject.class.php:8582
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:7046
CommonObject\commonReplaceProduct
static commonReplaceProduct(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a product id with another one.
Definition: commonobject.class.php:8553
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:3129
CommonObject\deleteEcmFiles
deleteEcmFiles($mode=0)
Delete related files of object in database.
Definition: commonobject.class.php:10166
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:1023
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1741
DiscountAbsolute
Class to manage absolute discounts.
Definition: discount.class.php:29
MultiCurrency\getIdAndTxFromCode
static getIdAndTxFromCode($dbs, $code, $date_document='')
Get id and rate of currency from code.
Definition: multicurrency.class.php:528
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:3845
CommonObject\line_max
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
Definition: commonobject.class.php:3337
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:6006
Commande\cloture
cloture($user, $notrigger=0)
Close order.
Definition: commande.class.php:773
$sql
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
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:3997
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:6624
Commande\STATUS_DRAFT
const STATUS_DRAFT
Draft status.
Definition: commande.class.php:394
Commande\info
info($id)
Charge les informations d'ordre info dans l'objet commande.
Definition: commande.class.php:3961
Commande\set_remise_absolue
set_remise_absolue($user, $remise, $notrigger=0)
Set a fixed amount discount.
Definition: commande.class.php:2546
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:207
Commande\getTooltipContentArray
getTooltipContentArray($params)
getTooltipContentArray
Definition: commande.class.php:3777
OrderLine\insert
insert($user=null, $notrigger=0)
Insert line into database.
Definition: commande.class.php:4504
ref
$object ref
Definition: info.php:78
User
Class to manage Dolibarr users.
Definition: user.class.php:47
Commande\load_state_board
load_state_board()
Charge indicateurs this->nb de tableau de bord.
Definition: commande.class.php:4093
Commande\getLinesArray
getLinesArray()
Create an array of order lines.
Definition: commande.class.php:4130
CommonObject\deleteExtraFields
deleteExtraFields()
Delete all extra fields values for the current object.
Definition: commonobject.class.php:6117
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:385
Commande\create
create($user, $notrigger=0)
Create order Note that this->ref can be set or empty.
Definition: commande.class.php:906
OrderLine\update_total
update_total()
Update DB line fields total_xxx Used by migration.
Definition: commande.class.php:4836
Product
Class to manage products or services.
Definition: product.class.php:46
Commande\replaceThirdparty
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
Definition: commande.class.php:4179
getMarginInfos
getMarginInfos($pvht, $remise_percent, $tva_tx, $localtax1_tx, $localtax2_tx, $fk_pa, $paht)
Return an array with margins information of a line.
Definition: margins.lib.php:118
dol_delete_preview
dol_delete_preview($object)
Delete all preview files linked to object instance.
Definition: files.lib.php:1537
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:3780
dolGetStatus
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
Definition: functions.lib.php:10967
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:4473
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:3056
Commande\getNbOfServicesLines
getNbOfServicesLines()
Return number of line with type service.
Definition: commande.class.php:2243
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:5829
CommonObject\call_trigger
call_trigger($triggerName, $user)
Call trigger based on this instance.
Definition: commonobject.class.php:5790
Commande\createFromClone
createFromClone(User $user, $socid=0)
Load an object from its id and create a new one in database.
Definition: commande.class.php:1213
Commande\$module_source
$module_source
key of module source when order generated from a dedicated module ('cashdesk', 'takepos',...
Definition: commande.class.php:280
Commande\replaceProduct
static replaceProduct(DoliDB $db, $origin_id, $dest_id)
Function used to replace a product id with another one.
Definition: commande.class.php:4196
CommonOrderLine
Superclass for orders classes.
Definition: commonorder.class.php:82
Commande\setDraft
setDraft($user, $idwarehouse=-1)
Set draft status.
Definition: commande.class.php:632
getDolGlobalInt
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
Definition: functions.lib.php:156
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:3015
OrderLine\fetch
fetch($rowid)
Load line order.
Definition: commande.class.php:4329
CommonObject\commonReplaceThirdparty
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
Definition: commonobject.class.php:8524
Commande\getLabelSource
getLabelSource()
Return source label of order.
Definition: commande.class.php:3671
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:718
Commande\initAsSpecimen
initAsSpecimen()
Initialise an instance with random values.
Definition: commande.class.php:4004
OrderLine\update
update(User $user, $notrigger=0)
Update the line object into db.
Definition: commande.class.php:4671
Commande\classifyBilled
classifyBilled(User $user, $notrigger=0)
Classify the order as invoiced.
Definition: commande.class.php:2999