dolibarr 23.0.3
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-2025 Frédéric France <frederic.france@free.fr>
10 * Copyright (C) 2024-2025 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
32require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
33require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
34require_once DOL_DOCUMENT_ROOT.'/core/class/commonincoterm.class.php';
35require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
36if (isModEnabled("propal")) {
37 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
38}
39if (isModEnabled('order')) {
40 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
41}
42
43
48{
49 use CommonIncoterm;
50
54 public $element = "delivery";
55
60 public $TRIGGER_PREFIX = 'DELIVERY';
61
65 public $fk_element = "fk_delivery";
66
70 public $table_element = "delivery";
71
75 public $table_element_line = "deliverydet";
76
80 public $picto = 'sending';
81
85 public $draft;
86
90 public $socid;
91
95 public $ref_customer;
96
100 public $date_delivery;
101
105 public $date_valid;
106
110 public $model_pdf;
111
115 public $commande_id;
116
120 public $lines = array();
121
125 public $user_author_id;
126
127
128 const STATUS_DRAFT = 0;
129 const STATUS_VALIDATED = 1;
130 const STATUS_CANCELED = -1;
131
132
138 public function __construct($db)
139 {
140 $this->db = $db;
141
142 // List of short language codes for status
143 $this->labelStatus[-1] = 'StatusDeliveryCanceled';
144 $this->labelStatus[0] = 'StatusDeliveryDraft';
145 $this->labelStatus[1] = 'StatusDeliveryValidated';
146 }
147
154 public function create($user)
155 {
156 global $conf;
157
158 dol_syslog("Delivery::create");
159
160 if (empty($this->model_pdf)) {
161 $this->model_pdf = getDolGlobalString('DELIVERY_ADDON_PDF');
162 }
163
164 $error = 0;
165 $now = dol_now();
166 $this->ref_customer = trim((string) $this->ref_customer);
167
168 /* Delivery note as draft On positionne en mode draft le bon de livraison */
169 $this->draft = 1;
170
171 $this->user = $user;
172
173 $this->db->begin();
174
175 $sql = "INSERT INTO ".MAIN_DB_PREFIX."delivery (";
176 $sql .= "ref";
177 $sql .= ", entity";
178 $sql .= ", fk_soc";
179 $sql .= ", ref_customer";
180 $sql .= ", date_creation";
181 $sql .= ", fk_user_author";
182 $sql .= ", date_delivery";
183 $sql .= ", fk_address";
184 $sql .= ", note_private";
185 $sql .= ", note_public";
186 $sql .= ", model_pdf";
187 $sql .= ", fk_incoterms, location_incoterms";
188 $sql .= ") VALUES (";
189 $sql .= "'(PROV)'";
190 $sql .= ", ".((int) $conf->entity);
191 $sql .= ", ".((int) $this->socid);
192 $sql .= ", '".$this->db->escape($this->ref_customer)."'";
193 $sql .= ", '".$this->db->idate($now)."'";
194 $sql .= ", ".((int) $user->id);
195 $sql .= ", ".($this->date_delivery ? "'".$this->db->idate($this->date_delivery)."'" : "null");
196 $sql .= ", ".($this->fk_delivery_address > 0 ? $this->fk_delivery_address : "null");
197 $sql .= ", ".(!empty($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null");
198 $sql .= ", ".(!empty($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null");
199 $sql .= ", ".(!empty($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null");
200 $sql .= ", ".(int) $this->fk_incoterms;
201 $sql .= ", '".$this->db->escape($this->location_incoterms)."'";
202 $sql .= ")";
203
204 dol_syslog("Delivery::create", LOG_DEBUG);
205
206 $resql = $this->db->query($sql);
207 if ($resql) {
208 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."delivery");
209
210 $numref = "(PROV".$this->id.")";
211
212 $sql = "UPDATE ".MAIN_DB_PREFIX."delivery ";
213 $sql .= "SET ref = '".$this->db->escape($numref)."'";
214 $sql .= " WHERE rowid = ".((int) $this->id);
215
216 dol_syslog("Delivery::create", LOG_DEBUG);
217 $resql = $this->db->query($sql);
218 if ($resql) {
219 if (!getDolGlobalInt('MAIN_SUBMODULE_EXPEDITION')) {
220 $commande = new Commande($this->db);
221 $commande->id = $this->commande_id;
222 $commande->fetch_lines();
223 }
224
225
226 /*
227 * Inserting products into the database
228 */
229 $num = count($this->lines);
230 for ($i = 0; $i < $num; $i++) {
231 $origin_id = $this->lines[$i]->origin_line_id;
232 if (!$origin_id) {
233 $origin_id = $this->lines[$i]->commande_ligne_id; // For backward compatibility
234 }
235
236 if (!$this->create_line($origin_id, $this->lines[$i]->qty, $this->lines[$i]->fk_product, $this->lines[$i]->description, $this->lines[$i]->array_options)) {
237 $error++;
238 }
239 }
240
241 if (!$error && $this->id && $this->origin_id) {
242 $ret = $this->add_object_linked();
243 if (!$ret) {
244 $error++;
245 }
246
247 if (!getDolGlobalInt('MAIN_SUBMODULE_EXPEDITION')) {
248 $ret = $this->setStatut(2, $this->origin_id, $this->origin);
249 if (!$ret) {
250 $error++;
251 }
252 }
253 }
254
255 if (!$error) {
256 $this->db->commit();
257 return $this->id;
258 } else {
259 $error++;
260 $this->error = $this->db->lasterror()." - sql=".$this->db->lastqueryerror;
261 $this->db->rollback();
262 return -3;
263 }
264 } else {
265 $error++;
266 $this->error = $this->db->lasterror()." - sql=".$this->db->lastqueryerror;
267 $this->db->rollback();
268 return -2;
269 }
270 } else {
271 $error++;
272 $this->error = $this->db->lasterror()." - sql=".$this->db->lastqueryerror;
273 $this->db->rollback();
274 return -1;
275 }
276 }
277
278 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
289 public function create_line($origin_id, $qty, $fk_product, $description, $array_options = [])
290 {
291 // phpcs:enable
292 $error = 0;
293
294 $sql = "INSERT INTO ".MAIN_DB_PREFIX."deliverydet (fk_delivery, fk_origin_line,";
295 $sql .= " fk_product, description, qty)";
296 $sql .= " VALUES (".$this->id.",".((int) $origin_id).",";
297 $sql .= " ".($fk_product > 0 ? ((int) $fk_product) : "null").",";
298 $sql .= " ".($description ? "'".$this->db->escape($description)."'" : "null").",";
299 $sql .= (price2num($qty, 'MS')).")";
300
301 dol_syslog(get_class($this)."::create_line", LOG_DEBUG);
302 if (!$this->db->query($sql)) {
303 $error++;
304 }
305
306 $id = $this->db->last_insert_id(MAIN_DB_PREFIX."deliverydet");
307
308 if (is_array($array_options) && count($array_options) > 0) {
309 $line = new DeliveryLine($this->db);
310 $line->id = $id;
311 $line->array_options = $array_options;
312 $result = $line->insertExtraFields();
313 }
314
315 if (!$error) {
316 return 1;
317 }
318
319 return -1;
320 }
321
328 public function fetch($id)
329 {
330 $sql = "SELECT l.rowid, l.fk_soc, l.date_creation, l.date_valid, l.ref, l.ref_customer, l.fk_user_author,";
331 $sql .= " l.total_ht, l.fk_statut, l.fk_user_valid, l.note_private, l.note_public";
332 $sql .= ", l.date_delivery, l.fk_address, l.model_pdf";
333 $sql .= ", el.fk_source as origin_id, el.sourcetype as origin";
334 $sql .= ', l.fk_incoterms, l.location_incoterms';
335 $sql .= ", i.libelle as label_incoterms";
336 $sql .= " FROM ".MAIN_DB_PREFIX."delivery as l";
337 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = l.rowid AND el.targettype = '".$this->db->escape($this->element)."'";
338 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON l.fk_incoterms = i.rowid';
339 $sql .= " WHERE l.rowid = ".((int) $id);
340
341 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
342 $result = $this->db->query($sql);
343 if ($result) {
344 if ($this->db->num_rows($result)) {
345 $obj = $this->db->fetch_object($result);
346
347 $this->id = $obj->rowid;
348 $this->date_delivery = $this->db->jdate($obj->date_delivery);
349 $this->date_creation = $this->db->jdate($obj->date_creation);
350 $this->date_valid = $this->db->jdate($obj->date_valid);
351 $this->ref = $obj->ref;
352 $this->ref_customer = $obj->ref_customer;
353 $this->socid = $obj->fk_soc;
354 $this->statut = $obj->fk_statut;
355 $this->status = $obj->fk_statut;
356 $this->user_author_id = $obj->fk_user_author;
357 $this->user_validation_id = $obj->fk_user_valid;
358 $this->fk_delivery_address = $obj->fk_address;
359 $this->note = $obj->note_private; //TODO deprecated
360 $this->note_private = $obj->note_private;
361 $this->note_public = $obj->note_public;
362 $this->model_pdf = $obj->model_pdf;
363 $this->origin = $obj->origin; // May be 'shipping'
364 $this->origin_type = $obj->origin; // May be 'shipping'
365 $this->origin_id = $obj->origin_id; // May be id of shipping
366
367 //Incoterms
368 $this->fk_incoterms = $obj->fk_incoterms;
369 $this->location_incoterms = $obj->location_incoterms;
370 $this->label_incoterms = $obj->label_incoterms;
371 $this->db->free($result);
372
373 if ($this->status == 0) {
374 $this->draft = 1;
375 }
376
377 // Retrieve all extrafields
378 // fetch optionals attributes and labels
379 $this->fetch_optionals();
380
381 // Load lines
382 $result = $this->fetch_lines();
383 if ($result < 0) {
384 return -3;
385 }
386
387 return 1;
388 } else {
389 $this->error = 'Delivery with id '.$id.' not found sql='.$sql;
390 dol_syslog(get_class($this).'::fetch Error '.$this->error, LOG_ERR);
391 return -2;
392 }
393 } else {
394 $this->error = $this->db->error();
395 return -1;
396 }
397 }
398
406 public function valid($user, $notrigger = 0)
407 {
408 global $conf;
409
410 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
411
412 dol_syslog(get_class($this)."::valid begin");
413
414 if (!isset($this->socid)) {
415 dol_syslog(get_class($this)."::can't valid socid not set", LOG_WARNING);
416 return 0;
417 }
418
419 $this->db->begin();
420
421 $error = 0;
422
423 if ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'delivery', 'creer'))
424 || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'delivery_advance', 'validate'))) {
425 if (getDolGlobalString('DELIVERY_ADDON_NUMBER')) {
426 // Setting the command numbering module name
427 $modName = getDolGlobalString('DELIVERY_ADDON_NUMBER');
428
429 if (is_readable(DOL_DOCUMENT_ROOT.'/core/modules/delivery/'.$modName.'.php')) {
430 require_once DOL_DOCUMENT_ROOT.'/core/modules/delivery/'.$modName.'.php';
431
432 $now = dol_now();
433
434 // Retrieving the new reference
435 $objMod = new $modName($this->db);
436 '@phan-var-force ModeleNumRefDeliveryOrder $objMod';
438 $soc = new Societe($this->db);
439 $soc->fetch($this->socid);
440
441 if (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref)) { // empty should not happened, but when it occurs, the test save life
442 $numref = $objMod->getNextValue($soc, $this);
443 } else {
444 $numref = (string) $this->ref;
445 }
446 $this->newref = dol_sanitizeFileName($numref);
447
448 // Test if is not already in valid status. If so, we stop to avoid decrementing the stock twice.
449 $sql = "SELECT ref";
450 $sql .= " FROM ".MAIN_DB_PREFIX."delivery";
451 $sql .= " WHERE ref = '".$this->db->escape($numref)."'";
452 $sql .= " AND fk_statut <> 0";
453 $sql .= " AND entity = ".((int) $conf->entity);
454
455 $resql = $this->db->query($sql);
456 if ($resql) {
457 $num = $this->db->num_rows($resql);
458 if ($num > 0) {
459 return 0;
460 }
461 }
462
463 $sql = "UPDATE ".MAIN_DB_PREFIX."delivery SET";
464 $sql .= " ref = '".$this->db->escape($numref)."'";
465 $sql .= ", fk_statut = 1";
466 $sql .= ", date_valid = '".$this->db->idate($now)."'";
467 if (!empty($this->date_delivery)) {
468 $sql .= ", date_delivery = '".$this->db->idate($this->date_delivery)."'";
469 }
470 $sql .= ", fk_user_valid = ".((int) $user->id);
471 $sql .= " WHERE rowid = ".((int) $this->id);
472 $sql .= " AND fk_statut = 0";
473
474 $resql = $this->db->query($sql);
475 if (!$resql) {
476 dol_print_error($this->db);
477 $this->error = $this->db->lasterror();
478 $error++;
479 }
480
481 if (!$error && !$notrigger) {
482 // Call trigger
483 $result = $this->call_trigger('DELIVERY_VALIDATE', $user);
484 if ($result < 0) {
485 $error++;
486 }
487 // End call triggers
488 }
489
490 if (!$error) {
491 $this->oldref = $this->ref;
492
493 // Rename directory if dir was a temporary ref
494 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
495 // Now we rename also files into index
496 $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)."'";
497 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'expedition/receipt/".$this->db->escape($this->ref)."' and entity = ".((int) $conf->entity);
498 $resql = $this->db->query($sql);
499 if (!$resql) {
500 $error++;
501 $this->error = $this->db->lasterror();
502 }
503 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'expedition/receipt/".$this->db->escape($this->newref)."'";
504 $sql .= " WHERE filepath = 'expedition/receipt/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
505 $resql = $this->db->query($sql);
506 if (!$resql) {
507 $error++;
508 $this->error = $this->db->lasterror();
509 }
510
511 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
512 $oldref = dol_sanitizeFileName($this->ref);
513 $newref = dol_sanitizeFileName($numref);
514 $dirsource = $conf->expedition->dir_output.'/receipt/'.$oldref;
515 $dirdest = $conf->expedition->dir_output.'/receipt/'.$newref;
516 if (!$error && file_exists($dirsource)) {
517 dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
518
519 if (@rename($dirsource, $dirdest)) {
520 dol_syslog("Rename ok");
521 // Rename docs starting with $oldref with $newref
522 $listoffiles = dol_dir_list($conf->expedition->dir_output.'/receipt/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
523 foreach ($listoffiles as $fileentry) {
524 $dirsource = $fileentry['name'];
525 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
526 $dirsource = $fileentry['path'].'/'.$dirsource;
527 $dirdest = $fileentry['path'].'/'.$dirdest;
528 @rename($dirsource, $dirdest);
529 }
530 }
531 }
532 }
533
534 // Set new ref and current status
535 if (!$error) {
536 $this->ref = $numref;
537 $this->status = 1;
538 }
539
540 dol_syslog(get_class($this)."::valid ok");
541 }
542
543 if (!$error) {
544 $this->db->commit();
545 return 1;
546 } else {
547 $this->db->rollback();
548 return -1;
549 }
550 }
551 }
552
553 return -1;
554 } else {
555 $this->error = "NotAllowed";
556 dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
557 return -1;
558 }
559 }
560
561 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
569 public function create_from_sending($user, $sending_id)
570 {
571 // phpcs:enable
572 global $conf;
573
574 $expedition = new Expedition($this->db);
575 $result = $expedition->fetch($sending_id);
576 if ($result <= 0) {
577 return $result;
578 }
579
580 $this->lines = array();
581
582 $num = count($expedition->lines);
583 for ($i = 0; $i < $num; $i++) {
584 $line = new DeliveryLine($this->db);
585 $line->origin_line_id = $expedition->lines[$i]->origin_line_id;
586 $line->label = $expedition->lines[$i]->label;
587 $line->description = $expedition->lines[$i]->description;
588 $line->qty = $expedition->lines[$i]->qty_shipped;
589 $line->fk_product = $expedition->lines[$i]->fk_product;
590 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
591 $line->array_options = $expedition->lines[$i]->array_options;
592 }
593 $this->lines[$i] = $line;
594 }
595
596 $this->origin = $expedition->element;
597 $this->origin_id = $expedition->id;
598 $this->note_private = $expedition->note_private;
599 $this->note_public = $expedition->note_public;
600 $this->fk_project = $expedition->fk_project;
601 $this->date_delivery = ''; // Date of real reception. The Expedition->date_delivery is the planned one.
602 $this->fk_delivery_address = $expedition->fk_delivery_address;
603 $this->socid = $expedition->socid;
604 $this->ref_customer = $expedition->ref_customer;
605
606 //Incoterms
607 $this->fk_incoterms = $expedition->fk_incoterms;
608 $this->location_incoterms = $expedition->location_incoterms;
609
610 return $this->create($user);
611 }
612
613 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
621 public function update_line($id, $array_options = [])
622 {
623 // phpcs:enable
624 global $conf;
625 $error = 0;
626
627 if ($id > 0 && !$error && !getDolGlobalString('MAIN_EXTRAFIELDS_DISABLED') && is_array($array_options) && count($array_options) > 0) { // For avoid conflicts if trigger used
628 $line = new DeliveryLine($this->db);
629 $line->array_options = $array_options;
630 $line->id = $id;
631 $result = $line->insertExtraFields();
632
633 if ($result < 0) {
634 $this->errors[] = $line->error;
635 $error++;
636 }
637 }
638
639 if (!$error) {
640 return 1;
641 } else {
642 return -1;
643 }
644 }
645
646
655 public function addline($origin_id, $qty, $array_options = [])
656 {
657 $num = count($this->lines);
658 $line = new DeliveryLine($this->db);
659
660 $line->origin_id = $origin_id;
661 $line->qty = $qty;
662 if (!getDolGlobalString('MAIN_EXTRAFIELDS_DISABLED') && is_array($array_options) && count($array_options) > 0) { // For avoid conflicts if trigger used
663 $line->array_options = $array_options;
664 }
665 $this->lines[$num] = $line;
666 }
667
674 public function deleteLine($lineid)
675 {
676 if ($this->status == 0) {
677 $sql = "DELETE FROM ".MAIN_DB_PREFIX."commandedet";
678 $sql .= " WHERE rowid = ".((int) $lineid);
679
680 if ($this->db->query($sql)) {
681 $this->update_price(1);
682
683 return 1;
684 } else {
685 return -1;
686 }
687 }
688
689 return 0;
690 }
691
698 public function delete($user = null)
699 {
700 global $conf, $langs;
701
702 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
703
704 $this->db->begin();
705
706 $error = 0;
707
708 $sql = "DELETE FROM ".MAIN_DB_PREFIX."deliverydet";
709 $sql .= " WHERE fk_delivery = ".((int) $this->id);
710 if ($this->db->query($sql)) {
711 // Delete linked object
712 $res = $this->deleteObjectLinked();
713 if ($res < 0) {
714 $error++;
715 }
716
717 if (!$error) {
718 $sql = "DELETE FROM ".MAIN_DB_PREFIX."delivery";
719 $sql .= " WHERE rowid = ".((int) $this->id);
720 if ($this->db->query($sql)) {
721 $this->db->commit();
722
723 // Deleting pdf folder's draft On efface le repertoire de pdf provisoire
724 $ref = dol_sanitizeFileName($this->ref);
725 if (!empty($conf->expedition->dir_output)) {
726 $dir = $conf->expedition->dir_output.'/receipt/'.$ref;
727 $file = $dir.'/'.$ref.'.pdf';
728 if (file_exists($file)) {
729 if (!dol_delete_file($file)) {
730 return 0;
731 }
732 }
733 if (file_exists($dir)) {
734 if (!dol_delete_dir($dir)) {
735 $this->error = $langs->trans("ErrorCanNotDeleteDir", $dir);
736 return 0;
737 }
738 }
739 }
740
741 // Call trigger
742 $result = $this->call_trigger('DELIVERY_DELETE', $user);
743 if ($result < 0) {
744 $this->db->rollback();
745 return -4;
746 }
747 // End call triggers
748
749 return 1;
750 } else {
751 $this->error = $this->db->lasterror()." - sql=$sql";
752 $this->db->rollback();
753 return -3;
754 }
755 } else {
756 $this->error = $this->db->lasterror()." - sql=$sql";
757 $this->db->rollback();
758 return -2;
759 }
760 } else {
761 $this->error = $this->db->lasterror()." - sql=$sql";
762 $this->db->rollback();
763 return -1;
764 }
765 }
766
773 public function getTooltipContentArray($params)
774 {
775 global $langs;
776
777 $langs->load('sendings');
778
779 $datas = [];
780
781 $datas['picto'] = img_picto('', $this->picto, '', 0, 0, 0, '', 'paddingrightonly').' <u>'.$langs->trans("ShowReceiving").'</u>:<br>';
782 $datas['ref'] = '<b>'.$langs->trans("Ref").'</b>: '.$this->ref;
783
784 return $datas;
785 }
786
794 public function getNomUrl($withpicto = 0, $save_lastsearch_value = -1)
795 {
796 global $langs, $hookmanager;
797
798 $result = '';
799
800 $params = [
801 'id' => $this->id,
802 'objecttype' => $this->element,
803 ];
804 $classfortooltip = 'classfortooltip';
805 $dataparams = '';
806 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
807 $classfortooltip = 'classforajaxtooltip';
808 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
809 $label = '';
810 } else {
811 $label = implode($this->getTooltipContentArray($params));
812 }
813
814 $url = DOL_URL_ROOT.'/delivery/card.php?id='.$this->id;
815
816 //if ($option !== 'nolink')
817 //{
818 // Add param to save lastsearch_values or not
819 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
820 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
821 $add_save_lastsearch_values = 1;
822 }
823 if ($add_save_lastsearch_values) {
824 $url .= '&save_lastsearch_values=1';
825 }
826 //}
827
828 $linkstart = '<a href="'.$url.'"';
829 $linkstart .= ($label ? ' title="'.dolPrintHTMLForAttribute($label).'"' : ' title="tocomplete"');
830 $linkstart .= $dataparams.' class="'.$classfortooltip.'">';
831 $linkend = '</a>';
832
833 if ($withpicto) {
834 $result .= ($linkstart.img_object($label, $this->picto, $dataparams.' class="'.$classfortooltip.'"').$linkend);
835 }
836 if ($withpicto && $withpicto != 2) {
837 $result .= ' ';
838 }
839 $result .= $linkstart.$this->ref.$linkend;
840
841 global $action;
842 $hookmanager->initHooks(array($this->element . 'dao'));
843 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
844 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
845 if ($reshook > 0) {
846 $result = $hookmanager->resPrint;
847 } else {
848 $result .= $hookmanager->resPrint;
849 }
850 return $result;
851 }
852
853 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
859 public function fetch_lines()
860 {
861 // phpcs:enable
862 $this->lines = array();
863
864 $sql = "SELECT ld.rowid, ld.fk_product, ld.description, ld.subprice, ld.total_ht, ld.qty as qty_shipped, ld.fk_origin_line, ld.extraparams,";
865 $sql .= " cd.qty as qty_asked, cd.label as custom_label, cd.fk_unit,";
866 $sql .= " p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc,";
867 $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";
868 $sql .= " FROM ".MAIN_DB_PREFIX."commandedet as cd, ".MAIN_DB_PREFIX."deliverydet as ld";
869 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p on p.rowid = ld.fk_product";
870 $sql .= " WHERE ld.fk_origin_line = cd.rowid";
871 $sql .= " AND ld.fk_delivery = ".((int) $this->id);
872
873 dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
874 $resql = $this->db->query($sql);
875 if ($resql) {
876 $num = $this->db->num_rows($resql);
877 $i = 0;
878 while ($i < $num) {
879 $obj = $this->db->fetch_object($resql);
880
881 $line = new DeliveryLine($this->db);
882
883 $line->id = $obj->rowid;
884 $line->label = $obj->custom_label;
885 $line->description = $obj->description;
886 $line->fk_product = $obj->fk_product;
887 $line->qty_asked = $obj->qty_asked;
888 $line->qty_shipped = $obj->qty_shipped;
889
890 $line->product_label = $obj->product_label; // Product label
891 $line->product_ref = $obj->product_ref; // Product ref
892 $line->product_desc = $obj->product_desc; // Product description
893 $line->product_type = $obj->fk_product_type;
894
895 $line->fk_origin_line = $obj->fk_origin_line;
896
897 $line->price = $obj->subprice;
898 $line->total_ht = $obj->total_ht;
899
900 // units
901 $line->weight = $obj->weight;
902 $line->weight_units = $obj->weight_units;
903 $line->width = $obj->width;
904 $line->width_units = $obj->width_units;
905 $line->height = $obj->height;
906 $line->height_units = $obj->height_units;
907 $line->length = $obj->length;
908 $line->length_units = $obj->length_units;
909 $line->surface = $obj->surface;
910 $line->surface_units = $obj->surface_units;
911 $line->volume = $obj->volume;
912 $line->volume_units = $obj->volume_units;
913
914 $line->fk_unit = $obj->fk_unit;
915 $line->fetch_optionals();
916
917 $line->extraparams = !empty($obj->extraparams) ? (array) json_decode($obj->extraparams, true) : array();
918
919 $this->lines[$i] = $line;
920
921 $i++;
922 }
923 $this->db->free($resql);
924
925 return 1;
926 } else {
927 return -1;
928 }
929 }
930
931
938 public function getLibStatut($mode = 0)
939 {
940 return $this->LibStatut($this->status, $mode);
941 }
942
943 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
951 public function LibStatut($status, $mode)
952 {
953 // phpcs:enable
954 global $langs;
955
956 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
957 global $langs;
958 //$langs->load("mymodule");
959 $this->labelStatus[-1] = $langs->transnoentitiesnoconv('StatusDeliveryCanceled');
960 $this->labelStatus[0] = $langs->transnoentitiesnoconv('StatusDeliveryDraft');
961 $this->labelStatus[1] = $langs->transnoentitiesnoconv('StatusDeliveryValidated');
962 $this->labelStatusShort[-1] = $langs->transnoentitiesnoconv('StatusDeliveryCanceled');
963 $this->labelStatusShort[0] = $langs->transnoentitiesnoconv('StatusDeliveryDraft');
964 $this->labelStatusShort[1] = $langs->transnoentitiesnoconv('StatusDeliveryValidated');
965 }
966
967 $statusType = 'status0';
968 if ($status == -1) {
969 $statusType = 'status5';
970 }
971 if ($status == 1) {
972 $statusType = 'status4';
973 }
974
975 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
976 }
977
978
986 public function initAsSpecimen()
987 {
988 $now = dol_now();
989
990 // Load array of products prodids
991 $num_prods = 0;
992 $prodids = array();
993 $sql = "SELECT rowid";
994 $sql .= " FROM ".MAIN_DB_PREFIX."product";
995 $sql .= " WHERE entity IN (".getEntity('product').")";
996 $sql .= " AND tosell = 1";
997 $sql .= $this->db->plimit(100);
998
999 $resql = $this->db->query($sql);
1000 if ($resql) {
1001 $num_prods = $this->db->num_rows($resql);
1002 $i = 0;
1003 while ($i < $num_prods) {
1004 $i++;
1005 $row = $this->db->fetch_row($resql);
1006 $prodids[$i] = $row[0];
1007 }
1008 }
1009
1010 // Initialise parameters
1011 $this->id = 0;
1012 $this->ref = 'SPECIMEN';
1013 $this->specimen = 1;
1014 $this->socid = 1;
1015 $this->date_delivery = $now;
1016 $this->note_public = 'Public note';
1017 $this->note_private = 'Private note';
1018
1019 $i = 0;
1020 $line = new DeliveryLine($this->db);
1021 $line->fk_product = reset($prodids);
1022 $line->qty_asked = 10;
1023 $line->qty_shipped = 9;
1024 $line->product_ref = 'REFPROD';
1025 $line->label = 'Specimen';
1026 $line->description = 'Description';
1027 $line->price = 100;
1028 $line->total_ht = 100;
1029
1030 $this->lines[$i] = $line;
1031
1032 return 1;
1033 }
1034
1041 public function getRemainingDelivered()
1042 {
1043 // Get the linked object
1044 $this->fetchObjectLinked(null, '', $this->id, $this->element);
1045 //var_dump($this->linkedObjectsIds);
1046 // Get the product ref and qty in source
1047 $sqlSourceLine = "SELECT st.rowid, st.description, st.qty";
1048 $sqlSourceLine .= ", p.ref, p.label";
1049 $sqlSourceLine .= " FROM ".MAIN_DB_PREFIX.$this->linkedObjectsIds[0]['type']."det as st";
1050 $sqlSourceLine .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON st.fk_product = p.rowid";
1051 $sqlSourceLine .= " WHERE fk_".$this->linked_objects[0]['type']." = ".((int) $this->linked_objects[0]['linkid']);
1052
1053 $resultSourceLine = $this->db->query($sqlSourceLine);
1054 if ($resultSourceLine) {
1055 $num_lines = $this->db->num_rows($resultSourceLine);
1056 $i = 0;
1057 $array = array();
1058 while ($i < $num_lines) {
1059 $objSourceLine = $this->db->fetch_object($resultSourceLine);
1060
1061 // Get lines of sources already delivered
1062 $sql = "SELECT ld.fk_origin_line, sum(ld.qty) as qty";
1063 $sql .= " FROM ".MAIN_DB_PREFIX."deliverydet as ld, ".MAIN_DB_PREFIX."delivery as l,";
1064 $sql .= " ".MAIN_DB_PREFIX.$this->linked_objects[0]['type']." as c";
1065 $sql .= ", ".MAIN_DB_PREFIX.$this->linked_objects[0]['type']."det as cd";
1066 $sql .= " WHERE ld.fk_delivery = l.rowid";
1067 $sql .= " AND ld.fk_origin_line = cd.rowid";
1068 $sql .= " AND cd.fk_".$this->linked_objects[0]['type']." = c.rowid";
1069 $sql .= " AND cd.fk_".$this->linked_objects[0]['type']." = ".((int) $this->linked_objects[0]['linkid']);
1070 $sql .= " AND ld.fk_origin_line = ".((int) $objSourceLine->rowid);
1071 $sql .= " GROUP BY ld.fk_origin_line";
1072
1073 $result = $this->db->query($sql);
1074 $row = $this->db->fetch_row($result);
1075
1076 if ($objSourceLine->qty - $row[1] > 0) {
1077 if ($row[0] == $objSourceLine->rowid) {
1078 $array[$i]['qty'] = $objSourceLine->qty - $row[1];
1079 } else {
1080 $array[$i]['qty'] = $objSourceLine->qty;
1081 }
1082
1083 $array[$i]['ref'] = $objSourceLine->ref;
1084 $array[$i]['label'] = $objSourceLine->label ? $objSourceLine->label : $objSourceLine->description;
1085 } elseif ($objSourceLine->qty - $row[1] < 0) {
1086 $array[$i]['qty'] = $objSourceLine->qty - $row[1]." Erreur livraison !";
1087 $array[$i]['ref'] = $objSourceLine->ref;
1088 $array[$i]['label'] = $objSourceLine->label ? $objSourceLine->label : $objSourceLine->description;
1089 }
1090
1091 $i++;
1092 }
1093 return $array;
1094 } else {
1095 $this->error = $this->db->error()." - sql=$sqlSourceLine";
1096 return -1;
1097 }
1098 }
1099
1107 public function setDeliveryDate($user, $delivery_date)
1108 {
1109 if ($user->hasRight('expedition', 'creer')) {
1110 $sql = "UPDATE ".MAIN_DB_PREFIX."delivery";
1111 $sql .= " SET date_delivery = ".($delivery_date ? "'".$this->db->idate($delivery_date)."'" : 'null');
1112 $sql .= " WHERE rowid = ".((int) $this->id);
1113
1114 dol_syslog(get_class($this)."::setDeliveryDate", LOG_DEBUG);
1115 $resql = $this->db->query($sql);
1116 if ($resql) {
1117 $this->date_delivery = $delivery_date;
1118 return 1;
1119 } else {
1120 $this->error = $this->db->error();
1121 return -1;
1122 }
1123 } else {
1124 return -2;
1125 }
1126 }
1127
1138 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1139 {
1140 global $langs;
1141
1142 $langs->load("sendings");
1143 $outputlangs->load("products");
1144
1145 if (!dol_strlen($modele)) {
1146 $modele = 'typhon';
1147
1148 if ($this->model_pdf) {
1149 $modele = $this->model_pdf;
1150 } elseif (getDolGlobalString('DELIVERY_ADDON_PDF')) {
1151 $modele = getDolGlobalString('DELIVERY_ADDON_PDF');
1152 }
1153 }
1154
1155 $modelpath = "core/modules/delivery/doc/";
1156
1157 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
1158 }
1159
1168 public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
1169 {
1170 $tables = array(
1171 'delivery'
1172 );
1173
1174 return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
1175 }
1176
1185 public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
1186 {
1187 $tables = array(
1188 'deliverydet'
1189 );
1190
1191 return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
1192 }
1193}
1194
1195
1200{
1204 public $db;
1205
1209 public $element = 'deliverydet';
1210
1214 public $table_element = 'deliverydet';
1215
1219 public $label;
1220
1224 public $description;
1225
1231 public $ref;
1237 public $libelle;
1238
1239 // From llx_expeditiondet
1243 public $qty;
1244
1248 public $qty_asked;
1249
1253 public $qty_shipped;
1254
1258 public $fk_product;
1262 public $product_desc;
1266 public $product_type;
1270 public $product_ref;
1274 public $product_label;
1275
1279 public $price;
1280
1284 public $fk_origin_line;
1288 public $origin_id;
1289
1293 public $origin_line_id;
1294
1300 public $commande_ligne_id;
1301
1302
1308 public function __construct($db)
1309 {
1310 $this->db = $db;
1311 }
1312}
$object ref
Definition info.php:90
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).
setStatut($status, $elementId=null, $elementType='', $trigkey='', $fieldstatus='')
Set status of an object.
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.
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 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.
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.
__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()
Get data list of Products remaining to be delivered for an order (with qty)
getNomUrl($withpicto=0, $save_lastsearch_value=-1)
Return clickable name (with picto eventually)
Management class of delivery note lines.
__construct($db)
Constructor.
Class to manage Dolibarr database access.
Class to manage third parties objects (customers, suppliers, prospects...)
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
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after 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.
dol_delete_dir($dir, $nophperrors=0)
Remove a directory (not recursive, so content must be empty).
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_now($mode='gmt')
Return date for now.
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)
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
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.
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_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.
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:129