dolibarr  20.0.0-alpha
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-2024 Frédéric France <frederic.france@free.fr>
10  * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program. If not, see <https://www.gnu.org/licenses/>.
24  */
25 
32 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
33 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
34 require_once DOL_DOCUMENT_ROOT.'/core/class/commonincoterm.class.php';
35 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
36 if (isModEnabled("propal")) {
37  require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
38 }
39 if (isModEnabled('order')) {
40  require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
41 }
42 
43 
47 class Delivery extends CommonObject
48 {
49  use CommonIncoterm;
50 
54  public $element = "delivery";
55 
59  public $fk_element = "fk_delivery";
60 
64  public $table_element = "delivery";
65 
69  public $table_element_line = "deliverydet";
70 
74  public $picto = 'sending';
75 
79  public $draft;
80 
84  public $socid;
85 
89  public $ref_customer;
90 
94  public $date_delivery;
95 
99  public $date_creation;
100 
104  public $date_valid;
105 
109  public $model_pdf;
110 
111  public $commande_id;
112 
116  public $labelStatus;
117 
121  public $lines = array();
122 
126  public $user_author_id;
127 
128 
134  public function __construct($db)
135  {
136  $this->db = $db;
137 
138  // List of short language codes for status
139  $this->labelStatus[-1] = 'StatusDeliveryCanceled';
140  $this->labelStatus[0] = 'StatusDeliveryDraft';
141  $this->labelStatus[1] = 'StatusDeliveryValidated';
142  }
143 
150  public function create($user)
151  {
152  global $conf;
153 
154  dol_syslog("Delivery::create");
155 
156  if (empty($this->model_pdf)) {
157  $this->model_pdf = getDolGlobalString('DELIVERY_ADDON_PDF');
158  }
159 
160  $error = 0;
161 
162  $now = dol_now();
163 
164  /* Delivery note as draft On positionne en mode draft le bon de livraison */
165  $this->draft = 1;
166 
167  $this->user = $user;
168 
169  $this->db->begin();
170 
171  $sql = "INSERT INTO ".MAIN_DB_PREFIX."delivery (";
172  $sql .= "ref";
173  $sql .= ", entity";
174  $sql .= ", fk_soc";
175  $sql .= ", ref_customer";
176  $sql .= ", date_creation";
177  $sql .= ", fk_user_author";
178  $sql .= ", date_delivery";
179  $sql .= ", fk_address";
180  $sql .= ", note_private";
181  $sql .= ", note_public";
182  $sql .= ", model_pdf";
183  $sql .= ", fk_incoterms, location_incoterms";
184  $sql .= ") VALUES (";
185  $sql .= "'(PROV)'";
186  $sql .= ", ".((int) $conf->entity);
187  $sql .= ", ".((int) $this->socid);
188  $sql .= ", '".$this->db->escape($this->ref_customer)."'";
189  $sql .= ", '".$this->db->idate($now)."'";
190  $sql .= ", ".((int) $user->id);
191  $sql .= ", ".($this->date_delivery ? "'".$this->db->idate($this->date_delivery)."'" : "null");
192  $sql .= ", ".($this->fk_delivery_address > 0 ? $this->fk_delivery_address : "null");
193  $sql .= ", ".(!empty($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null");
194  $sql .= ", ".(!empty($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null");
195  $sql .= ", ".(!empty($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null");
196  $sql .= ", ".(int) $this->fk_incoterms;
197  $sql .= ", '".$this->db->escape($this->location_incoterms)."'";
198  $sql .= ")";
199 
200  dol_syslog("Delivery::create", LOG_DEBUG);
201  $resql = $this->db->query($sql);
202  if ($resql) {
203  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."delivery");
204 
205  $numref = "(PROV".$this->id.")";
206 
207  $sql = "UPDATE ".MAIN_DB_PREFIX."delivery ";
208  $sql .= "SET ref = '".$this->db->escape($numref)."'";
209  $sql .= " WHERE rowid = ".((int) $this->id);
210 
211  dol_syslog("Delivery::create", LOG_DEBUG);
212  $resql = $this->db->query($sql);
213  if ($resql) {
214  if (!getDolGlobalInt('MAIN_SUBMODULE_EXPEDITION')) {
215  $commande = new Commande($this->db);
216  $commande->id = $this->commande_id;
217  $commande->fetch_lines();
218  }
219 
220 
221  /*
222  * Inserting products into the database
223  */
224  $num = count($this->lines);
225  for ($i = 0; $i < $num; $i++) {
226  $origin_id = $this->lines[$i]->origin_line_id;
227  if (!$origin_id) {
228  $origin_id = $this->lines[$i]->commande_ligne_id; // For backward compatibility
229  }
230 
231  if (!$this->create_line($origin_id, $this->lines[$i]->qty, $this->lines[$i]->fk_product, $this->lines[$i]->description, $this->lines[$i]->array_options)) {
232  $error++;
233  }
234  }
235 
236  if (!$error && $this->id && $this->origin_id) {
237  $ret = $this->add_object_linked();
238  if (!$ret) {
239  $error++;
240  }
241 
242  if (!getDolGlobalInt('MAIN_SUBMODULE_EXPEDITION')) {
243  $ret = $this->setStatut(2, $this->origin_id, $this->origin);
244  if (!$ret) {
245  $error++;
246  }
247  }
248  }
249 
250  if (!$error) {
251  $this->db->commit();
252  return $this->id;
253  } else {
254  $error++;
255  $this->error = $this->db->lasterror()." - sql=".$this->db->lastqueryerror;
256  $this->db->rollback();
257  return -3;
258  }
259  } else {
260  $error++;
261  $this->error = $this->db->lasterror()." - sql=".$this->db->lastqueryerror;
262  $this->db->rollback();
263  return -2;
264  }
265  } else {
266  $error++;
267  $this->error = $this->db->lasterror()." - sql=".$this->db->lastqueryerror;
268  $this->db->rollback();
269  return -1;
270  }
271  }
272 
273  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
284  public function create_line($origin_id, $qty, $fk_product, $description, $array_options = [])
285  {
286  // phpcs:enable
287  $error = 0;
288  $idprod = $fk_product;
289 
290  $sql = "INSERT INTO ".MAIN_DB_PREFIX."deliverydet (fk_delivery, fk_origin_line,";
291  $sql .= " fk_product, description, qty)";
292  $sql .= " VALUES (".$this->id.",".((int) $origin_id).",";
293  $sql .= " ".($idprod > 0 ? ((int) $idprod) : "null").",";
294  $sql .= " ".($description ? "'".$this->db->escape($description)."'" : "null").",";
295  $sql .= (price2num($qty, 'MS')).")";
296 
297  dol_syslog(get_class($this)."::create_line", LOG_DEBUG);
298  if (!$this->db->query($sql)) {
299  $error++;
300  }
301 
302  $id = $this->db->last_insert_id(MAIN_DB_PREFIX."deliverydet");
303 
304  if (is_array($array_options) && count($array_options) > 0) {
305  $line = new DeliveryLine($this->db);
306  $line->id = $id;
307  $line->array_options = $array_options;
308  $result = $line->insertExtraFields();
309  }
310 
311  if (!$error) {
312  return 1;
313  }
314 
315  return -1;
316  }
317 
324  public function fetch($id)
325  {
326  $sql = "SELECT l.rowid, l.fk_soc, l.date_creation, l.date_valid, l.ref, l.ref_customer, l.fk_user_author,";
327  $sql .= " l.total_ht, l.fk_statut, l.fk_user_valid, l.note_private, l.note_public";
328  $sql .= ", l.date_delivery, l.fk_address, l.model_pdf";
329  $sql .= ", el.fk_source as origin_id, el.sourcetype as origin";
330  $sql .= ', l.fk_incoterms, l.location_incoterms';
331  $sql .= ", i.libelle as label_incoterms";
332  $sql .= " FROM ".MAIN_DB_PREFIX."delivery as l";
333  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = l.rowid AND el.targettype = '".$this->db->escape($this->element)."'";
334  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON l.fk_incoterms = i.rowid';
335  $sql .= " WHERE l.rowid = ".((int) $id);
336 
337  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
338  $result = $this->db->query($sql);
339  if ($result) {
340  if ($this->db->num_rows($result)) {
341  $obj = $this->db->fetch_object($result);
342 
343  $this->id = $obj->rowid;
344  $this->date_delivery = $this->db->jdate($obj->date_delivery);
345  $this->date_creation = $this->db->jdate($obj->date_creation);
346  $this->date_valid = $this->db->jdate($obj->date_valid);
347  $this->ref = $obj->ref;
348  $this->ref_customer = $obj->ref_customer;
349  $this->socid = $obj->fk_soc;
350  $this->statut = $obj->fk_statut;
351  $this->status = $obj->fk_statut;
352  $this->user_author_id = $obj->fk_user_author;
353  $this->user_validation_id = $obj->fk_user_valid;
354  $this->fk_delivery_address = $obj->fk_address;
355  $this->note = $obj->note_private; //TODO deprecated
356  $this->note_private = $obj->note_private;
357  $this->note_public = $obj->note_public;
358  $this->model_pdf = $obj->model_pdf;
359  $this->origin = $obj->origin; // May be 'shipping'
360  $this->origin_id = $obj->origin_id; // May be id of shipping
361 
362  //Incoterms
363  $this->fk_incoterms = $obj->fk_incoterms;
364  $this->location_incoterms = $obj->location_incoterms;
365  $this->label_incoterms = $obj->label_incoterms;
366  $this->db->free($result);
367 
368  if ($this->statut == 0) {
369  $this->draft = 1;
370  }
371 
372  // Retrieve all extrafields
373  // fetch optionals attributes and labels
374  $this->fetch_optionals();
375 
376  // Load lines
377  $result = $this->fetch_lines();
378  if ($result < 0) {
379  return -3;
380  }
381 
382  return 1;
383  } else {
384  $this->error = 'Delivery with id '.$id.' not found sql='.$sql;
385  dol_syslog(get_class($this).'::fetch Error '.$this->error, LOG_ERR);
386  return -2;
387  }
388  } else {
389  $this->error = $this->db->error();
390  return -1;
391  }
392  }
393 
401  public function valid($user, $notrigger = 0)
402  {
403  global $conf;
404 
405  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
406 
407  dol_syslog(get_class($this)."::valid begin");
408 
409  $this->db->begin();
410 
411  $error = 0;
412 
413  if ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'delivery', 'creer'))
414  || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'delivery_advance', 'validate'))) {
415  if (getDolGlobalString('DELIVERY_ADDON_NUMBER')) {
416  // Setting the command numbering module name
417  $modName = getDolGlobalString('DELIVERY_ADDON_NUMBER');
418 
419  if (is_readable(DOL_DOCUMENT_ROOT.'/core/modules/delivery/'.$modName.'.php')) {
420  require_once DOL_DOCUMENT_ROOT.'/core/modules/delivery/'.$modName.'.php';
421 
422  $now = dol_now();
423 
424  // Retrieving the new reference
425  $objMod = new $modName($this->db);
426  $soc = new Societe($this->db);
427  $soc->fetch($this->socid);
428 
429  if (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref)) { // empty should not happened, but when it occurs, the test save life
430  $numref = $objMod->delivery_get_num($soc, $this);
431  } else {
432  $numref = $this->ref;
433  }
434  $this->newref = dol_sanitizeFileName($numref);
435 
436  // Test if is not already in valid status. If so, we stop to avoid decrementing the stock twice.
437  $sql = "SELECT ref";
438  $sql .= " FROM ".MAIN_DB_PREFIX."delivery";
439  $sql .= " WHERE ref = '".$this->db->escape($numref)."'";
440  $sql .= " AND fk_statut <> 0";
441  $sql .= " AND entity = ".((int) $conf->entity);
442 
443  $resql = $this->db->query($sql);
444  if ($resql) {
445  $num = $this->db->num_rows($resql);
446  if ($num > 0) {
447  return 0;
448  }
449  }
450 
451  $sql = "UPDATE ".MAIN_DB_PREFIX."delivery SET";
452  $sql .= " ref='".$this->db->escape($numref)."'";
453  $sql .= ", fk_statut = 1";
454  $sql .= ", date_valid = '".$this->db->idate($now)."'";
455  $sql .= ", fk_user_valid = ".$user->id;
456  $sql .= " WHERE rowid = ".((int) $this->id);
457  $sql .= " AND fk_statut = 0";
458 
459  $resql = $this->db->query($sql);
460  if (!$resql) {
461  dol_print_error($this->db);
462  $this->error = $this->db->lasterror();
463  $error++;
464  }
465 
466  if (!$error && !$notrigger) {
467  // Call trigger
468  $result = $this->call_trigger('DELIVERY_VALIDATE', $user);
469  if ($result < 0) {
470  $error++;
471  }
472  // End call triggers
473  }
474 
475  if (!$error) {
476  $this->oldref = $this->ref;
477 
478  // Rename directory if dir was a temporary ref
479  if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
480  // Now we rename also files into index
481  $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)."'";
482  $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'expedition/receipt/".$this->db->escape($this->ref)."' and entity = ".((int) $conf->entity);
483  $resql = $this->db->query($sql);
484  if (!$resql) {
485  $error++;
486  $this->error = $this->db->lasterror();
487  }
488  $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'expedition/receipt/".$this->db->escape($this->newref)."'";
489  $sql .= " WHERE filepath = 'expedition/receipt/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
490  $resql = $this->db->query($sql);
491  if (!$resql) {
492  $error++;
493  $this->error = $this->db->lasterror();
494  }
495 
496  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
497  $oldref = dol_sanitizeFileName($this->ref);
498  $newref = dol_sanitizeFileName($numref);
499  $dirsource = $conf->expedition->dir_output.'/receipt/'.$oldref;
500  $dirdest = $conf->expedition->dir_output.'/receipt/'.$newref;
501  if (!$error && file_exists($dirsource)) {
502  dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
503 
504  if (@rename($dirsource, $dirdest)) {
505  dol_syslog("Rename ok");
506  // Rename docs starting with $oldref with $newref
507  $listoffiles = dol_dir_list($conf->expedition->dir_output.'/receipt/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
508  foreach ($listoffiles as $fileentry) {
509  $dirsource = $fileentry['name'];
510  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
511  $dirsource = $fileentry['path'].'/'.$dirsource;
512  $dirdest = $fileentry['path'].'/'.$dirdest;
513  @rename($dirsource, $dirdest);
514  }
515  }
516  }
517  }
518 
519  // Set new ref and current status
520  if (!$error) {
521  $this->ref = $numref;
522  $this->statut = 1;
523  }
524 
525  dol_syslog(get_class($this)."::valid ok");
526  }
527 
528  if (!$error) {
529  $this->db->commit();
530  return 1;
531  } else {
532  $this->db->rollback();
533  return -1;
534  }
535  }
536  }
537 
538  return -1;
539  } else {
540  $this->error = "NotAllowed";
541  dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
542  return -1;
543  }
544  }
545 
546  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
554  public function create_from_sending($user, $sending_id)
555  {
556  // phpcs:enable
557  global $conf;
558 
559  $expedition = new Expedition($this->db);
560  $result = $expedition->fetch($sending_id);
561  if ($result <= 0) {
562  return $result;
563  }
564 
565  $this->lines = array();
566 
567  $num = count($expedition->lines);
568  for ($i = 0; $i < $num; $i++) {
569  $line = new DeliveryLine($this->db);
570  $line->origin_line_id = $expedition->lines[$i]->origin_line_id;
571  $line->label = $expedition->lines[$i]->label;
572  $line->description = $expedition->lines[$i]->description;
573  $line->qty = $expedition->lines[$i]->qty_shipped;
574  $line->fk_product = $expedition->lines[$i]->fk_product;
575  if (!getDolGlobalString('MAIN_EXTRAFIELDS_DISABLED') && is_array($expedition->lines[$i]->array_options) && count($expedition->lines[$i]->array_options) > 0) { // For avoid conflicts if trigger used
576  $line->array_options = $expedition->lines[$i]->array_options;
577  }
578  $this->lines[$i] = $line;
579  }
580 
581  $this->origin = $expedition->element;
582  $this->origin_id = $expedition->id;
583  $this->note_private = $expedition->note_private;
584  $this->note_public = $expedition->note_public;
585  $this->fk_project = $expedition->fk_project;
586  $this->date_delivery = $expedition->date_delivery;
587  $this->fk_delivery_address = $expedition->fk_delivery_address;
588  $this->socid = $expedition->socid;
589  $this->ref_customer = $expedition->ref_customer;
590 
591  //Incoterms
592  $this->fk_incoterms = $expedition->fk_incoterms;
593  $this->location_incoterms = $expedition->location_incoterms;
594 
595  return $this->create($user);
596  }
597 
598  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
606  public function update_line($id, $array_options = [])
607  {
608  // phpcs:enable
609  global $conf;
610  $error = 0;
611 
612  if ($id > 0 && !$error && !getDolGlobalString('MAIN_EXTRAFIELDS_DISABLED') && is_array($array_options) && count($array_options) > 0) { // For avoid conflicts if trigger used
613  $line = new DeliveryLine($this->db);
614  $line->array_options = $array_options;
615  $line->id = $id;
616  $result = $line->insertExtraFields();
617 
618  if ($result < 0) {
619  $this->errors[] = $line->error;
620  $error++;
621  }
622  }
623 
624  if (!$error) {
625  return 1;
626  } else {
627  return -1;
628  }
629  }
630 
631 
640  public function addline($origin_id, $qty, $array_options = [])
641  {
642  global $conf;
643 
644  $num = count($this->lines);
645  $line = new DeliveryLine($this->db);
646 
647  $line->origin_id = $origin_id;
648  $line->qty = $qty;
649  if (!getDolGlobalString('MAIN_EXTRAFIELDS_DISABLED') && is_array($array_options) && count($array_options) > 0) { // For avoid conflicts if trigger used
650  $line->array_options = $array_options;
651  }
652  $this->lines[$num] = $line;
653  }
654 
661  public function deleteLine($lineid)
662  {
663  if ($this->statut == 0) {
664  $sql = "DELETE FROM ".MAIN_DB_PREFIX."commandedet";
665  $sql .= " WHERE rowid = ".((int) $lineid);
666 
667  if ($this->db->query($sql)) {
668  $this->update_price(1);
669 
670  return 1;
671  } else {
672  return -1;
673  }
674  }
675 
676  return 0;
677  }
678 
685  public function delete($user = null)
686  {
687  global $conf, $langs;
688 
689  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
690 
691  $this->db->begin();
692 
693  $error = 0;
694 
695  $sql = "DELETE FROM ".MAIN_DB_PREFIX."deliverydet";
696  $sql .= " WHERE fk_delivery = ".((int) $this->id);
697  if ($this->db->query($sql)) {
698  // Delete linked object
699  $res = $this->deleteObjectLinked();
700  if ($res < 0) {
701  $error++;
702  }
703 
704  if (!$error) {
705  $sql = "DELETE FROM ".MAIN_DB_PREFIX."delivery";
706  $sql .= " WHERE rowid = ".((int) $this->id);
707  if ($this->db->query($sql)) {
708  $this->db->commit();
709 
710  // Deleting pdf folder's draft On efface le repertoire de pdf provisoire
711  $ref = dol_sanitizeFileName($this->ref);
712  if (!empty($conf->expedition->dir_output)) {
713  $dir = $conf->expedition->dir_output.'/receipt/'.$ref;
714  $file = $dir.'/'.$ref.'.pdf';
715  if (file_exists($file)) {
716  if (!dol_delete_file($file)) {
717  return 0;
718  }
719  }
720  if (file_exists($dir)) {
721  if (!dol_delete_dir($dir)) {
722  $this->error = $langs->trans("ErrorCanNotDeleteDir", $dir);
723  return 0;
724  }
725  }
726  }
727 
728  // Call trigger
729  $result = $this->call_trigger('DELIVERY_DELETE', $user);
730  if ($result < 0) {
731  $this->db->rollback();
732  return -4;
733  }
734  // End call triggers
735 
736  return 1;
737  } else {
738  $this->error = $this->db->lasterror()." - sql=$sql";
739  $this->db->rollback();
740  return -3;
741  }
742  } else {
743  $this->error = $this->db->lasterror()." - sql=$sql";
744  $this->db->rollback();
745  return -2;
746  }
747  } else {
748  $this->error = $this->db->lasterror()." - sql=$sql";
749  $this->db->rollback();
750  return -1;
751  }
752  }
753 
760  public function getTooltipContentArray($params)
761  {
762  global $langs;
763 
764  $langs->load('deliveries');
765 
766  $datas = [];
767 
768  $datas['picto'] = img_picto('', $this->picto).' <u>'.$langs->trans("ShowReceiving").'</u>:<br>';
769  $datas['picto'] .= '<b>'.$langs->trans("Status").'</b>: '.$this->ref;
770 
771  return $datas;
772  }
773 
781  public function getNomUrl($withpicto = 0, $save_lastsearch_value = -1)
782  {
783  global $langs, $hookmanager;
784 
785  $result = '';
786 
787  $params = [
788  'id' => $this->id,
789  'objecttype' => $this->element,
790  ];
791  $classfortooltip = 'classfortooltip';
792  $dataparams = '';
793  if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
794  $classfortooltip = 'classforajaxtooltip';
795  $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
796  $label = '';
797  } else {
798  $label = implode($this->getTooltipContentArray($params));
799  }
800 
801  $url = DOL_URL_ROOT.'/delivery/card.php?id='.$this->id;
802 
803  //if ($option !== 'nolink')
804  //{
805  // Add param to save lastsearch_values or not
806  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
807  if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
808  $add_save_lastsearch_values = 1;
809  }
810  if ($add_save_lastsearch_values) {
811  $url .= '&save_lastsearch_values=1';
812  }
813  //}
814 
815  $linkstart = '<a href="'.$url.'"';
816  $linkstart .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
817  $linkstart .= $dataparams.' class="'.$classfortooltip.'">';
818  $linkend = '</a>';
819 
820  if ($withpicto) {
821  $result .= ($linkstart.img_object($label, $this->picto, $dataparams.' class="'.$classfortooltip.'"').$linkend);
822  }
823  if ($withpicto && $withpicto != 2) {
824  $result .= ' ';
825  }
826  $result .= $linkstart.$this->ref.$linkend;
827 
828  global $action;
829  $hookmanager->initHooks(array($this->element . 'dao'));
830  $parameters = array('id' => $this->id, 'getnomurl' => &$result);
831  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
832  if ($reshook > 0) {
833  $result = $hookmanager->resPrint;
834  } else {
835  $result .= $hookmanager->resPrint;
836  }
837  return $result;
838  }
839 
840  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
846  public function fetch_lines()
847  {
848  // phpcs:enable
849  $this->lines = array();
850 
851  $sql = "SELECT ld.rowid, ld.fk_product, ld.description, ld.subprice, ld.total_ht, ld.qty as qty_shipped, ld.fk_origin_line, ";
852  $sql .= " cd.qty as qty_asked, cd.label as custom_label, cd.fk_unit,";
853  $sql .= " p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc,";
854  $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";
855  $sql .= " FROM ".MAIN_DB_PREFIX."commandedet as cd, ".MAIN_DB_PREFIX."deliverydet as ld";
856  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p on p.rowid = ld.fk_product";
857  $sql .= " WHERE ld.fk_origin_line = cd.rowid";
858  $sql .= " AND ld.fk_delivery = ".((int) $this->id);
859 
860  dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
861  $resql = $this->db->query($sql);
862  if ($resql) {
863  $num = $this->db->num_rows($resql);
864  $i = 0;
865  while ($i < $num) {
866  $obj = $this->db->fetch_object($resql);
867 
868  $line = new DeliveryLine($this->db);
869 
870  $line->id = $obj->rowid;
871  $line->label = $obj->custom_label;
872  $line->description = $obj->description;
873  $line->fk_product = $obj->fk_product;
874  $line->qty_asked = $obj->qty_asked;
875  $line->qty_shipped = $obj->qty_shipped;
876 
877  $line->product_label = $obj->product_label; // Product label
878  $line->product_ref = $obj->product_ref; // Product ref
879  $line->product_desc = $obj->product_desc; // Product description
880  $line->product_type = $obj->fk_product_type;
881 
882  $line->fk_origin_line = $obj->fk_origin_line;
883 
884  $line->price = $obj->subprice;
885  $line->total_ht = $obj->total_ht;
886 
887  // units
888  $line->weight = $obj->weight;
889  $line->weight_units = $obj->weight_units;
890  $line->width = $obj->width;
891  $line->width_units = $obj->width_units;
892  $line->height = $obj->height;
893  $line->height_units = $obj->height_units;
894  $line->length = $obj->length;
895  $line->length_units = $obj->length_units;
896  $line->surface = $obj->surface;
897  $line->surface_units = $obj->surface_units;
898  $line->volume = $obj->volume;
899  $line->volume_units = $obj->volume_units;
900 
901  $line->fk_unit = $obj->fk_unit;
902  $line->fetch_optionals();
903 
904  $this->lines[$i] = $line;
905 
906  $i++;
907  }
908  $this->db->free($resql);
909 
910  return 1;
911  } else {
912  return -1;
913  }
914  }
915 
916 
923  public function getLibStatut($mode = 0)
924  {
925  return $this->LibStatut($this->statut, $mode);
926  }
927 
928  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
936  public function LibStatut($status, $mode)
937  {
938  // phpcs:enable
939  global $langs;
940 
941  if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
942  global $langs;
943  //$langs->load("mymodule");
944  $this->labelStatus[-1] = $langs->transnoentitiesnoconv('StatusDeliveryCanceled');
945  $this->labelStatus[0] = $langs->transnoentitiesnoconv('StatusDeliveryDraft');
946  $this->labelStatus[1] = $langs->transnoentitiesnoconv('StatusDeliveryValidated');
947  $this->labelStatusShort[-1] = $langs->transnoentitiesnoconv('StatusDeliveryCanceled');
948  $this->labelStatusShort[0] = $langs->transnoentitiesnoconv('StatusDeliveryDraft');
949  $this->labelStatusShort[1] = $langs->transnoentitiesnoconv('StatusDeliveryValidated');
950  }
951 
952  $statusType = 'status0';
953  if ($status == -1) {
954  $statusType = 'status5';
955  }
956  if ($status == 1) {
957  $statusType = 'status4';
958  }
959 
960  return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
961  }
962 
963 
971  public function initAsSpecimen()
972  {
973  $now = dol_now();
974 
975  // Load array of products prodids
976  $num_prods = 0;
977  $prodids = array();
978  $sql = "SELECT rowid";
979  $sql .= " FROM ".MAIN_DB_PREFIX."product";
980  $sql .= " WHERE entity IN (".getEntity('product').")";
981  $sql .= " AND tosell = 1";
982  $sql .= $this->db->plimit(100);
983 
984  $resql = $this->db->query($sql);
985  if ($resql) {
986  $num_prods = $this->db->num_rows($resql);
987  $i = 0;
988  while ($i < $num_prods) {
989  $i++;
990  $row = $this->db->fetch_row($resql);
991  $prodids[$i] = $row[0];
992  }
993  }
994 
995  // Initialise parameters
996  $this->id = 0;
997  $this->ref = 'SPECIMEN';
998  $this->specimen = 1;
999  $this->socid = 1;
1000  $this->date_delivery = $now;
1001  $this->note_public = 'Public note';
1002  $this->note_private = 'Private note';
1003 
1004  $i = 0;
1005  $line = new DeliveryLine($this->db);
1006  $line->fk_product = reset($prodids);
1007  $line->qty_asked = 10;
1008  $line->qty_shipped = 9;
1009  $line->ref = 'REFPROD';
1010  $line->label = 'Specimen';
1011  $line->description = 'Description';
1012  $line->price = 100;
1013  $line->total_ht = 100;
1014 
1015  $this->lines[$i] = $line;
1016 
1017  return 1;
1018  }
1019 
1026  public function getRemainingDelivered()
1027  {
1028  // Get the linked object
1029  $this->fetchObjectLinked('', '', $this->id, $this->element);
1030  //var_dump($this->linkedObjectsIds);
1031  // Get the product ref and qty in source
1032  $sqlSourceLine = "SELECT st.rowid, st.description, st.qty";
1033  $sqlSourceLine .= ", p.ref, p.label";
1034  $sqlSourceLine .= " FROM ".MAIN_DB_PREFIX.$this->linkedObjectsIds[0]['type']."det as st";
1035  $sqlSourceLine .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON st.fk_product = p.rowid";
1036  $sqlSourceLine .= " WHERE fk_".$this->linked_objects[0]['type']." = ".((int) $this->linked_objects[0]['linkid']);
1037 
1038  $resultSourceLine = $this->db->query($sqlSourceLine);
1039  if ($resultSourceLine) {
1040  $num_lines = $this->db->num_rows($resultSourceLine);
1041  $i = 0;
1042  $array = array();
1043  while ($i < $num_lines) {
1044  $objSourceLine = $this->db->fetch_object($resultSourceLine);
1045 
1046  // Get lines of sources already delivered
1047  $sql = "SELECT ld.fk_origin_line, sum(ld.qty) as qty";
1048  $sql .= " FROM ".MAIN_DB_PREFIX."deliverydet as ld, ".MAIN_DB_PREFIX."delivery as l,";
1049  $sql .= " ".MAIN_DB_PREFIX.$this->linked_objects[0]['type']." as c";
1050  $sql .= ", ".MAIN_DB_PREFIX.$this->linked_objects[0]['type']."det as cd";
1051  $sql .= " WHERE ld.fk_delivery = l.rowid";
1052  $sql .= " AND ld.fk_origin_line = cd.rowid";
1053  $sql .= " AND cd.fk_".$this->linked_objects[0]['type']." = c.rowid";
1054  $sql .= " AND cd.fk_".$this->linked_objects[0]['type']." = ".((int) $this->linked_objects[0]['linkid']);
1055  $sql .= " AND ld.fk_origin_line = ".((int) $objSourceLine->rowid);
1056  $sql .= " GROUP BY ld.fk_origin_line";
1057 
1058  $result = $this->db->query($sql);
1059  $row = $this->db->fetch_row($result);
1060 
1061  if ($objSourceLine->qty - $row[1] > 0) {
1062  if ($row[0] == $objSourceLine->rowid) {
1063  $array[$i]['qty'] = $objSourceLine->qty - $row[1];
1064  } else {
1065  $array[$i]['qty'] = $objSourceLine->qty;
1066  }
1067 
1068  $array[$i]['ref'] = $objSourceLine->ref;
1069  $array[$i]['label'] = $objSourceLine->label ? $objSourceLine->label : $objSourceLine->description;
1070  } elseif ($objSourceLine->qty - $row[1] < 0) {
1071  $array[$i]['qty'] = $objSourceLine->qty - $row[1]." Erreur livraison !";
1072  $array[$i]['ref'] = $objSourceLine->ref;
1073  $array[$i]['label'] = $objSourceLine->label ? $objSourceLine->label : $objSourceLine->description;
1074  }
1075 
1076  $i++;
1077  }
1078  return $array;
1079  } else {
1080  $this->error = $this->db->error()." - sql=$sqlSourceLine";
1081  return -1;
1082  }
1083  }
1084 
1092  public function setDeliveryDate($user, $delivery_date)
1093  {
1094  if ($user->hasRight('expedition', 'creer')) {
1095  $sql = "UPDATE ".MAIN_DB_PREFIX."delivery";
1096  $sql .= " SET date_delivery = ".($delivery_date ? "'".$this->db->idate($delivery_date)."'" : 'null');
1097  $sql .= " WHERE rowid = ".((int) $this->id);
1098 
1099  dol_syslog(get_class($this)."::setDeliveryDate", LOG_DEBUG);
1100  $resql = $this->db->query($sql);
1101  if ($resql) {
1102  $this->date_delivery = $delivery_date;
1103  return 1;
1104  } else {
1105  $this->error = $this->db->error();
1106  return -1;
1107  }
1108  } else {
1109  return -2;
1110  }
1111  }
1112 
1123  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1124  {
1125  global $conf, $langs;
1126 
1127  $langs->load("deliveries");
1128  $outputlangs->load("products");
1129 
1130  if (!dol_strlen($modele)) {
1131  $modele = 'typhon';
1132 
1133  if ($this->model_pdf) {
1134  $modele = $this->model_pdf;
1135  } elseif (getDolGlobalString('DELIVERY_ADDON_PDF')) {
1136  $modele = getDolGlobalString('DELIVERY_ADDON_PDF');
1137  }
1138  }
1139 
1140  $modelpath = "core/modules/delivery/doc/";
1141 
1142  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
1143  }
1144 
1153  public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
1154  {
1155  $tables = array(
1156  'delivery'
1157  );
1158 
1159  return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
1160  }
1161 
1170  public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
1171  {
1172  $tables = array(
1173  'deliverydet'
1174  );
1175 
1176  return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
1177  }
1178 }
1179 
1180 
1185 {
1189  public $db;
1190 
1194  public $element = 'deliverydet';
1195 
1199  public $table_element = 'deliverydet';
1200 
1204  public $label;
1205 
1209  public $description;
1210 
1215  public $ref;
1220  public $libelle;
1221 
1222  // From llx_expeditiondet
1223  public $qty;
1224  public $qty_asked;
1225  public $qty_shipped;
1226 
1227  public $fk_product;
1228  public $product_desc;
1229  public $product_type;
1230  public $product_ref;
1231  public $product_label;
1232 
1233  public $price;
1234 
1235  public $fk_origin_line;
1236  public $origin_id;
1237 
1241  public $origin_line_id;
1242 
1248  public $commande_ligne_id;
1249 
1250 
1256  public function __construct($db)
1257  {
1258  $this->db = $db;
1259  }
1260 }
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition: security.php:604
$object ref
Definition: info.php:79
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...
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.
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=0, $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.
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.
create_line($origin_id, $qty, $fk_product, $description, $array_options=[])
Create a line.
valid($user, $notrigger=0)
Validate object and update stock if option enabled.
__construct($db)
Constructor.
static replaceProduct(DoliDB $db, $origin_id, $dest_id)
Function used to replace a product id with another one.
deleteLine($lineid)
Delete line.
setDeliveryDate($user, $delivery_date)
Set the planned delivery date.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Create object on disk.
update_line($id, $array_options=[])
Update a livraison line (only extrafields)
addline($origin_id, $qty, $array_options=[])
Add line.
fetch($id)
Load a delivery receipt.
create($user)
Create delivery receipt in database.
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.
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('invoice') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&!getDolGlobalString('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') && $user->hasRight('tax', 'charges', 'lire')) if(isModEnabled('invoice') &&isModEnabled('order') && $user->hasRight("commande", "lire") &&!getDolGlobalString('WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER')) $sql
Social contributions to pay.
Definition: index.php:744
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:1438
dol_delete_dir($dir, $nophperrors=0)
Remove a directory (not recursive, so content must be empty).
Definition: files.lib.php:1564
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:63
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
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.
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 dolibarr global constant string value.
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
Active Directory does not allow anonymous connections.
Definition: repair.php:126