41require_once DOL_DOCUMENT_ROOT.
'/core/class/commonobject.class.php';
42require_once DOL_DOCUMENT_ROOT.
"/expedition/class/expeditionligne.class.php";
43require_once DOL_DOCUMENT_ROOT.
'/core/class/commonincoterm.class.php';
45 require_once DOL_DOCUMENT_ROOT.
'/comm/propal/class/propal.class.php';
48 require_once DOL_DOCUMENT_ROOT.
'/commande/class/commande.class.php';
50require_once DOL_DOCUMENT_ROOT.
'/expedition/class/expeditionlinebatch.class.php';
51require_once DOL_DOCUMENT_ROOT.
'/core/class/commonsignedobject.class.php';
52require_once DOL_DOCUMENT_ROOT.
'/subtotals/class/commonsubtotal.class.php';
62 use CommonSignedObject;
68 public $element =
"shipping";
73 public $fk_element =
"fk_expedition";
78 public $table_element =
"expedition";
83 public $table_element_line =
"expeditiondet";
88 public $class_element_line =
'ExpeditionLigne';
93 public $picto =
'dolly';
99 public $fields = array();
105 public $user_author_id;
111 public $fk_user_author;
117 public $fk_user_valid;
134 public $ref_customer;
144 public $tracking_number;
149 public $tracking_url;
162 public $weight_units;
178 public $height_units;
195 public $livraison_id;
200 public $multicurrency_subprice;
230 public $date_delivery;
244 public $date_expedition;
250 public $date_shipping;
279 public $lines = array();
285 public $fk_multicurrency;
290 public $multicurrency_code;
294 public $multicurrency_tx;
298 public $multicurrency_total_ht;
302 public $multicurrency_total_tva;
306 public $multicurrency_total_ttc;
351 $this->ismultientitymanaged = 1;
352 $this->isextrafieldmanaged = 1;
355 $this->labelStatus = array();
356 $this->labelStatus[-1] =
'StatusSendingCanceled';
357 $this->labelStatus[0] =
'StatusSendingDraft';
358 $this->labelStatus[1] =
'StatusSendingValidated';
359 $this->labelStatus[2] =
'StatusSendingProcessed';
362 $this->labelStatusShort = array();
363 $this->labelStatusShort[-1] =
'StatusSendingCanceledShort';
364 $this->labelStatusShort[0] =
'StatusSendingDraftShort';
365 $this->labelStatusShort[1] =
'StatusSendingValidatedShort';
366 $this->labelStatusShort[2] =
'StatusSendingProcessedShort';
375 public function getNextNumRef($soc)
377 global $langs,
$conf;
378 $langs->load(
"sendings");
387 $dirmodels = array_merge(array(
'/'), (array)
$conf->modules_parts[
'models']);
389 foreach ($dirmodels as $reldir) {
393 $mybool = ((bool) @include_once $dir.$file) || $mybool;
397 dol_print_error(
null,
"Failed to include file ".$file);
401 $obj =
new $classname();
402 '@phan-var-force ModelNumRefExpedition $obj';
404 $numref = $obj->getNextValue($soc, $this);
409 dol_print_error($this->db, get_class($this).
"::getNextNumRef ".$obj->error);
413 print $langs->trans(
"Error").
" ".$langs->trans(
"Error_EXPEDITION_ADDON_NUMBER_NotDefined");
425 public function create($user, $notrigger = 0)
429 require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
434 $this->tracking_number = preg_replace(
'/\s+/',
'', $this->tracking_number);
436 if (empty($this->fk_project)) {
437 $this->fk_project = 0;
439 if (empty($this->date_creation)) {
440 $this->date_creation = $now;
442 if (empty($this->date_shipping) && !empty($this->date_expedition)) {
443 $this->date_shipping = $this->date_expedition;
451 $sql =
"INSERT INTO ".MAIN_DB_PREFIX.
"expedition (";
454 $sql .=
", ref_customer";
456 $sql .=
", date_creation";
457 $sql .=
", fk_user_author";
458 $sql .=
", date_expedition";
459 $sql .=
", date_delivery";
461 $sql .=
", fk_projet";
462 $sql .=
", fk_address";
463 $sql .=
", fk_shipping_method";
464 $sql .=
", tracking_number";
469 $sql .=
", weight_units";
470 $sql .=
", size_units";
471 $sql .=
", note_private";
472 $sql .=
", note_public";
473 $sql .=
", model_pdf";
474 $sql .=
", fk_incoterms, location_incoterms";
475 $sql .=
", signed_status";
477 $sql .=
") VALUES (";
479 $sql .=
", ".((int) $this->entity);
480 $sql .=
", ".($this->ref_customer ?
"'".$this->db->escape($this->ref_customer).
"'" :
"null");
481 $sql .=
", ".($this->ref_ext ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null");
482 $sql .=
", '".$this->db->idate($this->date_creation).
"'";
483 $sql .=
", ".((int) $user->id);
484 $sql .=
", ".($this->date_shipping > 0 ?
"'".$this->db->idate($this->date_shipping).
"'" :
"null");
485 $sql .=
", ".($this->date_delivery > 0 ?
"'".$this->db->idate($this->date_delivery).
"'" :
"null");
486 $sql .=
", ".($this->socid > 0 ? ((int) $this->socid) :
"null");
487 $sql .=
", ".($this->fk_project > 0 ? ((int) $this->fk_project) :
"null");
488 $sql .=
", ".($this->fk_delivery_address > 0 ? ((int) $this->fk_delivery_address) :
"null");
489 $sql .=
", ".($this->shipping_method_id > 0 ? ((int) $this->shipping_method_id) :
"null");
490 $sql .=
", '".$this->db->escape($this->tracking_number).
"'";
491 $sql .=
", ".(is_numeric($this->weight) ? (float) $this->weight :
'NULL');
492 $sql .=
", ".(is_numeric($this->sizeS) ? (float) $this->sizeS :
'NULL');
493 $sql .=
", ".(is_numeric($this->sizeW) ? (float) $this->sizeW :
'NULL');
494 $sql .=
", ".(is_numeric($this->sizeH) ? (float) $this->sizeH :
'NULL');
495 $sql .=
", ".($this->weight_units !=
'' ? (int) $this->weight_units :
'NULL');
496 $sql .=
", ".($this->size_units !=
'' ? (int) $this->size_units :
'NULL');
497 $sql .=
", ".(!empty($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
"null");
498 $sql .=
", ".(!empty($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
"null");
499 $sql .=
", ".(!empty($this->model_pdf) ?
"'".$this->db->escape($this->model_pdf).
"'" :
"null");
500 $sql .=
", ".((int) $this->fk_incoterms);
501 $sql .=
", '".$this->db->escape($this->location_incoterms).
"'";
502 $sql .=
", ".((int) $this->signed_status);
503 $sql .=
", ".((int) $this->billed);
506 dol_syslog(get_class($this).
"::create", LOG_DEBUG);
507 $resql = $this->db->query($sql);
509 $this->
id = $this->db->last_insert_id(MAIN_DB_PREFIX.
"expedition");
512 $initialref =
'(PROV'.$this->id.
')';
513 if (!empty($this->
ref)) {
514 $initialref = $this->ref;
517 $sql =
"UPDATE ".MAIN_DB_PREFIX.
"expedition";
518 $sql .=
" SET ref = '".$this->db->escape($initialref).
"'";
519 $sql .=
" WHERE rowid = ".((int) $this->
id);
521 dol_syslog(get_class($this).
"::create", LOG_DEBUG);
522 if ($this->db->query($sql)) {
523 $this->
ref = $initialref;
525 $num = count($this->lines);
526 $kits_list = array();
528 for ($i = 0; $i < $num; $i++) {
530 $objectsrc->fetch($this->lines[$i]->origin_line_id);
531 if ($this->lines[$i]->product_type ==
"9" && $objectsrc->special_code == SUBTOTALS_SPECIAL_CODE) {
532 if ($this->
create_line($this->lines[$i]->entrepot_id, $this->lines[$i]->origin_line_id, $this->lines[$i]->qty, $this->lines[$i]->rang, $this->lines[$i]->array_options) <= 0) {
539 $line = $this->lines[$i];
540 if ($line->fk_product > 0) {
546 if (!isset($kits_list[$line->fk_elementdet])) {
547 if (!is_object($line->product)) {
548 $line_product =
new Product($this->db);
549 $result = $line_product->fetch($line->fk_product,
'',
'',
'', 1, 1, 1);
554 $line_product = $line->product;
558 $line_product->get_sousproduits_arbo();
559 $prods_arbo = $line_product->get_arbo_each_prod($line->qty);
560 if (count($prods_arbo) > 0) {
561 $kits_list[$line->fk_elementdet] = array(
562 'arbo' => $prods_arbo,
563 'total_qty' => $line->qty,
567 $kits_list[$line->fk_elementdet][
'total_qty'] += $line->qty;
573 $kits_id_cached = array();
574 $sub_kits_id_cached = array();
575 $sub_parents_cached = array();
576 for ($i = 0; $i < $num; $i++) {
577 $line = $this->lines[$i];
580 if (!isset($kits_id_cached[$line->fk_elementdet])) {
581 if (!isset($line->detail_batch) || (isset($kits_list[$line->fk_elementdet]) && !
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE'))) {
582 $qty = isset($kits_list[$line->fk_elementdet]) ? $kits_list[$line->fk_elementdet][
'total_qty'] : $line->qty;
583 $warehouse_id = (isset($kits_list[$line->fk_elementdet]) && !
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE')) ? 0 : $line->entrepot_id;
584 $line_id = $this->
create_line($warehouse_id, $line->origin_line_id, $qty, $line->rang, $line->array_options, 0, $line->fk_product);
588 if (isset($kits_list[$line->fk_elementdet])) {
589 $kits_id_cached[$line->fk_elementdet] = $line_id;
597 $line_id = $kits_id_cached[$line->fk_elementdet];
601 if (isset($kits_list[$line->fk_elementdet]) && !
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE')) {
602 $prods_arbo = $kits_list[$line->fk_elementdet][
'arbo'];
605 $parent_line_id = $line_id;
607 $product_child_id = 0;
608 foreach ($prods_arbo as $index => $product_child_arr) {
623 $product_child_level = (int) $product_child_arr[
'level'];
624 $product_child_incdec = !empty($product_child_arr[
'incdec']);
627 if ($product_child_level != $level_last) {
628 $parent_line_id = $line_id;
629 $parent_product_id = $product_child_id;
630 if (isset($sub_parents_cached[$line->fk_elementdet][$parent_product_id])) {
631 $parent_line_id = $sub_parents_cached[$line->fk_elementdet][$parent_product_id];
633 $sub_parents_cached[$line->fk_elementdet][$parent_product_id] = $parent_line_id;
639 $next_level = $product_child_level;
640 $next_index = $index + 1;
641 if (isset($prods_arbo[$next_index])) {
642 $next_level = (int) $prods_arbo[$next_index][
'level'];
644 if ($next_level > $product_child_level) {
649 $product_child_id = (int) $product_child_arr[
'id'];
650 $product_child_qty = (float) $product_child_arr[
'nb_total'];
651 $warehouse_id = $line->entrepot_id;
652 if ($is_kit || !$product_child_incdec) {
653 if (!$product_child_incdec) {
654 $product_child_qty = 0;
660 if (!isset($sub_kits_id_cached[$line->fk_elementdet][$product_child_id]) || $warehouse_id > 0) {
661 $line_id = $this->
create_line($warehouse_id, ($parent_line_id ? 0 : $line->origin_line_id), $product_child_qty, $line->rang, $line->array_options, $parent_line_id, $product_child_id);
669 if (empty($warehouse_id)) {
670 $sub_kits_id_cached[$line->fk_elementdet][$product_child_id] = $line_id;
674 $level_last = $product_child_level;
680 if (!$error && $this->
id && $this->origin_id) {
687 if (!$error && $this->
id &&
getDolGlobalInt(
'SHIPPING_USE_ITS_OWN_CONTACTS') &&
getDolGlobalString(
'MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN') && !empty($this->origin_type) && !empty($this->origin_id)) {
688 $originforcontact = $this->origin_type;
689 $originidforcontact = $this->origin_id;
691 $sqlcontact =
"SELECT ctc.code, ctc.source, ec.fk_socpeople FROM ".MAIN_DB_PREFIX.
"element_contact as ec, ".MAIN_DB_PREFIX.
"c_type_contact as ctc";
692 $sqlcontact .=
" WHERE element_id = ".((int) $originidforcontact).
" AND ec.fk_c_type_contact = ctc.rowid AND ctc.element = '".$this->db->escape($originforcontact).
"'";
694 $resqlcontact = $this->db->query($sqlcontact);
696 while ($objcontact = $this->db->fetch_object($resqlcontact)) {
697 $this->
add_contact($objcontact->fk_socpeople, $objcontact->code, $objcontact->source);
700 dol_print_error($this->db);
712 if (!$error && !$notrigger) {
714 $result = $this->call_trigger(
'SHIPPING_CREATE', $user);
724 foreach ($this->errors as $errmsg) {
725 dol_syslog(get_class($this).
"::create ".$errmsg, LOG_ERR);
726 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
728 $this->db->rollback();
733 $this->db->rollback();
738 $this->error = $this->db->lasterror().
" - sql=$sql";
739 $this->db->rollback();
744 $this->error = $this->db->error().
" - sql=$sql";
745 $this->db->rollback();
763 public function create_line($entrepot_id, $origin_line_id, $qty, $rang = 0, $array_options = [], $parent_line_id = 0, $product_id = 0)
769 $expeditionline->fk_expedition = $this->id;
770 $expeditionline->entrepot_id = $entrepot_id;
771 $expeditionline->fk_elementdet = $origin_line_id;
772 $expeditionline->element_type = $this->origin;
773 $expeditionline->fk_parent = $parent_line_id;
774 $expeditionline->fk_product = $product_id;
775 $expeditionline->qty = $qty;
776 $expeditionline->rang = $rang;
777 $expeditionline->array_options = $array_options;
779 if (!($expeditionline->fk_product > 0)) {
781 $order_line->fetch($expeditionline->fk_elementdet);
782 $expeditionline->fk_product = $order_line->fk_product;
785 if (($lineId = $expeditionline->insert($user)) < 0) {
786 $this->errors[] = $expeditionline->error;
804 $stockLocationQty = array();
806 $tab = $line_ext->detail_batch;
808 foreach ($tab as $detbatch) {
809 if (!empty($detbatch->fk_warehouse)) {
810 if (empty($stockLocationQty[$detbatch->fk_warehouse])) {
811 $stockLocationQty[$detbatch->fk_warehouse] = 0;
813 $stockLocationQty[$detbatch->fk_warehouse] += $detbatch->qty;
817 foreach ($stockLocationQty as $stockLocation => $qty) {
818 $line_id = $this->
create_line($stockLocation, $line_ext->origin_line_id, $qty, $line_ext->rang, $array_options);
823 foreach ($tab as $detbatch) {
824 if ($detbatch->fk_warehouse == $stockLocation) {
825 if (!($detbatch->create($line_id) > 0)) {
826 $this->errors = $detbatch->errors;
850 public function fetch($id, $ref =
'', $ref_ext =
'', $notused =
'')
855 if (empty($id) && empty($ref) && empty($ref_ext)) {
859 $sql =
"SELECT e.rowid, e.entity, e.ref, e.fk_soc as socid, e.date_creation, e.ref_customer, e.ref_ext, e.fk_user_author, e.fk_statut, e.signed_status, e.fk_projet as fk_project, e.billed";
860 $sql .=
", e.date_valid";
861 $sql .=
", e.weight, e.weight_units, e.size, e.size_units, e.width, e.height";
862 $sql .=
", e.date_expedition as date_expedition, e.model_pdf, e.fk_address, e.date_delivery";
863 $sql .=
", e.fk_shipping_method, e.tracking_number";
864 $sql .=
", e.note_private, e.note_public";
865 $sql .=
', e.fk_incoterms, e.location_incoterms';
866 $sql .=
', e.signed_status';
867 $sql .=
', i.libelle as label_incoterms';
868 $sql .=
', s.libelle as shipping_method';
869 $sql .=
", el.fk_source as origin_id, el.sourcetype as origin_type";
870 $sql .=
" FROM ".MAIN_DB_PREFIX.
"expedition as e";
871 $sql .=
" LEFT JOIN ".MAIN_DB_PREFIX.
"element_element as el ON el.fk_target = e.rowid AND el.targettype = '".$this->db->escape($this->element).
"'";
872 $sql .=
' LEFT JOIN '.MAIN_DB_PREFIX.
'c_incoterms as i ON e.fk_incoterms = i.rowid';
873 $sql .=
' LEFT JOIN '.MAIN_DB_PREFIX.
'c_shipment_mode as s ON e.fk_shipping_method = s.rowid';
874 $sql .=
" WHERE e.entity IN (".getEntity(
'expedition').
")";
876 $sql .=
" AND e.rowid = ".((int) $id);
879 $sql .=
" AND e.ref='".$this->db->escape($ref).
"'";
882 $sql .=
" AND e.ref_ext='".$this->db->escape($ref_ext).
"'";
885 dol_syslog(get_class($this).
"::fetch", LOG_DEBUG);
886 $result = $this->db->query($sql);
888 if ($this->db->num_rows($result)) {
889 $obj = $this->db->fetch_object($result);
891 $this->
id = (int) $obj->rowid;
892 $this->entity = $obj->entity;
893 $this->
ref = $obj->ref;
894 $this->socid = $obj->socid;
895 $this->ref_customer = $obj->ref_customer;
896 $this->ref_ext = $obj->ref_ext;
897 $this->
status = $obj->fk_statut;
898 $this->statut = $this->status;
899 $this->signed_status = $obj->signed_status;
900 $this->user_author_id = $obj->fk_user_author;
901 $this->fk_user_author = $obj->fk_user_author;
902 $this->user_creation_id = $obj->fk_user_author;
903 $this->date_creation = $this->db->jdate($obj->date_creation);
904 $this->date_valid = $this->db->jdate($obj->date_valid);
905 $this->
date = $this->db->jdate($obj->date_expedition);
906 $this->date_expedition = $this->db->jdate($obj->date_expedition);
907 $this->date_shipping = $this->db->jdate($obj->date_expedition);
908 $this->date_delivery = $this->db->jdate($obj->date_delivery);
909 $this->fk_delivery_address = $obj->fk_address;
910 $this->model_pdf = $obj->model_pdf;
911 $this->shipping_method_id = $obj->fk_shipping_method;
912 $this->shipping_method = $obj->shipping_method;
913 $this->tracking_number = $obj->tracking_number;
914 $this->origin = ($obj->origin_type ? $obj->origin_type :
'commande');
915 $this->origin_type = ($obj->origin_type ? $obj->origin_type :
'commande');
916 $this->origin_id = $obj->origin_id;
917 $this->billed = $obj->billed;
918 $this->fk_project = $obj->fk_project;
919 $this->signed_status = $obj->signed_status;
920 $this->trueWeight = $obj->weight;
921 $this->weight_units = $obj->weight_units;
923 $this->trueWidth = $obj->width;
924 $this->width_units = $obj->size_units;
925 $this->trueHeight = $obj->height;
926 $this->height_units = $obj->size_units;
927 $this->trueDepth = $obj->size;
928 $this->depth_units = $obj->size_units;
930 $this->note_public = $obj->note_public;
931 $this->note_private = $obj->note_private;
934 $this->trueSize = $obj->size.
"x".$obj->width.
"x".$obj->height;
935 $this->size_units = $obj->size_units;
938 $this->fk_incoterms = $obj->fk_incoterms;
939 $this->location_incoterms = $obj->location_incoterms;
940 $this->label_incoterms = $obj->label_incoterms;
942 $this->db->free($result);
955 if (!empty($this->multicurrency_code)) {
956 $this->multicurrency_code = $this->thirdparty->multicurrency_code;
958 if (
getDolGlobalString(
'MULTICURRENCY_USE_ORIGIN_TX') && !empty($this->thirdparty->multicurrency_tx)) {
959 $this->multicurrency_tx = $this->thirdparty->multicurrency_tx;
966 if (empty($obj->origin_id)) {
977 dol_syslog(get_class($this).
'::Fetch no expedition found', LOG_ERR);
978 $this->error =
'Shipment with id '.$id.
' not found';
982 $this->error = $this->db->error();
994 public function valid($user, $notrigger = 0)
998 require_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1004 dol_syslog(get_class($this).
"::valid not in draft status", LOG_WARNING);
1008 if (!isset($this->socid)) {
1009 dol_syslog(get_class($this).
"::can't valid socid not set", LOG_WARNING);
1013 if (!((!
getDolGlobalString(
'MAIN_USE_ADVANCED_PERMS') && $user->hasRight(
'expedition',
'creer'))
1014 || (
getDolGlobalString(
'MAIN_USE_ADVANCED_PERMS') && $user->hasRight(
'expedition',
'shipping_advance',
'validate')))) {
1015 $this->error =
'Permission denied';
1016 dol_syslog(get_class($this).
"::valid ".$this->error, LOG_ERR);
1025 $soc =
new Societe($this->db);
1026 $soc->fetch($this->socid);
1029 $result = $soc->setAsCustomer();
1032 if (preg_match(
'/^[\(]?PROV/i', $this->
ref) || empty($this->
ref)) {
1033 $numref = $this->getNextNumRef($soc);
1034 } elseif (!empty($this->
ref)) {
1035 $numref = (string) $this->
ref;
1037 $numref =
"EXP".$this->id;
1044 $sql =
"UPDATE ".MAIN_DB_PREFIX.
"expedition SET";
1045 $sql .=
" ref = '".$this->db->escape($numref).
"'";
1046 $sql .=
", fk_statut = 1";
1047 $sql .=
", date_valid = '".$this->db->idate($now).
"'";
1048 $sql .=
", fk_user_valid = ".((int) $user->id);
1049 $sql .=
" WHERE rowid = ".((int) $this->
id);
1051 dol_syslog(get_class($this).
"::valid update expedition", LOG_DEBUG);
1052 $resql = $this->db->query($sql);
1054 $this->error = $this->db->lasterror();
1068 $triggerKey =
'SHIPPING_';
1069 if ($this->origin ==
'commande') {
1070 $triggerKey.=
'ORDER_SHIPMENTONPROCESS';
1072 $triggerKey.= strtoupper($this->origin).
'_SHIPMENTONPROCESS';
1082 if (!$error && !$notrigger) {
1084 $result = $this->call_trigger(
'SHIPPING_VALIDATE', $user);
1092 $this->oldref = $this->ref;
1095 if (preg_match(
'/^[\(]?PROV/i', $this->
ref)) {
1097 $sql =
'UPDATE '.MAIN_DB_PREFIX.
"ecm_files set filename = CONCAT('".$this->db->escape($this->newref).
"', SUBSTR(filename, ".(strlen($this->
ref) + 1).
")), filepath = 'expedition/sending/".$this->db->escape($this->newref).
"'";
1098 $sql .=
" WHERE filename LIKE '".$this->db->escape($this->
ref).
"%' AND filepath = 'expedition/sending/".$this->db->escape($this->
ref).
"' and entity = ".((int)
$conf->entity);
1099 $resql = $this->db->query($sql);
1102 $this->error = $this->db->lasterror();
1104 $sql =
'UPDATE '.MAIN_DB_PREFIX.
"ecm_files set filepath = 'expedition/sending/".$this->db->escape($this->newref).
"'";
1105 $sql .=
" WHERE filepath = 'expedition/sending/".$this->db->escape($this->
ref).
"' and entity = ".((int)
$conf->entity);
1106 $resql = $this->db->query($sql);
1109 $this->error = $this->db->lasterror();
1115 $dirsource =
$conf->expedition->dir_output.
'/sending/'.$oldref;
1116 $dirdest =
$conf->expedition->dir_output.
'/sending/'.$newref;
1117 if (!$error && file_exists($dirsource)) {
1118 dol_syslog(get_class($this).
"::valid rename dir ".$dirsource.
" into ".$dirdest);
1120 if (@rename($dirsource, $dirdest)) {
1123 $listoffiles =
dol_dir_list(
$conf->expedition->dir_output.
'/sending/'.$newref,
'files', 1,
'^'.preg_quote($oldref,
'/'));
1124 foreach ($listoffiles as $fileentry) {
1125 $dirsource = $fileentry[
'name'];
1126 $dirdest = preg_replace(
'/^'.preg_quote($oldref,
'/').
'/', $newref, $dirsource);
1127 $dirsource = $fileentry[
'path'].
'/'.$dirsource;
1128 $dirdest = $fileentry[
'path'].
'/'.$dirdest;
1129 @rename($dirsource, $dirdest);
1138 $this->
ref = $numref;
1144 $this->db->commit();
1147 $this->db->rollback();
1161 if (empty($rows) || !is_array($rows)) {
1165 $rowToOrigin = array();
1166 $originToRows = array();
1168 $sql =
"SELECT rowid, fk_elementdet";
1169 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet";
1170 $sql .=
" WHERE fk_expedition = ".((int) $this->
id);
1171 $sql .=
" ORDER BY rang ASC, rowid ASC";
1173 $resql = $this->db->query($sql);
1175 while ($obj = $this->db->fetch_object($resql)) {
1176 $rowid = (int) $obj->rowid;
1177 $originLine = (int) $obj->fk_elementdet;
1178 $rowToOrigin[$rowid] = $originLine;
1180 if (!isset($originToRows[$originLine])) {
1181 $originToRows[$originLine] = array();
1183 $originToRows[$originLine][] = $rowid;
1185 $this->db->free($resql);
1187 parent::line_ajaxorder($rows);
1191 $processedOrigins = array();
1194 foreach ($rows as $rowid) {
1195 $rowid = (int) $rowid;
1196 if (empty($rowid)) {
1200 $originLine = isset($rowToOrigin[$rowid]) ? $rowToOrigin[$rowid] : 0;
1201 if ($originLine > 0 && !empty($processedOrigins[$originLine])) {
1205 $rowidsToUpdate = array($rowid);
1206 if ($originLine > 0 && !empty($originToRows[$originLine])) {
1207 $rowidsToUpdate = $originToRows[$originLine];
1208 $processedOrigins[$originLine] = 1;
1211 foreach ($rowidsToUpdate as $childRowId) {
1230 if ($this->
status == self::STATUS_VALIDATED || $this->
status == self::STATUS_CLOSED) {
1232 include_once DOL_DOCUMENT_ROOT.
'/delivery/class/delivery.class.php';
1233 $delivery =
new Delivery($this->db);
1234 $result = $delivery->create_from_sending($user, $this->
id);
1256 private function checkLineStockRequirements($fk_product, $fk_entrepot, $qty, $product_type =
null, $forbid_batch_product =
false, $allowEmptyWarehouse =
false)
1260 if (!($fk_product > 0)) {
1264 $warehouseId = (int) $fk_entrepot;
1270 require_once DOL_DOCUMENT_ROOT.
'/product/class/product.class.php';
1272 $product =
new Product($this->db);
1273 $result = $product->fetch($fk_product);
1279 if ($product_type ===
null) {
1280 $product_type = $product->type;
1283 if ($forbid_batch_product &&
isModEnabled(
'productbatch') && $product->hasbatch()) {
1284 $langs->load(
'errors');
1285 $this->error = $langs->trans(
'ErrorTryToMakeMoveOnProductRequiringBatchData', $product->ref);
1286 $this->errorhidden =
'ErrorTryToMakeMoveOnProductRequiringBatchData';
1298 if (!$allowEmptyWarehouse && !empty($qty) && !($warehouseId > 0) && !
getDolGlobalString(
'STOCK_WAREHOUSE_NOT_REQUIRED_FOR_SHIPMENTS') && !(
getDolGlobalString(
'SHIPMENT_SUPPORTS_SERVICES') && $product_type ==
Product::TYPE_SERVICE) && $product->stockable_product == Product::ENABLED_STOCK) {
1299 $langs->load(
"errors");
1300 $this->error = $langs->trans(
"ErrorWarehouseRequiredIntoShipmentLine");
1305 if ($allowEmptyWarehouse && !($warehouseId > 0)) {
1310 $productChildrenNb = 0;
1312 $productChildrenNb = $product->hasFatherOrChild(1);
1314 if ($productChildrenNb > 0) {
1315 $product_stock =
null;
1316 $product->loadStockForVirtualProduct(
'warehouseopen', $qty);
1317 if ($warehouseId > 0) {
1318 if (isset($product->stock_warehouse[$warehouseId])) {
1319 $product_stock = $product->stock_warehouse[$warehouseId]->real;
1322 foreach ($product->stock_warehouse as $componentStockWarehouse) {
1323 if ($product_stock ===
null) {
1324 $product_stock = $componentStockWarehouse->real;
1326 $product_stock = min($product_stock, $componentStockWarehouse->real);
1330 if ($product_stock ===
null) {
1335 if ($warehouseId > 0) {
1336 $result = $product->load_stock(
'warehouseopen');
1341 $product_stock = empty($product->stock_warehouse[$warehouseId]) ? 0 : $product->stock_warehouse[$warehouseId]->real;
1343 $product_stock = $product->stock_reel;
1348 $isavirtualproduct = ($productChildrenNb > 0);
1353 || ($isavirtualproduct && !
getDolGlobalInt(
'STOCK_EXCLUDE_VIRTUAL_PRODUCTS'))
1356 if ($product->stockable_product == Product::ENABLED_STOCK && $product_stock < $qty) {
1357 $langs->load(
"errors");
1358 $this->error = $langs->trans(
'ErrorStockIsNotEnoughToAddProductOnShipment', $product->ref);
1359 $this->errorhidden =
'ErrorStockIsNotEnoughToAddProductOnShipment';
1384 public function addline($entrepot_id, $id, $qty, $array_options = [], $fk_product = 0, $fk_parent = 0)
1388 $num = count($this->lines);
1391 $line->entrepot_id = $entrepot_id;
1392 $line->origin_line_id = $id;
1393 $line->fk_elementdet = $id;
1394 $line->element_type =
'order';
1395 $line->fk_parent = $fk_parent;
1396 $line->fk_product = $fk_product;
1400 $orderline->fetch($id);
1403 $line->rang = $orderline->rang;
1404 $line->product_type = $orderline->product_type;
1405 if (!($line->fk_product > 0)) {
1406 $line->fk_product = $orderline->fk_product;
1409 if (!empty($orderline->fk_product)) {
1410 $result = $this->
checkLineStockRequirements((
int) $orderline->fk_product, $entrepot_id, (
float) $line->qty, (
int) $line->product_type);
1418 if (
isModEnabled(
'productbatch') && !empty($line->fk_product) && !empty($orderline->product_tobatch)) {
1419 $this->error =
'ADDLINE_WAS_CALLED_INSTEAD_OF_ADDLINEBATCH '.$orderline->id.
' '.$line->fk_product;
1424 if (!
getDolGlobalString(
'MAIN_EXTRAFIELDS_DISABLED') && is_array($array_options) && count($array_options) > 0) {
1425 $line->array_options = $array_options;
1428 $this->lines[$num] = $line;
1447 public function addlinefree($qty, $element_type, $fk_product, $fk_unit, $rang, $description, $fk_parent, $array_options = [], $fk_entrepot = 0)
1449 global
$mysoc, $langs, $user;
1451 if ($this->
status == self::STATUS_DRAFT) {
1467 if ($ranktouse == -1) {
1468 $rangmax = $this->
line_max($fk_parent);
1469 $ranktouse = $rangmax + 1;
1474 $this->line->fk_expedition = $this->id;
1475 $this->line->element_type = $element_type;
1476 $this->line->fk_product = $fk_product;
1477 $this->line->entrepot_id = (int) $fk_entrepot;
1478 $this->line->fk_entrepot = (int) $fk_entrepot;
1479 $this->line->description = $description;
1480 $this->line->desc = $description;
1481 $this->line->fk_parent = $fk_parent;
1482 $this->line->qty = (float) $qty;
1483 $this->line->fk_unit = $fk_unit;
1484 $this->line->rang = $ranktouse;
1486 if (is_array($array_options) && count($array_options) > 0) {
1487 $this->line->array_options = $array_options;
1490 $result = $this->line->insert($user);
1492 if (!isset($this->context[
'createfromclone'])) {
1493 if (!empty($fk_parent)) {
1495 } elseif ($ranktouse > 0 && $ranktouse <= count($this->lines)) {
1496 $linecount = count($this->lines);
1497 for ($ii = $ranktouse; $ii <= $linecount; $ii++) {
1501 $this->lines[] = $this->line;
1504 $this->db->commit();
1505 return $this->line->id;
1507 $this->error = $this->line->error;
1508 dol_syslog(get_class($this).
"::addlinefree error=".$this->error, LOG_ERR);
1509 $this->db->rollback();
1513 dol_syslog(get_class($this).
"::addlinefree status of shipment must be Draft to allow use of ->addlinefree()", LOG_ERR);
1534 public function updatelinefree($rowid, $qty, $element_type, $fk_product, $fk_unit, $rang, $description, $fk_parent, $notrigger, $array_options = array(), $fk_entrepot = -1)
1536 global
$mysoc, $langs, $user;
1538 if ($this->
status == self::STATUS_DRAFT) {
1548 $qty = (float) $qty;
1549 $description = trim($description);
1554 $result = $line->fetch($rowid);
1557 $this->db->rollback();
1560 $result = $line->fetch_optionals();
1563 $this->db->rollback();
1568 $fk_product = (int) $line->fk_product;
1569 if ($fk_entrepot < 0) {
1570 $fk_entrepot = (int) $line->entrepot_id;
1575 $this->db->rollback();
1579 $staticline = clone $line;
1581 $line->oldline = $staticline;
1582 $this->line = $line;
1583 $this->line->context = $this->context;
1584 $this->line->rang = $rang;
1585 $this->line->fk_expedition = $this->id;
1586 $this->line->element_type = $element_type;
1587 $this->line->fk_product = $fk_product;
1588 $this->line->entrepot_id = (int) $fk_entrepot;
1589 $this->line->fk_entrepot = (int) $fk_entrepot;
1590 $this->line->qty = $qty;
1591 $this->line->fk_unit = $fk_unit;
1592 $this->line->fk_parent = $fk_parent;
1593 $this->line->description = $description;
1595 if (is_array($array_options) && count($array_options) > 0) {
1597 foreach ($array_options as $key => $value) {
1598 $this->line->array_options[$key] = $array_options[$key];
1602 $result = $this->line->update($user, $notrigger);
1605 if (!empty($fk_parent)) {
1609 $this->db->commit();
1612 $this->error = $this->line->error;
1614 $this->db->rollback();
1618 $this->error = get_class($this).
"::updatelinefree Shipment status makes operation forbidden";
1619 $this->errors = array(
'ShipmentStatusMakeOperationForbidden');
1633 public function addline_batch($dbatch, $array_options = [], $origin_line =
null)
1638 $num = count($this->lines);
1640 if ($dbatch[
'qty'] > 0 || ($dbatch[
'qty'] == 0 &&
getDolGlobalString(
'SHIPMENT_GETS_ALL_ORDER_PRODUCTS'))) {
1643 foreach ($dbatch[
'detail'] as $key => $value) {
1644 if ($value[
'q'] > 0 || ($value[
'q'] == 0 &&
getDolGlobalString(
'SHIPMENT_GETS_ALL_ORDER_PRODUCTS'))) {
1650 $ret = $linebatch->fetchFromStock($value[
'id_batch']);
1655 $linebatch->qty = $value[
'q'];
1656 if ($linebatch->qty == 0 &&
getDolGlobalString(
'SHIPMENT_GETS_ALL_ORDER_PRODUCTS')) {
1657 $linebatch->batch =
null;
1659 $tab[] = $linebatch;
1662 require_once DOL_DOCUMENT_ROOT.
'/product/class/productbatch.class.php';
1664 $prod_batch->fetch($value[
'id_batch']);
1666 if ($prod_batch->qty < $linebatch->qty) {
1667 $langs->load(
"errors");
1668 $this->errors[] = $langs->trans(
'ErrorStockIsNotEnoughToAddProductOnShipment', $prod_batch->fk_product);
1669 dol_syslog(get_class($this).
"::addline_batch error=Product ".$prod_batch->batch.
": ".$this->errorsToString(), LOG_ERR);
1675 if (is_object($linebatch)) {
1676 $line->entrepot_id = $linebatch->fk_warehouse;
1678 $line->origin_line_id = $dbatch[
'ix_l'];
1679 $line->fk_elementdet = $dbatch[
'ix_l'];
1680 $line->qty = $dbatch[
'qty'];
1681 $line->detail_batch = $tab;
1682 if (!($line->rang > 0)) {
1683 $line->rang = $origin_line->rang;
1685 if (!($line->fk_product > 0)) {
1686 $line->fk_product = $origin_line->fk_product;
1690 if (!
getDolGlobalString(
'MAIN_EXTRAFIELDS_DISABLED') && is_array($array_options) && count($array_options) > 0) {
1691 $line->array_options = $array_options;
1695 $this->lines[$num] = $line;
1708 public function update($user =
null, $notrigger = 0)
1715 if (isset($this->
ref)) {
1716 $this->
ref = trim($this->
ref);
1718 if (isset($this->entity)) {
1719 $this->entity = (int) $this->entity;
1721 if (isset($this->ref_customer)) {
1722 $this->ref_customer = trim($this->ref_customer);
1724 if (isset($this->socid)) {
1725 $this->socid = (int) $this->socid;
1727 if (isset($this->fk_user_author)) {
1728 $this->fk_user_author = (int) $this->fk_user_author;
1730 if (isset($this->fk_user_valid)) {
1731 $this->fk_user_valid = (int) $this->fk_user_valid;
1733 if (isset($this->fk_delivery_address)) {
1734 $this->fk_delivery_address = (int) $this->fk_delivery_address;
1736 if (isset($this->shipping_method_id)) {
1737 $this->shipping_method_id = (int) $this->shipping_method_id;
1739 if (isset($this->tracking_number)) {
1740 $this->tracking_number = trim($this->tracking_number);
1742 if (isset($this->statut)) {
1743 $this->statut = (int) $this->statut;
1745 if (isset($this->
status)) {
1748 if (isset($this->trueDepth)) {
1749 $this->trueDepth = trim($this->trueDepth);
1751 if (isset($this->trueWidth)) {
1752 $this->trueWidth = trim($this->trueWidth);
1754 if (isset($this->trueHeight)) {
1755 $this->trueHeight = trim($this->trueHeight);
1757 if (isset($this->size_units)) {
1758 $this->size_units = trim($this->size_units);
1760 if (isset($this->weight_units)) {
1761 $this->weight_units = (int) $this->weight_units;
1763 if (isset($this->trueWeight)) {
1764 $this->weight = trim((
string) $this->trueWeight);
1766 if (isset($this->note_private)) {
1767 $this->note_private = trim($this->note_private);
1769 if (isset($this->note_public)) {
1770 $this->note_public = trim($this->note_public);
1772 if (isset($this->model_pdf)) {
1773 $this->model_pdf = trim($this->model_pdf);
1775 if (!empty($this->date_expedition)) {
1776 $this->date_shipping = $this->date_expedition;
1783 $sql =
"UPDATE ".MAIN_DB_PREFIX.
"expedition SET";
1784 $sql .=
" ref = ".(isset($this->
ref) ?
"'".$this->db->escape($this->
ref).
"'" :
"null").
",";
1785 $sql .=
" ref_ext = ".(isset($this->ref_ext) ?
"'".$this->db->escape($this->ref_ext).
"'" :
"null").
",";
1786 $sql .=
" ref_customer = ".(isset($this->ref_customer) ?
"'".$this->db->escape($this->ref_customer).
"'" :
"null").
",";
1787 $sql .=
" fk_soc = ".(isset($this->socid) ? ((int) $this->socid) :
"null").
",";
1788 $sql .=
" date_creation = ".(dol_strlen($this->date_creation) != 0 ?
"'".$this->db->idate($this->date_creation).
"'" :
'null').
",";
1789 $sql .=
" fk_user_author = ".(isset($this->fk_user_author) ? ((int) $this->fk_user_author) :
"null").
",";
1790 $sql .=
" date_valid = ".(dol_strlen($this->date_valid) != 0 ?
"'".$this->db->idate($this->date_valid).
"'" :
'null').
",";
1791 $sql .=
" fk_user_valid = ".(isset($this->fk_user_valid) ? ((int) $this->fk_user_valid) :
"null").
",";
1792 $sql .=
" date_expedition = ".(dol_strlen($this->date_shipping) != 0 ?
"'".$this->db->idate($this->date_shipping).
"'" :
'null').
",";
1793 $sql .=
" date_delivery = ".(dol_strlen($this->date_delivery) != 0 ?
"'".$this->db->idate($this->date_delivery).
"'" :
'null').
",";
1794 $sql .=
" fk_address = ".(isset($this->fk_delivery_address) ? ((int) $this->fk_delivery_address) :
"null").
",";
1795 $sql .=
" fk_shipping_method = ".((isset($this->shipping_method_id) && $this->shipping_method_id > 0) ? ((
int) $this->shipping_method_id) :
"null").
",";
1796 $sql .=
" tracking_number = ".(isset($this->tracking_number) ?
"'".$this->db->escape($this->tracking_number).
"'" :
"null").
",";
1797 $sql .=
" fk_statut = ".(isset($this->
status) ? ((int) $this->
status) :
"null").
",";
1798 $sql .=
" fk_projet = ".(isset($this->fk_project) ? ((int) $this->fk_project) :
"null").
",";
1799 $sql .=
" height = ".(($this->trueHeight !=
'') ? ((
float) $this->trueHeight) :
"null").
",";
1800 $sql .=
" width = ".(($this->trueWidth !=
'') ? ((
float) $this->trueWidth) :
"null").
",";
1801 $sql .=
" size_units = ".(isset($this->size_units) ? ((int) $this->size_units) :
"null").
",";
1802 $sql .=
" size = ".(($this->trueDepth !=
'') ? ((
float) $this->trueDepth) :
"null").
",";
1803 $sql .=
" weight_units = ".(isset($this->weight_units) ? ((int) $this->weight_units) :
"null").
",";
1804 $sql .=
" weight = ".(($this->trueWeight !=
'') ? ((
float) $this->trueWeight) :
"null").
",";
1805 $sql .=
" note_private = ".(isset($this->note_private) ?
"'".$this->db->escape($this->note_private).
"'" :
"null").
",";
1806 $sql .=
" note_public = ".(isset($this->note_public) ?
"'".$this->db->escape($this->note_public).
"'" :
"null").
",";
1807 $sql .=
" model_pdf = ".(isset($this->model_pdf) ?
"'".$this->db->escape($this->model_pdf).
"'" :
"null").
",";
1808 $sql .=
" entity = ".((int)
$conf->entity);
1809 $sql .=
" WHERE rowid = ".((int) $this->
id);
1813 dol_syslog(get_class($this).
"::update", LOG_DEBUG);
1814 $resql = $this->db->query($sql);
1817 $this->errors[] =
"Error ".$this->db->lasterror();
1828 if (!$error && !$notrigger) {
1830 $result = $this->call_trigger(
'SHIPPING_MODIFY', $user);
1839 foreach ($this->errors as $errmsg) {
1840 dol_syslog(get_class($this).
"::update ".$errmsg, LOG_ERR);
1841 $this->error .= ($this->error ?
', '.$errmsg : $errmsg);
1843 $this->db->rollback();
1846 $this->db->commit();
1860 public function cancel($user, $notrigger = 0, $also_update_stock =
false)
1862 global
$conf, $langs, $user;
1864 require_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
1873 if (isset($this->linkedObjectsIds[
'delivery']) && count($this->linkedObjectsIds[
'delivery']) > 0) {
1874 $this->error =
'ErrorThereIsSomeDeliveries';
1878 if (!$error && !$notrigger) {
1880 $result = $this->call_trigger(
'SHIPPING_CANCEL', $user);
1890 (
getDolGlobalString(
'STOCK_CALCULATE_ON_SHIPMENT_CLOSE') && $this->
status == self::STATUS_CLOSED && $also_update_stock));
1892 require_once DOL_DOCUMENT_ROOT.
"/product/stock/class/mouvementstock.class.php";
1894 $langs->load(
"agenda");
1898 $sql .=
" ed.fk_product";
1899 $sql .=
", ed.qty, ed.fk_entrepot, ed.rowid as expeditiondet_id";
1900 $sql .=
", SUM(".$this->db->ifsql(
"pa.rowid IS NOT NULL",
"1",
"0").
") as iskit";
1901 $sql .=
", ".$this->db->ifsql(
"pai.incdec IS NULL",
"1",
"pai.incdec").
" as incdec";
1902 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
1903 $sql .=
" LEFT JOIN ".$this->db->prefix().
"product_association as pa ON pa.fk_product_pere = ed.fk_product";
1904 $sql .=
" LEFT JOIN ".$this->db->prefix().
"expeditiondet as edp ON edp.rowid = ed.fk_parent";
1905 $sql .=
" LEFT JOIN ".$this->db->prefix().
"product_association as pai ON pai.fk_product_pere = edp.fk_product AND pai.fk_product_fils = ed.fk_product";
1906 $sql .=
" WHERE ed.fk_expedition = ".((int) $this->
id);
1907 $sql .=
" GROUP BY ed.fk_product, ed.qty, ed.fk_entrepot, ed.rowid, pai.incdec";
1908 $sql .= $this->db->order(
"ed.rowid",
"DESC");
1910 dol_syslog(get_class($this).
"::delete select details", LOG_DEBUG);
1911 $resql = $this->db->query($sql);
1913 $cpt = $this->db->num_rows($resql);
1917 for ($i = 0; $i < $cpt; $i++) {
1918 dol_syslog(get_class($this).
"::delete movement index ".$i);
1919 $obj = $this->db->fetch_object($resql);
1920 $line_id = (int) $obj->expeditiondet_id;
1922 if ($can_update_stock && (empty($obj->iskit) ||
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE')) && !empty($obj->incdec)) {
1925 $mouvS->origin =
'';
1929 $lotArray = $shipmentlinebatch->fetchAll($obj->expeditiondet_id);
1930 if (!is_array($lotArray)) {
1932 $this->errors[] =
"Error ".$this->db->lasterror();
1936 if (empty($lotArray)) {
1940 $result = $mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $obj->qty, 0, $langs->trans(
"ShipmentCanceledInDolibarr", $this->ref),
'',
'',
'',
'', 0,
'', 0, (empty($obj->iskit) ? 1 : 0));
1943 $this->errors = array_merge($this->errors, $mouvS->errors);
1949 foreach ($lotArray as $lot) {
1950 $result = $mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $lot->qty, 0, $langs->trans(
"ShipmentCanceledInDolibarr", $this->ref), $lot->eatby, $lot->sellby, (
string) $lot->batch,
'', 0,
'', 0, (empty($obj->iskit) ? 1 : 0));
1953 $this->errors = array_merge($this->errors, $mouvS->errors);
1966 $res = $shipment_line->fetch($line_id);
1968 $result = $shipment_line->delete($user);
1971 $this->errors[] =
"Error ".$shipment_line->errorsToString();
1975 $this->errors[] =
"Error ".$shipment_line->errorsToString();
1985 $this->errors[] =
"Error ".$this->db->lasterror();
1991 $sql =
"SELECT rowid FROM ".$this->db->prefix().
"expedition";
1992 $sql .=
" WHERE rowid = ".((int) $this->
id);
1994 if ($this->db->query($sql)) {
1995 if (!empty($this->origin) && $this->origin_id > 0) {
1998 '@phan-var-force Facture|Commande $origin_object';
2009 $this->db->commit();
2013 if (!empty(
$conf->expedition->dir_output)) {
2014 $dir =
$conf->expedition->dir_output.
'/sending/'.$ref;
2015 $file = $dir.
'/'.$ref.
'.pdf';
2016 if (file_exists($file)) {
2021 if (file_exists($dir)) {
2023 $this->error = $langs->trans(
"ErrorCanNotDeleteDir", $dir);
2031 $this->error = $this->db->lasterror().
" - sql=$sql";
2032 $this->db->rollback();
2036 $this->db->rollback();
2050 public function delete($user =
null, $notrigger = 0, $also_update_stock =
false)
2052 global
$conf, $langs;
2058 require_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
2067 if (isset($this->linkedObjectsIds[
'delivery']) && count($this->linkedObjectsIds[
'delivery']) > 0) {
2068 $this->error =
'ErrorThereIsSomeDeliveries';
2072 if (!$error && !$notrigger) {
2074 $result = $this->call_trigger(
'SHIPPING_DELETE', $user);
2084 (
getDolGlobalString(
'STOCK_CALCULATE_ON_SHIPMENT_CLOSE') && $this->
status == self::STATUS_CLOSED && $also_update_stock));
2086 require_once DOL_DOCUMENT_ROOT.
"/product/stock/class/mouvementstock.class.php";
2088 $langs->load(
"agenda");
2095 $sql .=
" ed.fk_product";
2096 $sql .=
", ed.qty, ed.fk_entrepot, ed.rowid as expeditiondet_id";
2097 $sql .=
", SUM(".$this->db->ifsql(
"pa.rowid IS NOT NULL",
"1",
"0").
") as iskit";
2098 $sql .=
", ".$this->db->ifsql(
"pai.incdec IS NULL",
"1",
"pai.incdec").
" as incdec";
2099 $sql .=
" FROM ".$this->db->prefix().
"expeditiondet as ed";
2100 $sql .=
" LEFT JOIN ".$this->db->prefix().
"product_association as pa ON pa.fk_product_pere = ed.fk_product";
2101 $sql .=
" LEFT JOIN ".$this->db->prefix().
"expeditiondet as edp ON edp.rowid = ed.fk_parent";
2102 $sql .=
" LEFT JOIN ".$this->db->prefix().
"product_association as pai ON pai.fk_product_pere = edp.fk_product AND pai.fk_product_fils = ed.fk_product";
2103 $sql .=
" WHERE ed.fk_expedition = ".((int) $this->
id);
2104 $sql .=
" GROUP BY ed.fk_product, ed.qty, ed.fk_entrepot, ed.rowid, pai.incdec";
2105 $sql .= $this->db->order(
"ed.rowid",
"DESC");
2107 dol_syslog(get_class($this).
"::delete select details", LOG_DEBUG);
2108 $resql = $this->db->query($sql);
2110 $cpt = $this->db->num_rows($resql);
2111 for ($i = 0; $i < $cpt; $i++) {
2112 dol_syslog(get_class($this).
"::delete movement index ".$i);
2113 $obj = $this->db->fetch_object($resql);
2114 $line_id = (int) $obj->expeditiondet_id;
2116 if ($can_update_stock && (empty($obj->iskit) ||
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE')) && !empty($obj->incdec)) {
2119 $mouvS->origin =
'';
2121 $lotArray = $shipmentlinebatch->fetchAll($line_id);
2122 if (!is_array($lotArray)) {
2124 $this->errors[] =
"Error ".$this->db->lasterror();
2126 if (empty($lotArray)) {
2130 $result = $mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $obj->qty, 0, $langs->trans(
"ShipmentDeletedInDolibarr", $this->ref),
'',
'',
'',
'', 0,
'', 0, (empty($obj->iskit) ? 1 : 0));
2133 $this->errors = array_merge($this->errors, $mouvS->errors);
2139 foreach ($lotArray as $lot) {
2140 if (empty($lot->qty)) {
2143 $result = $mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $lot->qty, 0, $langs->trans(
"ShipmentDeletedInDolibarr", $this->ref), $lot->eatby, $lot->sellby, (
string) $lot->batch,
'', 0,
'', 0, (empty($obj->iskit) ? 1 : 0));
2146 $this->errors = array_merge($this->errors, $mouvS->errors);
2159 $res = $shipment_line->fetch($line_id);
2161 $result = $shipment_line->delete($user);
2164 $this->errors[] =
"Error ".$shipment_line->errorsToString();
2168 $this->errors[] =
"Error ".$shipment_line->errorsToString();
2178 $this->errors[] =
"Error ".$this->db->lasterror();
2203 $sql =
"DELETE FROM ".$this->db->prefix().
"expedition";
2204 $sql .=
" WHERE rowid = ".((int) $this->
id);
2206 if ($this->db->query($sql)) {
2207 if (!empty($this->origin) && $this->origin_id > 0) {
2210 '@phan-var-force Facture|Commande $origin_object';
2220 $this->db->commit();
2228 if (!empty(
$conf->expedition->dir_output) && !empty($ref)) {
2229 $dir =
$conf->expedition->dir_output .
'/sending/' . $ref;
2230 $file = $dir .
'/' . $ref .
'.pdf';
2231 if (file_exists($file)) {
2236 if (file_exists($dir)) {
2238 $this->error = $langs->trans(
"ErrorCanNotDeleteDir", $dir);
2246 $this->error = $this->db->lasterror().
" - sql=$sql";
2247 $this->db->rollback();
2251 $this->db->rollback();
2255 $this->db->rollback();
2271 $this->lines = array();
2276 $sql =
"SELECT cd.rowid, cd.fk_product, cd.label as custom_label, cd.description, cd.qty as qty_asked, cd.product_type, cd.fk_unit";
2277 $sql .=
", cd.total_ht, cd.total_localtax1, cd.total_localtax2, cd.total_ttc, cd.total_tva";
2278 $sql .=
", cd.fk_remise_except, cd.fk_product_fournisseur_price as fk_fournprice";
2279 $sql .=
", cd.vat_src_code, cd.tva_tx, cd.localtax1_tx, cd.localtax2_tx, cd.localtax1_type, cd.localtax2_type, cd.info_bits, cd.price, cd.subprice, cd.remise_percent,cd.buy_price_ht as pa_ht";
2280 $sql .=
", cd.fk_multicurrency, cd.multicurrency_code, cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc, cd.rang, cd.date_start, cd.date_end, cd.special_code";
2281 $sql .=
", ed.rowid as line_id, ed.qty as qty_shipped, ed.fk_element, ed.fk_elementdet, ed.element_type, ed.fk_entrepot, ed.extraparams";
2282 $sql .=
", p.ref as product_ref, p.label as product_label, p.fk_product_type, p.barcode as product_barcode";
2283 $sql .=
", p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units";
2284 $sql .=
", p.surface, p.surface_units, p.volume, p.volume_units, p.tosell as product_tosell, p.tobuy as product_tobuy";
2285 $sql .=
", p.tobatch as product_tobatch, p.stockable_product";
2286 $sql .=
" FROM ".MAIN_DB_PREFIX.
"expeditiondet as ed, ".MAIN_DB_PREFIX.
"commandedet as cd";
2287 $sql .=
" LEFT JOIN ".MAIN_DB_PREFIX.
"product as p ON p.rowid = cd.fk_product";
2288 $sql .=
" WHERE ed.fk_expedition = ".((int) $this->
id);
2289 $sql .=
" AND ed.fk_elementdet = cd.rowid";
2290 $sql .=
" ORDER BY CASE WHEN ed.rang IS NULL OR ed.rang = 0 THEN cd.rang ELSE ed.rang END, ed.rowid";
2292 dol_syslog(get_class($this).
"::fetch_lines", LOG_DEBUG);
2293 $resql = $this->db->query($sql);
2295 include_once DOL_DOCUMENT_ROOT.
'/core/lib/price.lib.php';
2297 $num = $this->db->num_rows($resql);
2303 $this->total_ht = 0;
2304 $this->total_tva = 0;
2305 $this->total_ttc = 0;
2306 $this->total_localtax1 = 0;
2307 $this->total_localtax2 = 0;
2309 $this->multicurrency_total_ht = 0;
2310 $this->multicurrency_total_tva = 0;
2311 $this->multicurrency_total_ttc = 0;
2317 $obj = $this->db->fetch_object($resql);
2319 if ($originline > 0 && $originline == $obj->fk_elementdet) {
2321 $line->entrepot_id = 0;
2322 $line->qty_shipped += $obj->qty_shipped;
2325 $line->entrepot_id = $obj->fk_entrepot;
2326 $line->qty_shipped = $obj->qty_shipped;
2330 $detail_entrepot->entrepot_id = $obj->fk_entrepot;
2331 $detail_entrepot->qty_shipped = $obj->qty_shipped;
2332 $detail_entrepot->line_id = $obj->line_id;
2333 $line->details_entrepot[] = $detail_entrepot;
2335 $line->line_id = $obj->line_id;
2336 $line->rowid = $obj->line_id;
2337 $line->id = $obj->line_id;
2339 $line->fk_origin =
'orderline';
2341 $line->fk_element = $obj->fk_element;
2342 $line->origin_id = $obj->fk_element;
2343 $line->fk_elementdet = $obj->fk_elementdet;
2344 $line->origin_line_id = $obj->fk_elementdet;
2345 $line->element_type = $obj->element_type;
2347 $line->fk_expedition = $this->id;
2349 $line->stockable_product = $obj->stockable_product;
2350 $line->product_type = $obj->product_type;
2351 $line->fk_product = $obj->fk_product;
2352 $line->fk_product_type = $obj->fk_product_type;
2353 $line->ref = $obj->product_ref;
2354 $line->product_ref = $obj->product_ref;
2355 $line->product_label = $obj->product_label;
2356 $line->libelle = $obj->product_label;
2357 $line->product_barcode = $obj->product_barcode;
2358 $line->product_tosell = $obj->product_tosell;
2359 $line->product_tobuy = $obj->product_tobuy;
2360 $line->product_tobatch = $obj->product_tobatch;
2361 $line->fk_fournprice = $obj->fk_fournprice;
2362 $line->label = $obj->custom_label;
2363 $line->description = $obj->description;
2364 $line->qty_asked = $obj->qty_asked;
2365 $line->rang = $obj->rang;
2366 $line->weight = $obj->weight;
2367 $line->weight_units = $obj->weight_units;
2368 $line->length = $obj->length;
2369 $line->length_units = $obj->length_units;
2370 $line->width = $obj->width;
2371 $line->width_units = $obj->width_units;
2372 $line->height = $obj->height;
2373 $line->height_units = $obj->height_units;
2374 $line->surface = $obj->surface;
2375 $line->surface_units = $obj->surface_units;
2376 $line->volume = $obj->volume;
2377 $line->volume_units = $obj->volume_units;
2378 $line->stockable_product = $obj->stockable_product;
2379 $line->fk_unit = $obj->fk_unit;
2381 $line->extraparams = !empty($obj->extraparams) ? (array) json_decode($obj->extraparams,
true) : array();
2383 $line->pa_ht = $obj->pa_ht;
2386 $localtax_array = array(0 => $obj->localtax1_type, 1 => $obj->localtax1_tx, 2 => $obj->localtax2_type, 3 => $obj->localtax2_tx);
2387 $localtax1_tx =
get_localtax($obj->tva_tx, 1, $this->thirdparty);
2388 $localtax2_tx =
get_localtax($obj->tva_tx, 2, $this->thirdparty);
2391 $tabprice =
calcul_price_total($obj->qty_shipped, $obj->subprice, $obj->remise_percent, $obj->tva_tx, $localtax1_tx, $localtax2_tx, 0,
'HT', $obj->info_bits, $obj->fk_product_type,
$mysoc, $localtax_array);
2392 $line->desc = $obj->description;
2393 $line->qty = $line->qty_shipped;
2394 $line->total_ht = (float) $tabprice[0];
2395 $line->total_localtax1 = (float) $tabprice[9];
2396 $line->total_localtax2 = (float) $tabprice[10];
2397 $line->total_ttc = (float) $tabprice[2];
2398 $line->total_tva = (float) $tabprice[1];
2399 $line->vat_src_code = $obj->vat_src_code;
2400 $line->tva_tx = $obj->tva_tx;
2401 $line->localtax1_tx = $obj->localtax1_tx;
2402 $line->localtax2_tx = $obj->localtax2_tx;
2403 $line->info_bits = $obj->info_bits;
2404 $line->price = $obj->price;
2405 $line->subprice = $obj->subprice;
2406 $line->fk_remise_except = $obj->fk_remise_except;
2407 $line->remise_percent = $obj->remise_percent;
2409 $this->total_ht += $tabprice[0];
2410 $this->total_tva += $tabprice[1];
2411 $this->total_ttc += $tabprice[2];
2412 $this->total_localtax1 += $tabprice[9];
2413 $this->total_localtax2 += $tabprice[10];
2415 $line->date_start = $this->db->jdate($obj->date_start);
2416 $line->date_end = $this->db->jdate($obj->date_end);
2418 $line->special_code = $obj->special_code;
2421 $this->fk_multicurrency = $obj->fk_multicurrency;
2422 $this->multicurrency_code = $obj->multicurrency_code;
2423 $line->multicurrency_subprice = $obj->multicurrency_subprice;
2424 $line->multicurrency_total_ht = $obj->multicurrency_total_ht;
2425 $line->multicurrency_total_tva = $obj->multicurrency_total_tva;
2426 $line->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
2428 $this->multicurrency_total_ht += $obj->multicurrency_total_ht;
2429 $this->multicurrency_total_tva += $obj->multicurrency_total_tva;
2430 $this->multicurrency_total_ttc += $obj->multicurrency_total_ttc;
2433 if (
isModEnabled(
'productbatch') && $obj->line_id > 0 && $obj->product_tobatch > 0) {
2434 if ($originline != $obj->fk_elementdet) {
2435 $line->detail_batch = array();
2437 $newdetailbatch = $shipmentlinebatch->fetchAll($obj->line_id, $obj->fk_product);
2439 if (is_array($newdetailbatch)) {
2440 if ($originline != $obj->fk_elementdet) {
2441 $line->detail_batch = $newdetailbatch;
2443 $line->detail_batch = array_merge($line->detail_batch, $newdetailbatch);
2450 $detail_children = array();
2451 $line_child_list = array();
2452 $res = $line->findAllChild($line->id, $line_child_list, 1);
2454 foreach ($line_child_list as $child_line) {
2455 foreach ($child_line as $child_obj) {
2456 $child_product_id = (int) $child_obj->fk_product;
2457 $child_warehouse_id = (int) $child_obj->fk_warehouse;
2459 if ($child_warehouse_id > 0) {
2461 if (!isset($detail_children[$child_product_id])) {
2462 $detail_children[$child_product_id] = array();
2464 if (!isset($detail_children[$child_product_id][$child_warehouse_id])) {
2465 $detail_children[$child_product_id][$child_warehouse_id] = 0;
2467 $detail_children[$child_product_id][$child_warehouse_id] += $child_obj->qty;
2472 $line->detail_children = $detail_children;
2475 $line->fetch_optionals();
2477 if ($originline != $obj->fk_elementdet) {
2478 $this->lines[$lineindex] = $line;
2481 $line->total_ht += $tabprice[0];
2482 $line->total_localtax1 += $tabprice[9];
2483 $line->total_localtax2 += $tabprice[10];
2484 $line->total_ttc += $tabprice[2];
2485 $line->total_tva += $tabprice[1];
2489 $originline = $obj->fk_elementdet;
2491 $this->db->free($resql);
2494 $this->error = $this->db->error();
2511 $this->lines = array();
2513 $sql =
'SELECT ed.rowid, ed.fk_expedition, ed.fk_entrepot, ed.fk_product, ed.fk_parent, ed.fk_unit, ed.description, ed.fk_elementdet, ed.fk_element, ed.element_type, ed.qty, ed.rang';
2514 $sql .=
' FROM '.MAIN_DB_PREFIX.$this->table_element_line.
' as ed';
2515 $sql .=
' LEFT JOIN '.MAIN_DB_PREFIX.
'product as p ON (p.rowid = ed.fk_product)';
2516 $sql .=
' WHERE ed.fk_expedition = '.((int) $this->
id);
2517 $sql .=
' ORDER BY ed.rang, ed.rowid';
2519 dol_syslog(get_class($this).
"::fetch_lines_free", LOG_DEBUG);
2520 $result = $this->db->query($sql);
2522 $num = $this->db->num_rows($result);
2526 $objp = $this->db->fetch_object($result);
2530 $line->rowid = $objp->rowid;
2531 $line->id = $objp->rowid;
2532 $line->fk_expedition = $this->id;
2533 $line->description = $objp->description;
2534 $line->desc = $objp->description;
2535 $line->qty = $objp->qty;
2536 $line->fk_entrepot = $objp->fk_entrepot;
2537 $line->entrepot_id = $objp->fk_entrepot;
2538 $line->fk_product = $objp->fk_product;
2539 $line->fk_parent = $objp->fk_parent;
2540 $line->rang = $objp->rang;
2541 $line->fk_element = $objp->fk_element;
2542 $line->fk_unit = $objp->fk_unit;
2543 $line->fk_elementdet = $objp->fk_elementdet;
2544 $line->element_type = $objp->element_type;
2545 $line->fetch_optionals();
2547 $this->lines[$i] = $line;
2552 $this->db->free($result);
2556 $this->error = $this->db->error();
2582 if ($this->
status == self::STATUS_DRAFT) {
2588 $line->fetch($lineid);
2590 if ($this->
id > 0 && (
int) $line->fk_expedition !== (
int) $this->id) {
2591 $this->db->rollback();
2592 $this->error =
'ErrorLineIDDoesNotMatchWithObjectID';
2596 if ($line->delete($user) > 0) {
2599 $this->db->commit();
2602 $this->db->rollback();
2606 $this->error =
'ErrorDeleteLineNotAllowedByObjectStatus';
2620 global
$conf, $langs;
2622 $langs->load(
'sendings');
2624 $nofetch = !empty($params[
'nofetch']);
2627 $datas[
'picto'] = img_picto(
'', $this->picto).
' <u class="paddingrightonly">'.$langs->trans(
"Shipment").
'</u>';
2628 if (isset($this->
status)) {
2629 $datas[
'picto'] .=
' '.$this->getLibStatut(5);
2631 $datas[
'ref'] =
'<br><b>'.$langs->trans(
'Ref').
':</b> '.$this->ref;
2632 $datas[
'refcustomer'] =
'<br><b>'.$langs->trans(
'RefCustomer').
':</b> '.($this->ref_customer ? $this->ref_customer : $this->ref_client);
2634 $langs->load(
'companies');
2635 if (empty($this->thirdparty)) {
2638 $datas[
'customer'] =
'<br><b>'.$langs->trans(
'Customer').
':</b> '.$this->thirdparty->getNomUrl(1,
'', 0, 1);
2656 public function getNomUrl($withpicto = 0, $option =
'', $max = 0, $short = 0, $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0)
2658 global $langs, $hookmanager, $user;
2663 'objecttype' => $this->element,
2664 'option' => $option,
2667 $classfortooltip =
'classfortooltip';
2670 $classfortooltip =
'classforajaxtooltip';
2671 $dataparams =
' data-params="'.dol_escape_htmltag(json_encode($params)).
'"';
2677 $url = DOL_URL_ROOT.
'/expedition/card.php?id='.$this->id;
2683 if ($option !==
'nolink') {
2685 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
2686 if ($save_lastsearch_value == -1 && isset($_SERVER[
"PHP_SELF"]) && preg_match(
'/list\.php/', $_SERVER[
"PHP_SELF"])) {
2687 $add_save_lastsearch_values = 1;
2689 if ($add_save_lastsearch_values) {
2690 $url .=
'&save_lastsearch_values=1';
2695 if (empty($notooltip)) {
2697 $label = $langs->trans(
"Shipment");
2698 $linkclose .=
' alt="'.dolPrintHTMLForAttribute($label).
'"';
2700 $linkclose .= ($label ?
' title="'.dolPrintHTMLForAttribute($label).
'"' :
' title="tocomplete"');
2701 $linkclose .= $dataparams.
' class="'.$classfortooltip.
'"';
2704 $linkstart =
'<a href="'.$url.
'"';
2705 $linkstart .= $linkclose.
'>';
2708 $result .= $linkstart;
2710 $result .= img_object(($notooltip ?
'' : $label), ($this->picto ? $this->picto :
'generic'), ($notooltip ? (($withpicto != 2) ?
'class="paddingright"' :
'') :
'class="'.(($withpicto != 2) ?
'paddingright ' :
'').
'"'), 0, 0, $notooltip ? 0 : 1);
2712 if ($withpicto != 2) {
2713 $result .= $this->ref;
2715 $result .= $linkend;
2717 if ($addlinktonotes) {
2718 $txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
2721 $result .=
' <span class="note inline-block">';
2722 $result .=
'<a href="'.DOL_URL_ROOT.
'/expedition/note.php?id='.$this->
id.
'" class="classfortooltip" title="'.
dol_escape_htmltag($notetoshow).
'">';
2723 $result .= img_picto(
'',
'note');
2725 $result .=
'</span>';
2730 $hookmanager->initHooks(array($this->element .
'dao'));
2731 $parameters = array(
'id' => $this->
id,
'getnomurl' => &$result);
2732 $reshook = $hookmanager->executeHooks(
'getNomUrl', $parameters, $this, $action);
2734 $result = $hookmanager->resPrint;
2736 $result .= $hookmanager->resPrint;
2765 $labelStatus = $langs->transnoentitiesnoconv($this->labelStatus[$status]);
2766 $labelStatusShort = $langs->transnoentitiesnoconv($this->labelStatusShort[$status]);
2768 $statusType =
'status'.$status;
2769 if ($status == self::STATUS_VALIDATED) {
2770 $statusType =
'status4';
2772 if ($status == self::STATUS_CLOSED) {
2773 $statusType =
'status6';
2775 if ($status == self::STATUS_CANCELED) {
2776 $statusType =
'status9';
2780 $status_label = $this->signed_status ? $labelStatus . $signed_label : $labelStatus;
2781 $status_label_short = $this->signed_status ? $labelStatusShort . $signed_label : $labelStatusShort;
2783 return dolGetStatus($status_label, $status_label_short,
'', $statusType, $mode);
2795 global $langs,
$conf;
2797 $selected = (empty($arraydata[
'selected']) ? 0 : $arraydata[
'selected']);
2799 $return =
'<div class="box-flex-item box-flex-grow-zero">';
2800 $return .=
'<div class="info-box info-box-sm">';
2801 $return .=
'<div class="info-box-icon bg-infobox-action">';
2802 $return .= img_picto(
'',
'order');
2803 $return .=
'</div>';
2804 $return .=
'<div class="info-box-content">';
2805 $return .=
'<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . $this->
getNomUrl() .
'</span>';
2806 if ($selected >= 0) {
2807 $return .=
'<input id="cb'.$this->id.
'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->
id.
'"'.($selected ?
' checked="checked"' :
'').
'>';
2809 $return .=
'<br><div class="info-box-ref tdoverflowmax150">'.$this->thirdparty->getNomUrl(1).
'</div>';
2810 $return .=
'<div class="info-box-ref amount">'.price($this->total_ht, 0, $langs, 0, -1, -1,
getDolCurrency()).
' '.$langs->trans(
'HT').
'</div>';
2811 $return .=
'<div class="info-box-status">'.$this->getLibStatut(3).
'</div>';
2812 $return .=
'</div>';
2813 $return .=
'</div>';
2814 $return .=
'</div>';
2832 dol_syslog(get_class($this).
"::initAsSpecimen");
2835 $order->initAsSpecimen();
2839 $this->
ref =
'SPECIMEN';
2840 $this->specimen = 1;
2842 $this->livraison_id = 0;
2844 $this->date_creation = $now;
2845 $this->date_valid = $now;
2846 $this->date_delivery = $now + 24 * 3600;
2847 $this->date_expedition = $now + 24 * 3600;
2849 $this->entrepot_id = 0;
2850 $this->fk_delivery_address = 0;
2853 $this->commande_id = 0;
2854 $this->commande = $order;
2856 $this->origin_id = 1;
2857 $this->origin_type =
'commande';
2859 $this->note_private =
'Private note';
2860 $this->note_public =
'Public note';
2864 while ($xnbp < $nbp) {
2866 $line->product_desc = $langs->trans(
"Description").
" ".$xnbp;
2867 $line->product_label = $langs->trans(
"Description").
" ".$xnbp;
2869 $line->qty_asked = 5;
2870 $line->qty_shipped = 4;
2871 $line->fk_product = $this->commande->lines[$xnbp]->fk_product;
2873 $line->weight = 1.123456;
2874 $line->weight_units = 0;
2876 $line->volume = 2.34567;
2877 $line->volume_unit = 0;
2879 $this->lines[] = $line;
2911 if ($user->hasRight(
'expedition',
'creer')) {
2914 $sql =
"UPDATE ".MAIN_DB_PREFIX.
"expedition";
2915 $sql .=
" SET date_delivery = ".($delivery_date ?
"'".$this->db->idate($delivery_date).
"'" :
'null');
2916 $sql .=
" WHERE rowid = ".((int) $this->
id);
2918 dol_syslog(get_class($this).
"::setDeliveryDate", LOG_DEBUG);
2919 $resql = $this->db->query($sql);
2921 $this->date_delivery = $delivery_date;
2925 $result = $this->call_trigger(
'SHIPPING_MODIFY', $user);
2927 $this->db->rollback();
2933 $this->db->commit();
2936 $this->error = $this->db->error();
2937 $this->db->rollback();
2955 if ($user->hasRight(
'expedition',
'creer')) {
2958 $sql =
"UPDATE ".MAIN_DB_PREFIX.
"expedition";
2959 $sql .=
" SET date_expedition = ".($shipping_date ?
"'".$this->db->idate($shipping_date).
"'" :
'null');
2960 $sql .=
" WHERE rowid = ".((int) $this->
id);
2962 dol_syslog(get_class($this).
"::setShippingDate", LOG_DEBUG);
2963 $resql = $this->db->query($sql);
2965 $this->date_shipping = $shipping_date;
2969 $result = $this->call_trigger(
'SHIPPING_MODIFY', $user);
2971 $this->db->rollback();
2977 $this->db->commit();
2980 $this->error = $this->db->error();
2981 $this->db->rollback();
3001 $sql =
"SELECT em.rowid, em.code, em.libelle as label";
3002 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_shipment_mode as em";
3003 $sql .=
" WHERE em.active = 1";
3004 $sql .=
" ORDER BY em.libelle ASC";
3006 $resql = $this->db->query($sql);
3008 while ($obj = $this->db->fetch_object($resql)) {
3009 $label = $langs->trans(
'SendingMethod'.$obj->code);
3010 $this->meths[(int) $obj->rowid] = ($label !=
'SendingMethod'.$obj->code ? $label : $obj->label);
3027 $this->listmeths = [];
3030 $sql =
"SELECT em.rowid, em.code, em.libelle as label, em.description, em.tracking, em.active";
3031 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_shipment_mode as em";
3033 $sql .=
" WHERE em.rowid=".((int) $id);
3036 $resql = $this->db->query($sql);
3038 while ($obj = $this->db->fetch_object($resql)) {
3039 $label = $langs->trans(
'SendingMethod'.$obj->code);
3040 $this->listmeths[$i] = [
3041 'rowid' => (int) $obj->rowid,
3042 'code' => $obj->code,
3043 'libelle' => ($label !=
'SendingMethod'.$obj->code ? $label : $obj->label),
3044 'description' => $obj->description,
3045 'tracking' => $obj->tracking,
3046 'active' => (
int) $obj->active,
3062 if (!empty($this->shipping_method_id)) {
3063 $sql =
"SELECT em.code, em.tracking";
3064 $sql .=
" FROM ".MAIN_DB_PREFIX.
"c_shipment_mode as em";
3065 $sql .=
" WHERE em.rowid = ".((int) $this->shipping_method_id);
3067 $resql = $this->db->query($sql);
3069 if ($obj = $this->db->fetch_object($resql)) {
3070 $tracking = (string) $obj->tracking;
3075 if (!empty($tracking) && !empty($value)) {
3076 $url = str_replace(
'{TRACKID}', $value, $tracking);
3077 $this->tracking_url = sprintf(
'<a target="_blank" rel="noopener noreferrer" href="%s">%s</a>', $url, $value);
3079 $this->tracking_url = $value;
3095 if ($this->
status == self::STATUS_CLOSED) {
3100 if ($this->
status == self::STATUS_DRAFT) {
3101 $this->
valid($user);
3107 if (empty($this->date_shipping)) {
3108 $sql .=
", date_expedition = '".$this->db->escape($this->db->idate(
dol_now())).
"'";
3110 $sql .=
" WHERE rowid = ".((int) $this->
id).
" AND fk_statut > 0";
3112 $resql = $this->db->query($sql);
3115 if ($this->origin_type ==
'commande' && $this->origin_id > 0) {
3117 $order->fetch($this->origin_id);
3119 $order->loadExpeditions(self::STATUS_CLOSED);
3121 $shipments_match_order = 1;
3122 foreach ($order->lines as $line) {
3123 $lineid = $line->id;
3125 if (($line->product_type == 0 ||
getDolGlobalString(
'STOCK_SUPPORTS_SERVICES')) && $order->expeditions[$lineid] != $qty) {
3126 $shipments_match_order = 0;
3127 $text =
'Qty for order line id '.$lineid.
' is '.$qty.
'. However in the shipments with status Expedition::STATUS_CLOSED='.self::STATUS_CLOSED.
' we have qty = '.$order->expeditions[$lineid].
', so we can t close order';
3132 if ($shipments_match_order) {
3133 dol_syslog(
"Qty for the ".count($order->lines).
" lines of the origin order is same than qty for lines in the shipment we close (shipments_match_order is true), with new status Expedition::STATUS_CLOSED=".self::STATUS_CLOSED.
', so we close order');
3135 $order->cloture($user, 0, 0);
3153 $result = $this->call_trigger(
'SHIPPING_CLOSED', $user);
3159 dol_print_error($this->db);
3164 $this->db->commit();
3170 $this->db->rollback();
3184 private function manageStockMvtOnEvt($user, $labelmovement =
'ShipmentClassifyClosedInDolibarr', $reverse =
false)
3190 require_once DOL_DOCUMENT_ROOT .
'/product/stock/class/mouvementstock.class.php';
3192 $langs->load(
"agenda");
3196 $sql .=
" ed.rowid as edid, ed.fk_product, ed.qty, ed.fk_entrepot";
3197 $sql .=
", cd.rowid as cdid";
3198 $sql .=
", cd.subprice";
3199 $sql .=
", edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock";
3201 $sql .=
" FROM " . $this->db->prefix() .
"expeditiondet as ed";
3202 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"commandedet as cd ON cd.rowid = ed.fk_elementdet";
3203 $sql .=
" LEFT JOIN " . $this->db->prefix() .
"expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid";
3204 $sql .=
" INNER JOIN " . $this->db->prefix() .
"expedition as e ON ed.fk_expedition = e.rowid";
3205 $sql .=
" WHERE ed.fk_expedition = " . ((int) $this->
id);
3208 dol_syslog(get_class($this) .
"::valid select details", LOG_DEBUG);
3209 $resql = $this->db->query($sql);
3211 $cpt = $this->db->num_rows($resql);
3212 for ($i = 0; $i < $cpt; $i++) {
3213 $obj = $this->db->fetch_object($resql);
3214 if (empty($obj->edbrowid)) {
3217 $qty = $obj->edbqty;
3219 if ($qty <= 0 || ($qty < 0 && !
getDolGlobalInt(
'SHIPMENT_ALLOW_NEGATIVE_QTY'))) {
3222 dol_syslog(get_class($this) .
"::valid movement index " . $i .
" ed.rowid=" . $obj->edid .
" edb.rowid=" . $obj->edbrowid);
3227 $qtytouse = $reverse ? -$qty : $qty;
3230 $mouvS->origin = &$this;
3231 $mouvS->setOrigin($this->element, $this->
id, $obj->cdid, $obj->edid);
3233 if (empty($obj->edbrowid)) {
3237 $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qtytouse, $obj->subprice, $langs->trans($labelmovement, $obj->ref));
3247 $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qtytouse, $obj->subprice, $langs->trans($labelmovement, $obj->ref),
'', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock);
3257 $sqldelete =
"DELETE FROM ".$this->db->prefix().
"product_stock WHERE reel = 0 AND rowid NOT IN (SELECT fk_product_stock FROM ".$this->db->prefix().
"product_batch as pb)";
3258 $resqldelete = $this->db->query($sqldelete);
3264 if (!$resqldelete) {
3265 $this->error = $this->db->lasterror();
3266 $this->errors[] = $this->db->lasterror();
3272 $this->error = $this->db->lasterror();
3273 $this->errors[] = $this->db->lasterror();
3296 $sql =
'UPDATE '.MAIN_DB_PREFIX.
'expedition SET billed = 1';
3297 $sql .=
" WHERE rowid = ".((int) $this->
id).
' AND fk_statut > 0';
3299 $resql = $this->db->query($sql);
3304 $result = $this->call_trigger(
'SHIPPING_BILLED', $user);
3311 $this->errors[] = $this->db->lasterror;
3314 if (empty($error)) {
3315 $this->db->commit();
3318 $this->db->rollback();
3335 if ($this->
status <= self::STATUS_DRAFT) {
3347 require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
3349 $langs->load(
"agenda");
3358 $result = $this->
setStatusCommon($user, self::STATUS_DRAFT, $notrigger,
'SHIPMENT_UNVALIDATE');
3365 $this->db->commit();
3368 $this->db->rollback();
3380 global $langs, $user;
3385 if ($this->
status == self::STATUS_VALIDATED) {
3391 $oldbilled = $this->billed;
3393 $sql =
'UPDATE '.MAIN_DB_PREFIX.
'expedition SET fk_statut = 1';
3394 $sql .=
" WHERE rowid = ".((int) $this->
id).
' AND fk_statut > 0';
3396 $resql = $this->db->query($sql);
3404 require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
3406 $langs->load(
"agenda");
3410 $sql =
"SELECT cd.fk_product, cd.subprice,";
3411 $sql .=
" ed.rowid, ed.qty, ed.fk_entrepot,";
3412 $sql .=
" edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock";
3413 $sql .=
" FROM ".MAIN_DB_PREFIX.
"commandedet as cd,";
3414 $sql .=
" ".MAIN_DB_PREFIX.
"expeditiondet as ed";
3415 $sql .=
" LEFT JOIN ".MAIN_DB_PREFIX.
"expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid";
3416 $sql .=
" WHERE ed.fk_expedition = ".((int) $this->
id);
3417 $sql .=
" AND cd.rowid = ed.fk_elementdet";
3419 dol_syslog(get_class($this).
"::valid select details", LOG_DEBUG);
3420 $resql = $this->db->query($sql);
3422 $cpt = $this->db->num_rows($resql);
3423 for ($i = 0; $i < $cpt; $i++) {
3424 $obj = $this->db->fetch_object($resql);
3425 if (empty($obj->edbrowid)) {
3428 $qty = $obj->edbqty;
3433 dol_syslog(get_class($this).
"::reopen expedition movement index ".$i.
" ed.rowid=".$obj->rowid.
" edb.rowid=".$obj->edbrowid);
3437 $mouvS->origin = &$this;
3438 $mouvS->setOrigin($this->element, $this->
id);
3440 if (empty($obj->edbrowid)) {
3444 $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans(
"ShipmentUnClassifyCloseddInDolibarr", $this->ref));
3454 $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans(
"ShipmentUnClassifyCloseddInDolibarr", $this->ref),
'', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock);
3463 $this->error = $this->db->lasterror();
3470 $result = $this->call_trigger(
'SHIPPING_REOPEN', $user);
3477 $this->errors[] = $this->db->lasterror();
3481 $this->db->commit();
3486 $this->billed = $oldbilled;
3487 $this->db->rollback();
3503 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams =
null)
3505 $outputlangs->load(
"products");
3508 $modele =
'espadon';
3510 if (!empty($this->model_pdf)) {
3511 $modele = $this->model_pdf;
3517 $modelpath =
"core/modules/expedition/doc/";
3521 return $this->
commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
Class to manage customers orders.
const STATUS_SHIPMENTONPROCESS
Shipment on process.
const STATUS_VALIDATED
Validated status.
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true)
Save a new position (field rang) for details lines.
deleteEcmFiles($mode=0)
Delete related files of object in database.
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.
fetch_thirdparty($force_thirdparty_id=0)
Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty.
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid=0, $f_user=null, $notrigger=0)
Delete all links between an object $this.
setErrorsFromObject($object)
setErrorsFromObject
updateRangOfLine($rowid, $rang)
Update position of line (rang)
deleteExtraFields()
Delete all extra fields values for the current object.
setStatusCommon($user, $status, $notrigger=0, $triggercode='')
Set to a status.
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).
errorsToString()
Method to output saved errors.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
fetch_origin()
Read linked origin object.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
delete_linked_contact($source='', $code='')
Delete all links between an object $this and all its contacts in llx_element_contact.
add_contact($fk_socpeople, $type_contact, $source='external', $notrigger=0)
Add a link between element $this->element and a contact.
Class to manage receptions.
Class to manage Dolibarr database access.
addline_batch($dbatch, $array_options=[], $origin_line=null)
Add a shipment line with batch record.
create_delivery($user)
Create a delivery receipt from a shipment.
manageStockMvtOnEvt($user, $labelmovement='ShipmentClassifyClosedInDolibarr', $reverse=false)
Manage Stock MVt onb Close or valid Shipment.
setShippingDate($user, $shipping_date, $notrigger=0)
Set the shipping date.
setDraft($user, $notrigger=0)
Set draft status.
const STATUS_SHIPMENT_IN_PROGRESS
Expedition in progress -> package exit the warehouse and is now in the truck or into the hand of the ...
getUrlTrackingStatus($value='')
Forge an set tracking url.
setClosed()
Classify the shipping as closed (this records also the stock movement)
__construct($db)
Constructor.
create_line($entrepot_id, $origin_line_id, $qty, $rang=0, $array_options=[], $parent_line_id=0, $product_id=0)
Create a expedition line.
addline($entrepot_id, $id, $qty, $array_options=[], $fk_product=0, $fk_parent=0)
Add an expedition line.
create($user, $notrigger=0)
Create expedition en base.
LibStatut($status, $mode)
Return label of a status.
checkLineStockRequirements($fk_product, $fk_entrepot, $qty, $product_type=null, $forbid_batch_product=false, $allowEmptyWarehouse=false)
Check stock constraints for a shipment line.
setBilled()
Classify the shipping as invoiced (used for example by trigger when WORKFLOW_SHIPPING_CLASSIFY_BILLED...
updatelinefree($rowid, $qty, $element_type, $fk_product, $fk_unit, $rang, $description, $fk_parent, $notrigger, $array_options=array(), $fk_entrepot=-1)
Update a simple expedition line.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
getTooltipContentArray($params)
getTooltipContentArray
getKanbanView($option='', $arraydata=null)
Return clickable link of object (with eventually picto)
const STATUS_DRAFT
Draft status.
setDeliveryDate($user, $delivery_date, $notrigger=0)
Set the planned delivery date.
line_ajaxorder($rows)
Override to keep every expeditiondet row that belongs to the displayed line in sync when drag & drop ...
const STATUS_CANCELED
Canceled status.
getNomUrl($withpicto=0, $option='', $max=0, $short=0, $notooltip=0, $save_lastsearch_value=-1, $addlinktonotes=0)
Return clickable link of object (with eventually picto)
getLibStatut($mode=0)
Return status label.
set_date_livraison($user, $delivery_date)
Set delivery date.
initAsSpecimen()
Initialise an instance with random values.
const STATUS_CLOSED
Closed status -> parcel was received by customer / end of process prev status : validated or shipment...
const STATUS_VALIDATED
Validated status -> parcel is ready to be sent prev status : draft next status : closed or shipment_i...
create_line_batch($line_ext, $array_options=[])
Create the detail of the expedition line.
addlinefree($qty, $element_type, $fk_product, $fk_unit, $rang, $description, $fk_parent, $array_options=[], $fk_entrepot=0)
Add a simple expedition line.
valid($user, $notrigger=0)
Validate object and update stock if option enabled.
update($user=null, $notrigger=0)
Update database.
fetch_lines_free()
Load lines of simple shipment.
fetch_delivery_methods()
Fetch deliveries method and return an array.
fetch($id, $ref='', $ref_ext='', $notused='')
Get object and lines from database.
reOpen()
Classify the shipping as validated/opened.
deleteLine($user, $lineid)
Delete detail line.
getLinesArray()
Create an array of shipment lines.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
list_delivery_methods($id=0)
Fetch all deliveries method and return an array.
Class to manage lines of shipment.
CRUD class for batch number management within shipment.
Class to manage stock movements.
Class to manage order lines.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
Manage record for batch number management.
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...
getLibSignedStatus(int $mode=0)
Returns the label for signed status.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0, $level=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
dol_dir_list($utf8_path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
dol_now($mode='gmt')
Return date for now.
setEntity($currentobject)
Set entity id to use when to create an object.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
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.
getDolCurrency()
Return the main currency ('EUR', 'USD', ...)
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular VAT rate, when selling a product with vat $vatrate,...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $notused, $price_base_type, $info_bits, $type, $seller=null, $localtaxes_array=[], $progress=100, $multicurrency_tx=1, $pu_devise=0, $multicurrency_code='')
Calculate totals (net, vat, ...) of a line.
print $langs trans('Date')." left Ref Label right Qty right Price right TotalHT right TotalTTC right right right right right right right right right centpercent right TotalHT right n right VAT right n right TotalVAT right n No sujeto a RE IRPF right TotalLT1 right n right TotalLT2 right n right TotalTTC right n takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency right TotalTTC takeposcustomercurrency right takeposcustomercurrency n right Paid right PaymentTypeShortLIQ right SELECT p pos_change as p datep as date
$conf db user
Active Directory does not allow anonymous connections.