dolibarr 23.0.4
commande.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2003-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2014 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
6 * Copyright (C) 2010-2020 Juanjo Menent <jmenent@2byte.es>
7 * Copyright (C) 2011 Jean Heimburger <jean@tiaris.info>
8 * Copyright (C) 2012-2014 Christophe Battarel <christophe.battarel@altairis.fr>
9 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
10 * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
11 * Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
12 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
13 * Copyright (C) 2016-2022 Ferran Marcet <fmarcet@2byte.es>
14 * Copyright (C) 2021-2025 Frédéric France <frederic.france@free.fr>
15 * Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
16 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
17 * Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
18 * Copyright (C) 2026 Nick Fragoulis
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 3 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program. If not, see <https://www.gnu.org/licenses/>.
32 */
33
40require_once DOL_DOCUMENT_ROOT.'/core/class/commonorder.class.php';
41require_once DOL_DOCUMENT_ROOT.'/commande/class/orderline.class.php';
42require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
43require_once DOL_DOCUMENT_ROOT.'/margin/lib/margins.lib.php';
44require_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
45require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
46require_once DOL_DOCUMENT_ROOT.'/subtotals/class/commonsubtotal.class.php';
47
48
52class Commande extends CommonOrder
53{
54 use CommonSubtotal;
55
59 public $element = 'commande';
60
65 public $TRIGGER_PREFIX = 'ORDER';
66
70 public $table_element = 'commande';
71
75 public $table_element_line = 'commandedet';
76
80 public $class_element_line = 'OrderLine';
81
85 public $fk_element = 'fk_commande';
86
90 public $picto = 'order';
91
96 public $restrictiononfksoc = 1;
97
101 protected $table_ref_field = 'ref';
102
106 public $socid;
107
111 public $ref_client;
112
116 public $ref_customer;
117
121 public $contactid;
122
128 public $statut;
129
134 public $status;
135
139 public $billed;
140
144 public $date_lim_reglement;
148 public $cond_reglement_code;
149
153 public $cond_reglement_doc;
154
159 public $deposit_percent;
160
164 public $fk_account;
165
169 public $mode_reglement;
170
174 public $mode_reglement_id;
175
179 public $mode_reglement_code;
180
185 public $availability_id;
186
191 public $availability_code;
192
197 public $availability;
198
202 public $demand_reason_id;
203
207 public $demand_reason_code;
208
212 public $date;
213
219 public $date_commande;
220
224 public $delivery_date;
225
229 public $fk_remise_except;
230
235 public $remise_percent;
236
240 public $source;
241
246 public $signed_status = 0;
247
251 public $warehouse_id;
252
256 public $extraparams = array();
257
261 public $user_author_id;
262
266 public $line;
267
271 public $lines = array();
272
273
277 public $module_source;
281 public $pos_source;
282
286 public $expeditions;
287
291 public $online_payment_url;
292
293
294
320 // BEGIN MODULEBUILDER PROPERTIES
324 public $fields = array(
325 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10),
326 'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => '1', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 20, 'index' => 1),
327 'ref' => array('type' => 'varchar(30)', 'label' => 'Ref', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'showoncombobox' => 1, 'position' => 25),
328 'ref_ext' => array('type' => 'varchar(255)', 'label' => 'RefExt', 'enabled' => 1, 'visible' => 0, 'position' => 26),
329 'ref_client' => array('type' => 'varchar(255)', 'label' => 'RefCustomer', 'enabled' => 1, 'visible' => -1, 'position' => 28),
330 'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php', 'label' => 'ThirdParty', 'enabled' => 'isModEnabled("societe")', 'visible' => -1, 'notnull' => 1, 'position' => 20),
331 'fk_projet' => array('type' => 'integer:Project:projet/class/project.class.php:1:(fk_statut:=:1)', 'label' => 'Project', 'enabled' => "isModEnabled('project')", 'visible' => -1, 'position' => 25),
332 'date_commande' => array('type' => 'date', 'label' => 'Date', 'enabled' => 1, 'visible' => 1, 'position' => 60, 'csslist' => 'nowraponall'),
333 'date_valid' => array('type' => 'datetime', 'label' => 'DateValidation', 'enabled' => 1, 'visible' => -1, 'position' => 62, 'csslist' => 'nowraponall'),
334 'date_cloture' => array('type' => 'datetime', 'label' => 'DateClosing', 'enabled' => 1, 'visible' => -1, 'position' => 65, 'csslist' => 'nowraponall'),
335 'fk_user_valid' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserValidation', 'enabled' => 1, 'visible' => -1, 'position' => 85),
336 'fk_user_cloture' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserClosing', 'enabled' => 1, 'visible' => -1, 'position' => 90),
337 'source' => array('type' => 'smallint(6)', 'label' => 'Source', 'enabled' => 1, 'visible' => -1, 'position' => 95),
338 'total_tva' => array('type' => 'double(24,8)', 'label' => 'VAT', 'enabled' => 1, 'visible' => -1, 'position' => 125, 'isameasure' => 1),
339 'localtax1' => array('type' => 'double(24,8)', 'label' => 'LocalTax1', 'enabled' => 1, 'visible' => -1, 'position' => 130, 'isameasure' => 1),
340 'localtax2' => array('type' => 'double(24,8)', 'label' => 'LocalTax2', 'enabled' => 1, 'visible' => -1, 'position' => 135, 'isameasure' => 1),
341 'total_ht' => array('type' => 'double(24,8)', 'label' => 'TotalHT', 'enabled' => 1, 'visible' => -1, 'position' => 140, 'isameasure' => 1),
342 'total_ttc' => array('type' => 'double(24,8)', 'label' => 'TotalTTC', 'enabled' => 1, 'visible' => -1, 'position' => 145, 'isameasure' => 1),
343 'signed_status' => array('type' => 'smallint(6)', 'label' => 'SignedStatus', 'enabled' => 1, 'visible' => -1, 'position' => 146, 'arrayofkeyval' => array(0 => 'NoSignature', 1 => 'SignedSender', 2 => 'SignedReceiver', 9 => 'SignedAll')),
344 'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 150),
345 'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 155),
346 'model_pdf' => array('type' => 'varchar(255)', 'label' => 'PDFTemplate', 'enabled' => 1, 'visible' => 0, 'position' => 160),
347 'fk_account' => array('type' => 'integer', 'label' => 'BankAccount', 'enabled' => 'isModEnabled("bank")', 'visible' => -1, 'position' => 170),
348 'fk_currency' => array('type' => 'varchar(3)', 'label' => 'MulticurrencyID', 'enabled' => 1, 'visible' => -1, 'position' => 175),
349 'fk_cond_reglement' => array('type' => 'integer', 'label' => 'PaymentTerm', 'enabled' => 1, 'visible' => -1, 'position' => 180),
350 'deposit_percent' => array('type' => 'varchar(63)', 'label' => 'DepositPercent', 'enabled' => 1, 'visible' => -1, 'position' => 181),
351 'fk_mode_reglement' => array('type' => 'integer', 'label' => 'PaymentMode', 'enabled' => 1, 'visible' => -1, 'position' => 185),
352 'date_livraison' => array('type' => 'date', 'label' => 'DateDeliveryPlanned', 'enabled' => 1, 'visible' => -1, 'position' => 190, 'csslist' => 'nowraponall'),
353 'fk_shipping_method' => array('type' => 'integer', 'label' => 'ShippingMethod', 'enabled' => 1, 'visible' => -1, 'position' => 195),
354 'fk_warehouse' => array('type' => 'integer:Entrepot:product/stock/class/entrepot.class.php', 'label' => 'DefaultWarehouse', 'enabled' => 'isModEnabled("stock")', 'visible' => -1, 'position' => 200, 'nodepth' => 1),
355 'fk_availability' => array('type' => 'integer', 'label' => 'Availability', 'enabled' => 1, 'visible' => -1, 'position' => 205),
356 'fk_input_reason' => array('type' => 'integer', 'label' => 'InputReason', 'enabled' => 1, 'visible' => -1, 'position' => 210),
357 //'fk_delivery_address' =>array('type'=>'integer', 'label'=>'DeliveryAddress', 'enabled'=>1, 'visible'=>-1, 'position'=>215),
358 'extraparams' => array('type' => 'varchar(255)', 'label' => 'Extraparams', 'enabled' => 1, 'visible' => -1, 'position' => 225),
359 'fk_incoterms' => array('type' => 'integer', 'label' => 'IncotermCode', 'enabled' => 'isModEnabled("incoterm")', 'visible' => -1, 'position' => 230),
360 'location_incoterms' => array('type' => 'varchar(255)', 'label' => 'IncotermLabel', 'enabled' => 'isModEnabled("incoterm")', 'visible' => -1, 'position' => 235),
361 'fk_multicurrency' => array('type' => 'integer', 'label' => 'Fk multicurrency', 'enabled' => 'isModEnabled("multicurrency")', 'visible' => -1, 'position' => 240),
362 'multicurrency_code' => array('type' => 'varchar(255)', 'label' => 'MulticurrencyCurrency', 'enabled' => 'isModEnabled("multicurrency")', 'visible' => -1, 'position' => 245),
363 'multicurrency_tx' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyRate', 'enabled' => 'isModEnabled("multicurrency")', 'visible' => -1, 'position' => 250, 'isameasure' => 1),
364 'multicurrency_total_ht' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyAmountHT', 'enabled' => 'isModEnabled("multicurrency")', 'visible' => -1, 'position' => 255, 'isameasure' => 1),
365 'multicurrency_total_tva' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyAmountVAT', 'enabled' => 'isModEnabled("multicurrency")', 'visible' => -1, 'position' => 260, 'isameasure' => 1),
366 'multicurrency_total_ttc' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyAmountTTC', 'enabled' => 'isModEnabled("multicurrency")', 'visible' => -1, 'position' => 265, 'isameasure' => 1),
367 'last_main_doc' => array('type' => 'varchar(255)', 'label' => 'LastMainDoc', 'enabled' => 1, 'visible' => -1, 'position' => 270),
368 'module_source' => array('type' => 'varchar(32)', 'label' => 'POSModule', 'enabled' => 1, 'visible' => -1, 'position' => 275),
369 'pos_source' => array('type' => 'varchar(32)', 'label' => 'POSTerminal', 'enabled' => 1, 'visible' => -1, 'position' => 280),
370 'fk_user_author' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserAuthor', 'enabled' => 1, 'visible' => -1, 'position' => 300),
371 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 302),
372 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -2, 'position' => 304, 'csslist' => 'nowraponall'),
373 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 306),
374 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -2, 'position' => 400),
375 'fk_statut' => array('type' => 'smallint(6)', 'label' => 'Status', 'enabled' => 1, 'visible' => -1, 'position' => 500),
376 );
377 // END MODULEBUILDER PROPERTIES
378
383
387 const STATUS_CANCELED = -1;
391 const STATUS_DRAFT = 0;
399 const STATUS_SHIPMENTONPROCESS = 2; // We set this status when a shipment is validated
400
406
410 const STATUS_CLOSED = 3;
411
412 /*
413 * No signature
414 */
415 const STATUS_NO_SIGNATURE = 0;
416
417 /*
418 * Signed by sender
419 */
420 const STATUS_SIGNED_SENDER = 1;
421
422 /*
423 * Signed by receiver
424 */
425 const STATUS_SIGNED_RECEIVER = 2;
426
427 /*
428 * Signed by all
429 */
430 const STATUS_SIGNED_ALL = 9; // To handle future kind of signature (ex: tripartite contract)
431
432
438 public function __construct($db)
439 {
440 $this->db = $db;
441
442 $this->ismultientitymanaged = 1;
443 $this->isextrafieldmanaged = 1;
444
445 $this->fields['ref_ext']['visible'] = getDolGlobalInt('MAIN_LIST_SHOW_REF_EXT');
446 }
447
455 public function getNextNumRef($soc)
456 {
457 global $langs, $conf;
458 $langs->load("order");
459
460 if (getDolGlobalString('COMMANDE_ADDON')) {
461 $mybool = false;
462
463 $file = getDolGlobalString('COMMANDE_ADDON') . ".php";
464 $classname = getDolGlobalString('COMMANDE_ADDON');
465
466 // Include file with class
467 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
468 foreach ($dirmodels as $reldir) {
469 $dir = dol_buildpath($reldir."core/modules/commande/");
470
471 // Load file with numbering class (if found)
472 $mybool = ((bool) @include_once $dir.$file) || $mybool;
473 }
474
475 if (!$mybool) {
476 dol_print_error(null, "Failed to include file ".$file);
477 return '';
478 }
479
480 $obj = new $classname();
482 '@phan-var-force ModeleNumRefCommandes $obj';
483
484 $numref = $obj->getNextValue($soc, $this);
485
486 if ($numref != "") {
487 return $numref;
488 } else {
489 $this->error = $obj->error;
490 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
491 return "";
492 }
493 } else {
494 print $langs->trans("Error")." ".$langs->trans("Error_COMMANDE_ADDON_NotDefined");
495 return "";
496 }
497 }
498
499
508 public function valid($user, $idwarehouse = 0, $notrigger = 0)
509 {
510 global $conf, $langs;
511
512 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
513
514 $error = 0;
515
516 // Protection
517 if ($this->status == self::STATUS_VALIDATED) {
518 dol_syslog(get_class($this)."::valid action abandoned: already validated", LOG_WARNING);
519 return 0;
520 }
521
522 if (!((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('commande', 'creer'))
523 || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('commande', 'order_advance', 'validate')))) {
524 $this->error = 'NotEnoughPermissions';
525 dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
526 return -1;
527 }
528 if (empty($this->socid)) {
529 $this->error = 'ErrorWrongParameters';
530 return -1;
531 }
532 if (!getDolGlobalBool('ORDER_NOCHECK_ONSALE_PRODUCTS_ONVALID') && !$this->checkActiveProductInLines()) {
533 dol_syslog(get_class($this)."::valid checkActiveProductInLines ".$this->error, LOG_INFO);
534 return -1;
535 }
536 $now = dol_now();
537
538 $this->db->begin();
539
540 // Definition du nom de module de numerotation de commande
541 $soc = new Societe($this->db);
542 $soc->fetch($this->socid);
543
544 // Class of company linked to order
545 $result = $soc->setAsCustomer();
546
547 // Define new ref
548 if (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref)) { // empty should not happened, but when it occurs, the test save life
549 $num = $this->getNextNumRef($soc);
550 } else {
551 $num = (string) $this->ref;
552 }
553 $this->newref = dol_sanitizeFileName($num);
554
555 // Validate
556 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
557 $sql .= " SET ref = '".$this->db->escape($num)."',";
558 $sql .= " fk_statut = ".self::STATUS_VALIDATED.",";
559 $sql .= " date_valid = '".$this->db->idate($now)."',";
560 $sql .= " fk_user_valid = ".($user->id > 0 ? (int) $user->id : "null").",";
561 $sql .= " fk_user_modif = ".((int) $user->id);
562 $sql .= " WHERE rowid = ".((int) $this->id);
563
564 dol_syslog(get_class($this)."::valid", LOG_DEBUG);
565 $resql = $this->db->query($sql);
566 if (!$resql) {
567 dol_print_error($this->db);
568 $this->error = $this->db->lasterror();
569 $error++;
570 }
571
572 if (!$error) {
573 // If stock is incremented on validate order, we must increment it
574 if ($result >= 0 && isModEnabled('stock') && getDolGlobalInt('STOCK_CALCULATE_ON_VALIDATE_ORDER') == 1) {
575 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
576 $langs->load("agenda");
577
578 // Loop on each line
579 $cpt = count($this->lines);
580 for ($i = 0; $i < $cpt; $i++) {
581 if ($this->lines[$i]->fk_product > 0) {
582 $mouvP = new MouvementStock($this->db);
583 $mouvP->origin = &$this;
584 $mouvP->setOrigin($this->element, $this->id);
585 // We decrement stock of product (and sub-products)
586 $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("OrderValidatedInDolibarr", $num));
587 if ($result < 0) {
588 $error++;
589 $this->setErrorsFromObject($mouvP);
590 }
591 }
592 if ($error) {
593 break;
594 }
595 }
596 }
597 }
598
599 if (!$error && !$notrigger) {
600 // Call trigger
601 $result = $this->call_trigger('ORDER_VALIDATE', $user);
602 if ($result < 0) {
603 $error++;
604 }
605 // End call triggers
606 }
607
608 if (!$error) {
609 $this->oldref = $this->ref;
610
611 // Rename directory if dir was a temporary ref
612 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
613 // Now we rename also files into index
614 $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)."'";
615 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'commande/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
616 $resql = $this->db->query($sql);
617 if (!$resql) {
618 $error++;
619 $this->error = $this->db->lasterror();
620 }
621 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'commande/".$this->db->escape($this->newref)."'";
622 $sql .= " WHERE filepath = 'commande/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
623 $resql = $this->db->query($sql);
624 if (!$resql) {
625 $error++;
626 $this->error = $this->db->lasterror();
627 }
628
629 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
630 $oldref = dol_sanitizeFileName($this->ref);
631 $newref = dol_sanitizeFileName($num);
632 $dirsource = $conf->commande->multidir_output[$this->entity].'/'.$oldref;
633 $dirdest = $conf->commande->multidir_output[$this->entity].'/'.$newref;
634 if (!$error && file_exists($dirsource)) {
635 dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
636
637 if (@rename($dirsource, $dirdest)) {
638 dol_syslog("Rename ok");
639 // Rename docs starting with $oldref with $newref
640 $listoffiles = dol_dir_list($conf->commande->multidir_output[$this->entity].'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
641 foreach ($listoffiles as $fileentry) {
642 $dirsource = $fileentry['name'];
643 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
644 $dirsource = $fileentry['path'].'/'.$dirsource;
645 $dirdest = $fileentry['path'].'/'.$dirdest;
646 @rename($dirsource, $dirdest);
647 }
648 }
649 }
650 }
651 }
652
653 // Set new ref and current status
654 if (!$error) {
655 $this->ref = $num;
656 $this->statut = self::STATUS_VALIDATED; // deprecated
658 }
659
660 if (!$error) {
661 $this->db->commit();
662 return 1;
663 } else {
664 $this->db->rollback();
665 return -1;
666 }
667 }
668
669 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
677 public function setDraft($user, $idwarehouse = -1)
678 {
679 //phpcs:enable
680 global $langs;
681
682 $error = 0;
683
684 // Protection
685 if ($this->status <= self::STATUS_DRAFT && !getDolGlobalInt('ORDER_REOPEN_TO_DRAFT')) {
686 return 0;
687 }
688
689 if (!((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('commande', 'creer'))
690 || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('commande', 'order_advance', 'validate')))) {
691 $this->error = 'Permission denied';
692 return -1;
693 }
694
695 dol_syslog(__METHOD__, LOG_DEBUG);
696
697 $this->db->begin();
698
699 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
700 $sql .= " SET fk_statut = ".((int) self::STATUS_DRAFT).",";
701 $sql .= " fk_user_modif = ".((int) $user->id);
702 $sql .= " WHERE rowid = ".((int) $this->id);
703
704 if ($this->db->query($sql)) {
705 $this->oldcopy = clone $this;
706
707 // If stock is decremented on validate order, we must reincrement it
708 if (isModEnabled('stock') && getDolGlobalInt('STOCK_CALCULATE_ON_VALIDATE_ORDER') == 1) {
709 $result = 0;
710
711 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
712 $langs->load("agenda");
713
714 $num = count($this->lines);
715 for ($i = 0; $i < $num; $i++) {
716 if ($this->lines[$i]->fk_product > 0) {
717 $mouvP = new MouvementStock($this->db);
718 $mouvP->origin = &$this;
719 $mouvP->setOrigin($this->element, $this->id);
720 // We increment stock of product (and sub-products)
721 $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->transnoentitiesnoconv("OrderBackToDraftInDolibarr", $this->ref));
722 if ($result < 0) {
723 $error++;
724 $this->setErrorsFromObject($mouvP);
725 break;
726 }
727 }
728 }
729 }
730
731 if (!$error) {
732 // Call trigger
733 $result = $this->call_trigger('ORDER_UNVALIDATE', $user);
734 if ($result < 0) {
735 $error++;
736 }
737 }
738
739 if (!$error) {
740 $this->statut = self::STATUS_DRAFT; // deprecated
741 $this->status = self::STATUS_DRAFT;
742 $this->db->commit();
743 return 1;
744 } else {
745 $this->db->rollback();
746 return -1;
747 }
748 } else {
749 $this->error = $this->db->error();
750 $this->db->rollback();
751 return -1;
752 }
753 }
754
755
756 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
764 public function set_reopen($user)
765 {
766 // phpcs:enable
767 $error = 0;
768
769 if ($this->status != self::STATUS_CANCELED && $this->status != self::STATUS_CLOSED) {
770 dol_syslog(get_class($this)."::set_reopen order has not status closed", LOG_WARNING);
771 return 0;
772 }
773
774 $this->db->begin();
775
776 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
777 $sql .= ' SET fk_statut='.self::STATUS_VALIDATED.', facture=0,';
778 $sql .= " fk_user_modif = ".((int) $user->id);
779 $sql .= " WHERE rowid = ".((int) $this->id);
780
781 dol_syslog(get_class($this)."::set_reopen", LOG_DEBUG);
782 $resql = $this->db->query($sql);
783 if ($resql) {
784 // Call trigger
785 $result = $this->call_trigger('ORDER_REOPEN', $user);
786 if ($result < 0) {
787 $error++;
788 }
789 // End call triggers
790 } else {
791 $error++;
792 $this->error = $this->db->lasterror();
793 dol_print_error($this->db);
794 }
795
796 if (!$error) {
797 $this->statut = self::STATUS_VALIDATED; // deprecated
799 $this->billed = 0;
800
801 $this->db->commit();
802 return 1;
803 } else {
804 foreach ($this->errors as $errmsg) {
805 dol_syslog(get_class($this)."::set_reopen ".$errmsg, LOG_ERR);
806 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
807 }
808 $this->db->rollback();
809 return -1 * $error;
810 }
811 }
812
821 public function cloture($user, $notrigger = 0, $checkpermission = 1)
822 {
823 $error = 0;
824
825 $usercanclose = (!$checkpermission
826 || (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('commande', 'creer'))
827 || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('commande', 'order_advance', 'close')));
828
829 if ($usercanclose) {
830 if ($this->status == self::STATUS_CLOSED) {
831 return 0;
832 }
833 $this->db->begin();
834
835 $now = dol_now();
836
837 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
838 $sql .= ' SET fk_statut = '.self::STATUS_CLOSED.',';
839 $sql .= ' fk_user_cloture = '.((int) $user->id).',';
840 $sql .= " date_cloture = '".$this->db->idate($now)."',";
841 $sql .= " fk_user_modif = ".((int) $user->id);
842 $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > '.self::STATUS_DRAFT;
843
844 if ($this->db->query($sql)) {
845 if (!$notrigger) {
846 // Call trigger
847 $result = $this->call_trigger('ORDER_CLOSE', $user);
848 if ($result < 0) {
849 $error++;
850 }
851 // End call triggers
852 }
853
854 if (!$error) {
855 $this->statut = self::STATUS_CLOSED; // deprecated
857
858 $this->db->commit();
859 return 1;
860 } else {
861 $this->db->rollback();
862 return -1;
863 }
864 } else {
865 $this->error = $this->db->lasterror();
866
867 $this->db->rollback();
868 return -1;
869 }
870 }
871 return 0;
872 }
873
885 public function setCategories($categories)
886 {
887 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
888 return parent::setCategoriesCommon($categories, Categorie::TYPE_ORDER);
889 }
890
899 public function cancel($user, $idwarehouse = -1)
900 {
901 global $user, $langs;
902
903 $error = 0;
904
905 $this->db->begin();
906
907 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
908 $sql .= " SET fk_statut = ".self::STATUS_CANCELED.",";
909 $sql .= " fk_user_modif = ".((int) $user->id);
910 $sql .= " WHERE rowid = ".((int) $this->id);
911 $sql .= " AND fk_statut = ".self::STATUS_VALIDATED;
912
913 dol_syslog(get_class($this)."::cancel", LOG_DEBUG);
914 if ($this->db->query($sql)) {
915 // If stock is decremented on validate order, we must reincrement it
916 if (isModEnabled('stock') && getDolGlobalInt('STOCK_CALCULATE_ON_VALIDATE_ORDER') == 1) {
917 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
918 $langs->load("agenda");
919
920 $num = count($this->lines);
921 for ($i = 0; $i < $num; $i++) {
922 if ($this->lines[$i]->fk_product > 0) {
923 $mouvP = new MouvementStock($this->db);
924 $mouvP->setOrigin($this->element, $this->id);
925 // We increment stock of product (and sub-products)
926 $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
927 if ($result < 0) {
928 $error++;
929 $this->setErrorsFromObject($mouvP);
930 break;
931 }
932 }
933 }
934 }
935
936 if (!$error) {
937 // Call trigger
938 $result = $this->call_trigger('ORDER_CANCEL', $user);
939 if ($result < 0) {
940 $error++;
941 }
942 // End call triggers
943 }
944
945 if (!$error) {
946 $this->statut = self::STATUS_CANCELED; // deprecated
948 $this->db->commit();
949 return 1;
950 } else {
951 foreach ($this->errors as $errmsg) {
952 dol_syslog(get_class($this)."::cancel ".$errmsg, LOG_ERR);
953 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
954 }
955 $this->db->rollback();
956 return -1 * $error;
957 }
958 } else {
959 $this->error = $this->db->error();
960 $this->db->rollback();
961 return -1;
962 }
963 }
964
973 public function create($user, $notrigger = 0)
974 {
975 global $conf, $langs, $mysoc;
976 $error = 0;
977
978 // Clean parameters
979
980 if (empty($this->socid)) {
981 $this->error = 'ErrorWrongParameters';
982 return -1;
983 }
984
985 // Set tmp vars
986 $date = ($this->date_commande ? $this->date_commande : $this->date);
987 $this->import_key = trim((string) $this->import_key);
988 $delivery_date = $this->delivery_date;
989
990 // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
991 if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) {
992 list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $date);
993 } else {
994 $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
995 }
996 if (empty($this->fk_multicurrency)) {
997 $this->multicurrency_code = $conf->currency;
998 $this->fk_multicurrency = 0;
999 $this->multicurrency_tx = 1;
1000 }
1001 // setEntity will set entity with the right value if empty or change it for the right value if multicompany module is active
1002 $this->entity = setEntity($this);
1003
1004 dol_syslog(get_class($this)."::create user=".$user->id);
1005
1006 // Check parameters
1007 if (!empty($this->ref)) { // We check that ref is not already used
1008 $result = self::isExistingObject($this->element, 0, $this->ref); // Check ref is not yet used
1009 if ($result > 0) {
1010 $this->error = 'ErrorRefAlreadyExists';
1011 dol_syslog(get_class($this)."::create ".$this->error, LOG_WARNING);
1012 $this->db->rollback();
1013 return -1;
1014 }
1015 }
1016
1017 $soc = new Societe($this->db);
1018 $result = $soc->fetch($this->socid);
1019 if ($result < 0) {
1020 $this->error = "Failed to fetch company";
1021 dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
1022 return -2;
1023 }
1024 if (getDolGlobalString('ORDER_REQUIRE_SOURCE') && $this->source < 0) {
1025 $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Source"));
1026 dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
1027 return -1;
1028 }
1029
1030 $this->date_creation = dol_now();
1031
1032 $this->db->begin();
1033
1034 $sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (";
1035 $sql .= " ref, fk_soc, date_creation, fk_user_author, fk_projet, date_commande, source, note_private, note_public, ref_ext, ref_client";
1036 $sql .= ", model_pdf, fk_cond_reglement, deposit_percent, fk_mode_reglement, fk_account, fk_availability, fk_input_reason, date_livraison, fk_delivery_address";
1037 $sql .= ", fk_shipping_method";
1038 $sql .= ", fk_warehouse";
1039 $sql .= ", fk_incoterms, location_incoterms";
1040 $sql .= ", entity, module_source, pos_source";
1041 $sql .= ", fk_multicurrency";
1042 $sql .= ", multicurrency_code";
1043 $sql .= ", multicurrency_tx";
1044 $sql .= ", import_key";
1045 $sql .= ")";
1046 $sql .= " VALUES ('(PROV)', ".((int) $this->socid).", '".$this->db->idate($this->date_creation)."', ".($user->id > 0 ? ((int) $user->id) : "null");
1047 $sql .= ", ".($this->fk_project > 0 ? ((int) $this->fk_project) : "null");
1048 $sql .= ", '".$this->db->idate($date)."'";
1049 $sql .= ", ".($this->source >= 0 && $this->source != '' ? $this->db->escape((string) $this->source) : 'null');
1050 $sql .= ", '".$this->db->escape($this->note_private)."'";
1051 $sql .= ", '".$this->db->escape($this->note_public)."'";
1052 $sql .= ", ".($this->ref_ext ? "'".$this->db->escape($this->ref_ext)."'" : "null");
1053 $sql .= ", ".($this->ref_client ? "'".$this->db->escape($this->ref_client)."'" : "null");
1054 $sql .= ", '".$this->db->escape($this->model_pdf)."'";
1055 $sql .= ", ".($this->cond_reglement_id > 0 ? ((int) $this->cond_reglement_id) : "null");
1056 $sql .= ", ".(!empty($this->deposit_percent) ? "'".$this->db->escape($this->deposit_percent)."'" : "null");
1057 $sql .= ", ".($this->mode_reglement_id > 0 ? ((int) $this->mode_reglement_id) : "null");
1058 $sql .= ", ".($this->fk_account > 0 ? ((int) $this->fk_account) : 'NULL');
1059 $sql .= ", ".($this->availability_id > 0 ? ((int) $this->availability_id) : "null");
1060 $sql .= ", ".($this->demand_reason_id > 0 ? ((int) $this->demand_reason_id) : "null");
1061 $sql .= ", ".($delivery_date ? "'".$this->db->idate($delivery_date)."'" : "null");
1062 $sql .= ", ".($this->fk_delivery_address > 0 ? ((int) $this->fk_delivery_address) : 'NULL');
1063 $sql .= ", ".(!empty($this->shipping_method_id) && $this->shipping_method_id > 0 ? ((int) $this->shipping_method_id) : 'NULL');
1064 $sql .= ", ".(!empty($this->warehouse_id) && $this->warehouse_id > 0 ? ((int) $this->warehouse_id) : 'NULL');
1065 $sql .= ", ".(int) $this->fk_incoterms;
1066 $sql .= ", '".$this->db->escape($this->location_incoterms)."'";
1067 $sql .= ", ".(int) $this->entity;
1068 $sql .= ", ".($this->module_source ? "'".$this->db->escape($this->module_source)."'" : "null");
1069 $sql .= ", ".((!is_null($this->pos_source) && $this->pos_source != '') ? "'".$this->db->escape($this->pos_source)."'" : "null"); // Can be null, '', '0', '1'
1070 $sql .= ", ".(int) $this->fk_multicurrency;
1071 $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
1072 $sql .= ", ".(float) $this->multicurrency_tx;
1073 $sql .= ", '".$this->db->escape($this->import_key)."'";
1074 $sql .= ")";
1075
1076 dol_syslog(get_class($this)."::create", LOG_DEBUG);
1077 $resql = $this->db->query($sql);
1078 if ($resql) {
1079 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'commande');
1080
1081 if ($this->id) {
1082 $fk_parent_line = 0;
1083 $num = count($this->lines);
1084
1085 /*
1086 * Insert products details into db
1087 */
1088 for ($i = 0; $i < $num; $i++) {
1089 $line = $this->lines[$i];
1090
1091 // Test and convert into OrderLine object this->lines[$i]. When coming from REST API, we may still have an array
1092 //if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object.
1093 if (!is_object($line)) {
1094 $lineobj = new OrderLine($this->db);
1095 foreach ($line as $key => $val) {
1096 $lineobj->$key = $val;
1097 }
1098 $line = $lineobj;
1099 $this->lines[$i] = $line;
1100 }
1101
1102 // Reset fk_parent_line for no child products and special product
1103 if (($line->product_type != 9 && empty($line->fk_parent_line)) || $line->product_type == 9) {
1104 $fk_parent_line = 0;
1105 }
1106
1107 // Complete vat rate with code
1108 $vatrate = $line->tva_tx;
1109 if ($line->vat_src_code && !preg_match('/\‍(.*\‍)/', (string) $vatrate)) {
1110 $vatrate .= ' ('.$line->vat_src_code.')';
1111 }
1112
1113 if (getDolGlobalString('MAIN_CREATEFROM_KEEP_LINE_ORIGIN_INFORMATION')) {
1114 $originid = $line->origin_id;
1115 $origintype = empty($line->origin_type) ? $line->origin : $line->origin_type;
1116 } else {
1117 $originid = $line->id;
1118 $origintype = $this->element;
1119 }
1120
1121 // ref_ext
1122 if (empty($line->ref_ext)) {
1123 $line->ref_ext = '';
1124 }
1125
1126 $result = $this->addline(
1127 $line->desc,
1128 $line->subprice,
1129 $line->qty,
1130 $vatrate,
1131 $line->localtax1_tx,
1132 $line->localtax2_tx,
1133 $line->fk_product,
1134 $line->remise_percent,
1135 $line->info_bits,
1136 $line->fk_remise_except,
1137 'HT',
1138 0,
1139 $line->date_start,
1140 $line->date_end,
1141 $line->product_type,
1142 $line->rang,
1143 $line->special_code,
1144 $fk_parent_line,
1145 $line->fk_fournprice,
1146 $line->pa_ht,
1147 $line->label,
1148 $line->array_options,
1149 $line->fk_unit,
1150 (string) $origintype,
1151 $originid,
1152 0,
1153 $line->ref_ext,
1154 1
1155 );
1156
1157 if ($result < 0) {
1158 if ($result != self::STOCK_NOT_ENOUGH_FOR_ORDER) {
1159 $this->error = $this->db->lasterror();
1160 $this->errors[] = $this->error;
1161 dol_print_error($this->db);
1162 }
1163 $this->db->rollback();
1164 return -1;
1165 }
1166 // Defined the new fk_parent_line
1167 if ($result > 0 && $line->product_type == 9) {
1168 $fk_parent_line = $result;
1169 }
1170 }
1171
1172 $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.
1173
1174 // update ref
1175 $initialref = '(PROV'.$this->id.')';
1176 if (!empty($this->ref)) {
1177 $initialref = $this->ref;
1178 }
1179
1180 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element." SET ref='".$this->db->escape($initialref)."' WHERE rowid=".((int) $this->id);
1181 if ($this->db->query($sql)) {
1182 $this->ref = $initialref;
1183
1184 if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) { // To use new linkedObjectsIds instead of old linked_objects
1185 $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
1186 }
1187
1188 // Add object linked
1189 if (!empty($this->linked_objects) && is_array($this->linked_objects)) {
1190 foreach ($this->linked_objects as $origin => $tmp_origin_id) {
1191 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, ...))
1192 foreach ($tmp_origin_id as $origin_id) {
1193 $ret = $this->add_object_linked($origin, $origin_id);
1194 if (!$ret) {
1195 $this->error = $this->db->lasterror();
1196 $error++;
1197 }
1198 }
1199 } else { // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
1200 $origin_id = $tmp_origin_id;
1201 $ret = $this->add_object_linked($origin, $origin_id);
1202 if (!$ret) {
1203 $this->error = $this->db->lasterror();
1204 $error++;
1205 }
1206 }
1207 }
1208 }
1209
1210 if (!$error && getDolGlobalString('MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN') && !empty($this->origin) && !empty($this->origin_id)) { // Get contact from origin object
1211 $originforcontact = empty($this->origin_type) ? $this->origin : $this->origin_type;
1212 $originidforcontact = $this->origin_id;
1213 if ($originforcontact == 'shipping') { // shipment and order share the same contacts. If creating from shipment we take data of order
1214 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
1215 $exp = new Expedition($this->db);
1216 $exp->fetch($this->origin_id);
1217 $exp->fetchObjectLinked();
1218 if (count($exp->linkedObjectsIds['commande']) > 0) {
1219 foreach ($exp->linkedObjectsIds['commande'] as $key => $value) {
1220 $originforcontact = 'commande';
1221 if (is_object($value)) {
1222 $originidforcontact = $value->id;
1223 } else {
1224 $originidforcontact = $value;
1225 }
1226 break; // We take first one
1227 }
1228 }
1229 }
1230
1231 $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";
1232 $sqlcontact .= " WHERE element_id = ".((int) $originidforcontact)." AND ec.fk_c_type_contact = ctc.rowid AND ctc.element = '".$this->db->escape($originforcontact)."'";
1233
1234 $resqlcontact = $this->db->query($sqlcontact);
1235 if ($resqlcontact) {
1236 while ($objcontact = $this->db->fetch_object($resqlcontact)) {
1237 //print $objcontact->code.'-'.$objcontact->source.'-'.$objcontact->fk_socpeople."\n";
1238 $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
1239 }
1240 } else {
1241 dol_print_error($this->db);
1242 }
1243 }
1244
1245 if (!$error) {
1246 $result = $this->insertExtraFields();
1247 if ($result < 0) {
1248 $error++;
1249 }
1250 }
1251
1252 if (!$error && !$notrigger) {
1253 // Call trigger
1254 $result = $this->call_trigger('ORDER_CREATE', $user);
1255 if ($result < 0) {
1256 $error++;
1257 }
1258 // End call triggers
1259 }
1260
1261 if (!$error) {
1262 $this->db->commit();
1263 return $this->id;
1264 } else {
1265 $this->db->rollback();
1266 return -1 * $error;
1267 }
1268 } else {
1269 $this->error = $this->db->lasterror();
1270 $this->db->rollback();
1271 return -1;
1272 }
1273 }
1274
1275 return 0;
1276 } else {
1277 $this->error = $this->db->lasterror();
1278 $this->db->rollback();
1279 return -1;
1280 }
1281 }
1282
1283
1291 public function createFromClone(User $user, $socid = 0)
1292 {
1293 global $user, $hookmanager;
1294
1295 $error = 0;
1296
1297 $this->db->begin();
1298
1299 // get lines so they will be clone
1300 foreach ($this->lines as $line) {
1301 $line->fetch_optionals();
1302 }
1303
1304 // Load source object
1305 $objFrom = clone $this;
1306
1307 // Change socid if needed
1308 if (!empty($socid) && $socid != $this->socid) {
1309 $objsoc = new Societe($this->db);
1310
1311 if ($objsoc->fetch($socid) > 0) {
1312 $this->socid = $objsoc->id;
1313 $this->cond_reglement_id = (!empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0);
1314 $this->deposit_percent = (!empty($objsoc->deposit_percent) ? $objsoc->deposit_percent : '0');
1315 $this->mode_reglement_id = (!empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0);
1316 $this->fk_project = 0;
1317 $this->fk_delivery_address = 0;
1318 }
1319
1320 // TODO Change product price if multi-prices
1321 }
1322
1323 $this->id = 0;
1324 $this->ref = '';
1325 $this->statut = self::STATUS_DRAFT; // deprecated
1326 $this->status = self::STATUS_DRAFT;
1327
1328 // Clear fields
1329 $this->user_author_id = $user->id;
1330 $this->user_validation_id = 0;
1331 $this->date = dol_now();
1332 $this->date_commande = dol_now();
1333 $this->date_creation = '';
1334 $this->date_validation = '';
1335 if (!getDolGlobalString('MAIN_KEEP_REF_CUSTOMER_ON_CLONING')) {
1336 $this->ref_client = '';
1337 $this->ref_customer = '';
1338 }
1339
1340 // Do not clone ref_ext
1341 $num = count($this->lines);
1342 for ($i = 0; $i < $num; $i++) {
1343 $this->lines[$i]->ref_ext = '';
1344 }
1345
1346 // Create clone
1347 $this->context['createfromclone'] = 'createfromclone';
1348 $result = $this->create($user);
1349 if ($result < 0) {
1350 $error++;
1351 }
1352
1353 if (!$error) {
1354 // copy internal contacts
1355 if ($this->copy_linked_contact($objFrom, 'internal') < 0) {
1356 $error++;
1357 }
1358 }
1359
1360 if (!$error) {
1361 // copy external contacts if same company
1362 if ($this->socid == $objFrom->socid) {
1363 if ($this->copy_linked_contact($objFrom, 'external') < 0) {
1364 $error++;
1365 }
1366 }
1367 }
1368
1369 if (!$error) {
1370 // Hook of thirdparty module
1371 if (is_object($hookmanager)) {
1372 $parameters = array('objFrom' => $objFrom);
1373 $action = '';
1374 $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1375 if ($reshook < 0) {
1376 $this->setErrorsFromObject($hookmanager);
1377 $error++;
1378 }
1379 }
1380 }
1381
1382 unset($this->context['createfromclone']);
1383
1384 // End
1385 if (!$error) {
1386 $this->db->commit();
1387 return $this->id;
1388 } else {
1389 $this->db->rollback();
1390 return -1;
1391 }
1392 }
1393
1394
1402 public function createFromProposal($object, User $user)
1403 {
1404 global $conf, $hookmanager;
1405
1406 require_once DOL_DOCUMENT_ROOT . '/multicurrency/class/multicurrency.class.php';
1407 require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php';
1408
1409 $error = 0;
1410
1411 $this->date_commande = dol_now();
1412 $this->date = dol_now();
1413 $this->source = 0;
1414
1415 $num = count($object->lines);
1416 for ($i = 0; $i < $num; $i++) {
1417 $line = new OrderLine($this->db);
1418
1419 $line->libelle = $object->lines[$i]->libelle;
1420 $line->label = $object->lines[$i]->label;
1421 $line->desc = $object->lines[$i]->desc;
1422 $line->price = $object->lines[$i]->price;
1423 $line->subprice = $object->lines[$i]->subprice;
1424 $line->vat_src_code = $object->lines[$i]->vat_src_code;
1425 $line->tva_tx = $object->lines[$i]->tva_tx;
1426 $line->localtax1_tx = $object->lines[$i]->localtax1_tx;
1427 $line->localtax2_tx = $object->lines[$i]->localtax2_tx;
1428 $line->qty = $object->lines[$i]->qty;
1429 $line->fk_remise_except = $object->lines[$i]->fk_remise_except;
1430 $line->remise_percent = $object->lines[$i]->remise_percent;
1431 $line->fk_product = $object->lines[$i]->fk_product;
1432 $line->info_bits = $object->lines[$i]->info_bits;
1433 $line->product_type = $object->lines[$i]->product_type;
1434 $line->rang = $object->lines[$i]->rang;
1435 $line->special_code = $object->lines[$i]->special_code;
1436 $line->fk_parent_line = $object->lines[$i]->fk_parent_line;
1437 $line->fk_unit = $object->lines[$i]->fk_unit;
1438
1439 $line->date_start = $object->lines[$i]->date_start;
1440 $line->date_end = $object->lines[$i]->date_end;
1441
1442 $line->fk_fournprice = $object->lines[$i]->fk_fournprice;
1443 $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);
1444 $line->pa_ht = $marginInfos[0];
1445 $line->marge_tx = $marginInfos[1];
1446 $line->marque_tx = $marginInfos[2];
1447
1448 $line->origin = $object->element;
1449 $line->origin_id = $object->lines[$i]->id;
1450
1451 // get extrafields from original line
1452 $object->lines[$i]->fetch_optionals();
1453 foreach ($object->lines[$i]->array_options as $options_key => $value) {
1454 $line->array_options[$options_key] = $value;
1455 }
1456
1457 $this->lines[$i] = $line;
1458 }
1459
1460 $this->entity = $object->entity;
1461 $this->socid = $object->socid;
1462 $this->fk_project = $object->fk_project;
1463 $this->cond_reglement_id = $object->cond_reglement_id;
1464 $this->deposit_percent = $object->deposit_percent;
1465 $this->mode_reglement_id = $object->mode_reglement_id;
1466 $this->fk_account = $object->fk_account;
1467 $this->availability_id = $object->availability_id;
1468 $this->demand_reason_id = $object->demand_reason_id;
1469 $this->delivery_date = $object->delivery_date;
1470 $this->shipping_method_id = $object->shipping_method_id;
1471 $this->warehouse_id = $object->warehouse_id;
1472 $this->fk_delivery_address = $object->fk_delivery_address;
1473 $this->contact_id = $object->contact_id;
1474 $this->ref_client = $object->ref_client;
1475 $this->ref_customer = $object->ref_client;
1476
1477 if (!getDolGlobalString('MAIN_DISABLE_PROPAGATE_NOTES_FROM_ORIGIN')) {
1478 $this->note_private = $object->note_private;
1479 $this->note_public = $object->note_public;
1480 }
1481
1482 $this->origin = $object->element;
1483 $this->origin_id = $object->id;
1484
1485 // Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
1486 if (isModEnabled('multicurrency')) {
1487 if (!empty($object->multicurrency_code)) {
1488 $this->multicurrency_code = $object->multicurrency_code;
1489 }
1490 if (getDolGlobalString('MULTICURRENCY_USE_ORIGIN_TX') && !empty($object->multicurrency_tx)) {
1491 $this->multicurrency_tx = $object->multicurrency_tx;
1492 }
1493
1494 if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) {
1495 $tmparray = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code, $this->date_commande);
1496 $this->fk_multicurrency = $tmparray[0];
1497 $this->multicurrency_tx = $tmparray[1];
1498 } else {
1499 $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
1500 }
1501 if (empty($this->fk_multicurrency)) {
1502 $this->multicurrency_code = $conf->currency;
1503 $this->fk_multicurrency = 0;
1504 $this->multicurrency_tx = 1;
1505 }
1506 }
1507
1508 // get extrafields from original line
1509 $object->fetch_optionals();
1510
1511 $e = new ExtraFields($this->db);
1512 $element_extrafields = $e->fetch_name_optionals_label($this->table_element);
1513
1514 foreach ($object->array_options as $options_key => $value) {
1515 if (array_key_exists(str_replace('options_', '', $options_key), $element_extrafields)) {
1516 $this->array_options[$options_key] = $value;
1517 }
1518 }
1519 // Possibility to add external linked objects with hooks
1520 $this->linked_objects[$this->origin] = $this->origin_id;
1521 if (isset($object->other_linked_objects) && is_array($object->other_linked_objects) && !empty($object->other_linked_objects)) {
1522 $this->linked_objects = array_merge($this->linked_objects, $object->other_linked_objects);
1523 }
1524
1525 $ret = $this->create($user);
1526
1527 if ($ret > 0) {
1528 // Actions hooked (by external module)
1529 $hookmanager->initHooks(array('orderdao'));
1530
1531 $parameters = array('objFrom' => $object);
1532 $action = '';
1533 $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1534 if ($reshook < 0) {
1535 $this->setErrorsFromObject($hookmanager);
1536 $error++;
1537 }
1538
1539 if (!$error) {
1540 // Validate immediately the order
1541 if (getDolGlobalString('ORDER_VALID_AFTER_CLOSE_PROPAL')) {
1542 $this->fetch($ret);
1543 $this->valid($user);
1544 }
1545 return $ret;
1546 } else {
1547 return -1;
1548 }
1549 } else {
1550 return -1;
1551 }
1552 }
1553
1554
1595 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 = array(), $fk_unit = null, $origin = '', $origin_id = 0, $pu_ht_devise = 0, $ref_ext = '', $noupdateafterinsertline = 0)
1596 {
1597 global $mysoc, $langs, $user;
1598
1599 $logtext = "::addline commandeid=$this->id, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, fk_product=$fk_product, remise_percent=$remise_percent";
1600 $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";
1601 $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 rang=$rang";
1602 dol_syslog(get_class($this).$logtext, LOG_DEBUG);
1603
1604 if ($this->status == self::STATUS_DRAFT) {
1605 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1606
1607 // Clean parameters
1608
1609 if (empty($remise_percent)) {
1610 $remise_percent = 0;
1611 }
1612 if (empty($qty)) {
1613 $qty = 0;
1614 }
1615 if (empty($info_bits)) {
1616 $info_bits = 0;
1617 }
1618 if (empty($rang)) {
1619 $rang = 0;
1620 }
1621 if (empty($txtva)) {
1622 $txtva = 0;
1623 }
1624 if (empty($txlocaltax1)) {
1625 $txlocaltax1 = 0;
1626 }
1627 if (empty($txlocaltax2)) {
1628 $txlocaltax2 = 0;
1629 }
1630 if (empty($fk_parent_line) || $fk_parent_line < 0) {
1631 $fk_parent_line = 0;
1632 }
1633 if (empty($this->fk_multicurrency)) {
1634 $this->fk_multicurrency = 0;
1635 }
1636 if (empty($ref_ext)) {
1637 $ref_ext = '';
1638 }
1639
1640 $remise_percent = (float) price2num($remise_percent);
1641 $qty = (float) price2num($qty);
1642 $pu_ht = price2num($pu_ht);
1643 $pu_ht_devise = price2num($pu_ht_devise);
1644 $pu_ttc = price2num($pu_ttc);
1645 $pa_ht = price2num($pa_ht); // do not convert to float here, it breaks the functioning of $pa_ht_isemptystring
1646 if (!preg_match('/\‍((.*)\‍)/', (string) $txtva)) {
1647 $txtva = price2num($txtva); // $txtva can have format '5,1' or '5.1' or '5.1(XXX)', we must clean only if '5,1'
1648 }
1649 $txlocaltax1 = price2num($txlocaltax1);
1650 $txlocaltax2 = price2num($txlocaltax2);
1651 if ($price_base_type == 'HT') {
1652 $pu = $pu_ht;
1653 } else {
1654 $pu = $pu_ttc;
1655 }
1656 $label = trim($label);
1657 $desc = trim($desc);
1658
1659 // Check parameters
1660 if ($type < 0) {
1661 return -1;
1662 }
1663
1664 if ($date_start && $date_end && $date_start > $date_end) {
1665 $langs->load("errors");
1666 $this->error = $langs->trans('ErrorStartDateGreaterEnd');
1667 return -1;
1668 }
1669
1670 $this->db->begin();
1671
1672 $product_type = $type;
1673 if (!empty($fk_product) && $fk_product > 0) {
1674 $product = new Product($this->db);
1675 $result = $product->fetch($fk_product);
1676 $product_type = $product->type;
1677
1678 if (getDolGlobalString('STOCK_MUST_BE_ENOUGH_FOR_ORDER') && $product->isStockManaged()) {
1679 // get real stock
1680 $productChildrenNb = 0;
1681 if (getDolGlobalInt('PRODUIT_SOUSPRODUITS')) {
1682 $productChildrenNb = $product->hasFatherOrChild(1);
1683 }
1684 if ($productChildrenNb > 0) {
1685 // compute real stock from each subcomponent
1686 $product_stock = null;
1687 $product->loadStockForVirtualProduct('warehouseopen', $qty);
1688 foreach ($product->stock_warehouse as $componentStockWarehouse) {
1689 if ($product_stock === null) {
1690 $product_stock = $componentStockWarehouse->real;
1691 } else {
1692 $product_stock = min($product_stock, $componentStockWarehouse->real);
1693 }
1694 }
1695 if ($product_stock === null) {
1696 $product_stock = 0;
1697 }
1698 } else {
1699 $product_stock = $product->stock_reel;
1700 }
1701
1702 if ($product_stock < $qty) {
1703 $langs->load("errors");
1704 $this->error = $langs->trans('ErrorStockIsNotEnoughToAddProductOnOrder', $product->ref);
1705 $this->errors[] = $this->error;
1706 dol_syslog(get_class($this)."::addline error=Product ".$product->ref.": ".$this->error, LOG_ERR);
1707 $this->db->rollback();
1709 }
1710 }
1711 }
1712 // Calcul du total TTC et de la TVA pour la ligne a partir de
1713 // qty, pu, remise_percent et txtva
1714 // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1715 // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1716
1717 $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
1718
1719 if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) {
1720 $tmpproduct = new Product($this->db);
1721 $result = $tmpproduct->fetch($fk_product);
1722 $newqty = $this->roundQtyToPackaging($qty, $tmpproduct->packaging);
1723 if ($newqty != $qty) {
1724 $qty = $newqty;
1725 setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'warnings');
1726 }
1727 }
1728
1729 // Clean vat code
1730 $reg = array();
1731 $vat_src_code = '';
1732 if (preg_match('/\‍((.*)\‍)/', $txtva, $reg)) {
1733 $vat_src_code = $reg[1];
1734 $txtva = preg_replace('/\s*\‍(.*\‍)/', '', $txtva); // Remove code into vatrate.
1735 }
1736
1737 $tabprice = calcul_price_total($qty, (float) $pu, $remise_percent, $txtva, (float) $txlocaltax1, (float) $txlocaltax2, 0, $price_base_type, $info_bits, $product_type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, (float) $pu_ht_devise);
1738
1739 /*var_dump($txlocaltax1);
1740 var_dump($txlocaltax2);
1741 var_dump($localtaxes_type);
1742 var_dump($tabprice);
1743 var_dump($tabprice[9]);
1744 var_dump($tabprice[10]);
1745 exit;*/
1746
1747 $total_ht = $tabprice[0];
1748 $total_tva = $tabprice[1];
1749 $total_ttc = $tabprice[2];
1750 $total_localtax1 = $tabprice[9];
1751 $total_localtax2 = $tabprice[10];
1752 $pu_ht = $tabprice[3];
1753
1754 // MultiCurrency
1755 $multicurrency_total_ht = $tabprice[16];
1756 $multicurrency_total_tva = $tabprice[17];
1757 $multicurrency_total_ttc = $tabprice[18];
1758 $pu_ht_devise = $tabprice[19];
1759
1760 // Rang to use
1761 $ranktouse = $rang;
1762
1763 if (empty($ranktouse) || $ranktouse == -1) {
1764 $rangmax = $this->line_max($fk_parent_line);
1765 $ranktouse = $rangmax + 1;
1766 }
1767
1768 // Insert line
1769 $this->line = new OrderLine($this->db);
1770
1771 $this->line->context = $this->context;
1772
1773 $this->line->fk_commande = $this->id;
1774 $this->line->label = $label;
1775 $this->line->desc = $desc;
1776 $this->line->qty = (float) $qty;
1777 $this->line->ref_ext = $ref_ext;
1778
1779 $this->line->vat_src_code = $vat_src_code;
1780 $this->line->tva_tx = $txtva;
1781 $this->line->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0);
1782 $this->line->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0);
1783 $this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
1784 $this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
1785 $this->line->fk_product = $fk_product;
1786 $this->line->product_type = $product_type;
1787 $this->line->fk_remise_except = $fk_remise_except;
1788 $this->line->remise_percent = $remise_percent;
1789 $this->line->subprice = (float) $pu_ht;
1790 $this->line->rang = $ranktouse;
1791 $this->line->info_bits = $info_bits;
1792 $this->line->total_ht = (float) $total_ht;
1793 $this->line->total_tva = (float) $total_tva;
1794 $this->line->total_localtax1 = (float) $total_localtax1;
1795 $this->line->total_localtax2 = (float) $total_localtax2;
1796 $this->line->total_ttc = (float) $total_ttc;
1797 $this->line->special_code = $special_code;
1798 if (empty($qty) && empty($special_code)) {
1799 $this->line->special_code = 3;
1800 }
1801 $this->line->origin = $origin;
1802 $this->line->origin_id = $origin_id;
1803 $this->line->fk_parent_line = $fk_parent_line;
1804 $this->line->fk_unit = $fk_unit;
1805
1806 $this->line->date_start = $date_start;
1807 $this->line->date_end = $date_end;
1808
1809 $this->line->fk_fournprice = $fk_fournprice;
1810 $this->line->pa_ht = $pa_ht; // Can be '' when not defined or 0 if defined to 0 or a price value
1811
1812 // Multicurrency
1813 $this->line->fk_multicurrency = $this->fk_multicurrency;
1814 $this->line->multicurrency_code = $this->multicurrency_code;
1815 $this->line->multicurrency_subprice = (float) $pu_ht_devise;
1816 $this->line->multicurrency_total_ht = (float) $multicurrency_total_ht;
1817 $this->line->multicurrency_total_tva = (float) $multicurrency_total_tva;
1818 $this->line->multicurrency_total_ttc = (float) $multicurrency_total_ttc;
1819
1820 if (is_array($array_options) && count($array_options) > 0) {
1821 $this->line->array_options = $array_options;
1822 }
1823
1824 $result = $this->line->insert($user);
1825 if ($result > 0) {
1826 // Update denormalized fields at the order level
1827 if (empty($noupdateafterinsertline)) {
1828 $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.
1829 }
1830
1831 if ($result > 0) {
1832 if (!isset($this->context['createfromclone'])) {
1833 if (!empty($fk_parent_line)) {
1834 // Always reorder if child line
1835 $this->line_order(true, 'DESC');
1836 } elseif ($ranktouse > 0 && $ranktouse <= count($this->lines)) {
1837 // Update all rank of all other lines starting from the same $ranktouse
1838 foreach ($this->lines as $tmpline) {
1839 if ($tmpline->rang >= $ranktouse) {
1840 if (!empty($tmpline->id)) {
1841 $this->updateRangOfLine($tmpline->id, $tmpline->rang + 1);
1842 }
1843 }
1844 }
1845 }
1846
1847 $this->lines[] = $this->line;
1848 } else {
1849 foreach ($this->lines as $line) {
1850 if ($line->id == $origin_id) {
1851 $this->line->extraparams = $line->extraparams;
1852 $this->line->setExtraParameters();
1853 }
1854 }
1855 }
1856
1857 $this->db->commit();
1858 return $this->line->id;
1859 } else {
1860 $this->db->rollback();
1861 return -1;
1862 }
1863 } else {
1864 $this->setErrorsFromObject($this->line);
1865 dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR);
1866 $this->db->rollback();
1867 return -2;
1868 }
1869 } else {
1870 dol_syslog(get_class($this)."::addline status of order must be Draft to allow use of ->addline()", LOG_ERR);
1871 return -3;
1872 }
1873 }
1874
1875
1876 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1890 public function add_product($idproduct, $qty, $remise_percent = 0.0, $date_start = '', $date_end = '')
1891 {
1892 // phpcs:enable
1893 global $conf, $mysoc;
1894
1895 if (!$qty) {
1896 $qty = 1;
1897 }
1898
1899 if ($idproduct > 0) {
1900 $prod = new Product($this->db);
1901 $prod->fetch($idproduct);
1902
1903 $tva_tx = get_default_tva($mysoc, $this->thirdparty, $prod->id);
1904 $tva_npr = get_default_npr($mysoc, $this->thirdparty, $prod->id);
1905 if (empty($tva_tx)) {
1906 $tva_npr = 0;
1907 }
1908 $vat_src_code = ''; // May be defined into tva_tx
1909
1910 $localtax1_tx = get_localtax($tva_tx, 1, $this->thirdparty, $mysoc, $tva_npr);
1911 $localtax2_tx = get_localtax($tva_tx, 2, $this->thirdparty, $mysoc, $tva_npr);
1912
1913 // multiprix
1914 if (getDolGlobalString('PRODUIT_MULTIPRICES') && $this->thirdparty->price_level) {
1915 $price = $prod->multiprices[$this->thirdparty->price_level];
1916 $price_ttc = $prod->multiprices_ttc[$this->thirdparty->price_level];
1917 } else {
1918 $price = $prod->price;
1919 $price_ttc = $prod->price_ttc;
1920 }
1921
1922 $line = new OrderLine($this->db);
1923
1924 $line->context = $this->context;
1925
1926 $line->fk_product = $idproduct;
1927 $line->desc = $prod->description;
1928 $line->qty = $qty;
1929 $line->subprice = $price;
1930 $line->subprice_ttc = $price_ttc;
1931 $line->remise_percent = $remise_percent;
1932 $line->vat_src_code = $vat_src_code;
1933 $line->tva_tx = $tva_tx;
1934 $line->localtax1_tx = $localtax1_tx;
1935 $line->localtax2_tx = $localtax2_tx;
1936
1937 $line->product_ref = $prod->ref;
1938 $line->product_label = $prod->label;
1939 $line->product_desc = $prod->description;
1940 $line->fk_unit = $prod->fk_unit;
1941
1942 // Save the start and end date of the line in the object
1943 if ($date_start) {
1944 $line->date_start = $date_start;
1945 }
1946 if ($date_end) {
1947 $line->date_end = $date_end;
1948 }
1949
1950 $this->lines[] = $line;
1951
1969 }
1970 }
1971
1972
1982 public function fetch($id, $ref = '', $ref_ext = '', $notused = '')
1983 {
1984 // Check parameters
1985 if (empty($id) && empty($ref) && empty($ref_ext)) {
1986 return -1;
1987 }
1988
1989 $sql = 'SELECT c.rowid, c.entity, c.date_creation, c.ref, c.fk_soc, c.fk_user_author, c.fk_user_valid, c.fk_user_modif, c.fk_statut as status';
1990 $sql .= ', c.amount_ht, c.total_ht, c.total_ttc, c.total_tva, c.localtax1 as total_localtax1, c.localtax2 as total_localtax2, c.fk_cond_reglement, c.deposit_percent, c.fk_mode_reglement, c.fk_availability, c.fk_input_reason';
1991 $sql .= ', c.fk_account';
1992 $sql .= ', c.date_commande, c.date_valid, c.tms';
1993 $sql .= ', c.date_livraison as delivery_date';
1994 $sql .= ', c.fk_shipping_method';
1995 $sql .= ', c.fk_warehouse';
1996 $sql .= ', c.fk_projet as fk_project, c.source, c.facture as billed';
1997 $sql .= ', c.note_private, c.note_public, c.ref_client, c.ref_ext, c.model_pdf, c.last_main_doc, c.fk_delivery_address, c.extraparams';
1998 $sql .= ', c.fk_incoterms, c.location_incoterms';
1999 $sql .= ", c.fk_multicurrency, c.multicurrency_code, c.multicurrency_tx, c.multicurrency_total_ht, c.multicurrency_total_tva, c.multicurrency_total_ttc";
2000 $sql .= ", c.module_source, c.pos_source";
2001 $sql .= ", i.libelle as label_incoterms";
2002 $sql .= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
2003 $sql .= ', cr.code as cond_reglement_code, cr.libelle as cond_reglement_libelle, cr.libelle_facture as cond_reglement_libelle_doc';
2004 $sql .= ', ca.code as availability_code, ca.label as availability_label';
2005 $sql .= ', dr.code as demand_reason_code';
2006 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as c';
2007 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as cr ON c.fk_cond_reglement = cr.rowid';
2008 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON c.fk_mode_reglement = p.id';
2009 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_availability as ca ON c.fk_availability = ca.rowid';
2010 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_input_reason as dr ON c.fk_input_reason = dr.rowid';
2011 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON c.fk_incoterms = i.rowid';
2012
2013 if ($id) {
2014 $sql .= " WHERE c.rowid = ".((int) $id);
2015 } else {
2016 $sql .= " WHERE c.entity IN (".getEntity('commande').")"; // Don't use entity if you use rowid
2017 }
2018
2019 if ($ref) {
2020 $sql .= " AND c.ref = '".$this->db->escape($ref)."'";
2021 }
2022 if ($ref_ext) {
2023 $sql .= " AND c.ref_ext = '".$this->db->escape($ref_ext)."'";
2024 }
2025
2026 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
2027 $result = $this->db->query($sql);
2028 if ($result) {
2029 $obj = $this->db->fetch_object($result);
2030 if ($obj) {
2031 $this->id = $obj->rowid;
2032 $this->entity = $obj->entity;
2033
2034 $this->ref = $obj->ref;
2035 $this->ref_client = $obj->ref_client;
2036 $this->ref_customer = $obj->ref_client;
2037 $this->ref_ext = $obj->ref_ext;
2038
2039 $this->socid = $obj->fk_soc;
2040 $this->thirdparty = null; // Clear if another value was already set by fetch_thirdparty
2041
2042 $this->fk_project = $obj->fk_project;
2043 $this->project = null; // Clear if another value was already set by fetch_projet
2044
2045 $this->statut = $obj->status; // deprecated
2046 $this->status = $obj->status;
2047
2048 $this->user_author_id = $obj->fk_user_author;
2049 $this->user_creation_id = $obj->fk_user_author;
2050 $this->user_validation_id = $obj->fk_user_valid;
2051 $this->user_modification_id = $obj->fk_user_modif;
2052 $this->total_ht = $obj->total_ht;
2053 $this->total_tva = $obj->total_tva;
2054 $this->total_localtax1 = $obj->total_localtax1;
2055 $this->total_localtax2 = $obj->total_localtax2;
2056 $this->total_ttc = $obj->total_ttc;
2057 $this->date = $this->db->jdate($obj->date_commande);
2058 $this->date_commande = $this->db->jdate($obj->date_commande);
2059 $this->date_creation = $this->db->jdate($obj->date_creation);
2060 $this->date_validation = $this->db->jdate($obj->date_valid);
2061 $this->date_modification = $this->db->jdate($obj->tms);
2062 $this->source = $obj->source;
2063 $this->billed = $obj->billed;
2064 $this->note = $obj->note_private; // deprecated
2065 $this->note_private = $obj->note_private;
2066 $this->note_public = $obj->note_public;
2067 $this->model_pdf = $obj->model_pdf;
2068 $this->last_main_doc = $obj->last_main_doc;
2069 $this->mode_reglement_id = $obj->fk_mode_reglement;
2070 $this->mode_reglement_code = $obj->mode_reglement_code;
2071 $this->mode_reglement = $obj->mode_reglement_libelle;
2072 $this->cond_reglement_id = $obj->fk_cond_reglement;
2073 $this->cond_reglement_code = $obj->cond_reglement_code;
2074 $this->cond_reglement = $obj->cond_reglement_libelle;
2075 $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc;
2076 $this->deposit_percent = $obj->deposit_percent;
2077 $this->fk_account = $obj->fk_account;
2078 $this->availability_id = $obj->fk_availability;
2079 $this->availability_code = $obj->availability_code;
2080 $this->availability = $obj->availability_label;
2081 $this->demand_reason_id = $obj->fk_input_reason;
2082 $this->demand_reason_code = $obj->demand_reason_code;
2083 $this->delivery_date = $this->db->jdate($obj->delivery_date);
2084 $this->shipping_method_id = ($obj->fk_shipping_method > 0) ? $obj->fk_shipping_method : null;
2085 $this->warehouse_id = ($obj->fk_warehouse > 0) ? $obj->fk_warehouse : null;
2086 $this->fk_delivery_address = $obj->fk_delivery_address;
2087 $this->module_source = $obj->module_source;
2088 $this->pos_source = $obj->pos_source;
2089
2090 //Incoterms
2091 $this->fk_incoterms = $obj->fk_incoterms;
2092 $this->location_incoterms = $obj->location_incoterms;
2093 $this->label_incoterms = $obj->label_incoterms;
2094
2095 // Multicurrency
2096 $this->fk_multicurrency = $obj->fk_multicurrency;
2097 $this->multicurrency_code = $obj->multicurrency_code;
2098 $this->multicurrency_tx = $obj->multicurrency_tx;
2099 $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
2100 $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
2101 $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
2102
2103 $this->extraparams = !empty($obj->extraparams) ? (array) json_decode($obj->extraparams, true) : array();
2104
2105 $this->lines = array();
2106
2107 // Retrieve all extrafield
2108 // fetch optionals attributes and labels
2109 $this->fetch_optionals();
2110
2111 $this->db->free($result);
2112
2113 // Lines
2114 $result = $this->fetch_lines();
2115 if ($result < 0) {
2116 return -3;
2117 }
2118 return 1;
2119 } else {
2120 $this->error = 'Order with id '.$id.' not found sql='.$sql;
2121 return 0;
2122 }
2123 } else {
2124 $this->error = $this->db->error();
2125 return -1;
2126 }
2127 }
2128
2129
2130 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2137 public function insert_discount($idremise)
2138 {
2139 // phpcs:enable
2140 global $langs;
2141
2142 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2143 include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
2144
2145 $this->db->begin();
2146
2147 $remise = new DiscountAbsolute($this->db);
2148 $result = $remise->fetch($idremise);
2149
2150 if ($result > 0) {
2151 if ($remise->fk_facture) { // Protection against multiple submission
2152 $this->error = $langs->trans("ErrorDiscountAlreadyUsed");
2153 $this->db->rollback();
2154 return -5;
2155 }
2156
2157 $line = new OrderLine($this->db);
2158
2159 $line->fk_commande = $this->id;
2160 $line->fk_remise_except = $remise->id;
2161 $line->desc = $remise->description; // Description ligne
2162 $line->vat_src_code = $remise->vat_src_code;
2163 $line->tva_tx = $remise->tva_tx;
2164 $line->subprice = -(float) $remise->amount_ht;
2165 $line->price = -(float) $remise->amount_ht;
2166 $line->fk_product = 0; // Id produit predefini
2167 $line->qty = 1;
2168 $line->remise_percent = 0;
2169 $line->rang = -1;
2170 $line->info_bits = 2;
2171
2172 $line->total_ht = -(float) $remise->amount_ht;
2173 $line->total_tva = -(float) $remise->amount_tva;
2174 $line->total_ttc = -(float) $remise->amount_ttc;
2175
2176 $result = $line->insert();
2177 if ($result > 0) {
2178 $result = $this->update_price(1);
2179 if ($result > 0) {
2180 $this->db->commit();
2181 return 1;
2182 } else {
2183 $this->db->rollback();
2184 return -1;
2185 }
2186 } else {
2187 $this->setErrorsFromObject($line);
2188 $this->db->rollback();
2189 return -2;
2190 }
2191 } else {
2192 $this->db->rollback();
2193 return -2;
2194 }
2195 }
2196
2197
2198 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2206 public function fetch_lines($only_product = 0, $loadalsotranslation = 0)
2207 {
2208 // phpcs:enable
2209 $this->lines = array();
2210
2211 $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,';
2212 $sql .= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.fk_remise_except, l.remise_percent, l.subprice, l.subprice_ttc, l.fk_product_fournisseur_price as fk_fournprice, l.buy_price_ht as pa_ht, l.rang, l.info_bits, l.special_code,';
2213 $sql .= ' l.total_ht, l.total_ttc, l.total_tva, l.total_localtax1, l.total_localtax2, l.date_start, l.date_end,';
2214 $sql .= ' l.fk_unit, l.extraparams,';
2215 $sql .= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_subprice_ttc, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
2216 $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,';
2217 $sql .= ' p.customcode, p.fk_country as country_id, c.code as country_code,';
2218 $sql .= ' p.weight, p.weight_units, p.volume, p.volume_units, p.packaging';
2219 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line.' as l';
2220 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON (p.rowid = l.fk_product)';
2221 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_country as c ON c.rowid = p.fk_country';
2222 $sql .= ' WHERE l.fk_commande = '.((int) $this->id);
2223 if ($only_product) {
2224 $sql .= ' AND p.fk_product_type = 0';
2225 }
2226 $sql .= ' ORDER BY l.rang, l.rowid';
2227
2228 dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
2229 $result = $this->db->query($sql);
2230 if ($result) {
2231 $num = $this->db->num_rows($result);
2232
2233 $i = 0;
2234 while ($i < $num) {
2235 $objp = $this->db->fetch_object($result);
2236
2237 $line = new OrderLine($this->db);
2238
2239 $line->rowid = $objp->rowid;
2240 $line->id = $objp->rowid;
2241 $line->fk_commande = $objp->fk_commande;
2242 $line->commande_id = $objp->fk_commande;
2243 $line->label = $objp->custom_label;
2244 $line->desc = $objp->description;
2245 $line->description = $objp->description; // Description line
2246 $line->product_type = $objp->product_type;
2247 $line->qty = $objp->qty;
2248 $line->ref_ext = $objp->ref_ext;
2249
2250 $line->vat_src_code = $objp->vat_src_code;
2251 $line->tva_tx = $objp->tva_tx;
2252 $line->localtax1_tx = $objp->localtax1_tx;
2253 $line->localtax2_tx = $objp->localtax2_tx;
2254 $line->localtax1_type = $objp->localtax1_type;
2255 $line->localtax2_type = $objp->localtax2_type;
2256 $line->total_ht = $objp->total_ht;
2257 $line->total_ttc = $objp->total_ttc;
2258 $line->total_tva = $objp->total_tva;
2259 $line->total_localtax1 = $objp->total_localtax1;
2260 $line->total_localtax2 = $objp->total_localtax2;
2261 $line->subprice = (float) $objp->subprice;
2262 $line->subprice_ttc = (float) $objp->subprice_ttc;
2263 $line->fk_remise_except = $objp->fk_remise_except;
2264 $line->remise_percent = $objp->remise_percent;
2265 $line->price = $objp->price;
2266 $line->fk_product = $objp->fk_product;
2267 $line->fk_fournprice = $objp->fk_fournprice;
2268 $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht);
2269 $line->pa_ht = $marginInfos[0];
2270 $line->marge_tx = $marginInfos[1];
2271 $line->marque_tx = $marginInfos[2];
2272 $line->rang = $objp->rang;
2273 $line->info_bits = $objp->info_bits;
2274 $line->special_code = $objp->special_code;
2275 $line->fk_parent_line = $objp->fk_parent_line;
2276
2277 $line->ref = $objp->product_ref;
2278 $line->libelle = $objp->product_label;
2279
2280 $line->product_ref = $objp->product_ref;
2281 $line->product_label = $objp->product_label;
2282 $line->product_tosell = $objp->product_tosell;
2283 $line->product_tobuy = $objp->product_tobuy;
2284 $line->product_desc = $objp->product_desc;
2285 $line->product_tobatch = $objp->product_tobatch;
2286 $line->product_barcode = $objp->product_barcode;
2287 $line->product_custom_code = $objp->customcode;
2288 $line->product_custom_country_id = $objp->country_id;
2289 $line->product_custom_country_code = $objp->country_code;
2290
2291 $line->fk_product_type = $objp->fk_product_type; // Produit ou service
2292 $line->fk_unit = $objp->fk_unit;
2293
2294 $line->extraparams = !empty($objp->extraparams) ? (array) json_decode($objp->extraparams, true) : array();
2295
2296 $line->weight = $objp->weight;
2297 $line->weight_units = $objp->weight_units;
2298 $line->volume = $objp->volume;
2299 $line->volume_units = $objp->volume_units;
2300 $line->packaging = $objp->packaging;
2301
2302 $line->date_start = $this->db->jdate($objp->date_start);
2303 $line->date_end = $this->db->jdate($objp->date_end);
2304
2305 // Multicurrency
2306 $line->fk_multicurrency = $objp->fk_multicurrency;
2307 $line->multicurrency_code = $objp->multicurrency_code;
2308 $line->multicurrency_subprice = $objp->multicurrency_subprice;
2309 $line->multicurrency_subprice_ttc = $objp->multicurrency_subprice_ttc;
2310 $line->multicurrency_total_ht = $objp->multicurrency_total_ht;
2311 $line->multicurrency_total_tva = $objp->multicurrency_total_tva;
2312 $line->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
2313
2314 $line->fetch_optionals();
2315
2316 // multilangs
2317 if (getDolGlobalInt('MAIN_MULTILANGS') && !empty($objp->fk_product) && !empty($loadalsotranslation)) {
2318 $tmpproduct = new Product($this->db);
2319 $tmpproduct->fetch($objp->fk_product);
2320 $tmpproduct->getMultiLangs();
2321
2322 $line->multilangs = $tmpproduct->multilangs;
2323 }
2324
2325 $this->lines[$i] = $line;
2326
2327 $i++;
2328 }
2329
2330 $this->db->free($result);
2331
2332 return 1;
2333 } else {
2334 $this->error = $this->db->error();
2335 return -3;
2336 }
2337 }
2338
2339
2345 public function getNbOfProductsLines()
2346 {
2347 $nb = 0;
2348 foreach ($this->lines as $line) {
2349 if ($line->product_type == 0) {
2350 $nb++;
2351 }
2352 }
2353 return $nb;
2354 }
2355
2361 public function getNbOfServicesLines()
2362 {
2363 $nb = 0;
2364 foreach ($this->lines as $line) {
2365 if ($line->product_type == 1) {
2366 $nb++;
2367 }
2368 }
2369 return $nb;
2370 }
2371
2377 public function getNbOfShipments()
2378 {
2379 $nb = 0;
2380
2381 $sql = 'SELECT COUNT(DISTINCT ed.fk_expedition) as nb';
2382 $sql .= ' FROM '.MAIN_DB_PREFIX.'expeditiondet as ed,';
2383 $sql .= ' '.MAIN_DB_PREFIX.$this->table_element_line.' as cd';
2384 $sql .= ' WHERE';
2385 $sql .= ' ed.fk_elementdet = cd.rowid';
2386 $sql .= ' AND cd.fk_commande = '.((int) $this->id);
2387 //print $sql;
2388
2389 dol_syslog(get_class($this)."::getNbOfShipments", LOG_DEBUG);
2390 $resql = $this->db->query($sql);
2391 if ($resql) {
2392 $obj = $this->db->fetch_object($resql);
2393 if ($obj) {
2394 $nb = (int) $obj->nb;
2395 }
2396
2397 $this->db->free($resql);
2398 return $nb;
2399 } else {
2400 $this->error = $this->db->lasterror();
2401 return -1;
2402 }
2403 }
2404
2413 public function loadExpeditions($filtre_statut = -1, $fk_product = 0)
2414 {
2415 $this->expeditions = array();
2416
2417 $sql = 'SELECT cd.rowid, cd.fk_product,';
2418 $sql .= ' sum(ed.qty) as qty';
2419 $sql .= ' FROM '.MAIN_DB_PREFIX.'expeditiondet as ed,';
2420 if ($filtre_statut >= 0) {
2421 $sql .= ' '.MAIN_DB_PREFIX.'expedition as e,';
2422 }
2423 $sql .= ' '.MAIN_DB_PREFIX.$this->table_element_line.' as cd';
2424 $sql .= ' WHERE';
2425 if ($filtre_statut >= 0) {
2426 $sql .= ' ed.fk_expedition = e.rowid AND';
2427 }
2428 $sql .= ' ed.fk_elementdet = cd.rowid';
2429 $sql .= ' AND cd.fk_commande = '.((int) $this->id);
2430 if ($fk_product > 0) {
2431 $sql .= ' AND cd.fk_product = '.((int) $fk_product);
2432 }
2433 if ($filtre_statut >= 0) {
2434 $sql .= ' AND e.fk_statut >= '.((int) $filtre_statut);
2435 }
2436 $sql .= ' GROUP BY cd.rowid, cd.fk_product';
2437 //print $sql;
2438
2439 dol_syslog(get_class($this)."::loadExpeditions", LOG_DEBUG);
2440 $resql = $this->db->query($sql);
2441 if ($resql) {
2442 $num = $this->db->num_rows($resql);
2443 $i = 0;
2444 while ($i < $num) {
2445 $obj = $this->db->fetch_object($resql);
2446 $this->expeditions[$obj->rowid] = $obj->qty;
2447 $i++;
2448 }
2449 $this->db->free($resql);
2450 return $num;
2451 } else {
2452 $this->error = $this->db->lasterror();
2453 return -1;
2454 }
2455 }
2456
2462 public function countNbOfShipments()
2463 {
2464 $sql = 'SELECT count(*)';
2465 $sql .= ' FROM '.MAIN_DB_PREFIX.'expedition as e';
2466 $sql .= ', '.MAIN_DB_PREFIX.'element_element as el';
2467 $sql .= ' WHERE el.fk_source = '.((int) $this->id);
2468 $sql .= " AND el.sourcetype = 'commande'";
2469 $sql .= " AND el.fk_target = e.rowid";
2470 $sql .= " AND el.targettype = 'shipping'";
2471
2472 $resql = $this->db->query($sql);
2473 if ($resql) {
2474 $row = $this->db->fetch_row($resql);
2475 return $row[0];
2476 } else {
2477 dol_print_error($this->db);
2478 }
2479
2480 return 0;
2481 }
2482
2491 public function deleteLine($user = null, $lineid = 0, $id = 0)
2492 {
2493 if ($this->status == self::STATUS_DRAFT) {
2494 $this->db->begin();
2495
2496 // Delete line
2497 $line = new OrderLine($this->db);
2498
2499 $line->context = $this->context;
2500
2501 // Load data
2502 $line->fetch($lineid);
2503
2504 if ($id <= 0) {
2505 $id = $this->id;
2506 }
2507 if ($id > 0 && (int) $line->fk_commande !== (int) $id) {
2508 $this->db->rollback();
2509 $this->error = 'ErrorLineIDDoesNotMatchWithObjectID';
2510 return -1;
2511 }
2512
2513 // Memorize previous line for triggers
2514 $staticline = clone $line;
2515 $line->oldline = $staticline;
2516
2517 if ($line->delete($user) > 0) {
2518 $result = $this->update_price(1);
2519
2520 if ($result > 0) {
2521 $this->db->commit();
2522 return 1;
2523 } else {
2524 $this->db->rollback();
2525 $this->error = $this->db->lasterror();
2526 return -1;
2527 }
2528 } else {
2529 $this->db->rollback();
2530 $this->setErrorsFromObject($line);
2531 return -1;
2532 }
2533 } else {
2534 $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
2535 return -1;
2536 }
2537 }
2538
2539 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2550 public function set_remise($user, $remise, $notrigger = 0)
2551 {
2552 // phpcs:enable
2553 dol_syslog(get_class($this)."::set_remise is deprecated, use setDiscount instead", LOG_NOTICE);
2554 // @phan-suppress-next-line PhanDeprecatedFunction
2555 return $this->setDiscount($user, $remise, $notrigger);
2556 }
2557
2566 public function setDiscount($user, $remise, $notrigger = 0)
2567 {
2568 $remise = trim((string) $remise) ? trim((string) $remise) : 0;
2569
2570 if ($user->hasRight('commande', 'creer')) {
2571 $error = 0;
2572
2573 $this->db->begin();
2574
2575 $remise = price2num($remise, 2);
2576
2577 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2578 $sql .= ' SET remise_percent = '.((float) $remise);
2579 $sql .= ' WHERE rowid = '.((int) $this->id).' AND fk_statut = '.((int) self::STATUS_DRAFT);
2580
2581 dol_syslog(__METHOD__, LOG_DEBUG);
2582 $resql = $this->db->query($sql);
2583 if (!$resql) {
2584 $this->errors[] = $this->db->error();
2585 $error++;
2586 }
2587
2588 if (!$error) {
2589 $this->oldcopy = clone $this;
2590 $this->remise_percent = $remise;
2591 $this->update_price(1);
2592 }
2593
2594 if (!$notrigger && empty($error)) {
2595 // Call trigger
2596 $result = $this->call_trigger('ORDER_MODIFY', $user);
2597 if ($result < 0) {
2598 $error++;
2599 }
2600 // End call triggers
2601 }
2602
2603 if (!$error) {
2604 $this->db->commit();
2605 return 1;
2606 } else {
2607 foreach ($this->errors as $errmsg) {
2608 dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2609 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2610 }
2611 $this->db->rollback();
2612 return -1 * $error;
2613 }
2614 }
2615
2616 return 0;
2617 }
2618
2619
2620 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2629 public function set_date($user, $date, $notrigger = 0)
2630 {
2631 // phpcs:enable
2632 if ($user->hasRight('commande', 'creer')) {
2633 $error = 0;
2634
2635 $this->db->begin();
2636
2637 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2638 $sql .= " SET date_commande = ".($date ? "'".$this->db->idate($date)."'" : 'null');
2639 $sql .= " WHERE rowid = ".((int) $this->id)." AND fk_statut = ".((int) self::STATUS_DRAFT);
2640
2641 dol_syslog(__METHOD__, LOG_DEBUG);
2642 $resql = $this->db->query($sql);
2643 if (!$resql) {
2644 $this->errors[] = $this->db->error();
2645 $error++;
2646 }
2647
2648 if (!$error) {
2649 $this->oldcopy = clone $this;
2650 $this->date = $date;
2651 }
2652
2653 if (!$notrigger && empty($error)) {
2654 // Call trigger
2655 $result = $this->call_trigger('ORDER_MODIFY', $user);
2656 if ($result < 0) {
2657 $error++;
2658 }
2659 // End call triggers
2660 }
2661
2662 if (!$error) {
2663 $this->db->commit();
2664 return 1;
2665 } else {
2666 foreach ($this->errors as $errmsg) {
2667 dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2668 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2669 }
2670 $this->db->rollback();
2671 return -1 * $error;
2672 }
2673 } else {
2674 return -2;
2675 }
2676 }
2677
2678 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2688 public function set_date_livraison($user, $delivery_date, $notrigger = 0)
2689 {
2690 // phpcs:enable
2691 return $this->setDeliveryDate($user, $delivery_date, $notrigger);
2692 }
2693
2702 public function setDeliveryDate($user, $delivery_date, $notrigger = 0)
2703 {
2704 if ($user->hasRight('commande', 'creer')) {
2705 $error = 0;
2706
2707 $this->db->begin();
2708
2709 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2710 $sql .= " SET date_livraison = ".($delivery_date ? "'".$this->db->idate($delivery_date)."'" : 'null');
2711 $sql .= " WHERE rowid = ".((int) $this->id);
2712
2713 dol_syslog(__METHOD__, LOG_DEBUG);
2714 $resql = $this->db->query($sql);
2715 if (!$resql) {
2716 $this->errors[] = $this->db->error();
2717 $error++;
2718 }
2719
2720 if (!$error) {
2721 $this->oldcopy = clone $this;
2722 $this->delivery_date = $delivery_date;
2723 }
2724
2725 if (!$notrigger && empty($error)) {
2726 // Call trigger
2727 $result = $this->call_trigger('ORDER_MODIFY', $user);
2728 if ($result < 0) {
2729 $error++;
2730 }
2731 // End call triggers
2732 }
2733
2734 if (!$error) {
2735 $this->db->commit();
2736 return 1;
2737 } else {
2738 foreach ($this->errors as $errmsg) {
2739 dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2740 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2741 }
2742 $this->db->rollback();
2743 return -1 * $error;
2744 }
2745 } else {
2746 return -2;
2747 }
2748 }
2749
2750 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2764 public function liste_array($shortlist = 0, $draft = 0, $excluser = null, $socid = 0, $limit = 0, $offset = 0, $sortfield = 'c.date_commande', $sortorder = 'DESC')
2765 {
2766 // phpcs:enable
2767 global $user;
2768
2769 $ga = array();
2770
2771 $sql = "SELECT s.rowid, s.nom as name, s.client,";
2772 $sql .= " c.rowid as cid, c.ref";
2773 if (empty($user->socid) && !$user->hasRight('societe', 'client', 'voir')) {
2774 $sql .= ", sc.fk_soc, sc.fk_user";
2775 }
2776 $sql .= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX.$this->table_element." as c";
2777 if (empty($user->socid) && !$user->hasRight('societe', 'client', 'voir')) {
2778 $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
2779 }
2780 $sql .= " WHERE c.entity IN (".getEntity('commande').")";
2781 $sql .= " AND c.fk_soc = s.rowid";
2782 if (empty($user->socid) && !$user->hasRight('societe', 'client', 'voir')) {
2783 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
2784 }
2785 if ($socid) {
2786 $sql .= " AND s.rowid = ".((int) $socid);
2787 }
2788 if ($draft) {
2789 $sql .= " AND c.fk_statut = ".self::STATUS_DRAFT;
2790 }
2791 if (is_object($excluser)) {
2792 $sql .= " AND c.fk_user_author <> ".((int) $excluser->id);
2793 }
2794 $sql .= $this->db->order($sortfield, $sortorder);
2795 $sql .= $this->db->plimit($limit, $offset);
2796
2797 $result = $this->db->query($sql);
2798 if ($result) {
2799 $numc = $this->db->num_rows($result);
2800 if ($numc) {
2801 $i = 0;
2802 while ($i < $numc) {
2803 $obj = $this->db->fetch_object($result);
2804
2805 if ($shortlist == 1) {
2806 $ga[$obj->cid] = $obj->ref;
2807 } elseif ($shortlist == 2) {
2808 $ga[$obj->cid] = $obj->ref.' ('.$obj->name.')';
2809 } else {
2810 $ga[$i]['id'] = $obj->cid;
2811 $ga[$i]['ref'] = $obj->ref;
2812 $ga[$i]['name'] = $obj->name;
2813 }
2814 $i++;
2815 }
2816 }
2817 return $ga;
2818 } else {
2819 dol_print_error($this->db);
2820 return -1;
2821 }
2822 }
2823
2831 public function availability($availability_id, $notrigger = 0)
2832 {
2833 global $user;
2834
2835 dol_syslog('Commande::availability('.$availability_id.')');
2836 if ($this->status >= self::STATUS_DRAFT) {
2837 $error = 0;
2838
2839 $this->db->begin();
2840
2841 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2842 $sql .= ' SET fk_availability = '.((int) $availability_id);
2843 $sql .= ' WHERE rowid='.((int) $this->id);
2844
2845 dol_syslog(__METHOD__, LOG_DEBUG);
2846 $resql = $this->db->query($sql);
2847 if (!$resql) {
2848 $this->errors[] = $this->db->error();
2849 $error++;
2850 }
2851
2852 if (!$error) {
2853 $this->oldcopy = clone $this;
2854 $this->availability_id = $availability_id;
2855 }
2856
2857 if (!$notrigger && empty($error)) {
2858 // Call trigger
2859 $result = $this->call_trigger('ORDER_MODIFY', $user);
2860 if ($result < 0) {
2861 $error++;
2862 }
2863 // End call triggers
2864 }
2865
2866 if (!$error) {
2867 $this->db->commit();
2868 return 1;
2869 } else {
2870 foreach ($this->errors as $errmsg) {
2871 dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2872 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2873 }
2874 $this->db->rollback();
2875 return -1 * $error;
2876 }
2877 } else {
2878 $error_str = 'Command status do not meet requirement '.$this->status;
2879 dol_syslog(__METHOD__.$error_str, LOG_ERR);
2880 $this->error = $error_str;
2881 $this->errors[] = $this->error;
2882 return -2;
2883 }
2884 }
2885
2886 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2894 public function demand_reason($demand_reason_id, $notrigger = 0)
2895 {
2896 // phpcs:enable
2897 global $user;
2898
2899 dol_syslog('Commande::demand_reason('.$demand_reason_id.')');
2900 if ($this->status >= self::STATUS_DRAFT) {
2901 $error = 0;
2902
2903 $this->db->begin();
2904
2905 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2906 $sql .= ' SET fk_input_reason = '.((int) $demand_reason_id);
2907 $sql .= ' WHERE rowid='.((int) $this->id);
2908
2909 dol_syslog(__METHOD__, LOG_DEBUG);
2910 $resql = $this->db->query($sql);
2911 if (!$resql) {
2912 $this->errors[] = $this->db->error();
2913 $error++;
2914 }
2915
2916 if (!$error) {
2917 $this->oldcopy = clone $this;
2918 $this->demand_reason_id = $demand_reason_id;
2919 }
2920
2921 if (!$notrigger && empty($error)) {
2922 // Call trigger
2923 $result = $this->call_trigger('ORDER_MODIFY', $user);
2924 if ($result < 0) {
2925 $error++;
2926 }
2927 // End call triggers
2928 }
2929
2930 if (!$error) {
2931 $this->db->commit();
2932 return 1;
2933 } else {
2934 foreach ($this->errors as $errmsg) {
2935 dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2936 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2937 }
2938 $this->db->rollback();
2939 return -1 * $error;
2940 }
2941 } else {
2942 $error_str = 'order status do not meet requirement '.$this->status;
2943 dol_syslog(__METHOD__.$error_str, LOG_ERR);
2944 $this->error = $error_str;
2945 $this->errors[] = $this->error;
2946 return -2;
2947 }
2948 }
2949
2950 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2959 public function set_ref_client($user, $ref_client, $notrigger = 0)
2960 {
2961 // phpcs:enable
2962 if ($user->hasRight('commande', 'creer')) {
2963 $error = 0;
2964
2965 $this->db->begin();
2966
2967 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET';
2968 $sql .= ' ref_client = '.(empty($ref_client) ? 'NULL' : "'".$this->db->escape($ref_client)."'");
2969 $sql .= ' WHERE rowid = '.((int) $this->id);
2970
2971 dol_syslog(__METHOD__.' this->id='.$this->id.', ref_client='.$ref_client, LOG_DEBUG);
2972 $resql = $this->db->query($sql);
2973 if (!$resql) {
2974 $this->errors[] = $this->db->error();
2975 $error++;
2976 }
2977
2978 if (!$error) {
2979 $this->oldcopy = clone $this;
2980 $this->ref_client = $ref_client;
2981 $this->ref_customer = $ref_client;
2982 }
2983
2984 if (!$notrigger && empty($error)) {
2985 // Call trigger
2986 $result = $this->call_trigger('ORDER_MODIFY', $user);
2987 if ($result < 0) {
2988 $error++;
2989 }
2990 // End call triggers
2991 }
2992 if (!$error) {
2993 $this->db->commit();
2994 return 1;
2995 } else {
2996 foreach ($this->errors as $errmsg) {
2997 dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2998 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
2999 }
3000 $this->db->rollback();
3001 return -1 * $error;
3002 }
3003 } else {
3004 return -1;
3005 }
3006 }
3007
3015 public function classifyBilled(User $user, $notrigger = 0)
3016 {
3017 $error = 0;
3018
3019 if ($this->billed) {
3020 return 0;
3021 }
3022
3023 $this->db->begin();
3024
3025 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET facture = 1';
3026 $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > '.self::STATUS_DRAFT;
3027
3028 dol_syslog(get_class($this)."::classifyBilled", LOG_DEBUG);
3029 if ($this->db->query($sql)) {
3030 $this->oldcopy = clone $this;
3031 $this->billed = 1;
3032
3033 if (!$notrigger && empty($error)) {
3034 // Call trigger
3035 $result = $this->call_trigger('ORDER_CLASSIFY_BILLED', $user);
3036 if ($result < 0) {
3037 $error++;
3038 }
3039 // End call triggers
3040 }
3041
3042 if (!$error) {
3043 $this->db->commit();
3044 return 1;
3045 } else {
3046 foreach ($this->errors as $errmsg) {
3047 dol_syslog(get_class($this)."::classifyBilled ".$errmsg, LOG_ERR);
3048 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
3049 }
3050 $this->db->rollback();
3051 return -1 * $error;
3052 }
3053 } else {
3054 $this->error = $this->db->error();
3055 $this->db->rollback();
3056 return -1;
3057 }
3058 }
3059
3067 public function classifyUnBilled(User $user, $notrigger = 0)
3068 {
3069 $error = 0;
3070
3071 $this->db->begin();
3072
3073 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET facture = 0';
3074 $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > '.self::STATUS_DRAFT;
3075
3076 dol_syslog(get_class($this)."::classifyUnBilled", LOG_DEBUG);
3077 if ($this->db->query($sql)) {
3078 $this->oldcopy = clone $this;
3079 $this->billed = 1;
3080
3081 if (!$notrigger && empty($error)) {
3082 // Call trigger
3083 $result = $this->call_trigger('ORDER_CLASSIFY_UNBILLED', $user);
3084 if ($result < 0) {
3085 $error++;
3086 }
3087 // End call triggers
3088 }
3089
3090 if (!$error) {
3091 $this->billed = 0;
3092
3093 $this->db->commit();
3094 return 1;
3095 } else {
3096 foreach ($this->errors as $errmsg) {
3097 dol_syslog(get_class($this)."::classifyUnBilled ".$errmsg, LOG_ERR);
3098 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
3099 }
3100 $this->db->rollback();
3101 return -1 * $error;
3102 }
3103 } else {
3104 $this->error = $this->db->error();
3105 $this->db->rollback();
3106 return -1;
3107 }
3108 }
3109
3110
3141 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 = array(), $fk_unit = null, $pu_ht_devise = 0, $notrigger = 0, $ref_ext = '', $rang = 0)
3142 {
3143 global $mysoc, $langs, $user;
3144
3145 if (!$this->isLineOfObject($rowid)) {
3146 $this->error = 'ErrorLineIDDoesNotMatchWithObjectID';
3147 return -1;
3148 }
3149
3150 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");
3151 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
3152
3153 if ($this->status == Commande::STATUS_DRAFT) {
3154 // Clean parameters
3155 if (empty($qty)) {
3156 $qty = 0;
3157 }
3158 if (empty($info_bits)) {
3159 $info_bits = 0;
3160 }
3161 if (empty($txtva)) {
3162 $txtva = 0;
3163 }
3164 if (empty($txlocaltax1)) {
3165 $txlocaltax1 = 0;
3166 }
3167 if (empty($txlocaltax2)) {
3168 $txlocaltax2 = 0;
3169 }
3170 if (empty($remise_percent)) {
3171 $remise_percent = 0;
3172 }
3173 if (empty($qty) && empty($special_code)) {
3174 $special_code = 3; // Set option tag
3175 }
3176 if (!empty($qty) && $special_code == 3) {
3177 $special_code = 0; // Remove option tag
3178 }
3179 if (empty($ref_ext)) {
3180 $ref_ext = '';
3181 }
3182
3183 if ($date_start && $date_end && $date_start > $date_end) {
3184 $langs->load("errors");
3185 $this->error = $langs->trans('ErrorStartDateGreaterEnd');
3186 return -1;
3187 }
3188
3189 $remise_percent = (float) price2num($remise_percent);
3190 $qty = (float) price2num($qty);
3191 $pu = price2num($pu);
3192 $pa_ht = price2num($pa_ht); // do not convert to float here, it breaks the functioning of $pa_ht_isemptystring
3193 $pu_ht_devise = price2num($pu_ht_devise);
3194 if (!preg_match('/\‍((.*)\‍)/', (string) $txtva)) {
3195 $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
3196 }
3197 $txlocaltax1 = (float) price2num($txlocaltax1);
3198 $txlocaltax2 = (float) price2num($txlocaltax2);
3199
3200 $this->db->begin();
3201
3202 // Calcul du total TTC et de la TVA pour la ligne a partir de
3203 // qty, pu, remise_percent et txtva
3204 // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
3205 // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
3206
3207 $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
3208
3209 // Clean vat code
3210 $vat_src_code = '';
3211 $reg = array();
3212 if (preg_match('/\‍((.*)\‍)/', $txtva, $reg)) {
3213 $vat_src_code = $reg[1];
3214 $txtva = preg_replace('/\s*\‍(.*\‍)/', '', $txtva); // Remove code into vatrate.
3215 }
3216
3217 // Round the quantity to the packaging before computing the amounts of the line (and checking the stock),
3218 // else the line is saved with the rounded quantity but with the amounts of the quantity before rounding
3219 if (getDolGlobalString('PRODUCT_USE_CUSTOMER_PACKAGING')) {
3220 $tmpline = new OrderLine($this->db);
3221 if ($tmpline->fetch($rowid) > 0) {
3222 $newqty = $this->roundQtyToPackaging($qty, $tmpline->packaging);
3223 if ($newqty != $qty) {
3224 $qty = $newqty;
3225 setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'warnings');
3226 }
3227 }
3228 }
3229
3230 $tabprice = calcul_price_total($qty, (float) $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, (float) $pu_ht_devise);
3231
3232 $total_ht = $tabprice[0];
3233 $total_tva = $tabprice[1];
3234 $total_ttc = $tabprice[2];
3235 $total_localtax1 = $tabprice[9];
3236 $total_localtax2 = $tabprice[10];
3237 $pu_ht = $tabprice[3];
3238 $pu_tva = $tabprice[4];
3239 $pu_ttc = $tabprice[5];
3240
3241 // MultiCurrency
3242 $multicurrency_total_ht = $tabprice[16];
3243 $multicurrency_total_tva = $tabprice[17];
3244 $multicurrency_total_ttc = $tabprice[18];
3245 $pu_ht_devise = $tabprice[19];
3246
3247 // Fetch current line from the database and then clone the object and set it in $oldline property
3248 $line = new OrderLine($this->db);
3249 $line->fetch($rowid);
3250 $line->fetch_optionals();
3251
3252 if (!empty($line->fk_product)) {
3253 $product = new Product($this->db);
3254 $result = $product->fetch($line->fk_product);
3255 $product_type = $product->type;
3256
3257 if (getDolGlobalString('STOCK_MUST_BE_ENOUGH_FOR_ORDER') && $product->isStockManaged()) {
3258 // get real stock
3259 $productChildrenNb = 0;
3260 if (getDolGlobalInt('PRODUIT_SOUSPRODUITS')) {
3261 $productChildrenNb = $product->hasFatherOrChild(1);
3262 }
3263 if ($productChildrenNb > 0) {
3264 // compute real stock from each subcomponent
3265 $product_stock = null;
3266 $product->loadStockForVirtualProduct('warehouseopen', $qty);
3267 foreach ($product->stock_warehouse as $componentStockWarehouse) {
3268 if ($product_stock === null) {
3269 $product_stock = $componentStockWarehouse->real;
3270 } else {
3271 $product_stock = min($product_stock, $componentStockWarehouse->real);
3272 }
3273 }
3274 if ($product_stock === null) {
3275 $product_stock = 0;
3276 }
3277 } else {
3278 $product_stock = $product->stock_reel;
3279 }
3280
3281 if ($product_stock < $qty) {
3282 $langs->load("errors");
3283 $this->error = $langs->trans('ErrorStockIsNotEnoughToAddProductOnOrder', (string) $product->ref);
3284 $this->errors[] = $this->error;
3285
3286 dol_syslog(get_class($this)."::addline error=Product ".$product->ref.": ".$this->error, LOG_ERR);
3287
3288 $this->db->rollback();
3290 }
3291 }
3292 }
3293
3294 $staticline = clone $line;
3295
3296 $line->oldline = $staticline;
3297 $this->line = $line;
3298 $this->line->context = $this->context;
3299 $this->line->rang = $rang;
3300
3301 // Reorder if fk_parent_line change
3302 if (!empty($fk_parent_line) && !empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line) {
3303 $rangmax = $this->line_max($fk_parent_line);
3304 $this->line->rang = $rangmax + 1;
3305 }
3306
3307
3308 $this->line->id = $rowid;
3309 $this->line->label = $label;
3310 $this->line->desc = $desc;
3311 $this->line->qty = $qty;
3312 $this->line->ref_ext = $ref_ext;
3313
3314 $this->line->vat_src_code = $vat_src_code;
3315 $this->line->tva_tx = $txtva;
3316 $this->line->localtax1_tx = $txlocaltax1;
3317 $this->line->localtax2_tx = $txlocaltax2;
3318 $this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
3319 $this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
3320 $this->line->remise_percent = $remise_percent;
3321 $this->line->subprice = (float) $pu_ht;
3322 $this->line->info_bits = $info_bits;
3323 $this->line->special_code = $special_code;
3324 $this->line->total_ht = (float) $total_ht;
3325 $this->line->total_tva = (float) $total_tva;
3326 $this->line->total_localtax1 = (float) $total_localtax1;
3327 $this->line->total_localtax2 = (float) $total_localtax2;
3328 $this->line->total_ttc = (float) $total_ttc;
3329 $this->line->date_start = $date_start;
3330 $this->line->date_end = $date_end;
3331 $this->line->product_type = $type;
3332 $this->line->fk_parent_line = $fk_parent_line;
3333 $this->line->skip_update_total = $skip_update_total;
3334 $this->line->fk_unit = $fk_unit;
3335
3336 $this->line->fk_fournprice = $fk_fournprice;
3337 $this->line->pa_ht = $pa_ht;
3338
3339 // Multicurrency
3340 $this->line->multicurrency_subprice = (float) $pu_ht_devise;
3341 $this->line->multicurrency_total_ht = (float) $multicurrency_total_ht;
3342 $this->line->multicurrency_total_tva = (float) $multicurrency_total_tva;
3343 $this->line->multicurrency_total_ttc = (float) $multicurrency_total_ttc;
3344
3345 if (is_array($array_options) && count($array_options) > 0) {
3346 // We replace values in this->line->array_options only for entries defined into $array_options
3347 foreach ($array_options as $key => $value) {
3348 $this->line->array_options[$key] = $array_options[$key];
3349 }
3350 }
3351
3352 $result = $this->line->update($user, $notrigger);
3353 if ($result > 0) {
3354 // Reorder if child line
3355 if (!empty($fk_parent_line)) {
3356 $this->line_order(true, 'DESC');
3357 }
3358
3359 // Mise a jour info denormalisees
3360 $this->update_price(1, 'auto');
3361
3362 $this->db->commit();
3363 return $result;
3364 } else {
3365 $this->setErrorsFromObject($this->line);
3366
3367 $this->db->rollback();
3368 return -1;
3369 }
3370 } else {
3371 $this->error = get_class($this)."::updateline Order status makes operation forbidden";
3372 $this->errors = array('OrderStatusMakeOperationForbidden');
3373 return -2;
3374 }
3375 }
3376
3384 public function update(User $user, $notrigger = 0)
3385 {
3386 $error = 0;
3387
3388 // Clean parameters
3389 if (isset($this->ref)) {
3390 $this->ref = trim($this->ref);
3391 }
3392 if (isset($this->ref_client)) {
3393 $this->ref_client = trim($this->ref_client);
3394 }
3395 if (isset($this->ref_customer)) {
3396 $this->ref_customer = trim($this->ref_customer);
3397 }
3398 if (isset($this->note) || isset($this->note_private)) {
3399 $this->note_private = (isset($this->note_private) ? trim($this->note_private) : trim($this->note));
3400 }
3401 if (isset($this->note_public)) {
3402 $this->note_public = trim($this->note_public);
3403 }
3404 if (isset($this->model_pdf)) {
3405 $this->model_pdf = trim($this->model_pdf);
3406 }
3407 if (isset($this->import_key)) {
3408 $this->import_key = trim($this->import_key);
3409 }
3410 $delivery_date = $this->delivery_date;
3411
3412 // Check parameters
3413 // Put here code to add control on parameters values
3414
3415 // Update request
3416 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
3417
3418 $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").",";
3419 $sql .= " ref_client=".(isset($this->ref_client) ? "'".$this->db->escape($this->ref_client)."'" : "null").",";
3420 $sql .= " ref_ext=".(isset($this->ref_ext) ? "'".$this->db->escape($this->ref_ext)."'" : "null").",";
3421 $sql .= " fk_soc=".(isset($this->socid) ? $this->socid : "null").",";
3422 $sql .= " date_commande=".(strval($this->date_commande) != '' ? "'".$this->db->idate($this->date_commande)."'" : 'null').",";
3423 $sql .= " date_valid=".(strval($this->date_validation) != '' ? "'".$this->db->idate($this->date_validation)."'" : 'null').",";
3424 $sql .= " total_tva=".(isset($this->total_tva) ? (float) $this->total_tva : "null").",";
3425 $sql .= " localtax1=".(isset($this->total_localtax1) ? (float) $this->total_localtax1 : "null").",";
3426 $sql .= " localtax2=".(isset($this->total_localtax2) ? (float) $this->total_localtax2 : "null").",";
3427 $sql .= " total_ht=".(isset($this->total_ht) ? (float) $this->total_ht : "null").",";
3428 $sql .= " total_ttc=".(isset($this->total_ttc) ? (float) $this->total_ttc : "null").",";
3429 $sql .= " fk_statut=".(isset($this->status) ? (int) $this->status : "null").",";
3430 $sql .= " fk_user_modif=".(isset($user->id) ? (int) $user->id : "null").",";
3431 $sql .= " fk_user_valid=".((isset($this->user_validation_id) && $this->user_validation_id > 0) ? (int) $this->user_validation_id : "null").",";
3432 $sql .= " fk_projet=".(isset($this->fk_project) ? (int) $this->fk_project : "null").",";
3433 $sql .= " fk_cond_reglement=".(isset($this->cond_reglement_id) ? (int) $this->cond_reglement_id : "null").",";
3434 $sql .= " deposit_percent=".(!empty($this->deposit_percent) ? "'".$this->db->escape($this->deposit_percent)."'" : "null").",";
3435 $sql .= " fk_mode_reglement=".(isset($this->mode_reglement_id) ? $this->mode_reglement_id : "null").",";
3436 $sql .= " date_livraison=".(strval($this->delivery_date) != '' ? "'".$this->db->idate($this->delivery_date)."'" : 'null').",";
3437 $sql .= " fk_shipping_method=".(isset($this->shipping_method_id) ? (int) $this->shipping_method_id : "null").",";
3438 $sql .= " fk_account=".($this->fk_account > 0 ? (int) $this->fk_account : "null").",";
3439 $sql .= " fk_input_reason=".($this->demand_reason_id > 0 ? (int) $this->demand_reason_id : "null").",";
3440 $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
3441 $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
3442 $sql .= " model_pdf=".(isset($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null").",";
3443 $sql .= " fk_warehouse=".($this->warehouse_id > 0 ? (int) $this->warehouse_id : "null").",";
3444 $sql .= " import_key=".(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null").",";
3445 $sql .= " module_source = ".(isset($this->module_source) ? "'".$this->db->escape($this->module_source)."'" : "null").",";
3446 $sql .= " pos_source = ".(isset($this->pos_source) ? "'".$this->db->escape($this->pos_source)."'" : "null");
3447 $sql .= " WHERE rowid=".((int) $this->id);
3448
3449 $this->db->begin();
3450
3451 dol_syslog(get_class($this)."::update", LOG_DEBUG);
3452 $resql = $this->db->query($sql);
3453 if (!$resql) {
3454 $error++;
3455 $this->errors[] = "Error ".$this->db->lasterror();
3456 }
3457
3458 if (!$error) {
3459 $result = $this->insertExtraFields();
3460 if ($result < 0) {
3461 $error++;
3462 }
3463 }
3464
3465 if (!$error && !$notrigger) {
3466 // Call trigger
3467 $result = $this->call_trigger('ORDER_MODIFY', $user);
3468 if ($result < 0) {
3469 $error++;
3470 }
3471 // End call triggers
3472 }
3473
3474 // Commit or rollback
3475 if ($error) {
3476 foreach ($this->errors as $errmsg) {
3477 dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
3478 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
3479 }
3480 $this->db->rollback();
3481 return -1 * $error;
3482 } else {
3483 $this->db->commit();
3484 return 1;
3485 }
3486 }
3487
3495 public function delete($user, $notrigger = 0)
3496 {
3497 global $conf, $langs;
3498 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
3499
3500 $error = 0;
3501
3502 dol_syslog(get_class($this)."::delete ".$this->id, LOG_DEBUG);
3503
3504 $this->db->begin();
3505
3506 if (!$notrigger) {
3507 // Call trigger
3508 $result = $this->call_trigger('ORDER_DELETE', $user);
3509 if ($result < 0) {
3510 $error++;
3511 }
3512 // End call triggers
3513 }
3514
3515 // Test we can delete
3516 if ($this->countNbOfShipments() != 0) {
3517 $this->errors[] = $langs->trans('SomeShipmentExists');
3518 $error++;
3519 }
3520
3521 // Remove linked categories.
3522 if (!$error) {
3523 $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_order";
3524 $sql .= " WHERE fk_order = ".((int) $this->id);
3525
3526 $result = $this->db->query($sql);
3527 if (!$result) {
3528 $error++;
3529 $this->errors[] = $this->db->lasterror();
3530 }
3531 }
3532
3533 // Delete extrafields of lines and lines
3534 if (!$error && !empty($this->table_element_line)) {
3535 $tabletodelete = $this->table_element_line;
3536 $sqlef = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete."_extrafields WHERE fk_object IN (SELECT rowid FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".((int) $this->id).")";
3537 $sql = "DELETE FROM ".MAIN_DB_PREFIX.$tabletodelete." WHERE ".$this->fk_element." = ".((int) $this->id);
3538 if (!$this->db->query($sqlef) || !$this->db->query($sql)) {
3539 $error++;
3540 $this->error = $this->db->lasterror();
3541 $this->errors[] = $this->error;
3542 dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
3543 }
3544 }
3545
3546 if (!$error) {
3547 // Delete linked object
3548 $res = $this->deleteObjectLinked();
3549 if ($res < 0) {
3550 $error++;
3551 }
3552 }
3553
3554 if (!$error) {
3555 // Delete linked contacts
3556 $res = $this->delete_linked_contact();
3557 if ($res < 0) {
3558 $error++;
3559 }
3560 }
3561
3562 // Removed extrafields of object
3563 if (!$error) {
3564 $result = $this->deleteExtraFields();
3565 if ($result < 0) {
3566 $error++;
3567 dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
3568 }
3569 }
3570
3571 // Delete main record
3572 if (!$error) {
3573 $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element." WHERE rowid = ".((int) $this->id);
3574 $res = $this->db->query($sql);
3575 if (!$res) {
3576 $error++;
3577 $this->error = $this->db->lasterror();
3578 $this->errors[] = $this->error;
3579 dol_syslog(get_class($this)."::delete error ".$this->error, LOG_ERR);
3580 }
3581 }
3582
3583 // Delete record into ECM index and physically
3584 if (!$error) {
3585 $res = $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive, old method.
3586 $res = $this->deleteEcmFiles(1); // Deleting files physically is done later with the dol_delete_dir_recursive
3587 if (!$res) {
3588 $error++;
3589 }
3590 }
3591
3592 if (!$error) {
3593 // We remove directory
3594 $ref = dol_sanitizeFileName($this->ref);
3595 if ($conf->commande->multidir_output[$this->entity] && !empty($this->ref)) {
3596 $dir = $conf->commande->multidir_output[$this->entity]."/".$ref;
3597 $file = $dir."/".$ref.".pdf";
3598 if (file_exists($file)) {
3599 dol_delete_preview($this);
3600
3601 if (!dol_delete_file($file, 0, 0, 0, $this)) {
3602 $this->error = 'ErrorFailToDeleteFile';
3603 $this->errors[] = $this->error;
3604 $this->db->rollback();
3605 return 0;
3606 }
3607 }
3608 if (file_exists($dir)) {
3609 $res = @dol_delete_dir_recursive($dir);
3610 if (!$res) {
3611 $this->error = 'ErrorFailToDeleteDir';
3612 $this->errors[] = $this->error;
3613 $this->db->rollback();
3614 return 0;
3615 }
3616 }
3617 }
3618 }
3619
3620 if (!$error) {
3621 dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
3622 $this->db->commit();
3623 return 1;
3624 } else {
3625 $this->db->rollback();
3626 return -1;
3627 }
3628 }
3629
3630
3631 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3639 public function load_board($user, $mode)
3640 {
3641 // phpcs:enable
3642 global $conf, $langs, $hookmanager;
3643
3644 $clause = " WHERE";
3645
3646 $sql = "SELECT c.rowid, c.date_creation as datec, c.date_commande, c.date_livraison as delivery_date, c.fk_statut, c.total_ht";
3647 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as c";
3648 if (empty($user->socid) && !$user->hasRight('societe', 'client', 'voir')) {
3649 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON c.fk_soc = sc.fk_soc";
3650 $sql .= " WHERE sc.fk_user = ".((int) $user->id);
3651 $clause = " AND";
3652 }
3653 $sql .= $clause." c.entity IN (".getEntity('commande').")";
3654 //$sql.= " AND c.fk_statut IN (1,2,3) AND c.facture = 0";
3655 if ($mode == 'toship') {
3656 // An order to ship is an open order (validated or in progress)
3657 $sql .= " AND c.fk_statut IN (" . self::STATUS_VALIDATED . "," . self::STATUS_SHIPMENTONPROCESS . ")";
3658 }
3659 if ($mode == 'tobill') {
3660 // An order to bill is an order not already billed
3661 $sql .= " AND c.fk_statut IN (" . self::STATUS_VALIDATED . "," . self::STATUS_SHIPMENTONPROCESS . ", " . self::STATUS_CLOSED . ") AND c.facture = 0";
3662 }
3663 if ($mode == 'shippedtobill') {
3664 // An order shipped and to bill is a delivered order not already billed
3665 $sql .= " AND c.fk_statut IN (" . self::STATUS_CLOSED . ") AND c.facture = 0";
3666 }
3667 if ($user->socid) {
3668 $sql .= " AND c.fk_soc = ".((int) $user->socid);
3669 }
3670 // Add where from hooks
3671 $parameters = array('socid' => $user->socid);
3672 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $this); // Note that $action and $object may have been modified by hook
3673 $sql .= $hookmanager->resPrint;
3674 $resql = $this->db->query($sql);
3675 if ($resql) {
3676 $delay_warning = 0;
3677 $label = $labelShort = $url = '';
3678 if ($mode == 'toship') {
3679 $delay_warning = $conf->commande->client->warning_delay / 60 / 60 / 24;
3680 $url = DOL_URL_ROOT.'/commande/list.php?search_status=-2&mainmenu=commercial&leftmenu=orders';
3681 $label = $langs->transnoentitiesnoconv("OrdersToProcess");
3682 $labelShort = $langs->transnoentitiesnoconv("Opened");
3683 }
3684 if ($mode == 'tobill') {
3685 $url = DOL_URL_ROOT.'/commande/list.php?search_status=-3&search_billed=0&mainmenu=commercial&leftmenu=orders';
3686 $label = $langs->trans("OrdersToBill"); // We set here bill but may be billed or ordered
3687 $labelShort = $langs->trans("ToBill");
3688 }
3689 if ($mode == 'shippedtobill') {
3690 $url = DOL_URL_ROOT.'/commande/list.php?search_status=3&search_billed=0&mainmenu=commercial&leftmenu=orders';
3691 $label = $langs->trans("OrdersToBill"); // We set here bill but may be billed or ordered
3692 $labelShort = $langs->trans("StatusOrderDelivered").' '.$langs->trans("and").' '.$langs->trans("ToBill");
3693 }
3694
3695 $response = new WorkboardResponse();
3696
3697 $response->warning_delay = $delay_warning;
3698 $response->label = $label;
3699 $response->labelShort = $labelShort;
3700 $response->url = $url;
3701 $response->url_late = DOL_URL_ROOT.'/commande/list.php?search_option=late&mainmenu=commercial&leftmenu=orders';
3702 $response->img = img_object('', "order");
3703
3704 $generic_commande = new Commande($this->db);
3705
3706 while ($obj = $this->db->fetch_object($resql)) {
3707 $response->nbtodo++;
3708 $response->total += $obj->total_ht;
3709
3710 $generic_commande->status = $obj->fk_statut;
3711 $generic_commande->date = $this->db->jdate($obj->date_commande);
3712 $generic_commande->delivery_date = $this->db->jdate($obj->delivery_date);
3713
3714 if ($mode == 'toship' && $generic_commande->hasDelay()) {
3715 $response->nbtodolate++;
3716 }
3717 }
3718
3719 return $response;
3720 } else {
3721 $this->error = $this->db->error();
3722 return -1;
3723 }
3724 }
3725
3731 public function getLabelSource()
3732 {
3733 global $langs;
3734
3735 $label = $langs->trans('OrderSource'.$this->source);
3736
3737 if ($label == 'OrderSource') {
3738 return '';
3739 }
3740 return $label;
3741 }
3742
3749 public function getLibStatut($mode)
3750 {
3751 return $this->LibStatut($this->status, $this->billed, $mode);
3752 }
3753
3754 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3764 public function LibStatut($status, $billed, $mode, $donotshowbilled = 0)
3765 {
3766 // phpcs:enable
3767 global $langs, $hookmanager;
3768
3769 $billedtext = '';
3770 if (empty($donotshowbilled)) {
3771 $billedtext .= ($billed ? ' - '.$langs->transnoentitiesnoconv("Billed") : '');
3772 }
3773 $billedtextlong = ($billed ? ' - '.$langs->transnoentitiesnoconv("Billed") : '');
3774
3775 $labelTooltip = '';
3776
3777 $paramsBadge = array('badgeParams' => array('attr' => array(
3778 'data-status-element' => $this->element,
3779 'data-billed' => (int) $billed,
3780 'data-status' => (int) $status
3781 )));
3782
3783 if ($status == self::STATUS_CANCELED) {
3784 $labelStatus = $langs->transnoentitiesnoconv('StatusOrderCanceled');
3785 $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderCanceledShort');
3786 $statusType = 'status9';
3787 } elseif ($status == self::STATUS_DRAFT) {
3788 $labelStatus = $langs->transnoentitiesnoconv('StatusOrderDraft');
3789 $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderDraftShort');
3790 $statusType = 'status0';
3791 } elseif ($status == self::STATUS_VALIDATED) {
3792 $labelStatus = $langs->transnoentitiesnoconv('StatusOrderValidated').$billedtextlong;
3793 $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderValidatedShort').$billedtext;
3794 $statusType = 'status1';
3795 } elseif ($status == self::STATUS_SHIPMENTONPROCESS) {
3796 $labelStatus = $langs->transnoentitiesnoconv('StatusOrderSent').$billedtextlong;
3797 $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderSentShort').$billedtext;
3798 $labelTooltip = $langs->transnoentitiesnoconv("StatusOrderSent");
3799 if (!empty($this->delivery_date)) {
3800 $labelTooltip .= ' - '.$langs->transnoentitiesnoconv("DateDeliveryPlanned").dol_print_date($this->delivery_date, 'day').$billedtext;
3801 }
3802 $statusType = 'status4';
3803 } elseif ($status == self::STATUS_CLOSED) {
3804 $labelStatus = $langs->transnoentitiesnoconv('StatusOrderDelivered').$billedtextlong;
3805 $labelStatusShort = $langs->transnoentitiesnoconv('StatusOrderDeliveredShort').$billedtext;
3806 $statusType = 'status6';
3807 } else {
3808 $labelStatus = $langs->transnoentitiesnoconv('Unknown');
3809 $labelStatusShort = '';
3810 $statusType = '';
3811 $mode = 0;
3812 }
3813
3814 $paramsBadge['tooltip'] = $labelTooltip;
3815
3816 $parameters = array(
3817 'status' => $status,
3818 'mode' => $mode,
3819 'billed' => $billed,
3820 'donotshowbilled' => $donotshowbilled,
3821 'paramsBadge' => & $paramsBadge
3822 );
3823
3824 $reshook = $hookmanager->executeHooks('LibStatut', $parameters, $this); // Note that $action and $object may have been modified by hook
3825
3826 if ($reshook > 0) {
3827 return $hookmanager->resPrint;
3828 }
3829
3830 return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode, '', $paramsBadge);
3831 }
3832
3840 public function getTooltipContentArray($params)
3841 {
3842 global $conf, $langs, $user;
3843
3844 $langs->load('orders');
3845 $datas = [];
3846 $nofetch = !empty($params['nofetch']);
3847
3848 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
3849 return ['optimize' => $langs->trans("Order")];
3850 }
3851
3852 if ($user->hasRight('commande', 'lire')) {
3853 $datas['picto'] = img_picto('', $this->picto, '', 0, 0, 0, '', 'paddingrightonly').'<u>'.$langs->trans("Order").'</u>';
3854 if (isset($this->status)) {
3855 $datas['status'] = ' '.$this->getLibStatut(5);
3856 }
3857 $datas['Ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
3858 if (!$nofetch) {
3859 $langs->load('companies');
3860 if (empty($this->thirdparty)) {
3861 $this->fetch_thirdparty();
3862 }
3863 $datas['customer'] = '<br><b>'.$langs->trans('Customer').':</b> '.$this->thirdparty->getNomUrl(1, '', 0, 1);
3864 }
3865 $datas['RefCustomer'] = '<br><b>'.$langs->trans('RefCustomer').':</b> '.(empty($this->ref_customer) ? (empty($this->ref_client) ? '' : $this->ref_client) : $this->ref_customer);
3866 if (!$nofetch) {
3867 $langs->load('project');
3868 if (is_null($this->project) || (is_object($this->project) && $this->project->isEmpty())) {
3869 $res = $this->fetchProject();
3870 if ($res > 0 && $this->project instanceof Project) {
3871 $datas['project'] = '<br><b>'.$langs->trans('Project').':</b> '.$this->project->getNomUrl(1, '', 0, '1');
3872 }
3873 }
3874 }
3875 if (!empty($this->total_ht)) {
3876 $datas['AmountHT'] = '<br><b>'.$langs->trans('AmountHT').':</b> '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
3877 }
3878 if (!empty($this->total_tva)) {
3879 $datas['VAT'] = '<br><b>'.$langs->trans('VAT').':</b> '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
3880 }
3881 if (!empty($this->total_ttc)) {
3882 $datas['AmountTTC'] = '<br><b>'.$langs->trans('AmountTTC').':</b> '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
3883 }
3884 if (!empty($this->date)) {
3885 $datas['Date'] = '<br><b>'.$langs->trans('Date').':</b> '.dol_print_date($this->date, 'day');
3886 }
3887 if (!empty($this->delivery_date)) {
3888 $datas['DeliveryDate'] = '<br><b>'.$langs->trans('DeliveryDate').':</b> '.dol_print_date($this->delivery_date, 'dayhour');
3889 }
3890 }
3891
3892 return $datas;
3893 }
3894
3908 public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0, $target = '')
3909 {
3910 global $conf, $langs, $user, $hookmanager;
3911
3912 if (!empty($conf->dol_no_mouse_hover)) {
3913 $notooltip = 1; // Force disable tooltips
3914 }
3915
3916 $result = '';
3917
3918 if (isModEnabled("shipping") && ($option == '1' || $option == '2')) {
3919 $baseurl = DOL_URL_ROOT . '/expedition/shipment.php';
3920 } else {
3921 $baseurl = DOL_URL_ROOT . '/commande/card.php';
3922 }
3923 $query = ['id' => $this->id];
3924 if (!$user->hasRight('commande', 'lire')) {
3925 $option = 'nolink';
3926 }
3927
3928 if ($option !== 'nolink') {
3929 // Add param to save lastsearch_values or not
3930 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
3931 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
3932 $add_save_lastsearch_values = 1;
3933 }
3934 if ($add_save_lastsearch_values) {
3935 $query = array_merge($query, ['save_lastsearch_values' => 1]);
3936 }
3937 }
3938 $url = dolBuildUrl($baseurl, $query);
3939
3940 if ($short) {
3941 return $url;
3942 }
3943 $params = [
3944 'id' => $this->id,
3945 'objecttype' => $this->element,
3946 'option' => $option,
3947 'nofetch' => 1,
3948 ];
3949 $classfortooltip = 'classfortooltip';
3950 $dataparams = '';
3951 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
3952 $classfortooltip = 'classforajaxtooltip';
3953 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
3954 $label = '';
3955 } else {
3956 $label = implode($this->getTooltipContentArray($params));
3957 }
3958
3959 $linkclose = '';
3960 if (empty($notooltip) && $user->hasRight('commande', 'lire')) {
3961 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
3962 $label = $langs->trans("Order");
3963 $linkclose .= ' alt="'.dolPrintHTMLForAttribute($label).'"';
3964 }
3965 $linkclose .= ($label ? ' title="'.dolPrintHTMLForAttribute($label).'"' : ' title="tocomplete"');
3966 $linkclose .= $dataparams.' class="'.$classfortooltip.'"';
3967
3968 $target_value = array('_self', '_blank', '_parent', '_top');
3969 if (in_array($target, $target_value)) {
3970 $linkclose .= ' target="'.dol_escape_htmltag($target).'"';
3971 }
3972 }
3973
3974 $linkstart = '<a href="'.$url.'"';
3975 $linkstart .= $linkclose.'>';
3976 $linkend = '</a>';
3977
3978 if ($option === 'nolink') {
3979 $linkstart = '';
3980 $linkend = '';
3981 }
3982
3983 $result .= $linkstart;
3984 if ($withpicto) {
3985 $result .= img_object(($notooltip ? '' : $label), $this->picto, (($withpicto != 2) ? 'class="paddingright"' : ''), 0, 0, $notooltip ? 0 : 1);
3986 }
3987 if ($withpicto != 2) {
3988 $result .= $this->ref;
3989 }
3990 $result .= $linkend;
3991
3992 if ($addlinktonotes) {
3993 $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
3994 if ($txttoshow) {
3995 $notetoshow = $langs->trans("ViewPrivateNote").':<br>'.dol_string_nohtmltag($txttoshow, 1);
3996 $result .= ' <span class="note inline-block">';
3997 $result .= '<a href="'.DOL_URL_ROOT.'/commande/note.php?id='.$this->id.'" class="classfortooltip" title="'.dol_escape_htmltag($notetoshow).'">';
3998 $result .= img_picto('', 'note');
3999 $result .= '</a>';
4000 //$result.=img_picto($langs->trans("ViewNote"),'object_generic');
4001 //$result.='</a>';
4002 $result .= '</span>';
4003 }
4004 }
4005
4006 global $action;
4007 $hookmanager->initHooks(array($this->element . 'dao'));
4008 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
4009 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
4010 if ($reshook > 0) {
4011 $result = $hookmanager->resPrint;
4012 } else {
4013 $result .= $hookmanager->resPrint;
4014 }
4015 return $result;
4016 }
4017
4018
4025 public function info($id)
4026 {
4027 $sql = 'SELECT c.rowid, date_creation as datec, tms as datem,';
4028 $sql .= ' date_valid as datev,';
4029 $sql .= ' date_cloture as datecloture,';
4030 $sql .= ' fk_user_author, fk_user_valid, fk_user_cloture';
4031 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as c';
4032 $sql .= ' WHERE c.rowid = '.((int) $id);
4033 $result = $this->db->query($sql);
4034 if ($result) {
4035 if ($this->db->num_rows($result)) {
4036 $obj = $this->db->fetch_object($result);
4037 $this->id = $obj->rowid;
4038 if ($obj->fk_user_author) {
4039 $this->user_creation_id = $obj->fk_user_author;
4040 }
4041 if ($obj->fk_user_valid) {
4042 $this->user_validation_id = $obj->fk_user_valid;
4043 }
4044 if ($obj->fk_user_cloture) {
4045 $this->user_closing_id = $obj->fk_user_cloture;
4046 }
4047
4048 $this->date_creation = $this->db->jdate($obj->datec);
4049 $this->date_modification = $this->db->jdate($obj->datem);
4050 $this->date_validation = $this->db->jdate($obj->datev);
4051 $this->date_cloture = $this->db->jdate($obj->datecloture);
4052 }
4053
4054 $this->db->free($result);
4055 } else {
4056 dol_print_error($this->db);
4057 }
4058 }
4059
4060
4069 public function initAsSpecimen($param = array())
4070 {
4071 global $conf, $langs;
4072
4073 dol_syslog(get_class($this)."::initAsSpecimen");
4074
4075 // Load array of products prodids
4076 $num_prods = 0;
4077 $prodids = array();
4078 $sql = "SELECT rowid";
4079 $sql .= " FROM ".MAIN_DB_PREFIX."product";
4080 $sql .= " WHERE entity IN (".getEntity('product').")";
4081 if (array_key_exists('tosell', $param)) {
4082 $sql .= " AND tosell = ".((int) $param['tosell']);
4083 }
4084 $sql .= $this->db->plimit(100);
4085
4086 $resql = $this->db->query($sql);
4087 if ($resql) {
4088 $num_prods = $this->db->num_rows($resql);
4089 $i = 0;
4090 while ($i < $num_prods) {
4091 $i++;
4092 $row = $this->db->fetch_row($resql);
4093 $prodids[$i] = $row[0];
4094 }
4095 }
4096
4097 // Initialise parameters
4098 $this->id = 0;
4099 $this->ref = 'SPECIMEN';
4100 $this->specimen = 1;
4101 $this->entity = $conf->entity;
4102 $this->socid = 1;
4103 $this->date = time();
4104 $this->date_lim_reglement = $this->date + 3600 * 24 * 30;
4105 $this->cond_reglement_code = 'RECEP';
4106 $this->mode_reglement_code = 'CHQ';
4107 $this->availability_code = 'DSP';
4108 $this->demand_reason_code = 'SRC_00';
4109
4110 $this->note_public = 'This is a comment (public)';
4111 $this->note_private = 'This is a comment (private)';
4112
4113 $this->multicurrency_tx = 1;
4114 $this->multicurrency_code = $conf->currency;
4115
4116 $this->status = $this::STATUS_DRAFT;
4117
4118 // Lines
4119 $nbp = min(1000, GETPOSTINT('nblines') ? GETPOSTINT('nblines') : 5); // We can force the nb of lines to test from command line (but not more than 1000)
4120 $xnbp = 0;
4121
4122 while ($xnbp < $nbp) {
4123 $line = new OrderLine($this->db);
4124
4125 $line->desc = $langs->trans("Description")." ".$xnbp;
4126 $line->qty = 1;
4127 $line->subprice = 100;
4128 $line->price = 100;
4129 $line->tva_tx = 20;
4130 if ($xnbp == 2) {
4131 $line->total_ht = 50;
4132 $line->total_ttc = 60;
4133 $line->total_tva = 10;
4134 $line->remise_percent = 50;
4135 } else {
4136 $line->total_ht = 100;
4137 $line->total_ttc = 120;
4138 $line->total_tva = 20;
4139 $line->remise_percent = 0;
4140 }
4141 if ($num_prods > 0) {
4142 $prodid = mt_rand(1, $num_prods);
4143 $line->fk_product = $prodids[$prodid];
4144 $line->product_ref = 'SPECIMEN';
4145 }
4146
4147 $this->lines[$xnbp] = $line;
4148
4149 $this->total_ht += $line->total_ht;
4150 $this->total_tva += $line->total_tva;
4151 $this->total_ttc += $line->total_ttc;
4152
4153 $xnbp++;
4154 }
4155
4156 return 1;
4157 }
4158
4159
4165 public function loadStateBoard()
4166 {
4167 global $user, $hookmanager;
4168
4169 $this->nb = array();
4170 $clause = "WHERE";
4171
4172 $sql = "SELECT count(c.rowid) as nb";
4173 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as c";
4174 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON c.fk_soc = s.rowid";
4175 if (empty($user->socid) && !$user->hasRight('societe', 'client', 'voir')) {
4176 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
4177 $sql .= " WHERE sc.fk_user = ".((int) $user->id);
4178 $clause = "AND";
4179 }
4180 $sql .= " ".$clause." c.entity IN (".getEntity('commande').")";
4181 // Add where from hooks
4182 $parameters = array();
4183 $hookmanager->executeHooks('printFieldListWhere', $parameters, $this); // Note that $action and $object may have been modified by hook
4184 $sql .= $hookmanager->resPrint;
4185 $resql = $this->db->query($sql);
4186 if ($resql) {
4187 while ($obj = $this->db->fetch_object($resql)) {
4188 $this->nb["orders"] = $obj->nb;
4189 }
4190 $this->db->free($resql);
4191 return 1;
4192 } else {
4193 dol_print_error($this->db);
4194 $this->error = $this->db->error();
4195 return -1;
4196 }
4197 }
4198
4204 public function getLinesArray()
4205 {
4206 return $this->fetch_lines();
4207 }
4208
4220 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
4221 {
4222 global $langs;
4223
4224 $langs->load("orders");
4225 $outputlangs->load("products");
4226
4227 if (!dol_strlen($modele)) {
4228 $modele = 'einstein';
4229
4230 if (!empty($this->model_pdf)) {
4231 $modele = $this->model_pdf;
4232 } elseif (getDolGlobalString('COMMANDE_ADDON_PDF')) {
4233 $modele = getDolGlobalString('COMMANDE_ADDON_PDF');
4234 }
4235 }
4236
4237 $modelpath = "core/modules/commande/doc/";
4238
4239 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
4240 }
4241
4242
4251 public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
4252 {
4253 $tables = array(
4254 'commande'
4255 );
4256
4257 return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
4258 }
4259
4268 public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
4269 {
4270 $tables = array(
4271 'commandedet',
4272 );
4273
4274 return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
4275 }
4276
4282 public function hasDelay()
4283 {
4284 global $conf;
4285
4286 if (!($this->status > Commande::STATUS_DRAFT && $this->status < Commande::STATUS_CLOSED)) {
4287 return false; // Never late if not inside this status range
4288 }
4289
4290 $now = dol_now();
4291
4292 return max($this->date, $this->delivery_date) < ($now - $conf->commande->client->warning_delay);
4293 }
4294
4300 public function showDelay()
4301 {
4302 global $conf, $langs;
4303
4304 if (empty($this->delivery_date)) {
4305 $text = $langs->trans("OrderDate").' '.dol_print_date($this->date, 'day');
4306 } else {
4307 $text = $text = $langs->trans("DeliveryDate").' '.dol_print_date($this->delivery_date, 'day');
4308 }
4309 $text .= ' '.($conf->commande->client->warning_delay > 0 ? '+' : '-').' '.round(abs($conf->commande->client->warning_delay) / 3600 / 24, 1).' '.$langs->trans("days").' < '.$langs->trans("Today");
4310
4311 return $text;
4312 }
4313
4323 public function setSignedStatus(User $user, int $status = 0, int $notrigger = 0, $triggercode = ''): int
4324 {
4325 return $this->setSignedStatusCommon($user, $status, $notrigger, $triggercode);
4326 }
4327}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
$object ref
Definition info.php:90
Class to manage customers orders.
getNbOfServicesLines()
Return number of line with type service.
getNbOfShipments()
Count number of shipments for this order.
createFromProposal($object, User $user)
Load an object from a proposal and create a new order into database.
setDraft($user, $idwarehouse=-1)
Set draft status.
setDeliveryDate($user, $delivery_date, $notrigger=0)
Set the planned delivery date.
static replaceProduct(DoliDB $db, $origin_id, $dest_id)
Function used to replace a product id with another one.
getLinesArray()
Create an array of order lines.
showDelay()
Show the customer delayed info.
set_date($user, $date, $notrigger=0)
Set the order date.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
loadStateBoard()
Load the indicators this->nb for the state board.
fetch_lines($only_product=0, $loadalsotranslation=0)
Load array lines.
createFromClone(User $user, $socid=0)
Load an object from its id and create a new one in database.
const STATUS_SHIPMENTONPROCESS
Shipment on process.
LibStatut($status, $billed, $mode, $donotshowbilled=0)
Return label of status.
getLibStatut($mode)
Return status label of Order.
hasDelay()
Is the sales order delayed?
const STATUS_CLOSED
Closed (Sent, billed or not)
valid($user, $idwarehouse=0, $notrigger=0)
Validate order.
getLabelSource()
Return source label of order.
set_remise($user, $remise, $notrigger=0)
Applique une remise relative.
initAsSpecimen($param=array())
Initialise an instance with random values.
const STATUS_CANCELED
Canceled status.
getNomUrl($withpicto=0, $option='', $max=0, $short=0, $notooltip=0, $save_lastsearch_value=-1, $addlinktonotes=0, $target='')
Return clickable link of object (with eventually picto)
loadExpeditions($filtre_statut=-1, $fk_product=0)
Load array this->expeditions of lines of shipments with nb of products sent for each order line Note:...
__construct($db)
Constructor.
availability($availability_id, $notrigger=0)
Update delivery delay.
set_reopen($user)
Tag the order as validated (opened) Function used when order is reopend after being closed.
set_ref_client($user, $ref_client, $notrigger=0)
Set customer ref.
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=array(), $fk_unit=null, $origin='', $origin_id=0, $pu_ht_devise=0, $ref_ext='', $noupdateafterinsertline=0)
Add an order line into database (linked to product/service or not)
getTooltipContentArray($params)
getTooltipContentArray
create($user, $notrigger=0)
Create sale order Note that this->ref can be set or empty.
demand_reason($demand_reason_id, $notrigger=0)
Update order demand_reason.
const STATUS_DRAFT
Draft status.
const STOCK_NOT_ENOUGH_FOR_ORDER
ERR Not enough stock.
insert_discount($idremise)
Add a discount line into a sale order (as a sale order line) using an existing absolute discount (Con...
getNbOfProductsLines()
Return number of line with type product.
update(User $user, $notrigger=0)
Update database.
classifyUnBilled(User $user, $notrigger=0)
Classify the order as not invoiced.
setDiscount($user, $remise, $notrigger=0)
Set a percentage discount.
setCategories($categories)
Sets object to given categories.
const STATUS_ACCEPTED
For backward compatibility.
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=array(), $fk_unit=null, $pu_ht_devise=0, $notrigger=0, $ref_ext='', $rang=0)
Update a line in database.
classifyBilled(User $user, $notrigger=0)
Classify the order as invoiced.
info($id)
Charge les information d'ordre info dans l'objet commande.
load_board($user, $mode)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
const STATUS_VALIDATED
Validated status.
deleteLine($user=null, $lineid=0, $id=0)
Delete an order line.
countNbOfShipments()
Returns an array with expeditions lines number.
liste_array($shortlist=0, $draft=0, $excluser=null, $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($id, $ref='', $ref_ext='', $notused='')
Get object from database.
cloture($user, $notrigger=0, $checkpermission=1)
Close order.
set_date_livraison($user, $delivery_date, $notrigger=0)
Set delivery date.
add_product($idproduct, $qty, $remise_percent=0.0, $date_start='', $date_end='')
Add line into array $this->client must be loaded.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
setSignedStatus(User $user, int $status=0, int $notrigger=0, $triggercode='')
Set signed status.
cancel($user, $idwarehouse=-1)
Cancel an order If stock is decremented on order validation, we must reincrement it.
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true)
Save a new position (field rang) for details lines.
deleteEcmFiles($mode=0)
Delete related files of object in database.
update_price($exclspec=0, $roundingadjust='auto', $nodatabaseupdate=0, $seller=null)
Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines).
add_object_linked($origin=null, $origin_id=null, $f_user=null, $notrigger=0)
Add an object link into llx_element_element.
roundQtyToPackaging($qty, $packaging)
Round a quantity up to the next multiple of a packaging quantity (options PRODUCT_USE_CUSTOMER_PACKAG...
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
fetchProject()
Load the project with id $this->fk_project into this->project.
fetch_thirdparty($force_thirdparty_id=0)
Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty.
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid=0, $f_user=null, $notrigger=0)
Delete all links between an object $this.
setErrorsFromObject($object)
setErrorsFromObject
isLineOfObject($lineid)
Check that a line belongs to this object, using $this->table_element_line and $this->fk_element.
static isExistingObject($element, $id, $ref='', $ref_ext='')
Check if an object id or ref exists If you don't need or want to instantiate the object and just need...
updateRangOfLine($rowid, $rang)
Update position of line (rang)
checkActiveProductInLines($status='onsale')
Check if all products have the right status (on sale, on buy) called during validation of propal,...
deleteExtraFields()
Delete all extra fields values for the current object.
copy_linked_contact($objFrom, $source='internal')
Copy contact from one element to current.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
static commonReplaceProduct(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a product id with another one.
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
delete_linked_contact($source='', $code='')
Delete all links between an object $this and all its contacts in llx_element_contact.
add_contact($fk_socpeople, $type_contact, $source='external', $notrigger=0)
Add a link between element $this->element and a contact.
Superclass for orders classes.
Class to manage absolute discounts.
Class to manage Dolibarr database access.
Class to manage standard extra fields.
Class to manage stock movements.
static getIdAndTxFromCode($dbs, $code, $date_document=0)
Get id and rate of currency from code.
static getIdFromCode($dbs, $code)
Get id of currency from code.
Class to manage order lines.
Class to manage products or services.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:171
setSignedStatusCommon(User $user, int $status, int $notrigger=0, string $triggercode='')
Set signed status & call trigger with context message.
global $mysoc
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0, $level=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
dol_dir_list($utf8_path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:64
dol_delete_preview($object)
Delete all preview files linked to object instance.
dol_now($mode='gmt')
Return date for now.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
setEntity($currentobject)
Set entity id to use when to create an object.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dolBuildUrl($url, $params=[], $addtoken=false)
Return path of url.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
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.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
getDolGlobalBool($key, $default=false)
Return a Dolibarr global constant boolean value.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular VAT rate, when selling a product with vat $vatrate,...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
getMarginInfos($pv_ht, $remise_percent, $tva_tx, $localtax1_tx, $localtax2_tx, $fk_pa, $pa_ht)
Return an array with margins information of a line.
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller=null, $localtaxes_array=[], $progress=100, $multicurrency_tx=1, $pu_devise=0, $multicurrency_code='')
Calculate totals (net, vat, ...) of a line.
Definition price.lib.php:90
if(getDolGlobalString( 'TAKEPOS_SHOW_CUSTOMER')) print $langs trans('Date')." left Label right Qty right Price right TotalHT right TotalTTC right right right right right right right right right centpercent right TotalHT right n right VAT right n right TotalVAT right n No sujeto a RE IRPF right TotalLT1 right n right TotalLT2 right n right TotalTTC right n takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency right TotalTTC takeposcustomercurrency right takeposcustomercurrency n right PaymentTypeShortLIQ right SELECT p pos_change as p datep as date
Definition receipt.php:469