dolibarr  13.0.2
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-2018 Ferran Marcet <fmarcet@2byte.es>
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program. If not, see <https://www.gnu.org/licenses/>.
27  */
28 
34 include_once DOL_DOCUMENT_ROOT.'/core/class/commonorder.class.php';
35 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
36 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
37 require_once DOL_DOCUMENT_ROOT.'/margin/lib/margins.lib.php';
38 require_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
39 
40 
44 class Commande extends CommonOrder
45 {
49  public $element = 'commande';
50 
54  public $table_element = 'commande';
55 
59  public $table_element_line = 'commandedet';
60 
64  public $class_element_line = 'OrderLine';
65 
69  public $fk_element = 'fk_commande';
70 
74  public $picto = 'order';
75 
80  public $ismultientitymanaged = 1;
81 
86  public $restrictiononfksoc = 1;
87 
91  protected $table_ref_field = 'ref';
92 
96  public $socid;
97 
101  public $ref_client;
102 
107  public $ref_int;
108 
112  public $contactid;
113 
118  public $statut;
119 
123  public $billed;
124 
128  public $brouillon;
129  public $cond_reglement_code;
130 
134  public $fk_account;
135 
139  public $mode_reglement;
140 
144  public $mode_reglement_id;
145 
149  public $mode_reglement_code;
150 
155  public $availability_id;
156 
161  public $availability_code;
162 
167  public $availability;
168 
169  public $demand_reason_id; // Source reason. Why we receive order (after a phone campaign, ...)
170  public $demand_reason_code;
174  public $date;
175 
181  public $date_commande;
182 
187  public $date_livraison; // deprecated; Use delivery_date instead.
188 
189  public $delivery_date; // Date expected of shipment (date starting shipment, not the reception that occurs some days after)
190 
194  public $fk_remise_except;
195 
196  public $remise_percent;
197  public $remise_absolue;
198  public $info_bits;
199  public $rang;
200  public $special_code;
201  public $source; // Order mode. How we received order (by phone, by email, ...)
202 
203  public $extraparams = array();
204 
205  public $linked_objects = array();
206 
210  public $user_author_id;
211 
215  public $user_valid;
216 
220  public $lines = array();
221 
222  // Multicurrency
226  public $fk_multicurrency;
227 
228  public $multicurrency_code;
229  public $multicurrency_tx;
230  public $multicurrency_total_ht;
231  public $multicurrency_total_tva;
232  public $multicurrency_total_ttc;
233 
237  public $oldcopy;
238 
242  public $pos_source;
243 
244 
269  // BEGIN MODULEBUILDER PROPERTIES
273  public $fields = array(
274  'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
275  'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>20, 'index'=>1),
276  'ref' =>array('type'=>'varchar(30)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'showoncombobox'=>1, 'position'=>25),
277  'ref_ext' =>array('type'=>'varchar(255)', 'label'=>'RefExt', 'enabled'=>1, 'visible'=>0, 'position'=>26),
278  'ref_int' =>array('type'=>'varchar(255)', 'label'=>'RefInt', 'enabled'=>1, 'visible'=>0, 'position'=>27), // deprecated
279  'ref_client' =>array('type'=>'varchar(255)', 'label'=>'RefCustomer', 'enabled'=>1, 'visible'=>-1, 'position'=>28),
280  'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>20),
281  'fk_projet' =>array('type'=>'integer:Project:projet/class/project.class.php:1:fk_statut=1', 'label'=>'Project', 'enabled'=>1, 'visible'=>-1, 'position'=>25),
282  'date_creation' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-1, 'position'=>55),
283  'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>56),
284  'date_valid' =>array('type'=>'datetime', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>60),
285  'date_cloture' =>array('type'=>'datetime', 'label'=>'DateClosing', 'enabled'=>1, 'visible'=>-1, 'position'=>65),
286  'date_commande' =>array('type'=>'date', 'label'=>'Date', 'enabled'=>1, 'visible'=>-1, 'position'=>70),
287  'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-1, 'position'=>75),
288  'fk_user_modif' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>80),
289  'fk_user_valid' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>85),
290  'fk_user_cloture' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserClosing', 'enabled'=>1, 'visible'=>-1, 'position'=>90),
291  'source' =>array('type'=>'smallint(6)', 'label'=>'Source', 'enabled'=>1, 'visible'=>-1, 'position'=>95),
292  //'amount_ht' =>array('type'=>'double(24,8)', 'label'=>'AmountHT', 'enabled'=>1, 'visible'=>-1, 'position'=>105),
293  'remise_percent' =>array('type'=>'double', 'label'=>'RelativeDiscount', 'enabled'=>1, 'visible'=>-1, 'position'=>110),
294  'remise_absolue' =>array('type'=>'double', 'label'=>'CustomerRelativeDiscount', 'enabled'=>1, 'visible'=>-1, 'position'=>115),
295  //'remise' =>array('type'=>'double', 'label'=>'Remise', 'enabled'=>1, 'visible'=>-1, 'position'=>120),
296  'tva' =>array('type'=>'double(24,8)', 'label'=>'VAT', 'enabled'=>1, 'visible'=>-1, 'position'=>125, 'isameasure'=>1),
297  'localtax1' =>array('type'=>'double(24,8)', 'label'=>'LocalTax1', 'enabled'=>1, 'visible'=>-1, 'position'=>130, 'isameasure'=>1),
298  'localtax2' =>array('type'=>'double(24,8)', 'label'=>'LocalTax2', 'enabled'=>1, 'visible'=>-1, 'position'=>135, 'isameasure'=>1),
299  'total_ht' =>array('type'=>'double(24,8)', 'label'=>'TotalHT', 'enabled'=>1, 'visible'=>-1, 'position'=>140, 'isameasure'=>1),
300  'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'TotalTTC', 'enabled'=>1, 'visible'=>-1, 'position'=>145, 'isameasure'=>1),
301  'note_private' =>array('type'=>'text', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>150),
302  'note_public' =>array('type'=>'text', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>155),
303  'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'PDFTemplate', 'enabled'=>1, 'visible'=>0, 'position'=>160),
304  //'facture' =>array('type'=>'tinyint(4)', 'label'=>'ParentInvoice', 'enabled'=>1, 'visible'=>-1, 'position'=>165),
305  'fk_account' =>array('type'=>'integer', 'label'=>'BankAccount', 'enabled'=>1, 'visible'=>-1, 'position'=>170),
306  'fk_currency' =>array('type'=>'varchar(3)', 'label'=>'MulticurrencyID', 'enabled'=>1, 'visible'=>-1, 'position'=>175),
307  'fk_cond_reglement' =>array('type'=>'integer', 'label'=>'PaymentTerm', 'enabled'=>1, 'visible'=>-1, 'position'=>180),
308  'fk_mode_reglement' =>array('type'=>'integer', 'label'=>'PaymentMode', 'enabled'=>1, 'visible'=>-1, 'position'=>185),
309  'date_livraison' =>array('type'=>'date', 'label'=>'DateDeliveryPlanned', 'enabled'=>1, 'visible'=>-1, 'position'=>190),
310  'fk_shipping_method' =>array('type'=>'integer', 'label'=>'ShippingMethod', 'enabled'=>1, 'visible'=>-1, 'position'=>195),
311  'fk_warehouse' =>array('type'=>'integer:Entrepot:product/stock/class/entrepot.class.php', 'label'=>'Fk warehouse', 'enabled'=>1, 'visible'=>-1, 'position'=>200),
312  'fk_availability' =>array('type'=>'integer', 'label'=>'Availability', 'enabled'=>1, 'visible'=>-1, 'position'=>205),
313  'fk_input_reason' =>array('type'=>'integer', 'label'=>'InputReason', 'enabled'=>1, 'visible'=>-1, 'position'=>210),
314  //'fk_delivery_address' =>array('type'=>'integer', 'label'=>'DeliveryAddress', 'enabled'=>1, 'visible'=>-1, 'position'=>215),
315  'extraparams' =>array('type'=>'varchar(255)', 'label'=>'Extraparams', 'enabled'=>1, 'visible'=>-1, 'position'=>225),
316  'fk_incoterms' =>array('type'=>'integer', 'label'=>'IncotermCode', 'enabled'=>'$conf->incoterm->enabled', 'visible'=>-1, 'position'=>230),
317  'location_incoterms' =>array('type'=>'varchar(255)', 'label'=>'IncotermLabel', 'enabled'=>'$conf->incoterm->enabled', 'visible'=>-1, 'position'=>235),
318  'fk_multicurrency' =>array('type'=>'integer', 'label'=>'Fk multicurrency', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>240),
319  'multicurrency_code' =>array('type'=>'varchar(255)', 'label'=>'MulticurrencyCurrency', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>245),
320  'multicurrency_tx' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyRate', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>250, 'isameasure'=>1),
321  'multicurrency_total_ht' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyAmountHT', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>255, 'isameasure'=>1),
322  'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyAmountVAT', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>260, 'isameasure'=>1),
323  'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyAmountTTC', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>265, 'isameasure'=>1),
324  'last_main_doc' =>array('type'=>'varchar(255)', 'label'=>'LastMainDoc', 'enabled'=>1, 'visible'=>-1, 'position'=>270),
325  'module_source' =>array('type'=>'varchar(32)', 'label'=>'POSModule', 'enabled'=>1, 'visible'=>-1, 'position'=>275),
326  'pos_source' =>array('type'=>'varchar(32)', 'label'=>'POSTerminal', 'enabled'=>1, 'visible'=>-1, 'position'=>280),
327  'fk_statut' =>array('type'=>'smallint(6)', 'label'=>'Status', 'enabled'=>1, 'visible'=>-1, 'position'=>500),
328  'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>900),
329  );
330  // END MODULEBUILDER PROPERTIES
331 
336 
340  const STATUS_CANCELED = -1;
344  const STATUS_DRAFT = 0;
348  const STATUS_VALIDATED = 1;
353  const STATUS_ACCEPTED = 2; // For backward compatibility. Use key STATUS_SHIPMENTONPROCESS instead.
354 
358  const STATUS_CLOSED = 3;
359 
360 
366  public function __construct($db)
367  {
368  $this->db = $db;
369 
370  $this->remise = 0;
371  $this->remise_percent = 0;
372  }
373 
381  public function getNextNumRef($soc)
382  {
383  global $langs, $conf;
384  $langs->load("order");
385 
386  if (!empty($conf->global->COMMANDE_ADDON))
387  {
388  $mybool = false;
389 
390  $file = $conf->global->COMMANDE_ADDON.".php";
391  $classname = $conf->global->COMMANDE_ADDON;
392 
393  // Include file with class
394  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
395  foreach ($dirmodels as $reldir)
396  {
397  $dir = dol_buildpath($reldir."core/modules/commande/");
398 
399  // Load file with numbering class (if found)
400  $mybool |= @include_once $dir.$file;
401  }
402 
403  if ($mybool === false)
404  {
405  dol_print_error('', "Failed to include file ".$file);
406  return '';
407  }
408 
409  $obj = new $classname();
410  $numref = $obj->getNextValue($soc, $this);
411 
412  if ($numref != "")
413  {
414  return $numref;
415  } else {
416  $this->error = $obj->error;
417  //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
418  return "";
419  }
420  } else {
421  print $langs->trans("Error")." ".$langs->trans("Error_COMMANDE_ADDON_NotDefined");
422  return "";
423  }
424  }
425 
426 
435  public function valid($user, $idwarehouse = 0, $notrigger = 0)
436  {
437  global $conf, $langs;
438 
439  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
440 
441  $error = 0;
442 
443  // Protection
444  if ($this->statut == self::STATUS_VALIDATED)
445  {
446  dol_syslog(get_class($this)."::valid action abandonned: already validated", LOG_WARNING);
447  return 0;
448  }
449 
450  if (!((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->creer))
451  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->order_advance->validate))))
452  {
453  $this->error = 'NotEnoughPermissions';
454  dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
455  return -1;
456  }
457 
458  $now = dol_now();
459 
460  $this->db->begin();
461 
462  // Definition du nom de module de numerotation de commande
463  $soc = new Societe($this->db);
464  $soc->fetch($this->socid);
465 
466  // Class of company linked to order
467  $result = $soc->set_as_client();
468 
469  // Define new ref
470  if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life
471  {
472  $num = $this->getNextNumRef($soc);
473  } else {
474  $num = $this->ref;
475  }
476  $this->newref = dol_sanitizeFileName($num);
477 
478  // Validate
479  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
480  $sql .= " SET ref = '".$this->db->escape($num)."',";
481  $sql .= " fk_statut = ".self::STATUS_VALIDATED.",";
482  $sql .= " date_valid='".$this->db->idate($now)."',";
483  $sql .= " fk_user_valid = ".$user->id;
484  $sql .= " WHERE rowid = ".$this->id;
485 
486  dol_syslog(get_class($this)."::valid", LOG_DEBUG);
487  $resql = $this->db->query($sql);
488  if (!$resql)
489  {
490  dol_print_error($this->db);
491  $this->error = $this->db->lasterror();
492  $error++;
493  }
494 
495  if (!$error) {
496  // If stock is incremented on validate order, we must increment it
497  if ($result >= 0 && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1) {
498  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
499  $langs->load("agenda");
500 
501  // Loop on each line
502  $cpt = count($this->lines);
503  for ($i = 0; $i < $cpt; $i++) {
504  if ($this->lines[$i]->fk_product > 0) {
505  $mouvP = new MouvementStock($this->db);
506  $mouvP->origin = &$this;
507  // We decrement stock of product (and sub-products)
508  $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("OrderValidatedInDolibarr", $num));
509  if ($result < 0) {
510  $error++;
511  $this->error = $mouvP->error;
512  }
513  }
514  if ($error) break;
515  }
516  }
517  }
518 
519  if (!$error && !$notrigger) {
520  // Call trigger
521  $result = $this->call_trigger('ORDER_VALIDATE', $user);
522  if ($result < 0) $error++;
523  // End call triggers
524  }
525 
526  if (!$error) {
527  $this->oldref = $this->ref;
528 
529  // Rename directory if dir was a temporary ref
530  if (preg_match('/^[\(]?PROV/i', $this->ref))
531  {
532  // Now we rename also files into index
533  $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)."'";
534  $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'commande/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
535  $resql = $this->db->query($sql);
536  if (!$resql) { $error++; $this->error = $this->db->lasterror(); }
537 
538  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
539  $oldref = dol_sanitizeFileName($this->ref);
540  $newref = dol_sanitizeFileName($num);
541  $dirsource = $conf->commande->multidir_output[$this->entity].'/'.$oldref;
542  $dirdest = $conf->commande->multidir_output[$this->entity].'/'.$newref;
543  if (!$error && file_exists($dirsource))
544  {
545  dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
546 
547  if (@rename($dirsource, $dirdest))
548  {
549  dol_syslog("Rename ok");
550  // Rename docs starting with $oldref with $newref
551  $listoffiles = dol_dir_list($conf->commande->multidir_output[$this->entity].'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
552  foreach ($listoffiles as $fileentry)
553  {
554  $dirsource = $fileentry['name'];
555  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
556  $dirsource = $fileentry['path'].'/'.$dirsource;
557  $dirdest = $fileentry['path'].'/'.$dirdest;
558  @rename($dirsource, $dirdest);
559  }
560  }
561  }
562  }
563  }
564 
565  // Set new ref and current status
566  if (!$error)
567  {
568  $this->ref = $num;
569  $this->statut = self::STATUS_VALIDATED;
570  $this->brouillon = 0;
571  }
572 
573  if (!$error)
574  {
575  $this->db->commit();
576  return 1;
577  } else {
578  $this->db->rollback();
579  return -1;
580  }
581  }
582 
583  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
591  public function setDraft($user, $idwarehouse = -1)
592  {
593  //phpcs:enable
594  global $conf, $langs;
595 
596  $error = 0;
597 
598  // Protection
599  if ($this->statut <= self::STATUS_DRAFT)
600  {
601  return 0;
602  }
603 
604  if (!((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->creer))
605  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->order_advance->validate))))
606  {
607  $this->error = 'Permission denied';
608  return -1;
609  }
610 
611  dol_syslog(__METHOD__, LOG_DEBUG);
612 
613  $this->db->begin();
614 
615  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
616  $sql .= " SET fk_statut = ".self::STATUS_DRAFT;
617  $sql .= " WHERE rowid = ".$this->id;
618 
619  if ($this->db->query($sql))
620  {
621  if (!$error)
622  {
623  $this->oldcopy = clone $this;
624  }
625 
626  // If stock is decremented on validate order, we must reincrement it
627  if (!empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1)
628  {
629  $result = 0;
630 
631  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
632  $langs->load("agenda");
633 
634  $num = count($this->lines);
635  for ($i = 0; $i < $num; $i++)
636  {
637  if ($this->lines[$i]->fk_product > 0)
638  {
639  $mouvP = new MouvementStock($this->db);
640  $mouvP->origin = &$this;
641  // We increment stock of product (and sub-products)
642  $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("OrderBackToDraftInDolibarr", $this->ref));
643  if ($result < 0) { $error++; $this->error = $mouvP->error; break; }
644  }
645  }
646  }
647 
648  if (!$error) {
649  // Call trigger
650  $result = $this->call_trigger('ORDER_UNVALIDATE', $user);
651  if ($result < 0) $error++;
652  }
653 
654  if (!$error) {
655  $this->statut = self::STATUS_DRAFT;
656  $this->db->commit();
657  return 1;
658  } else {
659  $this->db->rollback();
660  return -1;
661  }
662  } else {
663  $this->error = $this->db->error();
664  $this->db->rollback();
665  return -1;
666  }
667  }
668 
669 
670  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
678  public function set_reopen($user)
679  {
680  // phpcs:enable
681  $error = 0;
682 
683  if ($this->statut != self::STATUS_CANCELED && $this->statut != self::STATUS_CLOSED)
684  {
685  dol_syslog(get_class($this)."::set_reopen order has not status closed", LOG_WARNING);
686  return 0;
687  }
688 
689  $this->db->begin();
690 
691  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
692  $sql .= ' SET fk_statut='.self::STATUS_VALIDATED.', facture=0';
693  $sql .= ' WHERE rowid = '.$this->id;
694 
695  dol_syslog(get_class($this)."::set_reopen", LOG_DEBUG);
696  $resql = $this->db->query($sql);
697  if ($resql)
698  {
699  // Call trigger
700  $result = $this->call_trigger('ORDER_REOPEN', $user);
701  if ($result < 0) $error++;
702  // End call triggers
703  } else {
704  $error++;
705  $this->error = $this->db->lasterror();
706  dol_print_error($this->db);
707  }
708 
709  if (!$error)
710  {
711  $this->statut = self::STATUS_VALIDATED;
712  $this->billed = 0;
713 
714  $this->db->commit();
715  return 1;
716  } else {
717  foreach ($this->errors as $errmsg)
718  {
719  dol_syslog(get_class($this)."::set_reopen ".$errmsg, LOG_ERR);
720  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
721  }
722  $this->db->rollback();
723  return -1 * $error;
724  }
725  }
726 
734  public function cloture($user, $notrigger = 0)
735  {
736  global $conf;
737 
738  $error = 0;
739 
740  $usercanclose = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->creer))
741  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->order_advance->close)));
742 
743  if ($usercanclose)
744  {
745  if ($this->statut == self::STATUS_CLOSED)
746  {
747  return 0;
748  }
749  $this->db->begin();
750 
751  $now = dol_now();
752 
753  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
754  $sql .= ' SET fk_statut = '.self::STATUS_CLOSED.',';
755  $sql .= ' fk_user_cloture = '.$user->id.',';
756  $sql .= " date_cloture = '".$this->db->idate($now)."'";
757  $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > '.self::STATUS_DRAFT;
758 
759  if ($this->db->query($sql))
760  {
761  if (!$notrigger)
762  {
763  // Call trigger
764  $result = $this->call_trigger('ORDER_CLOSE', $user);
765  if ($result < 0) $error++;
766  // End call triggers
767  }
768 
769  if (!$error)
770  {
771  $this->statut = self::STATUS_CLOSED;
772 
773  $this->db->commit();
774  return 1;
775  } else {
776  $this->db->rollback();
777  return -1;
778  }
779  } else {
780  $this->error = $this->db->lasterror();
781 
782  $this->db->rollback();
783  return -1;
784  }
785  }
786  return 0;
787  }
788 
796  public function cancel($idwarehouse = -1)
797  {
798  global $conf, $user, $langs;
799 
800  $error = 0;
801 
802  $this->db->begin();
803 
804  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
805  $sql .= " SET fk_statut = ".self::STATUS_CANCELED;
806  $sql .= " WHERE rowid = ".$this->id;
807  $sql .= " AND fk_statut = ".self::STATUS_VALIDATED;
808 
809  dol_syslog(get_class($this)."::cancel", LOG_DEBUG);
810  if ($this->db->query($sql))
811  {
812  // If stock is decremented on validate order, we must reincrement it
813  if (!empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1)
814  {
815  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
816  $langs->load("agenda");
817 
818  $num = count($this->lines);
819  for ($i = 0; $i < $num; $i++)
820  {
821  if ($this->lines[$i]->fk_product > 0)
822  {
823  $mouvP = new MouvementStock($this->db);
824  // We increment stock of product (and sub-products)
825  $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
826  if ($result < 0)
827  {
828  $error++;
829  $this->error = $mouvP->error;
830  break;
831  }
832  }
833  }
834  }
835 
836  if (!$error)
837  {
838  // Call trigger
839  $result = $this->call_trigger('ORDER_CANCEL', $user);
840  if ($result < 0) $error++;
841  // End call triggers
842  }
843 
844  if (!$error)
845  {
846  $this->statut = self::STATUS_CANCELED;
847  $this->db->commit();
848  return 1;
849  } else {
850  foreach ($this->errors as $errmsg)
851  {
852  dol_syslog(get_class($this)."::cancel ".$errmsg, LOG_ERR);
853  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
854  }
855  $this->db->rollback();
856  return -1 * $error;
857  }
858  } else {
859  $this->error = $this->db->error();
860  $this->db->rollback();
861  return -1;
862  }
863  }
864 
873  public function create($user, $notrigger = 0)
874  {
875  global $conf, $langs;
876  $error = 0;
877 
878  // Clean parameters
879  $this->brouillon = 1; // set command as draft
880 
881  // Set tmp vars
882  $date = ($this->date_commande ? $this->date_commande : $this->date);
883  $delivery_date = empty($this->delivery_date) ? $this->date_livraison : $this->delivery_date;
884 
885  // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
886  if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $date);
887  else $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
888  if (empty($this->fk_multicurrency))
889  {
890  $this->multicurrency_code = $conf->currency;
891  $this->fk_multicurrency = 0;
892  $this->multicurrency_tx = 1;
893  }
894 
895  dol_syslog(get_class($this)."::create user=".$user->id);
896 
897  // Check parameters
898  if (!empty($this->ref)) // We check that ref is not already used
899  {
900  $result = self::isExistingObject($this->element, 0, $this->ref); // Check ref is not yet used
901  if ($result > 0)
902  {
903  $this->error = 'ErrorRefAlreadyExists';
904  dol_syslog(get_class($this)."::create ".$this->error, LOG_WARNING);
905  $this->db->rollback();
906  return -1;
907  }
908  }
909 
910  $soc = new Societe($this->db);
911  $result = $soc->fetch($this->socid);
912  if ($result < 0)
913  {
914  $this->error = "Failed to fetch company";
915  dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
916  return -2;
917  }
918  if (!empty($conf->global->ORDER_REQUIRE_SOURCE) && $this->source < 0)
919  {
920  $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Source"));
921  dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
922  return -1;
923  }
924 
925  $now = dol_now();
926 
927  $this->db->begin();
928 
929  $sql = "INSERT INTO ".MAIN_DB_PREFIX."commande (";
930  $sql .= " ref, fk_soc, date_creation, fk_user_author, fk_projet, date_commande, source, note_private, note_public, ref_ext, ref_client, ref_int";
931  $sql .= ", model_pdf, fk_cond_reglement, fk_mode_reglement, fk_account, fk_availability, fk_input_reason, date_livraison, fk_delivery_address";
932  $sql .= ", fk_shipping_method";
933  $sql .= ", fk_warehouse";
934  $sql .= ", remise_absolue, remise_percent";
935  $sql .= ", fk_incoterms, location_incoterms";
936  $sql .= ", entity, module_source, pos_source";
937  $sql .= ", fk_multicurrency";
938  $sql .= ", multicurrency_code";
939  $sql .= ", multicurrency_tx";
940  $sql .= ")";
941  $sql .= " VALUES ('(PROV)', ".$this->socid.", '".$this->db->idate($now)."', ".$user->id;
942  $sql .= ", ".($this->fk_project > 0 ? $this->fk_project : "null");
943  $sql .= ", '".$this->db->idate($date)."'";
944  $sql .= ", ".($this->source >= 0 && $this->source != '' ? $this->db->escape($this->source) : 'null');
945  $sql .= ", '".$this->db->escape($this->note_private)."'";
946  $sql .= ", '".$this->db->escape($this->note_public)."'";
947  $sql .= ", ".($this->ref_ext ? "'".$this->db->escape($this->ref_ext)."'" : "null");
948  $sql .= ", ".($this->ref_client ? "'".$this->db->escape($this->ref_client)."'" : "null");
949  $sql .= ", ".($this->ref_int ? "'".$this->db->escape($this->ref_int)."'" : "null");
950  $sql .= ", '".$this->db->escape($this->model_pdf)."'";
951  $sql .= ", ".($this->cond_reglement_id > 0 ? $this->cond_reglement_id : "null");
952  $sql .= ", ".($this->mode_reglement_id > 0 ? $this->mode_reglement_id : "null");
953  $sql .= ", ".($this->fk_account > 0 ? $this->fk_account : 'NULL');
954  $sql .= ", ".($this->availability_id > 0 ? $this->availability_id : "null");
955  $sql .= ", ".($this->demand_reason_id > 0 ? $this->demand_reason_id : "null");
956  $sql .= ", ".($delivery_date ? "'".$this->db->idate($delivery_date)."'" : "null");
957  $sql .= ", ".($this->fk_delivery_address > 0 ? $this->fk_delivery_address : 'NULL');
958  $sql .= ", ".(!empty($this->shipping_method_id) && $this->shipping_method_id > 0 ? $this->shipping_method_id : 'NULL');
959  $sql .= ", ".(!empty($this->warehouse_id) && $this->warehouse_id > 0 ? $this->warehouse_id : 'NULL');
960  $sql .= ", ".($this->remise_absolue > 0 ? $this->db->escape($this->remise_absolue) : 'NULL');
961  $sql .= ", ".($this->remise_percent > 0 ? $this->db->escape($this->remise_percent) : 0);
962  $sql .= ", ".(int) $this->fk_incoterms;
963  $sql .= ", '".$this->db->escape($this->location_incoterms)."'";
964  $sql .= ", ".setEntity($this);
965  $sql .= ", ".($this->module_source ? "'".$this->db->escape($this->module_source)."'" : "null");
966  $sql .= ", ".($this->pos_source != '' ? "'".$this->db->escape($this->pos_source)."'" : "null");
967  $sql .= ", ".(int) $this->fk_multicurrency;
968  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
969  $sql .= ", ".(double) $this->multicurrency_tx;
970  $sql .= ")";
971 
972  dol_syslog(get_class($this)."::create", LOG_DEBUG);
973  $resql = $this->db->query($sql);
974  if ($resql)
975  {
976  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'commande');
977 
978  if ($this->id)
979  {
980  $fk_parent_line = 0;
981  $num = count($this->lines);
982 
983  /*
984  * Insert products details into db
985  */
986  for ($i = 0; $i < $num; $i++)
987  {
988  $line = $this->lines[$i];
989 
990  // Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
991  //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object.
992  if (!is_object($line)) $line = (object) $line;
993 
994  // Reset fk_parent_line for no child products and special product
995  if (($line->product_type != 9 && empty($line->fk_parent_line)) || $line->product_type == 9) {
996  $fk_parent_line = 0;
997  }
998 
999  // Complete vat rate with code
1000  $vatrate = $line->tva_tx;
1001  if ($line->vat_src_code && !preg_match('/\(.*\)/', $vatrate)) $vatrate .= ' ('.$line->vat_src_code.')';
1002 
1003  if (!empty($conf->global->MAIN_CREATEFROM_KEEP_LINE_ORIGIN_INFORMATION)) {
1004  $originid = $line->origin_id;
1005  $origintype = $line->origin;
1006  } else {
1007  $originid = $line->id;
1008  $origintype = $this->element;
1009  }
1010 
1011  // ref_ext
1012  if (empty($line->ref_ext)) {
1013  $line->ref_ext = '';
1014  }
1015 
1016  $result = $this->addline(
1017  $line->desc,
1018  $line->subprice,
1019  $line->qty,
1020  $vatrate,
1021  $line->localtax1_tx,
1022  $line->localtax2_tx,
1023  $line->fk_product,
1024  $line->remise_percent,
1025  $line->info_bits,
1026  $line->fk_remise_except,
1027  'HT',
1028  0,
1029  $line->date_start,
1030  $line->date_end,
1031  $line->product_type,
1032  $line->rang,
1033  $line->special_code,
1034  $fk_parent_line,
1035  $line->fk_fournprice,
1036  $line->pa_ht,
1037  $line->label,
1038  $line->array_options,
1039  $line->fk_unit,
1040  $origintype,
1041  $originid,
1042  0,
1043  $line->ref_ext
1044  );
1045  if ($result < 0)
1046  {
1047  if ($result != self::STOCK_NOT_ENOUGH_FOR_ORDER)
1048  {
1049  $this->error = $this->db->lasterror();
1050  $this->errors[] = $this->error;
1051  dol_print_error($this->db);
1052  }
1053  $this->db->rollback();
1054  return -1;
1055  }
1056  // Defined the new fk_parent_line
1057  if ($result > 0 && $line->product_type == 9) {
1058  $fk_parent_line = $result;
1059  }
1060  }
1061 
1062  // update ref
1063  $initialref = '(PROV'.$this->id.')';
1064  if (!empty($this->ref)) $initialref = $this->ref;
1065 
1066  $sql = 'UPDATE '.MAIN_DB_PREFIX."commande SET ref='".$this->db->escape($initialref)."' WHERE rowid=".$this->id;
1067  if ($this->db->query($sql))
1068  {
1069  $this->ref = $initialref;
1070 
1071  if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) // To use new linkedObjectsIds instead of old linked_objects
1072  {
1073  $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
1074  }
1075 
1076  // Add object linked
1077  if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects))
1078  {
1079  foreach ($this->linked_objects as $origin => $tmp_origin_id)
1080  {
1081  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, ...))
1082  {
1083  foreach ($tmp_origin_id as $origin_id)
1084  {
1085  $ret = $this->add_object_linked($origin, $origin_id);
1086  if (!$ret)
1087  {
1088  $this->error = $this->db->lasterror();
1089  $error++;
1090  }
1091  }
1092  } else // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
1093  {
1094  $origin_id = $tmp_origin_id;
1095  $ret = $this->add_object_linked($origin, $origin_id);
1096  if (!$ret)
1097  {
1098  $this->error = $this->db->lasterror();
1099  $error++;
1100  }
1101  }
1102  }
1103  }
1104 
1105  if (!$error && $this->id && !empty($conf->global->MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN) && !empty($this->origin) && !empty($this->origin_id)) // Get contact from origin object
1106  {
1107  $originforcontact = $this->origin;
1108  $originidforcontact = $this->origin_id;
1109  if ($originforcontact == 'shipping') // shipment and order share the same contacts. If creating from shipment we take data of order
1110  {
1111  require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
1112  $exp = new Expedition($this->db);
1113  $exp->fetch($this->origin_id);
1114  $exp->fetchObjectLinked();
1115  if (count($exp->linkedObjectsIds['commande']) > 0)
1116  {
1117  foreach ($exp->linkedObjectsIds['commande'] as $key => $value)
1118  {
1119  $originforcontact = 'commande';
1120  if (is_object($value)) $originidforcontact = $value->id;
1121  else $originidforcontact = $value;
1122  break; // We take first one
1123  }
1124  }
1125  }
1126 
1127  $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";
1128  $sqlcontact .= " WHERE element_id = ".$originidforcontact." AND ec.fk_c_type_contact = ctc.rowid AND ctc.element = '".$this->db->escape($originforcontact)."'";
1129 
1130  $resqlcontact = $this->db->query($sqlcontact);
1131  if ($resqlcontact)
1132  {
1133  while ($objcontact = $this->db->fetch_object($resqlcontact))
1134  {
1135  //print $objcontact->code.'-'.$objcontact->source.'-'.$objcontact->fk_socpeople."\n";
1136  $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
1137  }
1138  } else dol_print_error($resqlcontact);
1139  }
1140 
1141  if (!$error)
1142  {
1143  $result = $this->insertExtraFields();
1144  if ($result < 0) $error++;
1145  }
1146 
1147  if (!$error && !$notrigger)
1148  {
1149  // Call trigger
1150  $result = $this->call_trigger('ORDER_CREATE', $user);
1151  if ($result < 0) $error++;
1152  // End call triggers
1153  }
1154 
1155  if (!$error)
1156  {
1157  $this->db->commit();
1158  return $this->id;
1159  } else {
1160  $this->db->rollback();
1161  return -1 * $error;
1162  }
1163  } else {
1164  $this->error = $this->db->lasterror();
1165  $this->db->rollback();
1166  return -1;
1167  }
1168  }
1169  } else {
1170  dol_print_error($this->db);
1171  $this->db->rollback();
1172  return -1;
1173  }
1174  }
1175 
1176 
1184  public function createFromClone(User $user, $socid = 0)
1185  {
1186  global $conf, $user, $hookmanager;
1187 
1188  $error = 0;
1189 
1190  $this->db->begin();
1191 
1192  // get lines so they will be clone
1193  foreach ($this->lines as $line)
1194  $line->fetch_optionals();
1195 
1196  // Load source object
1197  $objFrom = clone $this;
1198 
1199  // Change socid if needed
1200  if (!empty($socid) && $socid != $this->socid)
1201  {
1202  $objsoc = new Societe($this->db);
1203 
1204  if ($objsoc->fetch($socid) > 0)
1205  {
1206  $this->socid = $objsoc->id;
1207  $this->cond_reglement_id = (!empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0);
1208  $this->mode_reglement_id = (!empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0);
1209  $this->fk_project = 0;
1210  $this->fk_delivery_address = 0;
1211  }
1212 
1213  // TODO Change product price if multi-prices
1214  }
1215 
1216  $this->id = 0;
1217  $this->ref = '';
1218  $this->statut = self::STATUS_DRAFT;
1219 
1220  // Clear fields
1221  $this->user_author_id = $user->id;
1222  $this->user_valid = '';
1223  $this->date = dol_now();
1224  $this->date_commande = dol_now();
1225  $this->date_creation = '';
1226  $this->date_validation = '';
1227  if (empty($conf->global->MAIN_KEEP_REF_CUSTOMER_ON_CLONING)) $this->ref_client = '';
1228 
1229  // Do not clone ref_ext
1230  $num = count($this->lines);
1231  for ($i = 0; $i < $num; $i++)
1232  {
1233  $this->lines[$i]->ref_ext = '';
1234  }
1235 
1236  // Create clone
1237  $this->context['createfromclone'] = 'createfromclone';
1238  $result = $this->create($user);
1239  if ($result < 0) $error++;
1240 
1241  if (!$error)
1242  {
1243  // copy internal contacts
1244  if ($this->copy_linked_contact($objFrom, 'internal') < 0)
1245  {
1246  $error++;
1247  }
1248  }
1249 
1250  if (!$error)
1251  {
1252  // copy external contacts if same company
1253  if ($this->socid == $objFrom->socid)
1254  {
1255  if ($this->copy_linked_contact($objFrom, 'external') < 0)
1256  $error++;
1257  }
1258  }
1259 
1260  if (!$error)
1261  {
1262  // Hook of thirdparty module
1263  if (is_object($hookmanager))
1264  {
1265  $parameters = array('objFrom'=>$objFrom);
1266  $action = '';
1267  $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1268  if ($reshook < 0) $error++;
1269  }
1270  }
1271 
1272  unset($this->context['createfromclone']);
1273 
1274  // End
1275  if (!$error)
1276  {
1277  $this->db->commit();
1278  return $this->id;
1279  } else {
1280  $this->db->rollback();
1281  return -1;
1282  }
1283  }
1284 
1285 
1293  public function createFromProposal($object, User $user)
1294  {
1295  global $conf, $hookmanager;
1296 
1297  dol_include_once('/core/class/extrafields.class.php');
1298 
1299  $error = 0;
1300 
1301 
1302  $this->date_commande = dol_now();
1303  $this->source = 0;
1304 
1305  $num = count($object->lines);
1306  for ($i = 0; $i < $num; $i++)
1307  {
1308  $line = new OrderLine($this->db);
1309 
1310  $line->libelle = $object->lines[$i]->libelle;
1311  $line->label = $object->lines[$i]->label;
1312  $line->desc = $object->lines[$i]->desc;
1313  $line->price = $object->lines[$i]->price;
1314  $line->subprice = $object->lines[$i]->subprice;
1315  $line->vat_src_code = $object->lines[$i]->vat_src_code;
1316  $line->tva_tx = $object->lines[$i]->tva_tx;
1317  $line->localtax1_tx = $object->lines[$i]->localtax1_tx;
1318  $line->localtax2_tx = $object->lines[$i]->localtax2_tx;
1319  $line->qty = $object->lines[$i]->qty;
1320  $line->fk_remise_except = $object->lines[$i]->fk_remise_except;
1321  $line->remise_percent = $object->lines[$i]->remise_percent;
1322  $line->fk_product = $object->lines[$i]->fk_product;
1323  $line->info_bits = $object->lines[$i]->info_bits;
1324  $line->product_type = $object->lines[$i]->product_type;
1325  $line->rang = $object->lines[$i]->rang;
1326  $line->special_code = $object->lines[$i]->special_code;
1327  $line->fk_parent_line = $object->lines[$i]->fk_parent_line;
1328  $line->fk_unit = $object->lines[$i]->fk_unit;
1329 
1330  $line->date_start = $object->lines[$i]->date_start;
1331  $line->date_end = $object->lines[$i]->date_end;
1332 
1333  $line->fk_fournprice = $object->lines[$i]->fk_fournprice;
1334  $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);
1335  $line->pa_ht = $marginInfos[0];
1336  $line->marge_tx = $marginInfos[1];
1337  $line->marque_tx = $marginInfos[2];
1338 
1339  // get extrafields from original line
1340  $object->lines[$i]->fetch_optionals();
1341  foreach ($object->lines[$i]->array_options as $options_key => $value)
1342  $line->array_options[$options_key] = $value;
1343 
1344  $this->lines[$i] = $line;
1345  }
1346 
1347  $this->entity = $object->entity;
1348  $this->socid = $object->socid;
1349  $this->fk_project = $object->fk_project;
1350  $this->cond_reglement_id = $object->cond_reglement_id;
1351  $this->mode_reglement_id = $object->mode_reglement_id;
1352  $this->fk_account = $object->fk_account;
1353  $this->availability_id = $object->availability_id;
1354  $this->demand_reason_id = $object->demand_reason_id;
1355  $this->date_livraison = $object->date_livraison; // deprecated
1356  $this->delivery_date = $object->date_livraison;
1357  $this->shipping_method_id = $object->shipping_method_id;
1358  $this->warehouse_id = $object->warehouse_id;
1359  $this->fk_delivery_address = $object->fk_delivery_address;
1360  $this->contact_id = $object->contact_id;
1361  $this->ref_client = $object->ref_client;
1362 
1363  if (empty($conf->global->MAIN_DISABLE_PROPAGATE_NOTES_FROM_ORIGIN))
1364  {
1365  $this->note_private = $object->note_private;
1366  $this->note_public = $object->note_public;
1367  }
1368 
1369  $this->origin = $object->element;
1370  $this->origin_id = $object->id;
1371 
1372  // get extrafields from original line
1373  $object->fetch_optionals();
1374 
1375  $e = new ExtraFields($this->db);
1376  $element_extrafields = $e->fetch_name_optionals_label($this->table_element);
1377 
1378  foreach ($object->array_options as $options_key => $value) {
1379  if (array_key_exists(str_replace('options_', '', $options_key), $element_extrafields)) {
1380  $this->array_options[$options_key] = $value;
1381  }
1382  }
1383  // Possibility to add external linked objects with hooks
1384  $this->linked_objects[$this->origin] = $this->origin_id;
1385  if (is_array($object->other_linked_objects) && !empty($object->other_linked_objects))
1386  {
1387  $this->linked_objects = array_merge($this->linked_objects, $object->other_linked_objects);
1388  }
1389 
1390  $ret = $this->create($user);
1391 
1392  if ($ret > 0)
1393  {
1394  // Actions hooked (by external module)
1395  $hookmanager->initHooks(array('orderdao'));
1396 
1397  $parameters = array('objFrom'=>$object);
1398  $action = '';
1399  $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1400  if ($reshook < 0) $error++;
1401 
1402  if (!$error)
1403  {
1404  // Validate immediatly the order
1405  if (!empty($conf->global->ORDER_VALID_AFTER_CLOSE_PROPAL))
1406  {
1407  $this->fetch($ret);
1408  $this->valid($user);
1409  }
1410  return $ret;
1411  } else return -1;
1412  } else return -1;
1413  }
1414 
1415 
1455  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 = '')
1456  {
1457  global $mysoc, $conf, $langs, $user;
1458 
1459  $logtext = "::addline commandeid=$this->id, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, fk_product=$fk_product, remise_percent=$remise_percent";
1460  $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";
1461  $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";
1462  dol_syslog(get_class($this).$logtext, LOG_DEBUG);
1463 
1464  if ($this->statut == self::STATUS_DRAFT)
1465  {
1466  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1467 
1468  // Clean parameters
1469 
1470  if (empty($remise_percent)) $remise_percent = 0;
1471  if (empty($qty)) $qty = 0;
1472  if (empty($info_bits)) $info_bits = 0;
1473  if (empty($rang)) $rang = 0;
1474  if (empty($txtva)) $txtva = 0;
1475  if (empty($txlocaltax1)) $txlocaltax1 = 0;
1476  if (empty($txlocaltax2)) $txlocaltax2 = 0;
1477  if (empty($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line = 0;
1478  if (empty($this->fk_multicurrency)) $this->fk_multicurrency = 0;
1479  if (empty($ref_ext)) $ref_ext = '';
1480 
1481  $remise_percent = price2num($remise_percent);
1482  $qty = price2num($qty);
1483  $pu_ht = price2num($pu_ht);
1484  $pu_ht_devise = price2num($pu_ht_devise);
1485  $pu_ttc = price2num($pu_ttc);
1486  $pa_ht = price2num($pa_ht);
1487  if (!preg_match('/\((.*)\)/', $txtva)) {
1488  $txtva = price2num($txtva); // $txtva can have format '5,1' or '5.1' or '5.1(XXX)', we must clean only if '5,1'
1489  }
1490  $txlocaltax1 = price2num($txlocaltax1);
1491  $txlocaltax2 = price2num($txlocaltax2);
1492  if ($price_base_type == 'HT')
1493  {
1494  $pu = $pu_ht;
1495  } else {
1496  $pu = $pu_ttc;
1497  }
1498  $label = trim($label);
1499  $desc = trim($desc);
1500 
1501  // Check parameters
1502  if ($type < 0) return -1;
1503 
1504  if ($date_start && $date_end && $date_start > $date_end) {
1505  $langs->load("errors");
1506  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
1507  return -1;
1508  }
1509 
1510  $this->db->begin();
1511 
1512  $product_type = $type;
1513  if (!empty($fk_product))
1514  {
1515  $product = new Product($this->db);
1516  $result = $product->fetch($fk_product);
1517  $product_type = $product->type;
1518 
1519  if (!empty($conf->global->STOCK_MUST_BE_ENOUGH_FOR_ORDER) && $product_type == 0 && $product->stock_reel < $qty)
1520  {
1521  $langs->load("errors");
1522  $this->error = $langs->trans('ErrorStockIsNotEnoughToAddProductOnOrder', $product->ref);
1523  $this->errors[] = $this->error;
1524  dol_syslog(get_class($this)."::addline error=Product ".$product->ref.": ".$this->error, LOG_ERR);
1525  $this->db->rollback();
1526  return self::STOCK_NOT_ENOUGH_FOR_ORDER;
1527  }
1528  }
1529  // Calcul du total TTC et de la TVA pour la ligne a partir de
1530  // qty, pu, remise_percent et txtva
1531  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1532  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1533 
1534  $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
1535 
1536  // Clean vat code
1537  $reg = array();
1538  $vat_src_code = '';
1539  if (preg_match('/\((.*)\)/', $txtva, $reg))
1540  {
1541  $vat_src_code = $reg[1];
1542  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
1543  }
1544 
1545  $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);
1546 
1547  /*var_dump($txlocaltax1);
1548  var_dump($txlocaltax2);
1549  var_dump($localtaxes_type);
1550  var_dump($tabprice);
1551  var_dump($tabprice[9]);
1552  var_dump($tabprice[10]);
1553  exit;*/
1554 
1555  $total_ht = $tabprice[0];
1556  $total_tva = $tabprice[1];
1557  $total_ttc = $tabprice[2];
1558  $total_localtax1 = $tabprice[9];
1559  $total_localtax2 = $tabprice[10];
1560  $pu_ht = $tabprice[3];
1561 
1562  // MultiCurrency
1563  $multicurrency_total_ht = $tabprice[16];
1564  $multicurrency_total_tva = $tabprice[17];
1565  $multicurrency_total_ttc = $tabprice[18];
1566  $pu_ht_devise = $tabprice[19];
1567 
1568  // Rang to use
1569  $ranktouse = $rang;
1570  if ($ranktouse == -1)
1571  {
1572  $rangmax = $this->line_max($fk_parent_line);
1573  $ranktouse = $rangmax + 1;
1574  }
1575 
1576  // TODO A virer
1577  // Anciens indicateurs: $price, $remise (a ne plus utiliser)
1578  $price = $pu;
1579  $remise = 0;
1580  if ($remise_percent > 0)
1581  {
1582  $remise = round(($pu * $remise_percent / 100), 2);
1583  $price = $pu - $remise;
1584  }
1585 
1586  // Insert line
1587  $this->line = new OrderLine($this->db);
1588 
1589  $this->line->context = $this->context;
1590 
1591  $this->line->fk_commande = $this->id;
1592  $this->line->label = $label;
1593  $this->line->desc = $desc;
1594  $this->line->qty = $qty;
1595  $this->line->ref_ext = $ref_ext;
1596 
1597  $this->line->vat_src_code = $vat_src_code;
1598  $this->line->tva_tx = $txtva;
1599  $this->line->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0);
1600  $this->line->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0);
1601  $this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
1602  $this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
1603  $this->line->fk_product = $fk_product;
1604  $this->line->product_type = $product_type;
1605  $this->line->fk_remise_except = $fk_remise_except;
1606  $this->line->remise_percent = $remise_percent;
1607  $this->line->subprice = $pu_ht;
1608  $this->line->rang = $ranktouse;
1609  $this->line->info_bits = $info_bits;
1610  $this->line->total_ht = $total_ht;
1611  $this->line->total_tva = $total_tva;
1612  $this->line->total_localtax1 = $total_localtax1;
1613  $this->line->total_localtax2 = $total_localtax2;
1614  $this->line->total_ttc = $total_ttc;
1615  $this->line->special_code = $special_code;
1616  $this->line->origin = $origin;
1617  $this->line->origin_id = $origin_id;
1618  $this->line->fk_parent_line = $fk_parent_line;
1619  $this->line->fk_unit = $fk_unit;
1620 
1621  $this->line->date_start = $date_start;
1622  $this->line->date_end = $date_end;
1623 
1624  $this->line->fk_fournprice = $fk_fournprice;
1625  $this->line->pa_ht = $pa_ht;
1626 
1627  // Multicurrency
1628  $this->line->fk_multicurrency = $this->fk_multicurrency;
1629  $this->line->multicurrency_code = $this->multicurrency_code;
1630  $this->line->multicurrency_subprice = $pu_ht_devise;
1631  $this->line->multicurrency_total_ht = $multicurrency_total_ht;
1632  $this->line->multicurrency_total_tva = $multicurrency_total_tva;
1633  $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
1634 
1635  // TODO Ne plus utiliser
1636  $this->line->price = $price;
1637  $this->line->remise = $remise;
1638 
1639  if (is_array($array_options) && count($array_options) > 0) {
1640  $this->line->array_options = $array_options;
1641  }
1642 
1643  $result = $this->line->insert($user);
1644  if ($result > 0)
1645  {
1646  // Reorder if child line
1647  if (!empty($fk_parent_line)) $this->line_order(true, 'DESC');
1648 
1649  // Mise a jour informations denormalisees au niveau de la commande meme
1650  $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.
1651  if ($result > 0)
1652  {
1653  $this->db->commit();
1654  return $this->line->id;
1655  } else {
1656  $this->db->rollback();
1657  return -1;
1658  }
1659  } else {
1660  $this->error = $this->line->error;
1661  dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR);
1662  $this->db->rollback();
1663  return -2;
1664  }
1665  } else {
1666  dol_syslog(get_class($this)."::addline status of order must be Draft to allow use of ->addline()", LOG_ERR);
1667  return -3;
1668  }
1669  }
1670 
1671 
1672  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1686  public function add_product($idproduct, $qty, $remise_percent = 0.0, $date_start = '', $date_end = '')
1687  {
1688  // phpcs:enable
1689  global $conf, $mysoc;
1690 
1691  if (!$qty) $qty = 1;
1692 
1693  if ($idproduct > 0)
1694  {
1695  $prod = new Product($this->db);
1696  $prod->fetch($idproduct);
1697 
1698  $tva_tx = get_default_tva($mysoc, $this->thirdparty, $prod->id);
1699  $tva_npr = get_default_npr($mysoc, $this->thirdparty, $prod->id);
1700  if (empty($tva_tx)) $tva_npr = 0;
1701  $vat_src_code = ''; // May be defined into tva_tx
1702 
1703  $localtax1_tx = get_localtax($tva_tx, 1, $this->thirdparty, $mysoc, $tva_npr);
1704  $localtax2_tx = get_localtax($tva_tx, 2, $this->thirdparty, $mysoc, $tva_npr);
1705 
1706  // multiprix
1707  if ($conf->global->PRODUIT_MULTIPRICES && $this->thirdparty->price_level) {
1708  $price = $prod->multiprices[$this->thirdparty->price_level];
1709  } else {
1710  $price = $prod->price;
1711  }
1712 
1713  $line = new OrderLine($this->db);
1714 
1715  $line->context = $this->context;
1716 
1717  $line->fk_product = $idproduct;
1718  $line->desc = $prod->description;
1719  $line->qty = $qty;
1720  $line->subprice = $price;
1721  $line->remise_percent = $remise_percent;
1722  $line->vat_src_code = $vat_src_code;
1723  $line->tva_tx = $tva_tx;
1724  $line->localtax1_tx = $localtax1_tx;
1725  $line->localtax2_tx = $localtax2_tx;
1726  $line->ref = $prod->ref;
1727  $line->libelle = $prod->label;
1728  $line->product_desc = $prod->description;
1729  $line->fk_unit = $prod->fk_unit;
1730 
1731  // Save the start and end date of the line in the object
1732  if ($date_start) { $line->date_start = $date_start; }
1733  if ($date_end) { $line->date_end = $date_end; }
1734 
1735  $this->lines[] = $line;
1736 
1755  }
1756  }
1757 
1758 
1768  public function fetch($id, $ref = '', $ref_ext = '', $notused = '')
1769  {
1770  // Check parameters
1771  if (empty($id) && empty($ref) && empty($ref_ext)) return -1;
1772 
1773  $sql = 'SELECT c.rowid, c.entity, c.date_creation, c.ref, c.fk_soc, c.fk_user_author, c.fk_user_valid, c.fk_statut';
1774  $sql .= ', c.amount_ht, c.total_ht, c.total_ttc, c.tva as total_tva, c.localtax1 as total_localtax1, c.localtax2 as total_localtax2, c.fk_cond_reglement, c.fk_mode_reglement, c.fk_availability, c.fk_input_reason';
1775  $sql .= ', c.fk_account';
1776  $sql .= ', c.date_commande, c.date_valid, c.tms';
1777  $sql .= ', c.date_livraison as delivery_date';
1778  $sql .= ', c.fk_shipping_method';
1779  $sql .= ', c.fk_warehouse';
1780  $sql .= ', c.fk_projet as fk_project, c.remise_percent, c.remise, c.remise_absolue, c.source, c.facture as billed';
1781  $sql .= ', c.note_private, c.note_public, c.ref_client, c.ref_ext, c.ref_int, c.model_pdf, c.last_main_doc, c.fk_delivery_address, c.extraparams';
1782  $sql .= ', c.fk_incoterms, c.location_incoterms';
1783  $sql .= ", c.fk_multicurrency, c.multicurrency_code, c.multicurrency_tx, c.multicurrency_total_ht, c.multicurrency_total_tva, c.multicurrency_total_ttc";
1784  $sql .= ", c.module_source, c.pos_source";
1785  $sql .= ", i.libelle as label_incoterms";
1786  $sql .= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
1787  $sql .= ', cr.code as cond_reglement_code, cr.libelle as cond_reglement_libelle, cr.libelle_facture as cond_reglement_libelle_doc';
1788  $sql .= ', ca.code as availability_code, ca.label as availability_label';
1789  $sql .= ', dr.code as demand_reason_code';
1790  $sql .= ' FROM '.MAIN_DB_PREFIX.'commande as c';
1791  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as cr ON c.fk_cond_reglement = cr.rowid';
1792  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON c.fk_mode_reglement = p.id';
1793  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_availability as ca ON c.fk_availability = ca.rowid';
1794  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_input_reason as dr ON c.fk_input_reason = dr.rowid';
1795  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON c.fk_incoterms = i.rowid';
1796 
1797  if ($id) $sql .= " WHERE c.rowid=".$id;
1798  else $sql .= " WHERE c.entity IN (".getEntity('commande').")"; // Dont't use entity if you use rowid
1799 
1800  if ($ref) $sql .= " AND c.ref='".$this->db->escape($ref)."'";
1801  if ($ref_ext) $sql .= " AND c.ref_ext='".$this->db->escape($ref_ext)."'";
1802  if ($notused) $sql .= " AND c.ref_int='".$this->db->escape($notused)."'";
1803 
1804  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
1805  $result = $this->db->query($sql);
1806  if ($result)
1807  {
1808  $obj = $this->db->fetch_object($result);
1809  if ($obj)
1810  {
1811  $this->id = $obj->rowid;
1812  $this->entity = $obj->entity;
1813 
1814  $this->ref = $obj->ref;
1815  $this->ref_client = $obj->ref_client;
1816  $this->ref_customer = $obj->ref_client;
1817  $this->ref_ext = $obj->ref_ext;
1818  $this->ref_int = $obj->ref_int;
1819 
1820  $this->socid = $obj->fk_soc;
1821  $this->thirdparty = null; // Clear if another value was already set by fetch_thirdparty
1822 
1823  $this->fk_project = $obj->fk_project;
1824  $this->project = null; // Clear if another value was already set by fetch_projet
1825 
1826  $this->statut = $obj->fk_statut;
1827  $this->status = $obj->fk_statut;
1828 
1829  $this->user_author_id = $obj->fk_user_author;
1830  $this->user_valid = $obj->fk_user_valid;
1831  $this->total_ht = $obj->total_ht;
1832  $this->total_tva = $obj->total_tva;
1833  $this->total_localtax1 = $obj->total_localtax1;
1834  $this->total_localtax2 = $obj->total_localtax2;
1835  $this->total_ttc = $obj->total_ttc;
1836  $this->date = $this->db->jdate($obj->date_commande);
1837  $this->date_commande = $this->db->jdate($obj->date_commande);
1838  $this->date_creation = $this->db->jdate($obj->date_creation);
1839  $this->date_validation = $this->db->jdate($obj->date_valid);
1840  $this->date_modification = $this->db->jdate($obj->tms);
1841  $this->remise = $obj->remise;
1842  $this->remise_percent = $obj->remise_percent;
1843  $this->remise_absolue = $obj->remise_absolue;
1844  $this->source = $obj->source;
1845  $this->billed = $obj->billed;
1846  $this->note = $obj->note_private; // deprecated
1847  $this->note_private = $obj->note_private;
1848  $this->note_public = $obj->note_public;
1849  $this->model_pdf = $obj->model_pdf;
1850  $this->modelpdf = $obj->model_pdf; // deprecated
1851  $this->last_main_doc = $obj->last_main_doc;
1852  $this->mode_reglement_id = $obj->fk_mode_reglement;
1853  $this->mode_reglement_code = $obj->mode_reglement_code;
1854  $this->mode_reglement = $obj->mode_reglement_libelle;
1855  $this->cond_reglement_id = $obj->fk_cond_reglement;
1856  $this->cond_reglement_code = $obj->cond_reglement_code;
1857  $this->cond_reglement = $obj->cond_reglement_libelle;
1858  $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc;
1859  $this->fk_account = $obj->fk_account;
1860  $this->availability_id = $obj->fk_availability;
1861  $this->availability_code = $obj->availability_code;
1862  $this->availability = $obj->availability_label;
1863  $this->demand_reason_id = $obj->fk_input_reason;
1864  $this->demand_reason_code = $obj->demand_reason_code;
1865  $this->date_livraison = $this->db->jdate($obj->delivery_date); // deprecated
1866  $this->delivery_date = $this->db->jdate($obj->delivery_date);
1867  $this->shipping_method_id = ($obj->fk_shipping_method > 0) ? $obj->fk_shipping_method : null;
1868  $this->warehouse_id = ($obj->fk_warehouse > 0) ? $obj->fk_warehouse : null;
1869  $this->fk_delivery_address = $obj->fk_delivery_address;
1870  $this->module_source = $obj->module_source;
1871  $this->pos_source = $obj->pos_source;
1872 
1873  //Incoterms
1874  $this->fk_incoterms = $obj->fk_incoterms;
1875  $this->location_incoterms = $obj->location_incoterms;
1876  $this->label_incoterms = $obj->label_incoterms;
1877 
1878  // Multicurrency
1879  $this->fk_multicurrency = $obj->fk_multicurrency;
1880  $this->multicurrency_code = $obj->multicurrency_code;
1881  $this->multicurrency_tx = $obj->multicurrency_tx;
1882  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
1883  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
1884  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
1885 
1886  $this->extraparams = (array) json_decode($obj->extraparams, true);
1887 
1888  $this->lines = array();
1889 
1890  if ($this->statut == self::STATUS_DRAFT) $this->brouillon = 1;
1891 
1892  // Retrieve all extrafield
1893  // fetch optionals attributes and labels
1894  $this->fetch_optionals();
1895 
1896  $this->db->free($result);
1897 
1898  // Lines
1899  $result = $this->fetch_lines();
1900  if ($result < 0)
1901  {
1902  return -3;
1903  }
1904  return 1;
1905  } else {
1906  $this->error = 'Order with id '.$id.' not found sql='.$sql;
1907  return 0;
1908  }
1909  } else {
1910  $this->error = $this->db->error();
1911  return -1;
1912  }
1913  }
1914 
1915 
1916  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1923  public function insert_discount($idremise)
1924  {
1925  // phpcs:enable
1926  global $langs;
1927 
1928  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1929  include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
1930 
1931  $this->db->begin();
1932 
1933  $remise = new DiscountAbsolute($this->db);
1934  $result = $remise->fetch($idremise);
1935 
1936  if ($result > 0)
1937  {
1938  if ($remise->fk_facture) // Protection against multiple submission
1939  {
1940  $this->error = $langs->trans("ErrorDiscountAlreadyUsed");
1941  $this->db->rollback();
1942  return -5;
1943  }
1944 
1945  $line = new OrderLine($this->db);
1946 
1947  $line->fk_commande = $this->id;
1948  $line->fk_remise_except = $remise->id;
1949  $line->desc = $remise->description; // Description ligne
1950  $line->vat_src_code = $remise->vat_src_code;
1951  $line->tva_tx = $remise->tva_tx;
1952  $line->subprice = -$remise->amount_ht;
1953  $line->price = -$remise->amount_ht;
1954  $line->fk_product = 0; // Id produit predefini
1955  $line->qty = 1;
1956  $line->remise = 0;
1957  $line->remise_percent = 0;
1958  $line->rang = -1;
1959  $line->info_bits = 2;
1960 
1961  $line->total_ht = -$remise->amount_ht;
1962  $line->total_tva = -$remise->amount_tva;
1963  $line->total_ttc = -$remise->amount_ttc;
1964 
1965  $result = $line->insert();
1966  if ($result > 0)
1967  {
1968  $result = $this->update_price(1);
1969  if ($result > 0)
1970  {
1971  $this->db->commit();
1972  return 1;
1973  } else {
1974  $this->db->rollback();
1975  return -1;
1976  }
1977  } else {
1978  $this->error = $line->error;
1979  $this->errors = $line->errors;
1980  $this->db->rollback();
1981  return -2;
1982  }
1983  } else {
1984  $this->db->rollback();
1985  return -2;
1986  }
1987  }
1988 
1989 
1990  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1998  public function fetch_lines($only_product = 0, $loadalsotranslation = 0)
1999  {
2000  global $langs, $conf;
2001  // phpcs:enable
2002  $this->lines = array();
2003 
2004  $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,';
2005  $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,';
2006  $sql .= ' l.total_ht, l.total_ttc, l.total_tva, l.total_localtax1, l.total_localtax2, l.date_start, l.date_end,';
2007  $sql .= ' l.fk_unit,';
2008  $sql .= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
2009  $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,';
2010  $sql .= ' p.weight, p.weight_units, p.volume, p.volume_units';
2011  $sql .= ' FROM '.MAIN_DB_PREFIX.'commandedet as l';
2012  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON (p.rowid = l.fk_product)';
2013  $sql .= ' WHERE l.fk_commande = '.$this->id;
2014  if ($only_product) $sql .= ' AND p.fk_product_type = 0';
2015  $sql .= ' ORDER BY l.rang, l.rowid';
2016 
2017  dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
2018  $result = $this->db->query($sql);
2019  if ($result)
2020  {
2021  $num = $this->db->num_rows($result);
2022 
2023  $i = 0;
2024  while ($i < $num)
2025  {
2026  $objp = $this->db->fetch_object($result);
2027 
2028  $line = new OrderLine($this->db);
2029 
2030  $line->rowid = $objp->rowid;
2031  $line->id = $objp->rowid;
2032  $line->fk_commande = $objp->fk_commande;
2033  $line->commande_id = $objp->fk_commande;
2034  $line->label = $objp->custom_label;
2035  $line->desc = $objp->description;
2036  $line->description = $objp->description; // Description line
2037  $line->product_type = $objp->product_type;
2038  $line->qty = $objp->qty;
2039  $line->ref_ext = $objp->ref_ext;
2040 
2041  $line->vat_src_code = $objp->vat_src_code;
2042  $line->tva_tx = $objp->tva_tx;
2043  $line->localtax1_tx = $objp->localtax1_tx;
2044  $line->localtax2_tx = $objp->localtax2_tx;
2045  $line->localtax1_type = $objp->localtax1_type;
2046  $line->localtax2_type = $objp->localtax2_type;
2047  $line->total_ht = $objp->total_ht;
2048  $line->total_ttc = $objp->total_ttc;
2049  $line->total_tva = $objp->total_tva;
2050  $line->total_localtax1 = $objp->total_localtax1;
2051  $line->total_localtax2 = $objp->total_localtax2;
2052  $line->subprice = $objp->subprice;
2053  $line->fk_remise_except = $objp->fk_remise_except;
2054  $line->remise_percent = $objp->remise_percent;
2055  $line->price = $objp->price;
2056  $line->fk_product = $objp->fk_product;
2057  $line->fk_fournprice = $objp->fk_fournprice;
2058  $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht);
2059  $line->pa_ht = $marginInfos[0];
2060  $line->marge_tx = $marginInfos[1];
2061  $line->marque_tx = $marginInfos[2];
2062  $line->rang = $objp->rang;
2063  $line->info_bits = $objp->info_bits;
2064  $line->special_code = $objp->special_code;
2065  $line->fk_parent_line = $objp->fk_parent_line;
2066 
2067  $line->ref = $objp->product_ref;
2068  $line->libelle = $objp->product_label;
2069 
2070  $line->product_ref = $objp->product_ref;
2071  $line->product_label = $objp->product_label;
2072  $line->product_desc = $objp->product_desc;
2073  $line->product_tosell = $objp->product_tosell;
2074  $line->product_tobuy = $objp->product_tobuy;
2075  $line->product_tobatch = $objp->product_tobatch;
2076  $line->product_barcode = $objp->product_barcode;
2077 
2078  $line->fk_product_type = $objp->fk_product_type; // Produit ou service
2079  $line->fk_unit = $objp->fk_unit;
2080 
2081  $line->weight = $objp->weight;
2082  $line->weight_units = $objp->weight_units;
2083  $line->volume = $objp->volume;
2084  $line->volume_units = $objp->volume_units;
2085 
2086  $line->date_start = $this->db->jdate($objp->date_start);
2087  $line->date_end = $this->db->jdate($objp->date_end);
2088 
2089  // Multicurrency
2090  $line->fk_multicurrency = $objp->fk_multicurrency;
2091  $line->multicurrency_code = $objp->multicurrency_code;
2092  $line->multicurrency_subprice = $objp->multicurrency_subprice;
2093  $line->multicurrency_total_ht = $objp->multicurrency_total_ht;
2094  $line->multicurrency_total_tva = $objp->multicurrency_total_tva;
2095  $line->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
2096 
2097  $line->fetch_optionals();
2098 
2099  // multilangs
2100  if (!empty($conf->global->MAIN_MULTILANGS) && !empty($objp->fk_product) && !empty($loadalsotranslation)) {
2101  $line = new Product($this->db);
2102  $line->fetch($objp->fk_product);
2103  $line->getMultiLangs();
2104  }
2105 
2106  $this->lines[$i] = $line;
2107 
2108  $i++;
2109  }
2110 
2111  $this->db->free($result);
2112 
2113  return 1;
2114  } else {
2115  $this->error = $this->db->error();
2116  return -3;
2117  }
2118  }
2119 
2120 
2126  public function getNbOfProductsLines()
2127  {
2128  $nb = 0;
2129  foreach ($this->lines as $line)
2130  {
2131  if ($line->product_type == 0) $nb++;
2132  }
2133  return $nb;
2134  }
2135 
2141  public function getNbOfServicesLines()
2142  {
2143  $nb = 0;
2144  foreach ($this->lines as $line)
2145  {
2146  if ($line->product_type == 1) $nb++;
2147  }
2148  return $nb;
2149  }
2150 
2156  public function getNbOfShipments()
2157  {
2158  $nb = 0;
2159 
2160  $sql = 'SELECT COUNT(DISTINCT ed.fk_expedition) as nb';
2161  $sql .= ' FROM '.MAIN_DB_PREFIX.'expeditiondet as ed,';
2162  $sql .= ' '.MAIN_DB_PREFIX.'commandedet as cd';
2163  $sql .= ' WHERE';
2164  $sql .= ' ed.fk_origin_line = cd.rowid';
2165  $sql .= ' AND cd.fk_commande ='.$this->id;
2166  //print $sql;
2167 
2168  dol_syslog(get_class($this)."::getNbOfShipments", LOG_DEBUG);
2169  $resql = $this->db->query($sql);
2170  if ($resql)
2171  {
2172  $obj = $this->db->fetch_object($resql);
2173  if ($obj) $nb = $obj->nb;
2174 
2175  $this->db->free($resql);
2176  return $nb;
2177  } else {
2178  $this->error = $this->db->lasterror();
2179  return -1;
2180  }
2181  }
2182 
2190  public function loadExpeditions($filtre_statut = -1)
2191  {
2192  $this->expeditions = array();
2193 
2194  $sql = 'SELECT cd.rowid, cd.fk_product,';
2195  $sql .= ' sum(ed.qty) as qty';
2196  $sql .= ' FROM '.MAIN_DB_PREFIX.'expeditiondet as ed,';
2197  if ($filtre_statut >= 0) $sql .= ' '.MAIN_DB_PREFIX.'expedition as e,';
2198  $sql .= ' '.MAIN_DB_PREFIX.'commandedet as cd';
2199  $sql .= ' WHERE';
2200  if ($filtre_statut >= 0) $sql .= ' ed.fk_expedition = e.rowid AND';
2201  $sql .= ' ed.fk_origin_line = cd.rowid';
2202  $sql .= ' AND cd.fk_commande ='.$this->id;
2203  if ($this->fk_product > 0) $sql .= ' AND cd.fk_product = '.$this->fk_product;
2204  if ($filtre_statut >= 0) $sql .= ' AND e.fk_statut >= '.$filtre_statut;
2205  $sql .= ' GROUP BY cd.rowid, cd.fk_product';
2206  //print $sql;
2207 
2208  dol_syslog(get_class($this)."::loadExpeditions", LOG_DEBUG);
2209  $resql = $this->db->query($sql);
2210  if ($resql)
2211  {
2212  $num = $this->db->num_rows($resql);
2213  $i = 0;
2214  while ($i < $num)
2215  {
2216  $obj = $this->db->fetch_object($resql);
2217  $this->expeditions[$obj->rowid] = $obj->qty;
2218  $i++;
2219  }
2220  $this->db->free($resql);
2221  return $num;
2222  } else {
2223  $this->error = $this->db->lasterror();
2224  return -1;
2225  }
2226  }
2227 
2228  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2236  public function nb_expedition()
2237  {
2238  // phpcs:enable
2239  $sql = 'SELECT count(*)';
2240  $sql .= ' FROM '.MAIN_DB_PREFIX.'expedition as e';
2241  $sql .= ', '.MAIN_DB_PREFIX.'element_element as el';
2242  $sql .= ' WHERE el.fk_source = '.$this->id;
2243  $sql .= " AND el.fk_target = e.rowid";
2244  $sql .= " AND el.targettype = 'shipping'";
2245 
2246  $resql = $this->db->query($sql);
2247  if ($resql)
2248  {
2249  $row = $this->db->fetch_row($resql);
2250  return $row[0];
2251  } else dol_print_error($this->db);
2252  }
2253 
2254  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2263  public function stock_array($filtre_statut = self::STATUS_CANCELED)
2264  {
2265  // phpcs:enable
2266  $this->stocks = array();
2267 
2268  // Tableau des id de produit de la commande
2269  $array_of_product = array();
2270 
2271  // Recherche total en stock pour chaque produit
2272  // TODO $array_of_product est dĂ©fini vide juste au dessus !!
2273  if (count($array_of_product))
2274  {
2275  $sql = "SELECT fk_product, sum(ps.reel) as total";
2276  $sql .= " FROM ".MAIN_DB_PREFIX."product_stock as ps";
2277  $sql .= " WHERE ps.fk_product IN (".join(',', $array_of_product).")";
2278  $sql .= ' GROUP BY fk_product ';
2279  $resql = $this->db->query($sql);
2280  if ($resql)
2281  {
2282  $num = $this->db->num_rows($resql);
2283  $i = 0;
2284  while ($i < $num)
2285  {
2286  $obj = $this->db->fetch_object($resql);
2287  $this->stocks[$obj->fk_product] = $obj->total;
2288  $i++;
2289  }
2290  $this->db->free($resql);
2291  }
2292  }
2293  return 0;
2294  }
2295 
2303  public function deleteline($user = null, $lineid = 0)
2304  {
2305  if ($this->statut == self::STATUS_DRAFT)
2306  {
2307  $this->db->begin();
2308 
2309  $sql = "SELECT fk_product, qty";
2310  $sql .= " FROM ".MAIN_DB_PREFIX."commandedet";
2311  $sql .= " WHERE rowid = ".$lineid;
2312 
2313  $result = $this->db->query($sql);
2314  if ($result)
2315  {
2316  $obj = $this->db->fetch_object($result);
2317 
2318  if ($obj)
2319  {
2320  $product = new Product($this->db);
2321  $product->id = $obj->fk_product;
2322 
2323  // Delete line
2324  $line = new OrderLine($this->db);
2325 
2326  // For triggers
2327  $line->fetch($lineid);
2328 
2329  if ($line->delete($user) > 0)
2330  {
2331  $result = $this->update_price(1);
2332 
2333  if ($result > 0)
2334  {
2335  $this->db->commit();
2336  return 1;
2337  } else {
2338  $this->db->rollback();
2339  $this->error = $this->db->lasterror();
2340  return -1;
2341  }
2342  } else {
2343  $this->db->rollback();
2344  $this->error = $line->error;
2345  return -1;
2346  }
2347  } else {
2348  $this->db->rollback();
2349  return 0;
2350  }
2351  } else {
2352  $this->db->rollback();
2353  $this->error = $this->db->lasterror();
2354  return -1;
2355  }
2356  } else {
2357  $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
2358  return -1;
2359  }
2360  }
2361 
2362  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2371  public function set_remise($user, $remise, $notrigger = 0)
2372  {
2373  // phpcs:enable
2374  $remise = trim($remise) ?trim($remise) : 0;
2375 
2376  if ($user->rights->commande->creer)
2377  {
2378  $error = 0;
2379 
2380  $this->db->begin();
2381 
2382  $remise = price2num($remise);
2383 
2384  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
2385  $sql .= ' SET remise_percent = '.$remise;
2386  $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut = '.self::STATUS_DRAFT.' ;';
2387 
2388  dol_syslog(__METHOD__, LOG_DEBUG);
2389  $resql = $this->db->query($sql);
2390  if (!$resql)
2391  {
2392  $this->errors[] = $this->db->error();
2393  $error++;
2394  }
2395 
2396  if (!$error)
2397  {
2398  $this->oldcopy = clone $this;
2399  $this->remise_percent = $remise;
2400  $this->update_price(1);
2401  }
2402 
2403  if (!$notrigger && empty($error))
2404  {
2405  // Call trigger
2406  $result = $this->call_trigger('ORDER_MODIFY', $user);
2407  if ($result < 0) $error++;
2408  // End call triggers
2409  }
2410 
2411  if (!$error)
2412  {
2413  $this->db->commit();
2414  return 1;
2415  } else {
2416  foreach ($this->errors as $errmsg)
2417  {
2418  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2419  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2420  }
2421  $this->db->rollback();
2422  return -1 * $error;
2423  }
2424  }
2425  }
2426 
2427 
2428  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2437  public function set_remise_absolue($user, $remise, $notrigger = 0)
2438  {
2439  // phpcs:enable
2440  $remise = trim($remise) ?trim($remise) : 0;
2441 
2442  if ($user->rights->commande->creer)
2443  {
2444  $error = 0;
2445 
2446  $this->db->begin();
2447 
2448  $remise = price2num($remise);
2449 
2450  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
2451  $sql .= ' SET remise_absolue = '.$remise;
2452  $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut = '.self::STATUS_DRAFT.' ;';
2453 
2454  dol_syslog(__METHOD__, LOG_DEBUG);
2455  $resql = $this->db->query($sql);
2456  if (!$resql)
2457  {
2458  $this->errors[] = $this->db->error();
2459  $error++;
2460  }
2461 
2462  if (!$error)
2463  {
2464  $this->oldcopy = clone $this;
2465  $this->remise_absolue = $remise;
2466  $this->update_price(1);
2467  }
2468 
2469  if (!$notrigger && empty($error))
2470  {
2471  // Call trigger
2472  $result = $this->call_trigger('ORDER_MODIFY', $user);
2473  if ($result < 0) $error++;
2474  // End call triggers
2475  }
2476 
2477  if (!$error)
2478  {
2479  $this->db->commit();
2480  return 1;
2481  } else {
2482  foreach ($this->errors as $errmsg)
2483  {
2484  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2485  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2486  }
2487  $this->db->rollback();
2488  return -1 * $error;
2489  }
2490  }
2491  }
2492 
2493 
2494  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2503  public function set_date($user, $date, $notrigger = 0)
2504  {
2505  // phpcs:enable
2506  if ($user->rights->commande->creer)
2507  {
2508  $error = 0;
2509 
2510  $this->db->begin();
2511 
2512  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
2513  $sql .= " SET date_commande = ".($date ? "'".$this->db->idate($date)."'" : 'null');
2514  $sql .= " WHERE rowid = ".$this->id." AND fk_statut = ".self::STATUS_DRAFT;
2515 
2516  dol_syslog(__METHOD__, LOG_DEBUG);
2517  $resql = $this->db->query($sql);
2518  if (!$resql)
2519  {
2520  $this->errors[] = $this->db->error();
2521  $error++;
2522  }
2523 
2524  if (!$error)
2525  {
2526  $this->oldcopy = clone $this;
2527  $this->date = $date;
2528  }
2529 
2530  if (!$notrigger && empty($error))
2531  {
2532  // Call trigger
2533  $result = $this->call_trigger('ORDER_MODIFY', $user);
2534  if ($result < 0) $error++;
2535  // End call triggers
2536  }
2537 
2538  if (!$error)
2539  {
2540  $this->db->commit();
2541  return 1;
2542  } else {
2543  foreach ($this->errors as $errmsg)
2544  {
2545  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2546  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2547  }
2548  $this->db->rollback();
2549  return -1 * $error;
2550  }
2551  } else {
2552  return -2;
2553  }
2554  }
2555 
2556  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2566  public function set_date_livraison($user, $delivery_date, $notrigger = 0)
2567  {
2568  // phpcs:enable
2569  return $this->setDeliveryDate($user, $delivery_date, $notrigger);
2570  }
2571 
2580  public function setDeliveryDate($user, $delivery_date, $notrigger = 0)
2581  {
2582  if ($user->rights->commande->creer)
2583  {
2584  $error = 0;
2585 
2586  $this->db->begin();
2587 
2588  $sql = "UPDATE ".MAIN_DB_PREFIX."commande";
2589  $sql .= " SET date_livraison = ".($delivery_date ? "'".$this->db->idate($delivery_date)."'" : 'null');
2590  $sql .= " WHERE rowid = ".$this->id;
2591 
2592  dol_syslog(__METHOD__, LOG_DEBUG);
2593  $resql = $this->db->query($sql);
2594  if (!$resql)
2595  {
2596  $this->errors[] = $this->db->error();
2597  $error++;
2598  }
2599 
2600  if (!$error)
2601  {
2602  $this->oldcopy = clone $this;
2603  $this->date_livraison = $delivery_date;
2604  $this->delivery_date = $delivery_date;
2605  }
2606 
2607  if (!$notrigger && empty($error))
2608  {
2609  // Call trigger
2610  $result = $this->call_trigger('ORDER_MODIFY', $user);
2611  if ($result < 0) $error++;
2612  // End call triggers
2613  }
2614 
2615  if (!$error)
2616  {
2617  $this->db->commit();
2618  return 1;
2619  } else {
2620  foreach ($this->errors as $errmsg)
2621  {
2622  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2623  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2624  }
2625  $this->db->rollback();
2626  return -1 * $error;
2627  }
2628  } else {
2629  return -2;
2630  }
2631  }
2632 
2633  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2647  public function liste_array($shortlist = 0, $draft = 0, $excluser = '', $socid = 0, $limit = 0, $offset = 0, $sortfield = 'c.date_commande', $sortorder = 'DESC')
2648  {
2649  // phpcs:enable
2650  global $user;
2651 
2652  $ga = array();
2653 
2654  $sql = "SELECT s.rowid, s.nom as name, s.client,";
2655  $sql .= " c.rowid as cid, c.ref";
2656  if (!$user->rights->societe->client->voir && !$socid) $sql .= ", sc.fk_soc, sc.fk_user";
2657  $sql .= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande as c";
2658  if (!$user->rights->societe->client->voir && !$socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
2659  $sql .= " WHERE c.entity IN (".getEntity('commande').")";
2660  $sql .= " AND c.fk_soc = s.rowid";
2661  if (!$user->rights->societe->client->voir && !$socid) //restriction
2662  {
2663  $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id;
2664  }
2665  if ($socid) $sql .= " AND s.rowid = ".$socid;
2666  if ($draft) $sql .= " AND c.fk_statut = ".self::STATUS_DRAFT;
2667  if (is_object($excluser)) $sql .= " AND c.fk_user_author <> ".$excluser->id;
2668  $sql .= $this->db->order($sortfield, $sortorder);
2669  $sql .= $this->db->plimit($limit, $offset);
2670 
2671  $result = $this->db->query($sql);
2672  if ($result)
2673  {
2674  $numc = $this->db->num_rows($result);
2675  if ($numc)
2676  {
2677  $i = 0;
2678  while ($i < $numc)
2679  {
2680  $obj = $this->db->fetch_object($result);
2681 
2682  if ($shortlist == 1)
2683  {
2684  $ga[$obj->cid] = $obj->ref;
2685  } elseif ($shortlist == 2)
2686  {
2687  $ga[$obj->cid] = $obj->ref.' ('.$obj->name.')';
2688  } else {
2689  $ga[$i]['id'] = $obj->cid;
2690  $ga[$i]['ref'] = $obj->ref;
2691  $ga[$i]['name'] = $obj->name;
2692  }
2693  $i++;
2694  }
2695  }
2696  return $ga;
2697  } else {
2698  dol_print_error($this->db);
2699  return -1;
2700  }
2701  }
2702 
2710  public function availability($availability_id, $notrigger = 0)
2711  {
2712  global $user;
2713 
2714  dol_syslog('Commande::availability('.$availability_id.')');
2715  if ($this->statut >= self::STATUS_DRAFT)
2716  {
2717  $error = 0;
2718 
2719  $this->db->begin();
2720 
2721  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
2722  $sql .= ' SET fk_availability = '.$availability_id;
2723  $sql .= ' WHERE rowid='.$this->id;
2724 
2725  dol_syslog(__METHOD__, LOG_DEBUG);
2726  $resql = $this->db->query($sql);
2727  if (!$resql)
2728  {
2729  $this->errors[] = $this->db->error();
2730  $error++;
2731  }
2732 
2733  if (!$error)
2734  {
2735  $this->oldcopy = clone $this;
2736  $this->availability_id = $availability_id;
2737  }
2738 
2739  if (!$notrigger && empty($error))
2740  {
2741  // Call trigger
2742  $result = $this->call_trigger('ORDER_MODIFY', $user);
2743  if ($result < 0) $error++;
2744  // End call triggers
2745  }
2746 
2747  if (!$error)
2748  {
2749  $this->db->commit();
2750  return 1;
2751  } else {
2752  foreach ($this->errors as $errmsg)
2753  {
2754  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2755  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2756  }
2757  $this->db->rollback();
2758  return -1 * $error;
2759  }
2760  } else {
2761  $error_str = 'Command status do not meet requirement '.$this->statut;
2762  dol_syslog(__METHOD__.$error_str, LOG_ERR);
2763  $this->error = $error_str;
2764  $this->errors[] = $this->error;
2765  return -2;
2766  }
2767  }
2768 
2769  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2777  public function demand_reason($demand_reason_id, $notrigger = 0)
2778  {
2779  // phpcs:enable
2780  global $user;
2781 
2782  dol_syslog('Commande::demand_reason('.$demand_reason_id.')');
2783  if ($this->statut >= self::STATUS_DRAFT)
2784  {
2785  $error = 0;
2786 
2787  $this->db->begin();
2788 
2789  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
2790  $sql .= ' SET fk_input_reason = '.$demand_reason_id;
2791  $sql .= ' WHERE rowid='.$this->id;
2792 
2793  dol_syslog(__METHOD__, LOG_DEBUG);
2794  $resql = $this->db->query($sql);
2795  if (!$resql)
2796  {
2797  $this->errors[] = $this->db->error();
2798  $error++;
2799  }
2800 
2801  if (!$error)
2802  {
2803  $this->oldcopy = clone $this;
2804  $this->demand_reason_id = $demand_reason_id;
2805  }
2806 
2807  if (!$notrigger && empty($error))
2808  {
2809  // Call trigger
2810  $result = $this->call_trigger('ORDER_MODIFY', $user);
2811  if ($result < 0) $error++;
2812  // End call triggers
2813  }
2814 
2815  if (!$error)
2816  {
2817  $this->db->commit();
2818  return 1;
2819  } else {
2820  foreach ($this->errors as $errmsg)
2821  {
2822  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2823  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2824  }
2825  $this->db->rollback();
2826  return -1 * $error;
2827  }
2828  } else {
2829  $error_str = 'order status do not meet requirement '.$this->statut;
2830  dol_syslog(__METHOD__.$error_str, LOG_ERR);
2831  $this->error = $error_str;
2832  $this->errors[] = $this->error;
2833  return -2;
2834  }
2835  }
2836 
2837  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2846  public function set_ref_client($user, $ref_client, $notrigger = 0)
2847  {
2848  // phpcs:enable
2849  if ($user->rights->commande->creer)
2850  {
2851  $error = 0;
2852 
2853  $this->db->begin();
2854 
2855  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande SET';
2856  $sql .= ' ref_client = '.(empty($ref_client) ? 'NULL' : '\''.$this->db->escape($ref_client).'\'');
2857  $sql .= ' WHERE rowid = '.$this->id;
2858 
2859  dol_syslog(__METHOD__.' this->id='.$this->id.', ref_client='.$ref_client, LOG_DEBUG);
2860  $resql = $this->db->query($sql);
2861  if (!$resql)
2862  {
2863  $this->errors[] = $this->db->error();
2864  $error++;
2865  }
2866 
2867  if (!$error)
2868  {
2869  $this->oldcopy = clone $this;
2870  $this->ref_client = $ref_client;
2871  }
2872 
2873  if (!$notrigger && empty($error))
2874  {
2875  // Call trigger
2876  $result = $this->call_trigger('ORDER_MODIFY', $user);
2877  if ($result < 0) $error++;
2878  // End call triggers
2879  }
2880  if (!$error)
2881  {
2882  $this->db->commit();
2883  return 1;
2884  } else {
2885  foreach ($this->errors as $errmsg)
2886  {
2887  dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2888  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2889  }
2890  $this->db->rollback();
2891  return -1 * $error;
2892  }
2893  } else {
2894  return -1;
2895  }
2896  }
2897 
2905  public function classifyBilled(User $user, $notrigger = 0)
2906  {
2907  $error = 0;
2908 
2909  if ($this->billed)
2910  {
2911  return 0;
2912  }
2913 
2914  $this->db->begin();
2915 
2916  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande SET facture = 1';
2917  $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > '.self::STATUS_DRAFT;
2918 
2919  dol_syslog(get_class($this)."::classifyBilled", LOG_DEBUG);
2920  if ($this->db->query($sql))
2921  {
2922  if (!$error)
2923  {
2924  $this->oldcopy = clone $this;
2925  $this->billed = 1;
2926  }
2927 
2928  if (!$notrigger && empty($error))
2929  {
2930  // Call trigger
2931  $result = $this->call_trigger('ORDER_CLASSIFY_BILLED', $user);
2932  if ($result < 0) $error++;
2933  // End call triggers
2934  }
2935 
2936  if (!$error)
2937  {
2938  $this->db->commit();
2939  return 1;
2940  } else {
2941  foreach ($this->errors as $errmsg)
2942  {
2943  dol_syslog(get_class($this)."::classifyBilled ".$errmsg, LOG_ERR);
2944  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2945  }
2946  $this->db->rollback();
2947  return -1 * $error;
2948  }
2949  } else {
2950  $this->error = $this->db->error();
2951  $this->db->rollback();
2952  return -1;
2953  }
2954  }
2955 
2961  public function classifyUnBilled()
2962  {
2963  global $conf, $user, $langs;
2964  $error = 0;
2965 
2966  $this->db->begin();
2967 
2968  $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande SET facture = 0';
2969  $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > '.self::STATUS_DRAFT;
2970 
2971  dol_syslog(get_class($this)."::classifyUnBilled", LOG_DEBUG);
2972  if ($this->db->query($sql))
2973  {
2974  if (!$error)
2975  {
2976  $this->oldcopy = clone $this;
2977  $this->billed = 1;
2978  }
2979 
2980  // Call trigger
2981  $result = $this->call_trigger('ORDER_CLASSIFY_UNBILLED', $user);
2982  if ($result < 0) $error++;
2983  // End call triggers
2984 
2985  if (!$error)
2986  {
2987  $this->billed = 0;
2988 
2989  $this->db->commit();
2990  return 1;
2991  } else {
2992  foreach ($this->errors as $errmsg)
2993  {
2994  dol_syslog(get_class($this)."::classifyUnBilled ".$errmsg, LOG_ERR);
2995  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2996  }
2997  $this->db->rollback();
2998  return -1 * $error;
2999  }
3000  } else {
3001  $this->error = $this->db->error();
3002  $this->db->rollback();
3003  return -1;
3004  }
3005  }
3006 
3007 
3037  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 = '')
3038  {
3039  global $conf, $mysoc, $langs, $user;
3040 
3041  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");
3042  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
3043 
3044  if ($this->statut == Commande::STATUS_DRAFT)
3045  {
3046  // Clean parameters
3047  if (empty($qty)) $qty = 0;
3048  if (empty($info_bits)) $info_bits = 0;
3049  if (empty($txtva)) $txtva = 0;
3050  if (empty($txlocaltax1)) $txlocaltax1 = 0;
3051  if (empty($txlocaltax2)) $txlocaltax2 = 0;
3052  if (empty($remise_percent)) $remise_percent = 0;
3053  if (empty($special_code) || $special_code == 3) $special_code = 0;
3054  if (empty($ref_ext)) $ref_ext = '';
3055 
3056  if ($date_start && $date_end && $date_start > $date_end) {
3057  $langs->load("errors");
3058  $this->error = $langs->trans('ErrorStartDateGreaterEnd');
3059  return -1;
3060  }
3061 
3062  $remise_percent = price2num($remise_percent);
3063  $qty = price2num($qty);
3064  $pu = price2num($pu);
3065  $pa_ht = price2num($pa_ht);
3066  $pu_ht_devise = price2num($pu_ht_devise);
3067  if (!preg_match('/\((.*)\)/', $txtva)) {
3068  $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
3069  }
3070  $txlocaltax1 = price2num($txlocaltax1);
3071  $txlocaltax2 = price2num($txlocaltax2);
3072 
3073  $this->db->begin();
3074 
3075  // Calcul du total TTC et de la TVA pour la ligne a partir de
3076  // qty, pu, remise_percent et txtva
3077  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
3078  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
3079 
3080  $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
3081 
3082  // Clean vat code
3083  $vat_src_code = '';
3084  $reg = array();
3085  if (preg_match('/\((.*)\)/', $txtva, $reg))
3086  {
3087  $vat_src_code = $reg[1];
3088  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
3089  }
3090 
3091  $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);
3092 
3093  $total_ht = $tabprice[0];
3094  $total_tva = $tabprice[1];
3095  $total_ttc = $tabprice[2];
3096  $total_localtax1 = $tabprice[9];
3097  $total_localtax2 = $tabprice[10];
3098  $pu_ht = $tabprice[3];
3099  $pu_tva = $tabprice[4];
3100  $pu_ttc = $tabprice[5];
3101 
3102  // MultiCurrency
3103  $multicurrency_total_ht = $tabprice[16];
3104  $multicurrency_total_tva = $tabprice[17];
3105  $multicurrency_total_ttc = $tabprice[18];
3106  $pu_ht_devise = $tabprice[19];
3107 
3108  // Anciens indicateurs: $price, $subprice (a ne plus utiliser)
3109  $price = $pu_ht;
3110  if ($price_base_type == 'TTC')
3111  {
3112  $subprice = $pu_ttc;
3113  } else {
3114  $subprice = $pu_ht;
3115  }
3116  $remise = 0;
3117  if ($remise_percent > 0)
3118  {
3119  $remise = round(($pu * $remise_percent / 100), 2);
3120  $price = ($pu - $remise);
3121  }
3122 
3123  //Fetch current line from the database and then clone the object and set it in $oldline property
3124  $line = new OrderLine($this->db);
3125  $line->fetch($rowid);
3126  $line->fetch_optionals();
3127 
3128  if (!empty($line->fk_product))
3129  {
3130  $product = new Product($this->db);
3131  $result = $product->fetch($line->fk_product);
3132  $product_type = $product->type;
3133 
3134  if (!empty($conf->global->STOCK_MUST_BE_ENOUGH_FOR_ORDER) && $product_type == 0 && $product->stock_reel < $qty)
3135  {
3136  $langs->load("errors");
3137  $this->error = $langs->trans('ErrorStockIsNotEnoughToAddProductOnOrder', $product->ref);
3138  $this->errors[] = $this->error;
3139  dol_syslog(get_class($this)."::addline error=Product ".$product->ref.": ".$this->error, LOG_ERR);
3140  $this->db->rollback();
3141  return self::STOCK_NOT_ENOUGH_FOR_ORDER;
3142  }
3143  }
3144 
3145  $staticline = clone $line;
3146 
3147  $line->oldline = $staticline;
3148  $this->line = $line;
3149  $this->line->context = $this->context;
3150 
3151  // Reorder if fk_parent_line change
3152  if (!empty($fk_parent_line) && !empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line)
3153  {
3154  $rangmax = $this->line_max($fk_parent_line);
3155  $this->line->rang = $rangmax + 1;
3156  }
3157 
3158  $this->line->id = $rowid;
3159  $this->line->label = $label;
3160  $this->line->desc = $desc;
3161  $this->line->qty = $qty;
3162  $this->line->ref_ext = $ref_ext;
3163 
3164  $this->line->vat_src_code = $vat_src_code;
3165  $this->line->tva_tx = $txtva;
3166  $this->line->localtax1_tx = $txlocaltax1;
3167  $this->line->localtax2_tx = $txlocaltax2;
3168  $this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
3169  $this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
3170  $this->line->remise_percent = $remise_percent;
3171  $this->line->subprice = $subprice;
3172  $this->line->info_bits = $info_bits;
3173  $this->line->special_code = $special_code;
3174  $this->line->total_ht = $total_ht;
3175  $this->line->total_tva = $total_tva;
3176  $this->line->total_localtax1 = $total_localtax1;
3177  $this->line->total_localtax2 = $total_localtax2;
3178  $this->line->total_ttc = $total_ttc;
3179  $this->line->date_start = $date_start;
3180  $this->line->date_end = $date_end;
3181  $this->line->product_type = $type;
3182  $this->line->fk_parent_line = $fk_parent_line;
3183  $this->line->skip_update_total = $skip_update_total;
3184  $this->line->fk_unit = $fk_unit;
3185 
3186  $this->line->fk_fournprice = $fk_fournprice;
3187  $this->line->pa_ht = $pa_ht;
3188 
3189  // Multicurrency
3190  $this->line->multicurrency_subprice = $pu_ht_devise;
3191  $this->line->multicurrency_total_ht = $multicurrency_total_ht;
3192  $this->line->multicurrency_total_tva = $multicurrency_total_tva;
3193  $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
3194 
3195  // TODO deprecated
3196  $this->line->price = $price;
3197  $this->line->remise = $remise;
3198 
3199  if (is_array($array_options) && count($array_options) > 0) {
3200  // We replace values in this->line->array_options only for entries defined into $array_options
3201  foreach ($array_options as $key => $value) {
3202  $this->line->array_options[$key] = $array_options[$key];
3203  }
3204  }
3205 
3206  $result = $this->line->update($user, $notrigger);
3207  if ($result > 0)
3208  {
3209  // Reorder if child line
3210  if (!empty($fk_parent_line)) $this->line_order(true, 'DESC');
3211 
3212  // Mise a jour info denormalisees
3213  $this->update_price(1);
3214 
3215  $this->db->commit();
3216  return $result;
3217  } else {
3218  $this->error = $this->line->error;
3219 
3220  $this->db->rollback();
3221  return -1;
3222  }
3223  } else {
3224  $this->error = get_class($this)."::updateline Order status makes operation forbidden";
3225  $this->errors = array('OrderStatusMakeOperationForbidden');
3226  return -2;
3227  }
3228  }
3229 
3237  public function update(User $user, $notrigger = 0)
3238  {
3239  global $conf;
3240 
3241  $error = 0;
3242 
3243  // Clean parameters
3244  if (isset($this->ref)) $this->ref = trim($this->ref);
3245  if (isset($this->ref_client)) $this->ref_client = trim($this->ref_client);
3246  if (isset($this->note) || isset($this->note_private)) $this->note_private = (isset($this->note_private) ? trim($this->note_private) : trim($this->note));
3247  if (isset($this->note_public)) $this->note_public = trim($this->note_public);
3248  if (isset($this->model_pdf)) $this->model_pdf = trim($this->model_pdf);
3249  if (isset($this->import_key)) $this->import_key = trim($this->import_key);
3250  $delivery_date = empty($this->delivery_date) ? $this->date_livraison : $this->delivery_date;
3251 
3252  // Check parameters
3253  // Put here code to add control on parameters values
3254 
3255  // Update request
3256  $sql = "UPDATE ".MAIN_DB_PREFIX."commande SET";
3257 
3258  $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").",";
3259  $sql .= " ref_client=".(isset($this->ref_client) ? "'".$this->db->escape($this->ref_client)."'" : "null").",";
3260  $sql .= " ref_ext=".(isset($this->ref_ext) ? "'".$this->db->escape($this->ref_ext)."'" : "null").",";
3261  $sql .= " fk_soc=".(isset($this->socid) ? $this->socid : "null").",";
3262  $sql .= " date_commande=".(strval($this->date_commande) != '' ? "'".$this->db->idate($this->date_commande)."'" : 'null').",";
3263  $sql .= " date_valid=".(strval($this->date_validation) != '' ? "'".$this->db->idate($this->date_validation)."'" : 'null').",";
3264  $sql .= " tva=".(isset($this->total_tva) ? $this->total_tva : "null").",";
3265  $sql .= " localtax1=".(isset($this->total_localtax1) ? $this->total_localtax1 : "null").",";
3266  $sql .= " localtax2=".(isset($this->total_localtax2) ? $this->total_localtax2 : "null").",";
3267  $sql .= " total_ht=".(isset($this->total_ht) ? $this->total_ht : "null").",";
3268  $sql .= " total_ttc=".(isset($this->total_ttc) ? $this->total_ttc : "null").",";
3269  $sql .= " fk_statut=".(isset($this->statut) ? $this->statut : "null").",";
3270  $sql .= " fk_user_author=".(isset($this->user_author_id) ? $this->user_author_id : "null").",";
3271  $sql .= " fk_user_valid=".(isset($this->user_valid) ? $this->user_valid : "null").",";
3272  $sql .= " fk_projet=".(isset($this->fk_project) ? $this->fk_project : "null").",";
3273  $sql .= " fk_cond_reglement=".(isset($this->cond_reglement_id) ? $this->cond_reglement_id : "null").",";
3274  $sql .= " fk_mode_reglement=".(isset($this->mode_reglement_id) ? $this->mode_reglement_id : "null").",";
3275  $sql .= " date_livraison=".(strval($this->delivery_date) != '' ? "'".$this->db->idate($this->delivery_date)."'" : 'null').",";
3276  $sql .= " fk_shipping_method=".(isset($this->shipping_method_id) ? $this->shipping_method_id : "null").",";
3277  $sql .= " fk_account=".($this->fk_account > 0 ? $this->fk_account : "null").",";
3278  $sql .= " fk_input_reason=".($this->demand_reason_id > 0 ? $this->demand_reason_id : "null").",";
3279  $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
3280  $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
3281  $sql .= " model_pdf=".(isset($this->modelpdf) ? "'".$this->db->escape($this->modelpdf)."'" : "null").",";
3282  $sql .= " import_key=".(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null")."";
3283 
3284  $sql .= " WHERE rowid=".$this->id;
3285 
3286  $this->db->begin();
3287 
3288  dol_syslog(get_class($this)."::update", LOG_DEBUG);
3289  $resql = $this->db->query($sql);
3290  if (!$resql) {
3291  $error++; $this->errors[] = "Error ".$this->db->lasterror();
3292  }
3293 
3294  if (!$error)
3295  {
3296  $result = $this->insertExtraFields();
3297  if ($result < 0)
3298  {
3299  $error++;
3300  }
3301  }
3302 
3303  if (!$error && !$notrigger)
3304  {
3305  // Call trigger
3306  $result = $this->call_trigger('ORDER_MODIFY', $user);
3307  if ($result < 0) $error++;
3308  // End call triggers
3309  }
3310 
3311  // Commit or rollback
3312  if ($error)
3313  {
3314  foreach ($this->errors as $errmsg)
3315  {
3316  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
3317  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
3318  }
3319  $this->db->rollback();
3320  return -1 * $error;
3321  } else {
3322  $this->db->commit();
3323  return 1;
3324  }
3325  }
3326 
3334  public function delete($user, $notrigger = 0)
3335  {
3336  global $conf, $langs;
3337  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
3338 
3339  $error = 0;
3340 
3341  dol_syslog(get_class($this)."::delete ".$this->id, LOG_DEBUG);
3342 
3343  $this->db->begin();
3344 
3345  if (!$notrigger) {
3346  // Call trigger
3347  $result = $this->call_trigger('ORDER_DELETE', $user);
3348  if ($result < 0) { $error++; }
3349  // End call triggers
3350  }
3351 
3352  // Test we can delete
3353  if ($this->nb_expedition() != 0)
3354  {
3355  $this->errors[] = $langs->trans('SomeShipmentExists');
3356  $error++;
3357  }
3358 
3359  // Delete extrafields of lines and lines
3360  if (!$error && !empty($this->table_element_line)) {
3361  $tabletodelete = $this->table_element_line;
3362  $sqlef = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete."_extrafields WHERE fk_object IN (SELECT rowid FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".$this->id.")";
3363  $sql = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".$this->id;
3364  if (!$this->db->query($sqlef) || !$this->db->query($sql)) {
3365  $error++;
3366  $this->error = $this->db->lasterror();
3367  $this->errors[] = $this->error;
3368  dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
3369  }
3370  }
3371 
3372  if (!$error) {
3373  // Delete linked object
3374  $res = $this->deleteObjectLinked();
3375  if ($res < 0) $error++;
3376  }
3377 
3378  if (!$error) {
3379  // Delete linked contacts
3380  $res = $this->delete_linked_contact();
3381  if ($res < 0) $error++;
3382  }
3383 
3384  // Removed extrafields of object
3385  if (!$error) {
3386  $result = $this->deleteExtraFields();
3387  if ($result < 0) {
3388  $error++;
3389  dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
3390  }
3391  }
3392 
3393  // Delete main record
3394  if (!$error) {
3395  $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element." WHERE rowid = ".$this->id;
3396  $res = $this->db->query($sql);
3397  if (!$res) {
3398  $error++;
3399  $this->error = $this->db->lasterror();
3400  $this->errors[] = $this->error;
3401  dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
3402  }
3403  }
3404 
3405  // Delete record into ECM index and physically
3406  if (!$error) {
3407  $res = $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive
3408  if (!$res) {
3409  $error++;
3410  }
3411  }
3412 
3413  if (!$error) {
3414  // We remove directory
3415  $ref = dol_sanitizeFileName($this->ref);
3416  if ($conf->commande->multidir_output[$this->entity] && !empty($this->ref)) {
3417  $dir = $conf->commande->multidir_output[$this->entity]."/".$ref;
3418  $file = $dir."/".$ref.".pdf";
3419  if (file_exists($file)) {
3420  dol_delete_preview($this);
3421 
3422  if (!dol_delete_file($file, 0, 0, 0, $this)) {
3423  $this->error = 'ErrorFailToDeleteFile';
3424  $this->errors[] = $this->error;
3425  $this->db->rollback();
3426  return 0;
3427  }
3428  }
3429  if (file_exists($dir)) {
3430  $res = @dol_delete_dir_recursive($dir);
3431  if (!$res) {
3432  $this->error = 'ErrorFailToDeleteDir';
3433  $this->errors[] = $this->error;
3434  $this->db->rollback();
3435  return 0;
3436  }
3437  }
3438  }
3439  }
3440 
3441  if (!$error) {
3442  dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
3443  $this->db->commit();
3444  return 1;
3445  } else {
3446  $this->db->rollback();
3447  return -1;
3448  }
3449  }
3450 
3451 
3452  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3459  public function load_board($user)
3460  {
3461  // phpcs:enable
3462  global $conf, $langs;
3463 
3464  $clause = " WHERE";
3465 
3466  $sql = "SELECT c.rowid, c.date_creation as datec, c.date_commande, c.date_livraison as delivery_date, c.fk_statut, c.total_ht";
3467  $sql .= " FROM ".MAIN_DB_PREFIX."commande as c";
3468  if (!$user->rights->societe->client->voir && !$user->socid)
3469  {
3470  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON c.fk_soc = sc.fk_soc";
3471  $sql .= " WHERE sc.fk_user = ".$user->id;
3472  $clause = " AND";
3473  }
3474  $sql .= $clause." c.entity IN (".getEntity('commande').")";
3475  //$sql.= " AND c.fk_statut IN (1,2,3) AND c.facture = 0";
3476  $sql .= " AND ((c.fk_statut IN (".self::STATUS_VALIDATED.",".self::STATUS_SHIPMENTONPROCESS.")) OR (c.fk_statut = ".self::STATUS_CLOSED." AND c.facture = 0))"; // If status is 2 and facture=1, it must be selected
3477  if ($user->socid) $sql .= " AND c.fk_soc = ".$user->socid;
3478 
3479  $resql = $this->db->query($sql);
3480  if ($resql)
3481  {
3482  $response = new WorkboardResponse();
3483  $response->warning_delay = $conf->commande->client->warning_delay / 60 / 60 / 24;
3484  $response->label = $langs->trans("OrdersToProcess");
3485  $response->labelShort = $langs->trans("Opened");
3486  $response->url = DOL_URL_ROOT.'/commande/list.php?search_status=-3&mainmenu=commercial&leftmenu=orders';
3487  $response->img = img_object('', "order");
3488 
3489  $generic_commande = new Commande($this->db);
3490 
3491  while ($obj = $this->db->fetch_object($resql))
3492  {
3493  $response->nbtodo++;
3494  $response->total += $obj->total_ht;
3495 
3496  $generic_commande->statut = $obj->fk_statut;
3497  $generic_commande->date_commande = $this->db->jdate($obj->date_commande);
3498  $generic_commande->date = $this->db->jdate($obj->date_commande);
3499  $generic_commande->date_livraison = $this->db->jdate($obj->delivery_date);
3500  $generic_commande->delivery_date = $this->db->jdate($obj->delivery_date);
3501 
3502  if ($generic_commande->hasDelay()) {
3503  $response->nbtodolate++;
3504  }
3505  }
3506 
3507  return $response;
3508  } else {
3509  $this->error = $this->db->error();
3510  return -1;
3511  }
3512  }
3513 
3519  public function getLabelSource()
3520  {
3521  global $langs;
3522 
3523  $label = $langs->trans('OrderSource'.$this->source);
3524 
3525  if ($label == 'OrderSource') return '';
3526  return $label;
3527  }
3528 
3535  public function getLibStatut($mode)
3536  {
3537  return $this->LibStatut($this->statut, $this->billed, $mode);
3538  }
3539 
3540  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3550  public function LibStatut($status, $billed, $mode, $donotshowbilled = 0)
3551  {
3552  // phpcs:enable
3553  global $langs, $conf;
3554 
3555  $billedtext = '';
3556  if (empty($donotshowbilled)) $billedtext .= ($billed ? ' - '.$langs->transnoentitiesnoconv("Billed") : '');
3557 
3558  $labelTooltip = '';
3559 
3560  if ($status == self::STATUS_CANCELED) {
3561  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderCanceled');
3562  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderCanceledShort');
3563  $statusType = 'status9';
3564  } elseif ($status == self::STATUS_DRAFT) {
3565  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderDraft');
3566  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderDraftShort');
3567  $statusType = 'status0';
3568  } elseif ($status == self::STATUS_VALIDATED) {
3569  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderValidated').$billedtext;
3570  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderValidatedShort').$billedtext;
3571  $statusType = 'status1';
3572  } elseif ($status == self::STATUS_SHIPMENTONPROCESS) {
3573  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderSent').$billedtext;
3574  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderSentShort').$billedtext;
3575  $labelTooltip = $langs->transnoentitiesnoconv("StatusOrderSent").' - '.$langs->transnoentitiesnoconv("DateDeliveryPlanned").dol_print_date($this->date_livraison).$billedtext;
3576  $statusType = 'status4';
3577  } elseif ($status == self::STATUS_CLOSED && (!$billed && empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) {
3578  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderToBill');
3579  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderToBillShort');
3580  $statusType = 'status4';
3581  } elseif ($status == self::STATUS_CLOSED && ($billed && empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) {
3582  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderProcessed').$billedtext;
3583  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderProcessedShort').$billedtext;
3584  $statusType = 'status6';
3585  } elseif ($status == self::STATUS_CLOSED && (!empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) {
3586  $labelStatus = $langs->transnoentitiesnoconv('StatusOrderDelivered');
3587  $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderDeliveredShort');
3588  $statusType = 'status6';
3589  } else {
3590  $labelStatus = $langs->transnoentitiesnoconv('Unknown');
3591  $labelStatusShort = '';
3592  $statusType = '';
3593  $mode = 0;
3594  }
3595 
3596  return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode, '', array('tooltip' => $labelTooltip));
3597  }
3598 
3599 
3612  public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0)
3613  {
3614  global $conf, $langs, $user;
3615 
3616  if (!empty($conf->dol_no_mouse_hover)) $notooltip = 1; // Force disable tooltips
3617 
3618  $result = '';
3619 
3620  if (!empty($conf->expedition->enabled) && ($option == '1' || $option == '2')) $url = DOL_URL_ROOT.'/expedition/shipment.php?id='.$this->id;
3621  else $url = DOL_URL_ROOT.'/commande/card.php?id='.$this->id;
3622 
3623  if (!$user->rights->commande->lire)
3624  $option = 'nolink';
3625 
3626  if ($option !== 'nolink')
3627  {
3628  // Add param to save lastsearch_values or not
3629  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
3630  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values = 1;
3631  if ($add_save_lastsearch_values) $url .= '&save_lastsearch_values=1';
3632  }
3633 
3634  if ($short) return $url;
3635 
3636  $label = '';
3637 
3638  if ($user->rights->commande->lire) {
3639  $label = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("Order").'</u>';
3640  if (isset($this->statut)) {
3641  $label .= ' '.$this->getLibStatut(5);
3642  }
3643  $label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
3644  $label .= '<br><b>'.$langs->trans('RefCustomer').':</b> '.($this->ref_customer ? $this->ref_customer : $this->ref_client);
3645  if (!empty($this->total_ht)) {
3646  $label .= '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
3647  }
3648  if (!empty($this->total_tva)) {
3649  $label .= '<br><b>'.$langs->trans('VAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
3650  }
3651  if (!empty($this->total_ttc)) {
3652  $label .= '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
3653  }
3654  if (!empty($this->date)) {
3655  $label .= '<br><b>'.$langs->trans('Date').':</b> '.dol_print_date($this->date, 'dayhour');
3656  }
3657  if (!empty($this->delivery_date)) {
3658  $label .= '<br><b>'.$langs->trans('DeliveryDate').':</b> '.dol_print_date($this->delivery_date, 'dayhour');
3659  }
3660  }
3661 
3662  $linkclose = '';
3663  if (empty($notooltip) && $user->rights->commande->lire)
3664  {
3665  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
3666  {
3667  $label = $langs->trans("Order");
3668  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
3669  }
3670  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
3671  $linkclose .= ' class="classfortooltip"';
3672  }
3673 
3674  $linkstart = '<a href="'.$url.'"';
3675  $linkstart .= $linkclose.'>';
3676  $linkend = '</a>';
3677 
3678  if ($option === 'nolink') {
3679  $linkstart = '';
3680  $linkend = '';
3681  }
3682 
3683  $result .= $linkstart;
3684  if ($withpicto) $result .= img_object(($notooltip ? '' : $label), $this->picto, ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
3685  if ($withpicto != 2) $result .= $this->ref;
3686  $result .= $linkend;
3687 
3688  if ($addlinktonotes)
3689  {
3690  $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
3691  if ($txttoshow)
3692  {
3693  $notetoshow = $langs->trans("ViewPrivateNote").':<br>'.dol_string_nohtmltag($txttoshow, 1);
3694  $result .= ' <span class="note inline-block">';
3695  $result .= '<a href="'.DOL_URL_ROOT.'/commande/note.php?id='.$this->id.'" class="classfortooltip" title="'.dol_escape_htmltag($notetoshow).'">';
3696  $result .= img_picto('', 'note');
3697  $result .= '</a>';
3698  //$result.=img_picto($langs->trans("ViewNote"),'object_generic');
3699  //$result.='</a>';
3700  $result .= '</span>';
3701  }
3702  }
3703 
3704  return $result;
3705  }
3706 
3707 
3714  public function info($id)
3715  {
3716  $sql = 'SELECT c.rowid, date_creation as datec, tms as datem,';
3717  $sql .= ' date_valid as datev,';
3718  $sql .= ' date_cloture as datecloture,';
3719  $sql .= ' fk_user_author, fk_user_valid, fk_user_cloture';
3720  $sql .= ' FROM '.MAIN_DB_PREFIX.'commande as c';
3721  $sql .= ' WHERE c.rowid = '.$id;
3722  $result = $this->db->query($sql);
3723  if ($result)
3724  {
3725  if ($this->db->num_rows($result))
3726  {
3727  $obj = $this->db->fetch_object($result);
3728  $this->id = $obj->rowid;
3729  if ($obj->fk_user_author)
3730  {
3731  $cuser = new User($this->db);
3732  $cuser->fetch($obj->fk_user_author);
3733  $this->user_creation = $cuser;
3734  }
3735 
3736  if ($obj->fk_user_valid)
3737  {
3738  $vuser = new User($this->db);
3739  $vuser->fetch($obj->fk_user_valid);
3740  $this->user_validation = $vuser;
3741  }
3742 
3743  if ($obj->fk_user_cloture)
3744  {
3745  $cluser = new User($this->db);
3746  $cluser->fetch($obj->fk_user_cloture);
3747  $this->user_cloture = $cluser;
3748  }
3749 
3750  $this->date_creation = $this->db->jdate($obj->datec);
3751  $this->date_modification = $this->db->jdate($obj->datem);
3752  $this->date_validation = $this->db->jdate($obj->datev);
3753  $this->date_cloture = $this->db->jdate($obj->datecloture);
3754  }
3755 
3756  $this->db->free($result);
3757  } else {
3758  dol_print_error($this->db);
3759  }
3760  }
3761 
3762 
3770  public function initAsSpecimen()
3771  {
3772  global $conf, $langs;
3773 
3774  dol_syslog(get_class($this)."::initAsSpecimen");
3775 
3776  // Load array of products prodids
3777  $num_prods = 0;
3778  $prodids = array();
3779  $sql = "SELECT rowid";
3780  $sql .= " FROM ".MAIN_DB_PREFIX."product";
3781  $sql .= " WHERE entity IN (".getEntity('product').")";
3782  $sql .= $this->db->plimit(100);
3783 
3784  $resql = $this->db->query($sql);
3785  if ($resql)
3786  {
3787  $num_prods = $this->db->num_rows($resql);
3788  $i = 0;
3789  while ($i < $num_prods)
3790  {
3791  $i++;
3792  $row = $this->db->fetch_row($resql);
3793  $prodids[$i] = $row[0];
3794  }
3795  }
3796 
3797  // Initialise parametres
3798  $this->id = 0;
3799  $this->ref = 'SPECIMEN';
3800  $this->specimen = 1;
3801  $this->socid = 1;
3802  $this->date = time();
3803  $this->date_lim_reglement = $this->date + 3600 * 24 * 30;
3804  $this->cond_reglement_code = 'RECEP';
3805  $this->mode_reglement_code = 'CHQ';
3806  $this->availability_code = 'DSP';
3807  $this->demand_reason_code = 'SRC_00';
3808 
3809  $this->note_public = 'This is a comment (public)';
3810  $this->note_private = 'This is a comment (private)';
3811 
3812  $this->multicurrency_tx = 1;
3813  $this->multicurrency_code = $conf->currency;
3814 
3815  // Lines
3816  $nbp = 5;
3817  $xnbp = 0;
3818  while ($xnbp < $nbp)
3819  {
3820  $line = new OrderLine($this->db);
3821 
3822  $line->desc = $langs->trans("Description")." ".$xnbp;
3823  $line->qty = 1;
3824  $line->subprice = 100;
3825  $line->price = 100;
3826  $line->tva_tx = 20;
3827  if ($xnbp == 2)
3828  {
3829  $line->total_ht = 50;
3830  $line->total_ttc = 60;
3831  $line->total_tva = 10;
3832  $line->remise_percent = 50;
3833  } else {
3834  $line->total_ht = 100;
3835  $line->total_ttc = 120;
3836  $line->total_tva = 20;
3837  $line->remise_percent = 0;
3838  }
3839  if ($num_prods > 0)
3840  {
3841  $prodid = mt_rand(1, $num_prods);
3842  $line->fk_product = $prodids[$prodid];
3843  $line->product_ref = 'SPECIMEN';
3844  }
3845 
3846  $this->lines[$xnbp] = $line;
3847 
3848  $this->total_ht += $line->total_ht;
3849  $this->total_tva += $line->total_tva;
3850  $this->total_ttc += $line->total_ttc;
3851 
3852  $xnbp++;
3853  }
3854  }
3855 
3856 
3857  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3863  public function load_state_board()
3864  {
3865  // phpcs:enable
3866  global $user;
3867 
3868  $this->nb = array();
3869  $clause = "WHERE";
3870 
3871  $sql = "SELECT count(co.rowid) as nb";
3872  $sql .= " FROM ".MAIN_DB_PREFIX."commande as co";
3873  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON co.fk_soc = s.rowid";
3874  if (!$user->rights->societe->client->voir && !$user->socid)
3875  {
3876  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
3877  $sql .= " WHERE sc.fk_user = ".$user->id;
3878  $clause = "AND";
3879  }
3880  $sql .= " ".$clause." co.entity IN (".getEntity('commande').")";
3881 
3882  $resql = $this->db->query($sql);
3883  if ($resql)
3884  {
3885  while ($obj = $this->db->fetch_object($resql))
3886  {
3887  $this->nb["orders"] = $obj->nb;
3888  }
3889  $this->db->free($resql);
3890  return 1;
3891  } else {
3892  dol_print_error($this->db);
3893  $this->error = $this->db->error();
3894  return -1;
3895  }
3896  }
3897 
3903  public function getLinesArray()
3904  {
3905  return $this->fetch_lines();
3906  }
3907 
3919  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
3920  {
3921  global $conf, $langs;
3922 
3923  $langs->load("orders");
3924  $outputlangs->load("products");
3925 
3926  if (!dol_strlen($modele)) {
3927  $modele = 'einstein';
3928 
3929  if (!empty($this->model_pdf)) {
3930  $modele = $this->model_pdf;
3931  } elseif (!empty($this->modelpdf)) { // dperecated
3932  $modele = $this->modelpdf;
3933  } elseif (!empty($conf->global->COMMANDE_ADDON_PDF)) {
3934  $modele = $conf->global->COMMANDE_ADDON_PDF;
3935  }
3936  }
3937 
3938  $modelpath = "core/modules/commande/doc/";
3939 
3940  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
3941  }
3942 
3943 
3952  public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
3953  {
3954  $tables = array(
3955  'commande'
3956  );
3957 
3958  return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
3959  }
3960 
3966  public function hasDelay()
3967  {
3968  global $conf;
3969 
3970  if (!($this->statut > Commande::STATUS_DRAFT && $this->statut < Commande::STATUS_CLOSED)) {
3971  return false; // Never late if not inside this status range
3972  }
3973 
3974  $now = dol_now();
3975 
3976  return max($this->date_commande, $this->date_livraison) < ($now - $conf->commande->client->warning_delay);
3977  }
3978 
3984  public function showDelay()
3985  {
3986  global $conf, $langs;
3987 
3988  if (empty($this->date_livraison)) $text = $langs->trans("OrderDate").' '.dol_print_date($this->date_commande, 'day');
3989  else $text = $text = $langs->trans("DeliveryDate").' '.dol_print_date($this->date_livraison, 'day');
3990  $text .= ' '.($conf->commande->client->warning_delay > 0 ? '+' : '-').' '.round(abs($conf->commande->client->warning_delay) / 3600 / 24, 1).' '.$langs->trans("days").' < '.$langs->trans("Today");
3991 
3992  return $text;
3993  }
3994 }
3995 
3996 
4001 {
4005  public $element = 'commandedet';
4006 
4007  public $table_element = 'commandedet';
4008 
4009  public $oldline;
4010 
4015  public $fk_commande;
4016 
4023  public $commande_id;
4024 
4025  public $fk_parent_line;
4026 
4030  public $fk_facture;
4031 
4035  public $ref_ext;
4036 
4037  public $fk_remise_except;
4038 
4042  public $rang = 0;
4043  public $fk_fournprice;
4044 
4049  public $pa_ht;
4050  public $marge_tx;
4051  public $marque_tx;
4052 
4057  public $remise;
4058 
4059  // Start and end date of the line
4060  public $date_start;
4061  public $date_end;
4062 
4063  public $skip_update_total; // Skip update price total for special lines
4064 
4065 
4071  public function __construct($db)
4072  {
4073  $this->db = $db;
4074  }
4075 
4082  public function fetch($rowid)
4083  {
4084  $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,';
4085  $sql .= ' cd.remise, cd.remise_percent, cd.fk_remise_except, cd.subprice, cd.ref_ext,';
4086  $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,';
4087  $sql .= ' cd.fk_unit,';
4088  $sql .= ' cd.fk_multicurrency, cd.multicurrency_code, cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc,';
4089  $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc, p.tobatch as product_tobatch,';
4090  $sql .= ' cd.date_start, cd.date_end';
4091  $sql .= ' FROM '.MAIN_DB_PREFIX.'commandedet as cd';
4092  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON cd.fk_product = p.rowid';
4093  $sql .= ' WHERE cd.rowid = '.$rowid;
4094  $result = $this->db->query($sql);
4095  if ($result)
4096  {
4097  $objp = $this->db->fetch_object($result);
4098  $this->rowid = $objp->rowid;
4099  $this->id = $objp->rowid;
4100  $this->fk_commande = $objp->fk_commande;
4101  $this->fk_parent_line = $objp->fk_parent_line;
4102  $this->label = $objp->custom_label;
4103  $this->desc = $objp->description;
4104  $this->qty = $objp->qty;
4105  $this->price = $objp->price;
4106  $this->subprice = $objp->subprice;
4107  $this->ref_ext = $objp->ref_ext;
4108  $this->vat_src_code = $objp->vat_src_code;
4109  $this->tva_tx = $objp->tva_tx;
4110  $this->localtax1_tx = $objp->localtax1_tx;
4111  $this->localtax2_tx = $objp->localtax2_tx;
4112  $this->remise = $objp->remise;
4113  $this->remise_percent = $objp->remise_percent;
4114  $this->fk_remise_except = $objp->fk_remise_except;
4115  $this->fk_product = $objp->fk_product;
4116  $this->product_type = $objp->product_type;
4117  $this->info_bits = $objp->info_bits;
4118  $this->special_code = $objp->special_code;
4119  $this->total_ht = $objp->total_ht;
4120  $this->total_tva = $objp->total_tva;
4121  $this->total_localtax1 = $objp->total_localtax1;
4122  $this->total_localtax2 = $objp->total_localtax2;
4123  $this->total_ttc = $objp->total_ttc;
4124  $this->fk_fournprice = $objp->fk_fournprice;
4125  $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $this->fk_fournprice, $objp->pa_ht);
4126  $this->pa_ht = $marginInfos[0];
4127  $this->marge_tx = $marginInfos[1];
4128  $this->marque_tx = $marginInfos[2];
4129  $this->special_code = $objp->special_code;
4130  $this->rang = $objp->rang;
4131 
4132  $this->ref = $objp->product_ref; // deprecated
4133 
4134  $this->product_ref = $objp->product_ref;
4135  $this->product_label = $objp->product_label;
4136  $this->product_desc = $objp->product_desc;
4137  $this->product_tobatch = $objp->product_tobatch;
4138  $this->fk_unit = $objp->fk_unit;
4139 
4140  $this->date_start = $this->db->jdate($objp->date_start);
4141  $this->date_end = $this->db->jdate($objp->date_end);
4142 
4143  $this->fk_multicurrency = $objp->fk_multicurrency;
4144  $this->multicurrency_code = $objp->multicurrency_code;
4145  $this->multicurrency_subprice = $objp->multicurrency_subprice;
4146  $this->multicurrency_total_ht = $objp->multicurrency_total_ht;
4147  $this->multicurrency_total_tva = $objp->multicurrency_total_tva;
4148  $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
4149 
4150  $this->db->free($result);
4151 
4152  return 1;
4153  } else {
4154  $this->error = $this->db->lasterror();
4155  return -1;
4156  }
4157  }
4158 
4166  public function delete(User $user, $notrigger = 0)
4167  {
4168  global $conf, $langs;
4169 
4170  $error = 0;
4171 
4172  // check if order line is not in a shipment line before deleting
4173  $sqlCheckShipmentLine = "SELECT";
4174  $sqlCheckShipmentLine .= " ed.rowid";
4175  $sqlCheckShipmentLine .= " FROM ".MAIN_DB_PREFIX."expeditiondet ed";
4176  $sqlCheckShipmentLine .= " WHERE ed.fk_origin_line = ".$this->rowid;
4177 
4178  $resqlCheckShipmentLine = $this->db->query($sqlCheckShipmentLine);
4179  if (!$resqlCheckShipmentLine) {
4180  $error++;
4181  $this->error = $this->db->lasterror();
4182  $this->errors[] = $this->error;
4183  } else {
4184  $langs->load('errors');
4185  $num = $this->db->num_rows($resqlCheckShipmentLine);
4186  if ($num > 0) {
4187  $error++;
4188  $objCheckShipmentLine = $this->db->fetch_object($resqlCheckShipmentLine);
4189  $this->error = $langs->trans('ErrorRecordAlreadyExists').' : '.$langs->trans('ShipmentLine').' '.$objCheckShipmentLine->rowid;
4190  $this->errors[] = $this->error;
4191  }
4192  $this->db->free($resqlCheckShipmentLine);
4193  }
4194  if ($error) {
4195  dol_syslog(__METHOD__.'Error ; '.$this->error, LOG_ERR);
4196  return -1;
4197  }
4198 
4199  $this->db->begin();
4200 
4201  $sql = 'DELETE FROM '.MAIN_DB_PREFIX."commandedet WHERE rowid=".$this->rowid;
4202 
4203  dol_syslog("OrderLine::delete", LOG_DEBUG);
4204  $resql = $this->db->query($sql);
4205  if ($resql)
4206  {
4207  // Remove extrafields
4208  if (!$error)
4209  {
4210  $this->id = $this->rowid;
4211  $result = $this->deleteExtraFields();
4212  if ($result < 0)
4213  {
4214  $error++;
4215  dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
4216  }
4217  }
4218 
4219  if (!$error && !$notrigger)
4220  {
4221  // Call trigger
4222  $result = $this->call_trigger('LINEORDER_DELETE', $user);
4223  if ($result < 0) $error++;
4224  // End call triggers
4225  }
4226 
4227  if (!$error) {
4228  $this->db->commit();
4229  return 1;
4230  }
4231 
4232  foreach ($this->errors as $errmsg)
4233  {
4234  dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
4235  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
4236  }
4237  $this->db->rollback();
4238  return -1 * $error;
4239  } else {
4240  $this->error = $this->db->lasterror();
4241  return -1;
4242  }
4243  }
4244 
4252  public function insert($user = null, $notrigger = 0)
4253  {
4254  global $langs, $conf;
4255 
4256  $error = 0;
4257 
4258  $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'.
4259 
4260  dol_syslog(get_class($this)."::insert rang=".$this->rang);
4261 
4262  // Clean parameters
4263  if (empty($this->tva_tx)) $this->tva_tx = 0;
4264  if (empty($this->localtax1_tx)) $this->localtax1_tx = 0;
4265  if (empty($this->localtax2_tx)) $this->localtax2_tx = 0;
4266  if (empty($this->localtax1_type)) $this->localtax1_type = 0;
4267  if (empty($this->localtax2_type)) $this->localtax2_type = 0;
4268  if (empty($this->total_localtax1)) $this->total_localtax1 = 0;
4269  if (empty($this->total_localtax2)) $this->total_localtax2 = 0;
4270  if (empty($this->rang)) $this->rang = 0;
4271  if (empty($this->remise)) $this->remise = 0;
4272  if (empty($this->remise_percent)) $this->remise_percent = 0;
4273  if (empty($this->info_bits)) $this->info_bits = 0;
4274  if (empty($this->special_code)) $this->special_code = 0;
4275  if (empty($this->fk_parent_line)) $this->fk_parent_line = 0;
4276  if (empty($this->pa_ht)) $this->pa_ht = 0;
4277  if (empty($this->ref_ext)) $this->ref_ext = '';
4278 
4279  // if buy price not defined, define buyprice as configured in margin admin
4280  if ($this->pa_ht == 0 && $pa_ht_isemptystring)
4281  {
4282  if (($result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product)) < 0)
4283  {
4284  return $result;
4285  } else {
4286  $this->pa_ht = $result;
4287  }
4288  }
4289 
4290  // Check parameters
4291  if ($this->product_type < 0) return -1;
4292 
4293  $this->db->begin();
4294 
4295  // Insertion dans base de la ligne
4296  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'commandedet';
4297  $sql .= ' (fk_commande, fk_parent_line, label, description, qty, ref_ext,';
4298  $sql .= ' vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
4299  $sql .= ' fk_product, product_type, remise_percent, subprice, price, remise, fk_remise_except,';
4300  $sql .= ' special_code, rang, fk_product_fournisseur_price, buy_price_ht,';
4301  $sql .= ' info_bits, total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, date_start, date_end,';
4302  $sql .= ' fk_unit';
4303  $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
4304  $sql .= ')';
4305  $sql .= " VALUES (".$this->fk_commande.",";
4306  $sql .= " ".($this->fk_parent_line > 0 ? "'".$this->db->escape($this->fk_parent_line)."'" : "null").",";
4307  $sql .= " ".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
4308  $sql .= " '".$this->db->escape($this->desc)."',";
4309  $sql .= " '".price2num($this->qty)."',";
4310  $sql .= " '".$this->db->escape($this->ref_ext)."',";
4311  $sql .= " ".(empty($this->vat_src_code) ? "''" : "'".$this->db->escape($this->vat_src_code)."'").",";
4312  $sql .= " '".price2num($this->tva_tx)."',";
4313  $sql .= " '".price2num($this->localtax1_tx)."',";
4314  $sql .= " '".price2num($this->localtax2_tx)."',";
4315  $sql .= " '".$this->db->escape($this->localtax1_type)."',";
4316  $sql .= " '".$this->db->escape($this->localtax2_type)."',";
4317  $sql .= ' '.(!empty($this->fk_product) ? $this->fk_product : "null").',';
4318  $sql .= " '".$this->db->escape($this->product_type)."',";
4319  $sql .= " '".price2num($this->remise_percent)."',";
4320  $sql .= " ".(price2num($this->subprice) !== '' ?price2num($this->subprice) : "null").",";
4321  $sql .= " ".($this->price != '' ? "'".price2num($this->price)."'" : "null").",";
4322  $sql .= " '".price2num($this->remise)."',";
4323  $sql .= ' '.(!empty($this->fk_remise_except) ? $this->fk_remise_except : "null").',';
4324  $sql .= ' '.$this->special_code.',';
4325  $sql .= ' '.$this->rang.',';
4326  $sql .= ' '.(!empty($this->fk_fournprice) ? $this->fk_fournprice : "null").',';
4327  $sql .= ' '.price2num($this->pa_ht).',';
4328  $sql .= " '".$this->db->escape($this->info_bits)."',";
4329  $sql .= " ".price2num($this->total_ht).",";
4330  $sql .= " ".price2num($this->total_tva).",";
4331  $sql .= " ".price2num($this->total_localtax1).",";
4332  $sql .= " ".price2num($this->total_localtax2).",";
4333  $sql .= " ".price2num($this->total_ttc).",";
4334  $sql .= " ".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null").',';
4335  $sql .= " ".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null").',';
4336  $sql .= ' '.(!$this->fk_unit ? 'NULL' : $this->fk_unit);
4337  $sql .= ", ".(!empty($this->fk_multicurrency) ? $this->fk_multicurrency : 'NULL');
4338  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
4339  $sql .= ", ".$this->multicurrency_subprice;
4340  $sql .= ", ".$this->multicurrency_total_ht;
4341  $sql .= ", ".$this->multicurrency_total_tva;
4342  $sql .= ", ".$this->multicurrency_total_ttc;
4343  $sql .= ')';
4344 
4345  dol_syslog(get_class($this)."::insert", LOG_DEBUG);
4346  $resql = $this->db->query($sql);
4347  if ($resql)
4348  {
4349  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'commandedet');
4350  $this->rowid = $this->id;
4351 
4352  if (!$error)
4353  {
4354  $result = $this->insertExtraFields();
4355  if ($result < 0)
4356  {
4357  $error++;
4358  }
4359  }
4360 
4361  if (!$error && !$notrigger)
4362  {
4363  // Call trigger
4364  $result = $this->call_trigger('LINEORDER_INSERT', $user);
4365  if ($result < 0) $error++;
4366  // End call triggers
4367  }
4368 
4369  if (!$error) {
4370  $this->db->commit();
4371  return 1;
4372  }
4373 
4374  foreach ($this->errors as $errmsg)
4375  {
4376  dol_syslog(get_class($this)."::insert ".$errmsg, LOG_ERR);
4377  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
4378  }
4379  $this->db->rollback();
4380  return -1 * $error;
4381  } else {
4382  $this->error = $this->db->error();
4383  $this->db->rollback();
4384  return -2;
4385  }
4386  }
4387 
4395  public function update(User $user, $notrigger = 0)
4396  {
4397  global $conf, $langs;
4398 
4399  $error = 0;
4400 
4401  $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'.
4402 
4403  // Clean parameters
4404  if (empty($this->tva_tx)) $this->tva_tx = 0;
4405  if (empty($this->localtax1_tx)) $this->localtax1_tx = 0;
4406  if (empty($this->localtax2_tx)) $this->localtax2_tx = 0;
4407  if (empty($this->localtax1_type)) $this->localtax1_type = 0;
4408  if (empty($this->localtax2_type)) $this->localtax2_type = 0;
4409  if (empty($this->qty)) $this->qty = 0;
4410  if (empty($this->total_localtax1)) $this->total_localtax1 = 0;
4411  if (empty($this->total_localtax2)) $this->total_localtax2 = 0;
4412  if (empty($this->marque_tx)) $this->marque_tx = 0;
4413  if (empty($this->marge_tx)) $this->marge_tx = 0;
4414  if (empty($this->remise)) $this->remise = 0;
4415  if (empty($this->remise_percent)) $this->remise_percent = 0;
4416  if (empty($this->info_bits)) $this->info_bits = 0;
4417  if (empty($this->special_code)) $this->special_code = 0;
4418  if (empty($this->product_type)) $this->product_type = 0;
4419  if (empty($this->fk_parent_line)) $this->fk_parent_line = 0;
4420  if (empty($this->pa_ht)) $this->pa_ht = 0;
4421  if (empty($this->ref_ext)) $this->ref_ext = '';
4422 
4423  // if buy price not defined, define buyprice as configured in margin admin
4424  if ($this->pa_ht == 0 && $pa_ht_isemptystring)
4425  {
4426  if (($result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product)) < 0)
4427  {
4428  return $result;
4429  } else {
4430  $this->pa_ht = $result;
4431  }
4432  }
4433 
4434  $this->db->begin();
4435 
4436  // Mise a jour ligne en base
4437  $sql = "UPDATE ".MAIN_DB_PREFIX."commandedet SET";
4438  $sql .= " description='".$this->db->escape($this->desc)."'";
4439  $sql .= " , label=".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null");
4440  $sql .= " , vat_src_code=".(!empty($this->vat_src_code) ? "'".$this->db->escape($this->vat_src_code)."'" : "''");
4441  $sql .= " , tva_tx=".price2num($this->tva_tx);
4442  $sql .= " , localtax1_tx=".price2num($this->localtax1_tx);
4443  $sql .= " , localtax2_tx=".price2num($this->localtax2_tx);
4444  $sql .= " , localtax1_type='".$this->db->escape($this->localtax1_type)."'";
4445  $sql .= " , localtax2_type='".$this->db->escape($this->localtax2_type)."'";
4446  $sql .= " , qty=".price2num($this->qty);
4447  $sql .= " , ref_ext='".$this->db->escape($this->ref_ext)."'";
4448  $sql .= " , subprice=".price2num($this->subprice)."";
4449  $sql .= " , remise_percent=".price2num($this->remise_percent)."";
4450  $sql .= " , price=".price2num($this->price).""; // TODO A virer
4451  $sql .= " , remise=".price2num($this->remise).""; // TODO A virer
4452  if (empty($this->skip_update_total))
4453  {
4454  $sql .= " , total_ht=".price2num($this->total_ht)."";
4455  $sql .= " , total_tva=".price2num($this->total_tva)."";
4456  $sql .= " , total_ttc=".price2num($this->total_ttc)."";
4457  $sql .= " , total_localtax1=".price2num($this->total_localtax1);
4458  $sql .= " , total_localtax2=".price2num($this->total_localtax2);
4459  }
4460  $sql .= " , fk_product_fournisseur_price=".(!empty($this->fk_fournprice) ? $this->fk_fournprice : "null");
4461  $sql .= " , buy_price_ht='".price2num($this->pa_ht)."'";
4462  $sql .= " , info_bits=".$this->info_bits;
4463  $sql .= " , special_code=".$this->special_code;
4464  $sql .= " , date_start=".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null");
4465  $sql .= " , date_end=".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null");
4466  $sql .= " , product_type=".$this->product_type;
4467  $sql .= " , fk_parent_line=".(!empty($this->fk_parent_line) ? $this->fk_parent_line : "null");
4468  if (!empty($this->rang)) $sql .= ", rang=".$this->rang;
4469  $sql .= " , fk_unit=".(!$this->fk_unit ? 'NULL' : $this->fk_unit);
4470 
4471  // Multicurrency
4472  $sql .= " , multicurrency_subprice=".price2num($this->multicurrency_subprice)."";
4473  $sql .= " , multicurrency_total_ht=".price2num($this->multicurrency_total_ht)."";
4474  $sql .= " , multicurrency_total_tva=".price2num($this->multicurrency_total_tva)."";
4475  $sql .= " , multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc)."";
4476 
4477  $sql .= " WHERE rowid = ".$this->rowid;
4478 
4479  dol_syslog(get_class($this)."::update", LOG_DEBUG);
4480  $resql = $this->db->query($sql);
4481  if ($resql)
4482  {
4483  if (!$error)
4484  {
4485  $this->id = $this->rowid;
4486  $result = $this->insertExtraFields();
4487  if ($result < 0)
4488  {
4489  $error++;
4490  }
4491  }
4492 
4493  if (!$error && !$notrigger)
4494  {
4495  // Call trigger
4496  $result = $this->call_trigger('LINEORDER_UPDATE', $user);
4497  if ($result < 0) $error++;
4498  // End call triggers
4499  }
4500 
4501  if (!$error) {
4502  $this->db->commit();
4503  return 1;
4504  }
4505 
4506  foreach ($this->errors as $errmsg)
4507  {
4508  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
4509  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
4510  }
4511  $this->db->rollback();
4512  return -1 * $error;
4513  } else {
4514  $this->error = $this->db->error();
4515  $this->db->rollback();
4516  return -2;
4517  }
4518  }
4519 
4520  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4527  public function update_total()
4528  {
4529  // phpcs:enable
4530  $this->db->begin();
4531 
4532  // Clean parameters
4533  if (empty($this->total_localtax1)) $this->total_localtax1 = 0;
4534  if (empty($this->total_localtax2)) $this->total_localtax2 = 0;
4535 
4536  // Mise a jour ligne en base
4537  $sql = "UPDATE ".MAIN_DB_PREFIX."commandedet SET";
4538  $sql .= " total_ht='".price2num($this->total_ht)."'";
4539  $sql .= ",total_tva='".price2num($this->total_tva)."'";
4540  $sql .= ",total_localtax1='".price2num($this->total_localtax1)."'";
4541  $sql .= ",total_localtax2='".price2num($this->total_localtax2)."'";
4542  $sql .= ",total_ttc='".price2num($this->total_ttc)."'";
4543  $sql .= " WHERE rowid = ".$this->rowid;
4544 
4545  dol_syslog("OrderLine::update_total", LOG_DEBUG);
4546 
4547  $resql = $this->db->query($sql);
4548  if ($resql)
4549  {
4550  $this->db->commit();
4551  return 1;
4552  } else {
4553  $this->error = $this->db->error();
4554  $this->db->rollback();
4555  return -2;
4556  }
4557  }
4558 }
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname= '')
Make an include_once using default root and alternate root if it fails.
getNbOfProductsLines()
Return number of line with type product.
Class to manage stock movements.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto= 'UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
const STATUS_CLOSED
Closed (Sent, billed or not)
getLinesArray()
Create an array of order lines.
LibStatut($status, $billed, $mode, $donotshowbilled=0)
Return label of status.
set_date($user, $date, $notrigger=0)
Set the order date.
if(!empty($arrayfields['u.datec']['checked'])) print_liste_field_titre("DateCreationShort"u if(!empty($arrayfields['u.tms']['checked'])) print_liste_field_titre("DateModificationShort"u if(!empty($arrayfields['u.statut']['checked'])) print_liste_field_titre("Status"u statut
Definition: list.php:632
cancel($idwarehouse=-1)
Cancel an order If stock is decremented on order validation, we must reincrement it.
getMarginInfos($pvht, $remise_percent, $tva_tx, $localtax1_tx, $localtax2_tx, $fk_pa, $paht)
Return an array with margins information of a line.
static getIdAndTxFromCode($db, $code, $date_document= '')
Get id and rate of currency from code.
set_date_livraison($user, $delivery_date, $notrigger=0)
Set delivery date.
getNextNumRef($soc)
Returns the reference to the following non used Order depending on the active numbering module define...
update(User $user, $notrigger=0)
Update the line object into db.
getNbOfServicesLines()
Return number of line with type service.
hasDelay()
Is the customer order delayed?
demand_reason($demand_reason_id, $notrigger=0)
Update order demand_reason.
fetch($id, $ref= '', $ref_ext= '', $notused= '')
Get object from database.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
__construct($db)
Constructor.
</td >< tdcolspan="3">< spanclass="opacitymedium"></span ></td ></tr >< trclass="liste_total"> CREANCES DETTES< tdcolspan="3"class="right"></td >< tdcolspan="3"class="right"></td ></tr > CREANCES DETTES RECETTES DEPENSES trips CREANCES DETTES Y m expensereport p date_valid Y m expensereport pe datep $db idate($date_start)."' AND $column < p rowid
Class to manage products or services.
setDraft($user, $idwarehouse=-1)
Set draft status.
dol_now($mode= 'auto')
Return date for now.
line_order($renum=false, $rowidorder= 'ASC', $fk_parent_line=true)
Save a new position (field rang) for details lines.
set_remise($user, $remise, $notrigger=0)
Applique une remise relative.
dol_delete_preview($object)
Delete all preview files linked to object instance.
Definition: files.lib.php:1335
delete_linked_contact($source= '', $code= '')
Delete all links between an object $this and all its contacts.
loadExpeditions($filtre_statut=-1)
Load array this-&gt;expeditions of lines of shipments with nb of products sent for each order line Note:...
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
Class to manage Dolibarr users.
Definition: user.class.php:44
load_board($user)
Load indicators for dashboard (this-&gt;nbtodo and this-&gt;nbtodolate)
Class to manage Dolibarr database access.
add_contact($fk_socpeople, $type_contact, $source= 'external', $notrigger=0)
Add a link between element $this-&gt;element and a contact.
initAsSpecimen()
Initialise an instance with random values.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
classifyBilled(User $user, $notrigger=0)
Classify the order as invoiced.
valid($user, $idwarehouse=0, $notrigger=0)
Validate order.
const STATUS_SHIPMENTONPROCESS
Shipment on process.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Fonction qui renvoie si tva doit etre tva percue recuperable.
availability($availability_id, $notrigger=0)
Update delivery delay.
$pos_source
key of pos source (&#39;0&#39;, &#39;1&#39;, ...)
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
get_localtax($vatrate, $local, $thirdparty_buyer="", $thirdparty_seller="", $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate, from a $thirdparty_buyer to a $thirdparty_seller Note: This function applies same rules than get_default_tva.
fetch_lines($only_product=0, $loadalsotranslation=0)
Load array lines.
$conf db
API class for accounts.
Definition: inc.php:54
nb_expedition()
Returns a array with expeditions lines number.
info($id)
Charge les informations d&#39;ordre info dans l&#39;objet commande.
set_remise_absolue($user, $remise, $notrigger=0)
Applique une remise absolue.
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...
Class to manage order lines.
$table_ref_field
{}
insertExtraFields($trigger= '', $userused=null)
Add/Update all extra fields values for the current object.
stock_array($filtre_statut=self::STATUS_CANCELED)
Return a array with the pending stock by product.
const STOCK_NOT_ENOUGH_FOR_ORDER
ERR Not enough stock.
Class to manage standard extra fields.
create($user, $notrigger=0)
Create order Note that this-&gt;ref can be set or empty.
insert_discount($idremise)
Adding line of fixed discount in the order in DB.
Class to manage third parties objects (customers, suppliers, prospects...)
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
dol_strlen($string, $stringencoding= 'UTF-8')
Make a strlen call.
price2num($amount, $rounding= '', $option=0)
Function that return a number with universal decimal format (decimal separator is &#39;...
insert($user=null, $notrigger=0)
Insert line into database.
static replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
deleteEcmFiles($mode=0)
Delete related files of object in database.
Class to manage shipments.
static commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
static getIdFromCode($db, $code)
Get id of currency from code.
img_picto($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt= '', $morecss= '', $marginleftonlyshort=2)
Show picto whatever it&#39;s its name (generic function)
Class to manage customers orders.
const STATUS_DRAFT
Draft status.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename= '', $restricttologhandler= '', $logcontext=null)
Write log message into outputs.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories) ...
Definition: files.lib.php:1286
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1)
Remove a file or several files with a mask.
Definition: files.lib.php:1144
img_object($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
deleteExtraFields()
Delete all extra fields values for the current object.
dol_sanitizeFileName($str, $newstr= '_', $unaccent=1)
Clean a string to use it as a file name.
set_reopen($user)
Tag the order as validated (opened) Function used when order is reopend after being closed...
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:60
deleteline($user=null, $lineid=0)
Delete an order line.
getLibStatut($mode)
Return status label of Order.
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.
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this-&gt;array_options This method is in most cases call...
Superclass for orders classes.
deleteObjectLinked($sourceid=null, $sourcetype= '', $targetid=null, $targettype= '', $rowid= '')
Delete all links between an object $this.
defineBuyPrice($unitPrice=0.0, $discountPercent=0.0, $fk_product=0)
Get buy price to use for margin calculation.
print $_SERVER["PHP_SELF"]
Edit parameters.
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= '')
Update a line in database.
const STATUS_VALIDATED
Validated status.
copy_linked_contact($objFrom, $source= 'internal')
Copy contact from one element to current.
add_product($idproduct, $qty, $remise_percent=0.0, $date_start= '', $date_end= '')
Add line into array $this-&gt;client must be loaded.
print
Draft customers invoices.
Definition: index.php:89
dol_print_date($time, $format= '', $tzoutput= 'auto', $outputlangs= '', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
call_trigger($triggerName, $user)
Call trigger based on this instance.
createFromClone(User $user, $socid=0)
Load an object from its id and create a new one in database.
$module_source
key of module source when order generated from a dedicated module (&#39;cashdesk&#39;, &#39;takepos&#39;, ...)
Superclass for orders classes.
getNomUrl($withpicto=0, $option= '', $max=0, $short=0, $notooltip=0, $save_lastsearch_value=-1, $addlinktonotes=0)
Return clicable link of object (with eventually picto)
cloture($user, $notrigger=0)
Close order.
if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) if(!empty($conf->don->enabled)&&$user->rights->don->lire) if(!empty($conf->tax->enabled)&&$user->rights->tax->charges->lire) if(!empty($conf->facture->enabled)&&!empty($conf->commande->enabled)&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1232
dol_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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) Si ...
getLabelSource()
Return source label of order.
classifyUnBilled()
Classify the order as not invoiced.
Class to manage absolute discounts.
dolGetStatus($statusLabel= '', $statusLabelShort= '', $html= '', $statusType= 'status0', $displayMode=0, $url= '', $params=array())
Output the badge of a status.
load_state_board()
Charge indicateurs this-&gt;nb de tableau de bord.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
update(User $user, $notrigger=0)
Update database.
add_object_linked($origin=null, $origin_id=null)
Add objects linked in llx_element_element.
createFromProposal($object, User $user)
Load an object from a proposal and create a new order into database.
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)...
update_total()
Update DB line fields total_xxx Used by migration.
if(!defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN'
Draft customers invoices.
setDeliveryDate($user, $delivery_date, $notrigger=0)
Set the planned delivery date.
if(!empty($search_group)) natural_search(array("g.nom"g note
Definition: list.php:122
fetch($rowid)
Load line order.
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= '')
Add an order line into database (linked to product/service or not)
showDelay()
Show the customer delayed info.
getNbOfShipments()
Count number of shipments for this order.
__construct($db)
Constructor.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $keepmoretags= '', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields...
set_ref_client($user, $ref_client, $notrigger=0)
Set customer ref.
const STATUS_CANCELED
Canceled status.