dolibarr  19.0.0-dev
delivery.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2005-2014 Regis Houssin <regis.houssin@inodbox.com>
4  * Copyright (C) 2006-2007 Laurent Destailleur <eldy@users.sourceforge.net>
5  * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerke@telenet.be>
6  * Copyright (C) 2011-2023 Philippe Grand <philippe.grand@atoo-net.com>
7  * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
8  * Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
9  * Copyright (C) 2023 Frédéric France <frederic.france@netlogic.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <https://www.gnu.org/licenses/>.
23  */
24 
31 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
32 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
33 require_once DOL_DOCUMENT_ROOT.'/core/class/commonincoterm.class.php';
34 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
35 if (isModEnabled("propal")) {
36  require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
37 }
38 if (isModEnabled('commande')) {
39  require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
40 }
41 
42 
46 class Delivery extends CommonObject
47 {
48  use CommonIncoterm;
49 
53  public $element = "delivery";
54 
58  public $fk_element = "fk_delivery";
59 
63  public $table_element = "delivery";
64 
68  public $table_element_line = "deliverydet";
69 
73  public $picto = 'sending';
74 
78  public $draft;
79 
83  public $socid;
84 
88  public $ref_customer;
89 
93  public $date_delivery;
94 
98  public $date_creation;
99 
103  public $date_valid;
104 
108  public $model_pdf;
109 
110  public $commande_id;
111 
115  public $statuts;
116 
120  public $lines = array();
121 
122 
128  public function __construct($db)
129  {
130  $this->db = $db;
131 
132  // List of short language codes for status
133  $this->statuts[-1] = 'StatusDeliveryCanceled';
134  $this->statuts[0] = 'StatusDeliveryDraft';
135  $this->statuts[1] = 'StatusDeliveryValidated';
136  }
137 
144  public function create($user)
145  {
146  global $conf;
147 
148  dol_syslog("Delivery::create");
149 
150  if (empty($this->model_pdf)) {
151  $this->model_pdf = $conf->global->DELIVERY_ADDON_PDF;
152  }
153 
154  $error = 0;
155 
156  $now = dol_now();
157 
158  /* Delivery note as draft On positionne en mode draft le bon de livraison */
159  $this->draft = 1;
160 
161  $this->user = $user;
162 
163  $this->db->begin();
164 
165  $sql = "INSERT INTO ".MAIN_DB_PREFIX."delivery (";
166  $sql .= "ref";
167  $sql .= ", entity";
168  $sql .= ", fk_soc";
169  $sql .= ", ref_customer";
170  $sql .= ", date_creation";
171  $sql .= ", fk_user_author";
172  $sql .= ", date_delivery";
173  $sql .= ", fk_address";
174  $sql .= ", note_private";
175  $sql .= ", note_public";
176  $sql .= ", model_pdf";
177  $sql .= ", fk_incoterms, location_incoterms";
178  $sql .= ") VALUES (";
179  $sql .= "'(PROV)'";
180  $sql .= ", ".((int) $conf->entity);
181  $sql .= ", ".((int) $this->socid);
182  $sql .= ", '".$this->db->escape($this->ref_customer)."'";
183  $sql .= ", '".$this->db->idate($now)."'";
184  $sql .= ", ".((int) $user->id);
185  $sql .= ", ".($this->date_delivery ? "'".$this->db->idate($this->date_delivery)."'" : "null");
186  $sql .= ", ".($this->fk_delivery_address > 0 ? $this->fk_delivery_address : "null");
187  $sql .= ", ".(!empty($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null");
188  $sql .= ", ".(!empty($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null");
189  $sql .= ", ".(!empty($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null");
190  $sql .= ", ".(int) $this->fk_incoterms;
191  $sql .= ", '".$this->db->escape($this->location_incoterms)."'";
192  $sql .= ")";
193 
194  dol_syslog("Delivery::create", LOG_DEBUG);
195  $resql = $this->db->query($sql);
196  if ($resql) {
197  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."delivery");
198 
199  $numref = "(PROV".$this->id.")";
200 
201  $sql = "UPDATE ".MAIN_DB_PREFIX."delivery ";
202  $sql .= "SET ref = '".$this->db->escape($numref)."'";
203  $sql .= " WHERE rowid = ".((int) $this->id);
204 
205  dol_syslog("Delivery::create", LOG_DEBUG);
206  $resql = $this->db->query($sql);
207  if ($resql) {
208  if (!getDolGlobalInt('MAIN_SUBMODULE_EXPEDITION')) {
209  $commande = new Commande($this->db);
210  $commande->id = $this->commande_id;
211  $commande->fetch_lines();
212  }
213 
214 
215  /*
216  * Inserting products into the database
217  */
218  $num = count($this->lines);
219  for ($i = 0; $i < $num; $i++) {
220  $origin_id = $this->lines[$i]->origin_line_id;
221  if (!$origin_id) {
222  $origin_id = $this->lines[$i]->commande_ligne_id; // For backward compatibility
223  }
224 
225  if (!$this->create_line($origin_id, $this->lines[$i]->qty, $this->lines[$i]->fk_product, $this->lines[$i]->description, $this->lines[$i]->array_options)) {
226  $error++;
227  }
228  }
229 
230  if (!$error && $this->id && $this->origin_id) {
231  $ret = $this->add_object_linked();
232  if (!$ret) {
233  $error++;
234  }
235 
236  if (!getDolGlobalInt('MAIN_SUBMODULE_EXPEDITION')) {
237  $ret = $this->setStatut(2, $this->origin_id, $this->origin);
238  if (!$ret) {
239  $error++;
240  }
241  }
242  }
243 
244  if (!$error) {
245  $this->db->commit();
246  return $this->id;
247  } else {
248  $error++;
249  $this->error = $this->db->lasterror()." - sql=".$this->db->lastqueryerror;
250  $this->db->rollback();
251  return -3;
252  }
253  } else {
254  $error++;
255  $this->error = $this->db->lasterror()." - sql=".$this->db->lastqueryerror;
256  $this->db->rollback();
257  return -2;
258  }
259  } else {
260  $error++;
261  $this->error = $this->db->lasterror()." - sql=".$this->db->lastqueryerror;
262  $this->db->rollback();
263  return -1;
264  }
265  }
266 
267  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
278  public function create_line($origin_id, $qty, $fk_product, $description, $array_options = null)
279  {
280  // phpcs:enable
281  $error = 0;
282  $idprod = $fk_product;
283 
284  $sql = "INSERT INTO ".MAIN_DB_PREFIX."deliverydet (fk_delivery, fk_origin_line,";
285  $sql .= " fk_product, description, qty)";
286  $sql .= " VALUES (".$this->id.",".((int) $origin_id).",";
287  $sql .= " ".($idprod > 0 ? ((int) $idprod) : "null").",";
288  $sql .= " ".($description ? "'".$this->db->escape($description)."'" : "null").",";
289  $sql .= (price2num($qty, 'MS')).")";
290 
291  dol_syslog(get_class($this)."::create_line", LOG_DEBUG);
292  if (!$this->db->query($sql)) {
293  $error++;
294  }
295 
296  $id = $this->db->last_insert_id(MAIN_DB_PREFIX."deliverydet");
297 
298  if (is_array($array_options) && count($array_options) > 0) {
299  $line = new DeliveryLine($this->db);
300  $line->id = $id;
301  $line->array_options = $array_options;
302  $result = $line->insertExtraFields();
303  }
304 
305  if (!$error) {
306  return 1;
307  }
308 
309  return -1;
310  }
311 
318  public function fetch($id)
319  {
320  $sql = "SELECT l.rowid, l.fk_soc, l.date_creation, l.date_valid, l.ref, l.ref_customer, l.fk_user_author,";
321  $sql .= " l.total_ht, l.fk_statut, l.fk_user_valid, l.note_private, l.note_public";
322  $sql .= ", l.date_delivery, l.fk_address, l.model_pdf";
323  $sql .= ", el.fk_source as origin_id, el.sourcetype as origin";
324  $sql .= ', l.fk_incoterms, l.location_incoterms';
325  $sql .= ", i.libelle as label_incoterms";
326  $sql .= " FROM ".MAIN_DB_PREFIX."delivery as l";
327  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = l.rowid AND el.targettype = '".$this->db->escape($this->element)."'";
328  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON l.fk_incoterms = i.rowid';
329  $sql .= " WHERE l.rowid = ".((int) $id);
330 
331  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
332  $result = $this->db->query($sql);
333  if ($result) {
334  if ($this->db->num_rows($result)) {
335  $obj = $this->db->fetch_object($result);
336 
337  $this->id = $obj->rowid;
338  $this->date_delivery = $this->db->jdate($obj->date_delivery);
339  $this->date_creation = $this->db->jdate($obj->date_creation);
340  $this->date_valid = $this->db->jdate($obj->date_valid);
341  $this->ref = $obj->ref;
342  $this->ref_customer = $obj->ref_customer;
343  $this->socid = $obj->fk_soc;
344  $this->statut = $obj->fk_statut;
345  $this->user_author_id = $obj->fk_user_author;
346  $this->user_valid_id = $obj->fk_user_valid;
347  $this->fk_delivery_address = $obj->fk_address;
348  $this->note = $obj->note_private; //TODO deprecated
349  $this->note_private = $obj->note_private;
350  $this->note_public = $obj->note_public;
351  $this->model_pdf = $obj->model_pdf;
352  $this->modelpdf = $obj->model_pdf; // deprecated
353  $this->origin = $obj->origin; // May be 'shipping'
354  $this->origin_id = $obj->origin_id; // May be id of shipping
355 
356  //Incoterms
357  $this->fk_incoterms = $obj->fk_incoterms;
358  $this->location_incoterms = $obj->location_incoterms;
359  $this->label_incoterms = $obj->label_incoterms;
360  $this->db->free($result);
361 
362  if ($this->statut == 0) {
363  $this->draft = 1;
364  }
365 
366  // Retrieve all extrafields
367  // fetch optionals attributes and labels
368  $this->fetch_optionals();
369 
370  // Load lines
371  $result = $this->fetch_lines();
372  if ($result < 0) {
373  return -3;
374  }
375 
376  return 1;
377  } else {
378  $this->error = 'Delivery with id '.$id.' not found sql='.$sql;
379  dol_syslog(get_class($this).'::fetch Error '.$this->error, LOG_ERR);
380  return -2;
381  }
382  } else {
383  $this->error = $this->db->error();
384  return -1;
385  }
386  }
387 
395  public function valid($user, $notrigger = 0)
396  {
397  global $conf;
398 
399  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
400 
401  dol_syslog(get_class($this)."::valid begin");
402 
403  $this->db->begin();
404 
405  $error = 0;
406 
407  if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->expedition->delivery->creer))
408  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->expedition->delivery_advance->validate))) {
409  if (!empty($conf->global->DELIVERY_ADDON_NUMBER)) {
410  // Setting the command numbering module name
411  $modName = $conf->global->DELIVERY_ADDON_NUMBER;
412 
413  if (is_readable(DOL_DOCUMENT_ROOT.'/core/modules/delivery/'.$modName.'.php')) {
414  require_once DOL_DOCUMENT_ROOT.'/core/modules/delivery/'.$modName.'.php';
415 
416  $now = dol_now();
417 
418  // Retrieving the new reference
419  $objMod = new $modName($this->db);
420  $soc = new Societe($this->db);
421  $soc->fetch($this->socid);
422 
423  if (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref)) { // empty should not happened, but when it occurs, the test save life
424  $numref = $objMod->delivery_get_num($soc, $this);
425  } else {
426  $numref = $this->ref;
427  }
428  $this->newref = dol_sanitizeFileName($numref);
429 
430  // Test if is not already in valid status. If so, we stop to avoid decrementing the stock twice.
431  $sql = "SELECT ref";
432  $sql .= " FROM ".MAIN_DB_PREFIX."delivery";
433  $sql .= " WHERE ref = '".$this->db->escape($numref)."'";
434  $sql .= " AND fk_statut <> 0";
435  $sql .= " AND entity = ".((int) $conf->entity);
436 
437  $resql = $this->db->query($sql);
438  if ($resql) {
439  $num = $this->db->num_rows($resql);
440  if ($num > 0) {
441  return 0;
442  }
443  }
444 
445  $sql = "UPDATE ".MAIN_DB_PREFIX."delivery SET";
446  $sql .= " ref='".$this->db->escape($numref)."'";
447  $sql .= ", fk_statut = 1";
448  $sql .= ", date_valid = '".$this->db->idate($now)."'";
449  $sql .= ", fk_user_valid = ".$user->id;
450  $sql .= " WHERE rowid = ".((int) $this->id);
451  $sql .= " AND fk_statut = 0";
452 
453  $resql = $this->db->query($sql);
454  if (!$resql) {
455  dol_print_error($this->db);
456  $this->error = $this->db->lasterror();
457  $error++;
458  }
459 
460  if (!$error && !$notrigger) {
461  // Call trigger
462  $result = $this->call_trigger('DELIVERY_VALIDATE', $user);
463  if ($result < 0) {
464  $error++;
465  }
466  // End call triggers
467  }
468 
469  if (!$error) {
470  $this->oldref = $this->ref;
471 
472  // Rename directory if dir was a temporary ref
473  if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
474  // Now we rename also files into index
475  $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'expedition/receipt/".$this->db->escape($this->newref)."'";
476  $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'expedition/receipt/".$this->db->escape($this->ref)."' and entity = ".((int) $conf->entity);
477  $resql = $this->db->query($sql);
478  if (!$resql) {
479  $error++; $this->error = $this->db->lasterror();
480  }
481 
482  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
483  $oldref = dol_sanitizeFileName($this->ref);
484  $newref = dol_sanitizeFileName($numref);
485  $dirsource = $conf->expedition->dir_output.'/receipt/'.$oldref;
486  $dirdest = $conf->expedition->dir_output.'/receipt/'.$newref;
487  if (!$error && file_exists($dirsource)) {
488  dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
489 
490  if (@rename($dirsource, $dirdest)) {
491  dol_syslog("Rename ok");
492  // Rename docs starting with $oldref with $newref
493  $listoffiles = dol_dir_list($conf->expedition->dir_output.'/receipt/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
494  foreach ($listoffiles as $fileentry) {
495  $dirsource = $fileentry['name'];
496  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
497  $dirsource = $fileentry['path'].'/'.$dirsource;
498  $dirdest = $fileentry['path'].'/'.$dirdest;
499  @rename($dirsource, $dirdest);
500  }
501  }
502  }
503  }
504 
505  // Set new ref and current status
506  if (!$error) {
507  $this->ref = $numref;
508  $this->statut = 1;
509  }
510 
511  dol_syslog(get_class($this)."::valid ok");
512  }
513 
514  if (!$error) {
515  $this->db->commit();
516  return 1;
517  } else {
518  $this->db->rollback();
519  return -1;
520  }
521  }
522  }
523 
524  return -1;
525  } else {
526  $this->error = "NotAllowed";
527  dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
528  return -1;
529  }
530  }
531 
532  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
540  public function create_from_sending($user, $sending_id)
541  {
542  // phpcs:enable
543  global $conf;
544 
545  $expedition = new Expedition($this->db);
546  $result = $expedition->fetch($sending_id);
547  if ($result <= 0) {
548  return $result;
549  }
550 
551  $this->lines = array();
552 
553  $num = count($expedition->lines);
554  for ($i = 0; $i < $num; $i++) {
555  $line = new DeliveryLine($this->db);
556  $line->origin_line_id = $expedition->lines[$i]->origin_line_id;
557  $line->label = $expedition->lines[$i]->label;
558  $line->description = $expedition->lines[$i]->description;
559  $line->qty = $expedition->lines[$i]->qty_shipped;
560  $line->fk_product = $expedition->lines[$i]->fk_product;
561  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($expedition->lines[$i]->array_options) && count($expedition->lines[$i]->array_options) > 0) { // For avoid conflicts if trigger used
562  $line->array_options = $expedition->lines[$i]->array_options;
563  }
564  $this->lines[$i] = $line;
565  }
566 
567  $this->origin = $expedition->element;
568  $this->origin_id = $expedition->id;
569  $this->note_private = $expedition->note_private;
570  $this->note_public = $expedition->note_public;
571  $this->fk_project = $expedition->fk_project;
572  $this->date_delivery = $expedition->date_delivery;
573  $this->fk_delivery_address = $expedition->fk_delivery_address;
574  $this->socid = $expedition->socid;
575  $this->ref_customer = $expedition->ref_customer;
576 
577  //Incoterms
578  $this->fk_incoterms = $expedition->fk_incoterms;
579  $this->location_incoterms = $expedition->location_incoterms;
580 
581  return $this->create($user);
582  }
583 
584  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
592  public function update_line($id, $array_options = 0)
593  {
594  // phpcs:enable
595  global $conf;
596  $error = 0;
597 
598  if ($id > 0 && !$error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options) > 0) { // For avoid conflicts if trigger used
599  $line = new DeliveryLine($this->db);
600  $line->array_options = $array_options;
601  $line->id = $id;
602  $result = $line->insertExtraFields();
603 
604  if ($result < 0) {
605  $this->error[] = $line->error;
606  $error++;
607  }
608  }
609 
610  if (!$error) {
611  return 1;
612  } else {
613  return -1;
614  }
615  }
616 
617 
626  public function addline($origin_id, $qty, $array_options = null)
627  {
628  global $conf;
629 
630  $num = count($this->lines);
631  $line = new DeliveryLine($this->db);
632 
633  $line->origin_id = $origin_id;
634  $line->qty = $qty;
635  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options) > 0) { // For avoid conflicts if trigger used
636  $line->array_options = $array_options;
637  }
638  $this->lines[$num] = $line;
639  }
640 
647  public function deleteline($lineid)
648  {
649  if ($this->statut == 0) {
650  $sql = "DELETE FROM ".MAIN_DB_PREFIX."commandedet";
651  $sql .= " WHERE rowid = ".((int) $lineid);
652 
653  if ($this->db->query($sql)) {
654  $this->update_price(1);
655 
656  return 1;
657  } else {
658  return -1;
659  }
660  }
661 
662  return 0;
663  }
664 
670  public function delete()
671  {
672  global $conf, $langs, $user;
673 
674  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
675  $this->db->begin();
676 
677  $error = 0;
678 
679  $sql = "DELETE FROM ".MAIN_DB_PREFIX."deliverydet";
680  $sql .= " WHERE fk_delivery = ".((int) $this->id);
681  if ($this->db->query($sql)) {
682  // Delete linked object
683  $res = $this->deleteObjectLinked();
684  if ($res < 0) {
685  $error++;
686  }
687 
688  if (!$error) {
689  $sql = "DELETE FROM ".MAIN_DB_PREFIX."delivery";
690  $sql .= " WHERE rowid = ".((int) $this->id);
691  if ($this->db->query($sql)) {
692  $this->db->commit();
693 
694  // Deleting pdf folder's draft On efface le repertoire de pdf provisoire
695  $ref = dol_sanitizeFileName($this->ref);
696  if (!empty($conf->expedition->dir_output)) {
697  $dir = $conf->expedition->dir_output.'/receipt/'.$ref;
698  $file = $dir.'/'.$ref.'.pdf';
699  if (file_exists($file)) {
700  if (!dol_delete_file($file)) {
701  return 0;
702  }
703  }
704  if (file_exists($dir)) {
705  if (!dol_delete_dir($dir)) {
706  $this->error = $langs->trans("ErrorCanNotDeleteDir", $dir);
707  return 0;
708  }
709  }
710  }
711 
712  // Call trigger
713  $result = $this->call_trigger('DELIVERY_DELETE', $user);
714  if ($result < 0) {
715  $this->db->rollback();
716  return -4;
717  }
718  // End call triggers
719 
720  return 1;
721  } else {
722  $this->error = $this->db->lasterror()." - sql=$sql";
723  $this->db->rollback();
724  return -3;
725  }
726  } else {
727  $this->error = $this->db->lasterror()." - sql=$sql";
728  $this->db->rollback();
729  return -2;
730  }
731  } else {
732  $this->error = $this->db->lasterror()." - sql=$sql";
733  $this->db->rollback();
734  return -1;
735  }
736  }
737 
744  public function getTooltipContentArray($params)
745  {
746  global $langs;
747 
748  $datas = [];
749 
750  $datas['picto'] = img_picto('', $this->picto).' <u>'.$langs->trans("ShowReceiving").'</u>:<br>';
751  $datas['picto'] .= '<b>'.$langs->trans("Status").'</b>: '.$this->ref;
752 
753  return $datas;
754  }
755 
763  public function getNomUrl($withpicto = 0, $save_lastsearch_value = -1)
764  {
765  global $langs, $hookmanager;
766 
767  $result = '';
768 
769  $params = [
770  'id' => $this->id,
771  'objecttype' => $this->element,
772  ];
773  $classfortooltip = 'classfortooltip';
774  $dataparams = '';
775  if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
776  $classfortooltip = 'classforajaxtooltip';
777  $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
778  $label = '';
779  } else {
780  $label = implode($this->getTooltipContentArray($params));
781  }
782 
783  $url = DOL_URL_ROOT.'/delivery/card.php?id='.$this->id;
784 
785  //if ($option !== 'nolink')
786  //{
787  // Add param to save lastsearch_values or not
788  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
789  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
790  $add_save_lastsearch_values = 1;
791  }
792  if ($add_save_lastsearch_values) {
793  $url .= '&save_lastsearch_values=1';
794  }
795  //}
796 
797  $linkstart = '<a href="'.$url.'"';
798  $linkstart .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
799  $linkstart .= $dataparams.' class="'.$classfortooltip.'">';
800  $linkend = '</a>';
801 
802  if ($withpicto) {
803  $result .= ($linkstart.img_object($label, $this->picto, $dataparams.' class="'.$classfortooltip.'"').$linkend);
804  }
805  if ($withpicto && $withpicto != 2) {
806  $result .= ' ';
807  }
808  $result .= $linkstart.$this->ref.$linkend;
809 
810  global $action;
811  $hookmanager->initHooks(array($this->element . 'dao'));
812  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
813  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
814  if ($reshook > 0) {
815  $result = $hookmanager->resPrint;
816  } else {
817  $result .= $hookmanager->resPrint;
818  }
819  return $result;
820  }
821 
822  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
828  public function fetch_lines()
829  {
830  // phpcs:enable
831  $this->lines = array();
832 
833  $sql = "SELECT ld.rowid, ld.fk_product, ld.description, ld.subprice, ld.total_ht, ld.qty as qty_shipped, ld.fk_origin_line, ";
834  $sql .= " cd.qty as qty_asked, cd.label as custom_label, cd.fk_unit,";
835  $sql .= " p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc,";
836  $sql .= " p.weight, p.weight_units, p.width, p.width_units, p.length, p.length_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units, p.tobatch as product_tobatch";
837  $sql .= " FROM ".MAIN_DB_PREFIX."commandedet as cd, ".MAIN_DB_PREFIX."deliverydet as ld";
838  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p on p.rowid = ld.fk_product";
839  $sql .= " WHERE ld.fk_origin_line = cd.rowid";
840  $sql .= " AND ld.fk_delivery = ".((int) $this->id);
841 
842  dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
843  $resql = $this->db->query($sql);
844  if ($resql) {
845  $num = $this->db->num_rows($resql);
846  $i = 0;
847  while ($i < $num) {
848  $obj = $this->db->fetch_object($resql);
849 
850  $line = new DeliveryLine($this->db);
851 
852  $line->id = $obj->rowid;
853  $line->label = $obj->custom_label;
854  $line->description = $obj->description;
855  $line->fk_product = $obj->fk_product;
856  $line->qty_asked = $obj->qty_asked;
857  $line->qty_shipped = $obj->qty_shipped;
858 
859  $line->ref = $obj->product_ref; // deprecated
860  $line->libelle = $obj->product_label; // deprecated
861  $line->product_label = $obj->product_label; // Product label
862  $line->product_ref = $obj->product_ref; // Product ref
863  $line->product_desc = $obj->product_desc; // Product description
864  $line->product_type = $obj->fk_product_type;
865  $line->fk_origin_line = $obj->fk_origin_line;
866 
867  $line->price = $obj->subprice;
868  $line->total_ht = $obj->total_ht;
869 
870  // units
871  $line->weight = $obj->weight;
872  $line->weight_units = $obj->weight_units;
873  $line->width = $obj->width;
874  $line->width_units = $obj->width_units;
875  $line->height = $obj->height;
876  $line->height_units = $obj->height_units;
877  $line->length = $obj->length;
878  $line->length_units = $obj->length_units;
879  $line->surface = $obj->surface;
880  $line->surface_units = $obj->surface_units;
881  $line->volume = $obj->volume;
882  $line->volume_units = $obj->volume_units;
883 
884  $line->fk_unit = $obj->fk_unit;
885  $line->fetch_optionals();
886 
887  $this->lines[$i] = $line;
888 
889  $i++;
890  }
891  $this->db->free($resql);
892 
893  return 1;
894  } else {
895  return -1;
896  }
897  }
898 
899 
906  public function getLibStatut($mode = 0)
907  {
908  return $this->LibStatut($this->statut, $mode);
909  }
910 
911  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
919  public function LibStatut($status, $mode)
920  {
921  // phpcs:enable
922  global $langs;
923 
924  if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
925  global $langs;
926  //$langs->load("mymodule");
927  $this->labelStatus[-1] = $langs->transnoentitiesnoconv('StatusDeliveryCanceled');
928  $this->labelStatus[0] = $langs->transnoentitiesnoconv('StatusDeliveryDraft');
929  $this->labelStatus[1] = $langs->transnoentitiesnoconv('StatusDeliveryValidated');
930  $this->labelStatusShort[-1] = $langs->transnoentitiesnoconv('StatusDeliveryCanceled');
931  $this->labelStatusShort[0] = $langs->transnoentitiesnoconv('StatusDeliveryDraft');
932  $this->labelStatusShort[1] = $langs->transnoentitiesnoconv('StatusDeliveryValidated');
933  }
934 
935  $statusType = 'status0';
936  if ($status == -1) {
937  $statusType = 'status5';
938  }
939  if ($status == 1) {
940  $statusType = 'status4';
941  }
942 
943  return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
944  }
945 
946 
954  public function initAsSpecimen()
955  {
956  $now = dol_now();
957 
958  // Load array of products prodids
959  $num_prods = 0;
960  $prodids = array();
961  $sql = "SELECT rowid";
962  $sql .= " FROM ".MAIN_DB_PREFIX."product";
963  $sql .= " WHERE entity IN (".getEntity('product').")";
964  $sql .= " AND tosell = 1";
965  $sql .= $this->db->plimit(100);
966 
967  $resql = $this->db->query($sql);
968  if ($resql) {
969  $num_prods = $this->db->num_rows($resql);
970  $i = 0;
971  while ($i < $num_prods) {
972  $i++;
973  $row = $this->db->fetch_row($resql);
974  $prodids[$i] = $row[0];
975  }
976  }
977 
978  // Initialise parametres
979  $this->id = 0;
980  $this->ref = 'SPECIMEN';
981  $this->specimen = 1;
982  $this->socid = 1;
983  $this->date_delivery = $now;
984  $this->note_public = 'Public note';
985  $this->note_private = 'Private note';
986 
987  $i = 0;
988  $line = new DeliveryLine($this->db);
989  $line->fk_product = reset($prodids);
990  $line->qty_asked = 10;
991  $line->qty_shipped = 9;
992  $line->ref = 'REFPROD';
993  $line->label = 'Specimen';
994  $line->description = 'Description';
995  $line->price = 100;
996  $line->total_ht = 100;
997 
998  $this->lines[$i] = $line;
999  }
1000 
1007  public function getRemainingDelivered()
1008  {
1009  // Get the linked object
1010  $this->fetchObjectLinked('', '', $this->id, $this->element);
1011  //var_dump($this->linkedObjectsIds);
1012  // Get the product ref and qty in source
1013  $sqlSourceLine = "SELECT st.rowid, st.description, st.qty";
1014  $sqlSourceLine .= ", p.ref, p.label";
1015  $sqlSourceLine .= " FROM ".MAIN_DB_PREFIX.$this->linkedObjectsIds[0]['type']."det as st";
1016  $sqlSourceLine .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON st.fk_product = p.rowid";
1017  $sqlSourceLine .= " WHERE fk_".$this->linked_objects[0]['type']." = ".((int) $this->linked_objects[0]['linkid']);
1018 
1019  $resultSourceLine = $this->db->query($sqlSourceLine);
1020  if ($resultSourceLine) {
1021  $num_lines = $this->db->num_rows($resultSourceLine);
1022  $i = 0;
1023  $array = array();
1024  while ($i < $num_lines) {
1025  $objSourceLine = $this->db->fetch_object($resultSourceLine);
1026 
1027  // Get lines of sources alread delivered
1028  $sql = "SELECT ld.fk_origin_line, sum(ld.qty) as qty";
1029  $sql .= " FROM ".MAIN_DB_PREFIX."deliverydet as ld, ".MAIN_DB_PREFIX."delivery as l,";
1030  $sql .= " ".MAIN_DB_PREFIX.$this->linked_objects[0]['type']." as c";
1031  $sql .= ", ".MAIN_DB_PREFIX.$this->linked_objects[0]['type']."det as cd";
1032  $sql .= " WHERE ld.fk_delivery = l.rowid";
1033  $sql .= " AND ld.fk_origin_line = cd.rowid";
1034  $sql .= " AND cd.fk_".$this->linked_objects[0]['type']." = c.rowid";
1035  $sql .= " AND cd.fk_".$this->linked_objects[0]['type']." = ".((int) $this->linked_objects[0]['linkid']);
1036  $sql .= " AND ld.fk_origin_line = ".((int) $objSourceLine->rowid);
1037  $sql .= " GROUP BY ld.fk_origin_line";
1038 
1039  $result = $this->db->query($sql);
1040  $row = $this->db->fetch_row($result);
1041 
1042  if ($objSourceLine->qty - $row[1] > 0) {
1043  if ($row[0] == $objSourceLine->rowid) {
1044  $array[$i]['qty'] = $objSourceLine->qty - $row[1];
1045  } else {
1046  $array[$i]['qty'] = $objSourceLine->qty;
1047  }
1048 
1049  $array[$i]['ref'] = $objSourceLine->ref;
1050  $array[$i]['label'] = $objSourceLine->label ? $objSourceLine->label : $objSourceLine->description;
1051  } elseif ($objSourceLine->qty - $row[1] < 0) {
1052  $array[$i]['qty'] = $objSourceLine->qty - $row[1]." Erreur livraison !";
1053  $array[$i]['ref'] = $objSourceLine->ref;
1054  $array[$i]['label'] = $objSourceLine->label ? $objSourceLine->label : $objSourceLine->description;
1055  }
1056 
1057  $i++;
1058  }
1059  return $array;
1060  } else {
1061  $this->error = $this->db->error()." - sql=$sqlSourceLine";
1062  return -1;
1063  }
1064  }
1065 
1073  public function setDeliveryDate($user, $delivery_date)
1074  {
1075  if ($user->rights->expedition->creer) {
1076  $sql = "UPDATE ".MAIN_DB_PREFIX."delivery";
1077  $sql .= " SET date_delivery = ".($delivery_date ? "'".$this->db->idate($delivery_date)."'" : 'null');
1078  $sql .= " WHERE rowid = ".((int) $this->id);
1079 
1080  dol_syslog(get_class($this)."::setDeliveryDate", LOG_DEBUG);
1081  $resql = $this->db->query($sql);
1082  if ($resql) {
1083  $this->date_delivery = $delivery_date;
1084  return 1;
1085  } else {
1086  $this->error = $this->db->error();
1087  return -1;
1088  }
1089  } else {
1090  return -2;
1091  }
1092  }
1093 
1104  public function generateDocument($modele, $outputlangs = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1105  {
1106  global $conf, $langs;
1107 
1108  $langs->load("deliveries");
1109  $outputlangs->load("products");
1110 
1111  if (!dol_strlen($modele)) {
1112  $modele = 'typhon';
1113 
1114  if ($this->model_pdf) {
1115  $modele = $this->model_pdf;
1116  } elseif (!empty($conf->global->DELIVERY_ADDON_PDF)) {
1117  $modele = $conf->global->DELIVERY_ADDON_PDF;
1118  }
1119  }
1120 
1121  $modelpath = "core/modules/delivery/doc/";
1122 
1123  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
1124  }
1125 
1134  public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
1135  {
1136  $tables = array(
1137  'delivery'
1138  );
1139 
1140  return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
1141  }
1142 
1151  public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
1152  {
1153  $tables = array(
1154  'deliverydet'
1155  );
1156 
1157  return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
1158  }
1159 }
1160 
1161 
1166 {
1170  public $db;
1171 
1175  public $element = 'deliverydet';
1176 
1180  public $table_element = 'deliverydet';
1181 
1185  public $label;
1186 
1190  public $description;
1191 
1196  public $ref;
1201  public $libelle;
1202 
1203  // From llx_expeditiondet
1204  public $qty;
1205  public $qty_asked;
1206  public $qty_shipped;
1207 
1208  public $fk_product;
1209  public $product_desc;
1210  public $product_type;
1211  public $product_ref;
1212  public $product_label;
1213 
1214  public $price;
1215 
1216  public $fk_origin_line;
1217  public $origin_id;
1218 
1222  public $origin_line_id;
1223 
1229  public $commande_ligne_id;
1230 
1231 
1237  public function __construct($db)
1238  {
1239  $this->db = $db;
1240  }
1241 }
$object ref
Definition: info.php:78
Class to manage customers orders.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
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...
add_object_linked($origin=null, $origin_id=null, $f_user=null, $notrigger=0)
Add an object link into llx_element_element.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='', $f_user=null, $notrigger=0)
Delete all links between an object $this.
setStatut($status, $elementId=null, $elementType='', $trigkey='', $fieldstatus='fk_statut')
Set status of an object.
update_price($exclspec=0, $roundingadjust='none', $nodatabaseupdate=0, $seller=null)
Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines).
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
fetchObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $clause='OR', $alsosametype=1, $orderby='sourcetype', $loadalsoobjects=1)
Fetch array of objects linked to current object (object of enabled modules only).
static commonReplaceProduct(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a product id with another one.
call_trigger($triggerName, $user)
Call trigger based on this instance.
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
Class to manage receptions.
generateDocument($modele, $outputlangs='', $hidedetails=0, $hidedesc=0, $hideref=0)
Create object on disk.
valid($user, $notrigger=0)
Validate object and update stock if option enabled.
addline($origin_id, $qty, $array_options=null)
Add line.
__construct($db)
Constructor.
static replaceProduct(DoliDB $db, $origin_id, $dest_id)
Function used to replace a product id with another one.
setDeliveryDate($user, $delivery_date)
Set the planned delivery date.
fetch($id)
Load a delivery receipt.
create($user)
Create delivery receipt in database.
create_line($origin_id, $qty, $fk_product, $description, $array_options=null)
Create a line.
initAsSpecimen()
Initialise an instance with random values.
create_from_sending($user, $sending_id)
Creating the delivery slip from an existing shipment.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
getTooltipContentArray($params)
getTooltipContentArray
getLibStatut($mode=0)
Return the label of the status.
LibStatut($status, $mode)
Return the label of a given status.
update_line($id, $array_options=0)
Update a livraison line (only extrafields)
deleteline($lineid)
Delete line.
fetch_lines()
Load lines insto $this->lines.
getRemainingDelivered()
Renvoie la quantite de produit restante a livrer pour une commande.
getNomUrl($withpicto=0, $save_lastsearch_value=-1)
Return clicable name (with picto eventually)
Management class of delivery note lines.
__construct($db)
Constructor.
Class to manage Dolibarr database access.
Class to manage shipments.
Class to manage third parties objects (customers, suppliers, prospects...)
trait CommonIncoterm
Superclass for incoterm classes.
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
print *****$script_file(".$version.") pid cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
Definition: files.lib.php:1334
dol_delete_dir($dir, $nophperrors=0)
Remove a directory (not recursive, so content must be empty).
Definition: files.lib.php:1460
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:62
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
$conf db user
Definition: repair.php:124