dolibarr 24.0.0-beta
expeditionligne.class.php
1<?php
2/* Copyright (C) 2003-2008 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerke@telenet.be>
5 * Copyright (C) 2006-2012 Laurent Destailleur <eldy@users.sourceforge.net>
6 * Copyright (C) 2011-2020 Juanjo Menent <jmenent@2byte.es>
7 * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
8 * Copyright (C) 2014 Cedric GROSS <c.gross@kreiz-it.fr>
9 * Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
10 * Copyright (C) 2014-2017 Francis Appels <francis.appels@yahoo.com>
11 * Copyright (C) 2015 Claudio Aschieri <c.aschieri@19.coop>
12 * Copyright (C) 2016-2024 Ferran Marcet <fmarcet@2byte.es>
13 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
14 * Copyright (C) 2018-2025 Frédéric France <frederic.france@free.fr>
15 * Copyright (C) 2020 Lenin Rivas <lenin@leninrivas.com>
16 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
17 * Copyright (C) 2025 Nick Fragoulis
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 3 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program. If not, see <https://www.gnu.org/licenses/>.
31 */
32
39require_once DOL_DOCUMENT_ROOT."/core/class/commonobjectline.class.php";
40require_once DOL_DOCUMENT_ROOT.'/expedition/class/expeditionlinebatch.class.php';
41
46{
50 public $element = 'expeditiondet';
51
55 public $table_element = 'expeditiondet';
56
60 public $parent_element = 'expedition';
61
65 public $fk_parent_attribute = 'fk_expedition';
66
73 public $line_id; // deprecated
74
78 public $fk_element;
79
83 public $origin_id;
84
88 public $fk_elementdet;
89
93 public $origin_line_id;
94
98 public $fk_parent;
99
103 public $element_type;
104
105
112 public $fk_origin; // Example: 'orderline'
113
117 public $fk_expedition;
118
122 public $db;
123
127 public $qty;
128
132 public $qty_shipped;
133
137 public $fk_product;
138
144 public $detail_batch;
145
150 public $detail_children;
151
156 public $details_entrepot;
157
158
162 public $entrepot_id;
163
164
168 public $qty_asked;
169
175 public $ref;
176
180 public $product_ref;
181
187 public $libelle;
188
192 public $product_label;
193
199 public $desc;
200
204 public $product_desc;
205
210 public $product_type = 0;
211
215 public $rang;
216
220 public $weight;
221
225 public $weight_units;
226
230 public $length;
231
235 public $length_units;
236
240 public $width;
241
245 public $width_units;
246
250 public $height;
251
255 public $height_units;
256
260 public $surface;
261
265 public $surface_units;
266
270 public $volume;
271
275 public $volume_units;
276
282 public $stockable_product = 1;
283
287 public $remise_percent;
288
292 public $tva_tx;
293
297 public $total_ht;
298
302 public $total_ttc;
303
307 public $total_tva;
308
312 public $total_localtax1;
313
317 public $total_localtax2;
318
319
325 public function __construct($db)
326 {
327 $this->db = $db;
328 }
329
336 public function fetch($rowid)
337 {
338 $sql = 'SELECT ed.rowid, ed.fk_expedition, ed.fk_entrepot, ed.description, ed.fk_unit, ed.fk_elementdet, ed.element_type, ed.qty, ed.rang, ed.extraparams';
339 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as ed';
340 $sql .= ' WHERE ed.rowid = '.((int) $rowid);
341 $result = $this->db->query($sql);
342 if ($result) {
343 $objp = $this->db->fetch_object($result);
344 $this->id = $objp->rowid;
345 $this->fk_expedition = $objp->fk_expedition;
346 $this->entrepot_id = $objp->fk_entrepot;
347 $this->description = $objp->description;
348 $this->fk_unit = $objp->fk_unit;
349 $this->fk_elementdet = $objp->fk_elementdet;
350 $this->element_type = $objp->element_type;
351 $this->qty = $objp->qty;
352 $this->rang = $objp->rang;
353
354 $this->extraparams = !empty($objp->extraparams) ? (array) json_decode($objp->extraparams, true) : array();
355
356 $this->db->free($result);
357
358 return 1;
359 } else {
360 $this->errors[] = $this->db->lasterror();
361 $this->error = $this->db->lasterror();
362 return -1;
363 }
364 }
365
373 public function insert($user = null, $notrigger = 0)
374 {
375 global $langs;
376 $error = 0;
377
378 $skip_check_parameters = false;
379
380 // Handling parent line subtotal line
381 if (!empty($this->element_type)
382 && !empty($this->fk_elementdet)
383 && $this->element_type == 'commande') {
384 $objectsrc_line = new OrderLine($this->db);
385 $objectsrc_line->fetch($this->fk_elementdet);
386 $skip_check_parameters = $objectsrc_line->special_code == SUBTOTALS_SPECIAL_CODE;
387 }
388
389 // Check parameters
390 $origin_id = $this->origin_id;
391 if ($origin_id > 0) {
392 if ((empty($this->fk_expedition)
393 || (empty($this->fk_elementdet) && empty($this->fk_parent)) // at least origin line id of parent line id is set
394 || !is_numeric($this->qty))
395 && !$skip_check_parameters) {
396 $langs->load('errors');
397 $this->errors[] = $langs->trans('ErrorMandatoryParametersNotProvided');
398 return -1;
399 }
400 } else {
401 if (empty($this->fk_expedition) || !is_numeric($this->qty)) {
402 $langs->load('errors');
403 $this->errors[] = $langs->trans('ErrorMandatoryParametersNotProvided');
404 return -1;
405 }
406 }
407 $this->db->begin();
408
409 if (getDolGlobalString('STOCK_EXPEDITION_NO_MORE_THAN_ORDER') && !empty($this->fk_elementdet) && !empty($this->fk_expedition)) {
410 $this->checkQtyVsOrderLine($this->fk_elementdet, $this->qty, 0);
411 if (!empty($this->error)) {
412 $this->db->rollback();
413 return -5;
414 }
415 }
416
417 if (empty($this->rang)) {
418 $this->rang = 0;
419 }
420
421 // Rank to use
422 $ranktouse = $this->rang;
423 if ($ranktouse == -1) {
424 $rangmax = $this->line_max($this->fk_expedition);
425 $ranktouse = $rangmax + 1;
426 }
427
428 $sql = "INSERT INTO ".MAIN_DB_PREFIX."expeditiondet (";
429 $sql .= "fk_expedition";
430 $sql .= ", fk_entrepot";
431 $sql .= ", fk_elementdet";
432 $sql .= ", fk_parent";
433 $sql .= ", fk_product";
434 $sql .= ", element_type";
435 $sql .= ", qty";
436 $sql .= ", fk_unit";
437 $sql .= ", description";
438 $sql .= ", rang";
439 $sql .= ") VALUES (";
440 $sql .= $this->fk_expedition;
441 $sql .= ", ".(empty($this->entrepot_id) ? 'NULL' : $this->entrepot_id);
442 $sql .= ", ".(empty($this->fk_elementdet) ? 'NULL' : $this->fk_elementdet);
443 $sql .= ", ".(empty($this->fk_parent) ? 'NULL' : $this->fk_parent);
444 $sql .= ", ".(empty($this->fk_product) ? 'NULL' : $this->fk_product);
445 $sql .= ", '".(empty($this->element_type) ? 'order' : $this->db->escape($this->element_type))."'";
446 $sql .= ", ".price2num($this->qty, 'MS');
447 $sql .= ", ".((int) $this->fk_unit);
448 $sql .= ", '".(empty($this->description) ? '' : $this->db->escape($this->description))."'";
449 $sql .= ", ".((int) $ranktouse);
450 $sql .= ")";
451
452 dol_syslog(get_class($this)."::insert", LOG_DEBUG);
453 $resql = $this->db->query($sql);
454 if ($resql) {
455 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."expeditiondet");
456
457 if (!$error) {
458 $result = $this->insertExtraFields();
459 if ($result < 0) {
460 $error++;
461 }
462 }
463
464 if (!$error && !$notrigger) {
465 // Call trigger
466 $result = $this->call_trigger('LINESHIPPING_INSERT', $user);
467 if ($result < 0) {
468 $error++;
469 }
470 // End call triggers
471 }
472
473 if ($error) {
474 foreach ($this->errors as $errmsg) {
475 dol_syslog(__METHOD__.' '.$errmsg, LOG_ERR);
476 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
477 }
478 }
479 } else {
480 $error++;
481 }
482
483 if ($error) {
484 $this->db->rollback();
485 return -1;
486 } else {
487 $this->db->commit();
488 return $this->id;
489 }
490 }
491
500 public function findAllChild($line_id, &$list = array(), $mode = 0)
501 {
502 if ($line_id > 0) {
503 // find all child
504 $sql = "SELECT ed.rowid as child_line_id";
505 if ($mode == 1) {
506 $sql .= ", ed.fk_product";
507 $sql .= ", ed.fk_parent";
508 $sql .= ", " . $this->db->ifsql('eb.rowid IS NULL', 'ed.qty', 'eb.qty') . " as qty";
509 $sql .= ", " . $this->db->ifsql('eb.rowid IS NULL', 'ed.fk_entrepot', 'eb.fk_warehouse') . " as fk_warehouse";
510 $sql .= ", eb.batch, eb.eatby, eb.sellby";
511 }
512 $sql .= " FROM " . $this->db->prefix() . $this->table_element . " as ed";
513 $sql .= " LEFT JOIN " . $this->db->prefix() . "expeditiondet_batch as eb ON eb.fk_expeditiondet = " . ((int) $line_id);
514 $sql .= " WHERE ed.fk_parent = " . ((int) $line_id);
515 $sql .= $this->db->order('ed.fk_product,ed.rowid', 'ASC,ASC');
516
517 $resql = $this->db->query($sql);
518 if ($resql) {
519 while ($obj = $this->db->fetch_object($resql)) {
520 $child_line_id = (int) $obj->child_line_id;
521 if (!isset($list[$line_id])) {
522 $list[$line_id] = array();
523 }
524
525 if ($mode == 0) {
526 $list[$line_id][] = $child_line_id;
527 } elseif ($mode == 1) {
528 $line_obj = new stdClass();
529 $line_obj->rowid = $child_line_id;
530 $line_obj->fk_product = $obj->fk_product;
531 $line_obj->fk_parent = $obj->fk_parent;
532 $line_obj->qty = $obj->qty;
533 $line_obj->fk_warehouse = $obj->fk_warehouse;
534 $line_obj->batch = $obj->batch;
535 $line_obj->eatby = $obj->eatby;
536 $line_obj->sellby = $obj->sellby;
537 $line_obj->iskit = 0;
538 $line_obj->incdec = 0;
539 $list[$line_id][] = $line_obj;
540 }
541
542 $this->findAllChild($child_line_id, $list, $mode);
543 }
544 $this->db->free($resql);
545 } else {
546 $this->error = $this->db->lasterror();
547 $this->errors[] = $this->error;
548 dol_syslog(__METHOD__.' '.$this->error, LOG_ERR);
549 }
550 }
551
552 return 1;
553 }
554
562 public function delete($user = null, $notrigger = 0)
563 {
564 $error = 0;
565
566 $this->db->begin();
567
568 // virtual products : delete all children and batch
569 if (getDolGlobalInt('PRODUIT_SOUSPRODUITS') && !($this->fk_parent > 0)) {
570 // find all children
571 $line_id_list = array();
572 $result = $this->findAllChild($this->id, $line_id_list);
573 if ($result) {
574 $child_line_id_list = array_reverse($line_id_list, true);
575 foreach ($child_line_id_list as $child_line_id_arr) {
576 foreach ($child_line_id_arr as $child_line_id) {
577 // delete batch expedition line
578 if (isModEnabled('productbatch')) {
579 $sql = "DELETE FROM " . $this->db->prefix() . "expeditiondet_batch";
580 $sql .= " WHERE fk_expeditiondet = " . ((int) $child_line_id);
581 if (!$this->db->query($sql)) {
582 $error++;
583 $this->errors[] = $this->db->lasterror() . " - sql=$sql";
584 }
585 }
586
587 $sql = "DELETE FROM " . $this->db->prefix() . "expeditiondet";
588 $sql .= " WHERE rowid = " . ((int) $child_line_id);
589 if (!$this->db->query($sql)) {
590 $error++;
591 $this->errors[] = $this->db->lasterror() . " - sql=$sql";
592 }
593
594 if ($error) {
595 break;
596 }
597 }
598 if ($error) {
599 break;
600 }
601 }
602 } else {
603 $error++;
604 }
605 }
606
607 if (!$error) {
608 // delete batch expedition line
609 if (isModEnabled('productbatch')) {
610 $sql = "DELETE FROM ".$this->db->prefix()."expeditiondet_batch";
611 $sql .= " WHERE fk_expeditiondet = ".((int) $this->id);
612
613 if (!$this->db->query($sql)) {
614 $this->errors[] = $this->db->lasterror()." - sql=$sql";
615 $error++;
616 }
617 }
618
619 $sql = "DELETE FROM ".$this->db->prefix()."expeditiondet";
620 $sql .= " WHERE rowid = ".((int) $this->id);
621
622 if (!$error && $this->db->query($sql)) {
623 // Remove extrafields
624 if (!$error) {
625 $result = $this->deleteExtraFields();
626 if ($result < 0) {
627 $this->errors[] = $this->error;
628 $error++;
629 }
630 }
631 if (!$error && !$notrigger) {
632 // Call trigger
633 $result = $this->call_trigger('LINESHIPPING_DELETE', $user);
634 if ($result < 0) {
635 $this->errors[] = $this->error;
636 $error++;
637 }
638 // End call triggers
639 }
640 } else {
641 $this->errors[] = $this->db->lasterror()." - sql=$sql";
642 $error++;
643 }
644 }
645
646 if (!$error) {
647 $this->db->commit();
648 return 1;
649 } else {
650 foreach ($this->errors as $errmsg) {
651 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
652 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
653 }
654 $this->db->rollback();
655 return -1 * $error;
656 }
657 }
658
666 public function update($user = null, $notrigger = 0)
667 {
668 global $langs;
669 $error = 0;
670
671 dol_syslog(get_class($this)."::update id=$this->id, entrepot_id=$this->entrepot_id, product_id=$this->fk_product, qty=$this->qty");
672
673 $this->db->begin();
674
675 if (!empty($this->id) && empty($this->fk_elementdet)) {
676 $sql = "SELECT fk_elementdet FROM ".MAIN_DB_PREFIX."expeditiondet";
677 $sql .= " WHERE rowid = ".((int) $this->id);
678 $resql = $this->db->query($sql);
679 if ($resql) {
680 $obj = $this->db->fetch_object($resql);
681 if ($obj) {
682 $this->fk_elementdet = $obj->fk_elementdet;
683 }
684 }
685 }
686
687 if (getDolGlobalString('STOCK_EXPEDITION_NO_MORE_THAN_ORDER') && !empty($this->fk_elementdet)) {
688 $qty_to_check = $this->qty;
689 if (!empty($this->detail_batch)) {
690 if (is_array($this->detail_batch)) {
691 $qty_to_check = array_sum(array_column($this->detail_batch, 'qty'));
692 } else {
693 $qty_to_check = $this->detail_batch->qty;
694 }
695 }
696 $this->checkQtyVsOrderLine($this->fk_elementdet, $qty_to_check, $this->id);
697 if (!empty($this->error)) {
698 $this->db->rollback();
699 return -5;
700 }
701 }
702
703 // Clean parameters
704 if (empty($this->qty)) {
705 $this->qty = 0;
706 }
707 $qty = price2num($this->qty);
708 $fk_unit = $this->fk_unit;
709 $remainingQty = 0;
710 $batch = null;
711 $batch_id = 0;
712 $expedition_batch_id = 0;
713 $origin_id = $this->origin_id;
714 if ($origin_id > 0) {
715 if (is_array($this->detail_batch)) { // array of ExpeditionLineBatch
716 if (count($this->detail_batch) > 1) {
717 dol_syslog(get_class($this).'::update only possible for one batch', LOG_ERR);
718 $this->errors[] = 'ErrorBadParameters';
719 $error++;
720 } else {
721 $batch = $this->detail_batch[0]->batch;
722 $batch_id = $this->detail_batch[0]->fk_origin_stock;
723 $expedition_batch_id = $this->detail_batch[0]->id;
724 if ($this->entrepot_id != $this->detail_batch[0]->entrepot_id) {
725 dol_syslog(get_class($this).'::update only possible for batch of same warehouse', LOG_ERR);
726 $this->errors[] = 'ErrorBadParameters';
727 $error++;
728 }
729 $qty = price2num($this->detail_batch[0]->qty);
730 }
731 } elseif (!empty($this->detail_batch)) {
732 $batch = $this->detail_batch->batch;
733 $batch_id = $this->detail_batch->fk_origin_stock;
734 $expedition_batch_id = $this->detail_batch->id;
735 if ($this->entrepot_id != $this->detail_batch->entrepot_id) {
736 dol_syslog(get_class($this).'::update only possible for batch of same warehouse', LOG_ERR);
737 $this->errors[] = 'ErrorBadParameters';
738 $error++;
739 }
740 $qty = price2num($this->detail_batch->qty);
741 }
742
743 // check parameters
744 if (!isset($this->id) || !isset($this->entrepot_id)) {
745 dol_syslog(get_class($this).'::update missing line id and/or warehouse id', LOG_ERR);
746 $langs->load('errors');
747 $this->errors[] = $langs->trans('ErrorMandatoryParametersNotProvided');
748 $error++;
749 return -1;
750 }
751
752 // update lot
753 if (!empty($batch) && isModEnabled('productbatch')) {
754 $batch_id_str = $batch_id ?? 'null';
755 dol_syslog(get_class($this)."::update expedition batch id=$expedition_batch_id, batch_id=$batch_id_str, batch=$batch");
756
757 if (empty($batch_id) || empty($this->fk_product)) {
758 dol_syslog(get_class($this).'::update missing fk_origin_stock (batch_id) and/or fk_product', LOG_ERR);
759 $langs->load('errors');
760 $this->errors[] = $langs->trans('ErrorMandatoryParametersNotProvided');
761 $error++;
762 }
763
764 // fetch remaining lot qty
765 $shipmentlinebatch = new ExpeditionLineBatch($this->db);
766 $lotArray = $shipmentlinebatch->fetchAll($this->id);
767 if (!$error && $lotArray < 0) {
768 $this->errors[] = $this->db->lasterror()." - ExpeditionLineBatch::fetchAll";
769 $error++;
770 } else {
771 // calculate new total line qty
772 foreach ($lotArray as $lot) {
773 if ($expedition_batch_id != $lot->id) {
774 $remainingQty += $lot->qty;
775 }
776 }
777 $qty += $remainingQty;
778
779 //fetch lot details
780 // fetch from product_lot
781 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
782 $lot = new Productlot($this->db);
783 if ($lot->fetch(0, $this->fk_product, $batch) < 0) {
784 $this->errors = array_merge($this->errors, $lot->errors);
785 $error++;
786 }
787 if (!$error && !empty($expedition_batch_id)) {
788 // delete lot expedition line
789 $sql = "DELETE FROM ".MAIN_DB_PREFIX."expeditiondet_batch";
790 $sql .= " WHERE fk_expeditiondet = ".((int) $this->id);
791 $sql .= " AND rowid = ".((int) $expedition_batch_id);
792
793 if (!$this->db->query($sql)) {
794 $this->errors[] = $this->db->lasterror()." - sql=$sql";
795 $error++;
796 }
797 }
798 if (!$error && $this->detail_batch->qty > 0) {
799 // create lot expedition line
800 if (isset($lot->id)) {
801 $shipmentLot = new ExpeditionLineBatch($this->db);
802 $shipmentLot->batch = $lot->batch;
803 $shipmentLot->eatby = $lot->eatby;
804 $shipmentLot->sellby = $lot->sellby;
805 $shipmentLot->fk_warehouse = $this->detail_batch->entrepot_id;
806 $shipmentLot->qty = $this->detail_batch->qty;
807 $shipmentLot->fk_origin_stock = (int) $batch_id;
808 if ($shipmentLot->create($this->id) < 0) {
809 $this->errors = $shipmentLot->errors;
810 $error++;
811 }
812 }
813 }
814 }
815 }
816 }
817 if (!$error) {
818 // update line
819 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
820 $sql .= " fk_entrepot = ".($this->entrepot_id > 0 ? $this->entrepot_id : 'null');
821 $sql .= " , qty = ".((float) price2num($qty, 'MS'));
822 $sql .= " , fk_unit = ".((int) $this->fk_unit);
823 $sql .= " WHERE rowid = ".((int) $this->id);
824
825 if (!$this->db->query($sql)) {
826 $this->errors[] = $this->db->lasterror()." - sql=$sql";
827 $error++;
828 }
829 }
830
831 if (!$error) {
832 $result = $this->insertExtraFields();
833 if ($result < 0) {
834 $this->errors[] = $this->error;
835 $error++;
836 }
837 }
838
839 if (!$error && !$notrigger) {
840 // Call trigger
841 $result = $this->call_trigger('LINESHIPPING_MODIFY', $user);
842 if ($result < 0) {
843 $this->errors[] = $this->error;
844 $error++;
845 }
846 // End call triggers
847 }
848 if (!$error) {
849 $this->db->commit();
850 return 1;
851 } else {
852 foreach ($this->errors as $errmsg) {
853 dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
854 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
855 }
856 $this->db->rollback();
857 return -1 * $error;
858 }
859 }
860
870 private function checkQtyVsOrderLine(int $fk_elementdet, float $qty, int $exclude_line_id): bool
871 {
872 global $langs;
873
874 // Ordered quantity on the source order line
875 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
876 $orderline = new OrderLine($this->db);
877 if ($orderline->fetch($fk_elementdet) <= 0) {
878 return true; // Order line not found, skip check
879 }
880 if ($orderline->product_type == 9) {
881 return true; // Skip check for title/separator lines, they have no deliverable quantity
882 }
883 $qty_ordered = (float) $orderline->qty;
884
885 // Quantity already shipped on other shipment lines
886 $sql = "SELECT COALESCE(SUM(ed.qty), 0) as qty_shipped";
887 $sql .= " FROM ".MAIN_DB_PREFIX."expeditiondet as ed";
888 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."expedition as e ON e.rowid = ed.fk_expedition";
889 $sql .= " WHERE ed.fk_elementdet = ".((int) $fk_elementdet);
890 $sql .= " AND e.fk_statut >= 0"; // exclude only deleted ones
891 if ($exclude_line_id > 0) {
892 $sql .= " AND ed.rowid != ".((int) $exclude_line_id); // exclude current line being edited
893 }
894
895 $resql = $this->db->query($sql);
896 if (!$resql) {
897 return true;
898 }
899 $obj = $this->db->fetch_object($resql);
900 $qty_already_shipped = $obj ? (float) $obj->qty_shipped : 0;
901
902 $qty_remaining = $qty_ordered - $qty_already_shipped;
903
904 if ($qty > $qty_remaining) {
905 $langs->load('errors');
906 $this->error = $langs->trans('ErrorExpeditionQtyTooHigh', $qty, max(0, $qty_remaining));
907 return false;
908 }
909
910 return true;
911 }
912}
deleteExtraFields()
Delete all extra fields values for the current object.
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
Class to manage lines of shipment.
insert($user=null, $notrigger=0)
Insert line into database.
fetch($rowid)
Load line expedition.
findAllChild($line_id, &$list=array(), $mode=0)
Find all children.
__construct($db)
Constructor.
checkQtyVsOrderLine(int $fk_elementdet, float $qty, int $exclude_line_id)
Check that qty to ship does not exceed remaining qty on order line.
update($user=null, $notrigger=0)
Update a line in database.
CRUD class for batch number management within shipment.
Class to manage order lines.
Class with list of lots and properties.
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.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
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.