35require
'../main.inc.php';
43require_once DOL_DOCUMENT_ROOT.
'/core/modules/supplier_order/modules_commandefournisseur.php';
44require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/entrepot.class.php';
45require_once DOL_DOCUMENT_ROOT.
'/core/lib/fourn.lib.php';
46require_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.commande.class.php';
47require_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.commande.dispatch.class.php';
48require_once DOL_DOCUMENT_ROOT.
'/product/class/html.formproduct.class.php';
49require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/mouvementstock.class.php';
50require_once DOL_DOCUMENT_ROOT.
'/core/lib/sendings.lib.php';
52 require_once DOL_DOCUMENT_ROOT.
'/projet/class/project.class.php';
56$langs->loadLangs(array(
"sendings",
"companies",
"bills",
'orders',
'stocks',
'other',
'propal',
'receptions'));
61if ($is_mod_batch_enabled) {
62 $langs->load(
'productbatch');
69$action =
GETPOST(
'action',
'aZ09');
70$fk_default_warehouse =
GETPOSTINT(
'fk_default_warehouse');
71$cancel =
GETPOST(
'cancel',
'alpha');
72$confirm =
GETPOST(
'confirm',
'alpha');
78 $socid = $user->socid;
81$hookmanager->initHooks(array(
'expeditiondispatch'));
93if ($id > 0 || !empty($ref)) {
94 $result =
$object->fetch($id, $ref);
98 $result =
$object->fetch_thirdparty();
117$usercancreate = $user->hasRight(
'expedition',
'creer');
118$permissiontoadd = $usercancreate;
125$parameters = array();
126$reshook = $hookmanager->executeHooks(
'doActions', $parameters, $object, $action);
131if (empty($reshook)) {
133 if ($action ==
'updatelines' && $usercancreate) {
142 foreach ($_POST as $key => $value) {
145 if (preg_match(
'/^(?:product|productbatch)([0-9]+)_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
148 if (preg_match(
'/^product([0-9]+)_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
149 $modebatch =
"barcode";
150 } elseif (preg_match(
'/^productbatch([0-9]+)_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
151 $modebatch =
"batch";
155 $dispatch_line_suffix = $reg[1].
'_'.$reg[2].
'_'.$reg[3];
156 if ($modebatch ==
"barcode") {
157 $prod =
"product".$dispatch_line_suffix;
159 $prod =
'productbatch'.$dispatch_line_suffix;
161 $qty =
"qty".$dispatch_line_suffix;
162 $ent =
"entrepot".$dispatch_line_suffix;
163 $fk_commandedet =
"fk_commandedet".$dispatch_line_suffix;
164 $idline =
GETPOSTINT(
"idline".$dispatch_line_suffix);
171 if ($modebatch ==
"batch") {
172 $lot =
GETPOST(
'lot_number'.$dispatch_line_suffix);
181 if (($modebatch ==
"batch" && $newqty >= 0) || ($modebatch ==
"barcode" && $newqty != 0)) {
183 if (!($warehouse_id > 0)) {
184 dol_syslog(
'No dispatch for line '.$key.
' as no warehouse was chosen.');
185 $text = $langs->transnoentities(
'Warehouse').
', '.$langs->transnoentities(
'Line').
' '.($numline);
186 setEventMessages($langs->trans(
'ErrorFieldRequired', $text),
null,
'errors');
189 if (!$error && $modebatch ==
"batch") {
190 $sql =
"SELECT pb.rowid ";
191 $sql .=
" FROM ".$db->prefix().
"product_batch as pb";
192 $sql .=
" JOIN ".$db->prefix().
"product_stock as ps";
193 $sql .=
" ON ps.rowid = pb.fk_product_stock";
194 $sql .=
" WHERE pb.batch = '".$db->escape($lot).
"'";
195 $sql .=
" AND ps.fk_product = ".((int) $prod_id) ;
196 $sql .=
" AND ps.fk_entrepot = ".((int) $warehouse_id) ;
198 $resql =
$db->query($sql);
200 $num =
$db->num_rows($resql);
202 dol_syslog(
'No dispatch for line '.$key.
' as too many combination warehouse, product, batch code was found ('.$num.
').');
203 setEventMessages($langs->trans(
'ErrorTooManyCombinationBatchcode', $numline, $num),
null,
'errors');
205 } elseif ($num < 1) {
207 $tmpwarehouse->fetch($warehouse_id);
209 $tmpprod->fetch($prod_id);
210 dol_syslog(
'No dispatch for line '.$key.
' as no combination warehouse, product, batch code was found.');
211 setEventMessages($langs->trans(
'ErrorNoCombinationBatchcode', $numline, $tmpwarehouse->ref, $tmpprod->ref, $lot),
null,
'errors');
223 $result = $expeditiondispatch->fetch($idline);
224 if ($result > 0 && (
int) $expeditiondispatch->fk_expedition !== (
int)
$object->id) {
226 $expeditiondispatch->error = $langs->trans(
'ErrorRecordNotFound');
230 setEventMessages($expeditiondispatch->error, $expeditiondispatch->errors,
'errors');
233 $qtystart = $expeditiondispatch->qty;
234 $expeditiondispatch->qty = $newqty;
235 $expeditiondispatch->entrepot_id =
GETPOSTINT($ent);
238 $result = $expeditiondispatch->update($user);
240 $result = $expeditiondispatch->delete($user);
243 setEventMessages($expeditiondispatch->error, $expeditiondispatch->errors,
'errors');
247 if (!$error && $modebatch ==
"batch") {
249 $suffixkeyfordate = preg_replace(
'/^productbatch/',
'', $key);
253 $sqlsearchdet =
"SELECT rowid FROM ".$db->prefix().$expeditionlinebatch->table_element;
254 $sqlsearchdet .=
" WHERE fk_expeditiondet = ".((int) $idline);
255 $resqlsearchdet =
$db->query($sqlsearchdet);
257 $objsearchdet =
null;
258 if ($resqlsearchdet) {
259 $objsearchdet =
$db->fetch_object($resqlsearchdet);
265 $sql =
"UPDATE ".$db->prefix().$expeditionlinebatch->table_element.
" SET";
266 $sql .=
" batch = '".$db->escape($lot).
"'";
267 $sql .=
", eatby = ".($eatby ?
"'".$db->idate($eatby).
"'" :
"null");
268 $sql .=
", sellby = ".($sellby ?
"'".$db->idate($sellby).
"'" :
"null");
269 $sql .=
", qty = ".((float) $newqty);
270 $sql .=
", fk_warehouse = ".((int) $warehouse_id);
271 $sql .=
" WHERE rowid = ".((int) $objsearchdet->rowid);
273 $sql =
"INSERT INTO ".$db->prefix().$expeditionlinebatch->table_element.
" (";
274 $sql .=
"fk_expeditiondet, eatby, sellby, batch, qty, fk_origin_stock, fk_warehouse)";
275 $sql .=
" VALUES (".((int) $idline).
", ".($eatby ?
"'".$db->idate($eatby).
"'" :
"null").
", ".($sellby ?
"'".
$db->idate($sellby).
"'" :
"null").
", ";
276 $sql .=
" '".$db->escape($lot).
"', ".((float) $newqty).
", 0, ".((int) $warehouse_id).
")";
279 $sql =
"DELETE FROM ".$db->prefix().$expeditionlinebatch->table_element;
280 $sql .=
" WHERE fk_expeditiondet = ".((int) $idline);
281 $sql .=
" AND batch = '".$db->escape($lot).
"'";
284 $resql =
$db->query($sql);
292 $expeditiondispatch->fk_expedition =
$object->id;
293 $expeditiondispatch->entrepot_id =
GETPOSTINT($ent);
294 $expeditiondispatch->fk_parent =
GETPOSTINT(
'fk_parent'.$dispatch_line_suffix);
295 $expeditiondispatch->fk_product = $prod_id;
296 if (!($expeditiondispatch->fk_parent > 0)) {
297 $expeditiondispatch->fk_elementdet =
GETPOSTINT($fk_commandedet);
299 $expeditiondispatch->qty = $newqty;
302 $idline = $expeditiondispatch->insert($user);
304 setEventMessages($expeditiondispatch->error, $expeditiondispatch->errors,
'errors');
308 if ($modebatch ==
"batch" && !$error) {
309 $expeditionlinebatch->sellby = $dDLC;
310 $expeditionlinebatch->eatby = $dDLUO;
311 $expeditionlinebatch->batch = $lot;
312 $expeditionlinebatch->qty = $newqty;
313 $expeditionlinebatch->fk_origin_stock = 0;
314 $expeditionlinebatch->fk_warehouse =
GETPOSTINT($ent);
316 $result = $expeditionlinebatch->create($idline);
318 setEventMessages($expeditionlinebatch->error, $expeditionlinebatch->errors,
'errors');
375 header(
"Location: ".DOL_URL_ROOT.
'/expedition/dispatch.php?id='.
$object->id);
378 } elseif ($action ==
'setdate_livraison' && $usercancreate) {
382 $result =
$object->setDeliveryDate($user, $datedelivery);
400$title =
$object->ref.
" - ".$langs->trans(
'ShipmentDistribution');
401$help_url =
'EN:Module_Shipments|FR:Module_Expéditions|ES:Módulo_Expediciones|DE:Modul_Lieferungen';
402$morejs = array(
'/expedition/js/lib_dispatch.js.php');
405llxHeader(
'', $title, $help_url,
'', 0, 0, $morejs,
'',
'',
'mod-expedition page-card_dispatch');
411 $num_prod = count($lines);
424 $author->fetch(
$object->user_author_id);
434 if ($action ==
'ask_deleteline') {
435 $formconfirm = $form->formconfirm($_SERVER[
"PHP_SELF"].
'?id='.
$object->id.
'&lineid='.$lineid, $langs->trans(
'DeleteLine'), $langs->trans(
'ConfirmDeleteLine'),
'confirm_deleteline',
'', 0, 1);
439 $parameters = array(
'lineid' => $lineid);
441 $reshook = $hookmanager->executeHooks(
'formConfirm', $parameters, $object, $action);
442 if (empty($reshook)) {
443 $formconfirm .= $hookmanager->resPrint;
444 } elseif ($reshook > 0) {
445 $formconfirm = $hookmanager->resPrint;
454 $objectsrc->fetch(
$object->origin_object->id);
458 $objectsrc->fetch(
$object->origin_object->id);
462 $linkback =
'<a href="'.DOL_URL_ROOT.
'/expedition/list.php?restore_lastsearch_values=1'.(!empty($socid) ?
'&socid='.$socid :
'').
'">'.$langs->trans(
"BackToList").
'</a>';
463 $morehtmlref =
'<div class="refidno">';
466 $morehtmlref .= $form->editfieldkey(
"RefCustomer",
'ref_customer',
$object->ref_customer, $object, $user->hasRight(
'expedition',
'creer'),
'string',
'', 0, 1);
467 $morehtmlref .= $form->editfieldval(
"RefCustomer",
'ref_customer',
$object->ref_customer, $object, $user->hasRight(
'expedition',
'creer'),
'string'.(isset(
$conf->global->THIRDPARTY_REF_INPUT_SIZE) ?
':' .
getDolGlobalString(
'THIRDPARTY_REF_INPUT_SIZE') :
''),
'', null, null,
'', 1);
470 $morehtmlref .=
'<br>'.$object->thirdparty->getNomUrl(1);
473 $langs->load(
"projects");
474 $morehtmlref .=
'<br>';
476 $morehtmlref .=
img_picto($langs->trans(
"Project"),
'project',
'class="pictofixedwidth"');
477 if ($action !=
'classify' && $permissiontoadd) {
478 $morehtmlref .=
'<a class="editfielda" href="'.dolBuildUrl($_SERVER[
'PHP_SELF'], [
'action' =>
'classify',
'id' =>
$object->id],
true).
'">'.
img_edit($langs->transnoentitiesnoconv(
'SetProject')).
'</a> ';
480 $morehtmlref .= $form->form_project($_SERVER[
'PHP_SELF'].
'?id='.
$object->id, (!
getDolGlobalString(
'PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS') ?
$object->socid : -1), (
string)
$object->fk_project, ($action ==
'classify' ?
'projectid' :
'none'), 0, 0, 0, 1,
'',
'maxwidth300');
482 if (!empty($objectsrc) && !empty($objectsrc->fk_project)) {
484 $proj->fetch($objectsrc->fk_project);
485 $morehtmlref .= $proj->getNomUrl(1);
487 $morehtmlref .=
'<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).
'</span>';
492 $morehtmlref .=
'</div>';
494 dol_banner_tab($object,
'ref', $linkback, 1,
'ref',
'ref', $morehtmlref);
497 print
'<div class="fichecenter">';
498 print
'<div class="underbanner clearboth"></div>';
500 print
'<table class="border tableforfield centpercent">';
507 print $langs->trans(
"RefOrder").
'</td>';
508 print
'<td colspan="3">';
509 print $objectsrc->getNomUrl(1,
'commande');
516 print $langs->trans(
"RefProposal").
'</td>';
517 print
'<td colspan="3">';
518 print $objectsrc->getNomUrl(1,
'expedition');
524 print
'<tr><td class="titlefield">'.$langs->trans(
"DateCreation").
'</td>';
525 print
'<td colspan="3">'.dol_print_date(
$object->date_creation,
"dayhour",
"tzuserrel").
"</td>\n";
529 print
'<tr><td height="10">';
530 print
'<table class="nobordernopadding" width="100%"><tr><td>';
531 print $langs->trans(
'DateDeliveryPlanned');
533 if ($action !=
'editdate_livraison') {
534 print
'<td class="right"><a class="editfielda" href="'.$_SERVER[
"PHP_SELF"].
'?action=editdate_livraison&token='.
newToken().
'&id='.
$object->id.
'">'.
img_edit($langs->trans(
'SetDeliveryDate'), 1).
'</a></td>';
536 print
'</tr></table>';
537 print
'</td><td colspan="2">';
538 if ($action ==
'editdate_livraison') {
539 print
'<form name="setdate_livraison" action="'.$_SERVER[
"PHP_SELF"].
'?id='.
$object->id.
'" method="post">';
540 print
'<input type="hidden" name="token" value="'.newToken().
'">';
541 print
'<input type="hidden" name="action" value="setdate_livraison">';
542 print $form->selectDate(
$object->date_delivery ?
$object->date_delivery : -1,
'liv_', 1, 1, 0,
"setdate_livraison", 1, 0);
543 print
'<input type="submit" class="button button-edit smallpaddingimp" value="'.$langs->trans(
'Modify').
'">';
549 print
'</tr></table>';
551 print
'<br><br><center>';
553 print
'<a href="'.$_SERVER[
"PHP_SELF"].
'?id='.
$object->id.
'&action=updatebyscaning&token='.
currentToken().
'" class="marginrightonly paddingright marginleftonly paddingleft">'.
img_picto(
'',
'barcode',
'class="paddingrightonly"').$langs->trans(
"UpdateByScaning").
'</a>';
555 print
'<a href="#" id="resetalltoexpected" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto(
"",
'autofill',
'class="pictofixedwidth"').$langs->trans(
"RestoreWithCurrentQtySaved").
'</a></td>';
557 print
'<a href="#" id="autoreset" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto(
"",
'eraser',
'class="pictofixedwidth"').$langs->trans(
"ClearQtys").
'</a></td>';
564 require_once DOL_DOCUMENT_ROOT.
'/product/class/html.formproduct.class.php';
566 $formproduct->loadWarehouses();
568 $listwarehouses = $entrepot->list_array(1);
576 print
'<form method="post" action="'.dolBuildUrl($_SERVER[
"PHP_SELF"]).
'">';
578 print
'<input type="hidden" name="token" value="'.newToken().
'">';
579 print
'<input type="hidden" name="action" value="updatelines">';
580 print
'<input type="hidden" name="id" value="'.$object->id.
'">';
582 print
'<div class="div-table-responsive-no-min">';
583 print
'<table class="noborder centpercent">';
586 $products_dispatched = array();
587 $sql =
"SELECT ed.fk_elementdet as rowid, sum(ed.qty) as qty";
588 $sql .=
" FROM ".$db->prefix().
"expeditiondet as ed";
589 $sql .=
" WHERE ed.fk_expedition = ".((int)
$object->id);
590 $sql .=
" GROUP BY ed.fk_elementdet";
592 $resql =
$db->query($sql);
594 $num =
$db->num_rows($resql);
599 $objd =
$db->fetch_object($resql);
600 $products_dispatched[$objd->rowid] =
price2num($objd->qty,
'MS');
607 if ($objectsrc instanceof
Commande) {
609 $sql =
"SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, '' AS sref, l.qty as qty,";
610 $sql .=
" p.ref, p.label, p.tobatch, p.fk_default_warehouse, p.barcode, p.stockable_product";
612 $parameters = array();
613 $reshook = $hookmanager->executeHooks(
614 'printFieldListSelect',
622 $sql .= $hookmanager->resPrint;
624 $sql .=
" FROM ".$db->prefix().
"commandedet as l";
625 $sql .=
" LEFT JOIN ".$db->prefix().
"product as p ON l.fk_product=p.rowid";
626 $sql .=
" WHERE l.fk_commande = ".((int) $objectsrc->id);
628 $sql .=
" AND l.product_type = 0";
631 $parameters = array();
632 $reshook = $hookmanager->executeHooks(
633 'printFieldListWhere',
641 $sql .= $hookmanager->resPrint;
644 $sql .=
" ORDER BY l.rang, p.ref, p.label";
646 $resql =
$db->query($sql);
648 $num =
$db->num_rows($resql);
653 print
'<tr class="liste_titre">';
655 print
'<td>'.$langs->trans(
"Description").
'</td>';
656 if ($is_mod_batch_enabled) {
657 print
'<td class="dispatch_batch_number_title">'.$langs->trans(
"batch_number").
'</td>';
658 if ($is_sell_by_enabled) {
659 print
'<td class="dispatch_dlc_title">'.$langs->trans(
"SellByDate").
'</td>';
661 if ($is_eat_by_enabled) {
662 print
'<td class="dispatch_dluo_title">'.$langs->trans(
"EatByDate").
'</td>';
669 print
'<td class="right">'.$langs->trans(
"QtyOrdered").
'</td>';
671 print
'<td class="right">'.$langs->trans(
"QtyToShip");
673 print
'<td class="right">'.$langs->trans(
"QtyDispatchedShort").
'</td>';
675 print
'<td class="right">'.$langs->trans(
"Details");
676 print
'<td width="32"></td>';
680 print
'<td class="right">'.$langs->trans(
"Price").
'</td>';
681 print
'<td class="right">'.$langs->trans(
"ReductionShort").
' (%)</td>';
682 print
'<td class="right">'.$langs->trans(
"UpdatePrice").
'</td>';
686 print
'<td class="right">'.$langs->trans(
"Warehouse");
689 if (count($listwarehouses) > 1) {
690 print
'<br><span class="opacitymedium">'.$langs->trans(
"ForceTo").
'</span> '.$form->selectarray(
'fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 1, 0, 0,
'', 0, 0, $disabled,
'',
'minwidth100 maxwidth300', 1);
691 } elseif (count($listwarehouses) == 1) {
692 print
'<br><span class="opacitymedium">'.$langs->trans(
"ForceTo").
'</span> '.$form->selectarray(
'fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 0, 0, 0,
'', 0, 0, $disabled,
'',
'minwidth100 maxwidth300', 1);
698 $parameters = array();
699 $reshook = $hookmanager->executeHooks(
700 'printFieldListTitle',
708 print $hookmanager->resPrint;
713 $conf->cache[
'product'] = array();
717 $objp =
$db->fetch_object($resql);
720 if (!$objp->fk_product > 0) {
723 $alreadydispatched = isset($products_dispatched[$objp->rowid]) ? $products_dispatched[$objp->rowid] : 0;
724 $remaintodispatch =
price2num($objp->qty, 5);
725 if ($remaintodispatch < 0 && !
getDolGlobalString(
'SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN')) {
726 $remaintodispatch = 0;
729 if ($remaintodispatch || !
getDolGlobalString(
'SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
738 print
'<!-- Line to dispatch '.$suffix.
' -->'.
"\n";
740 print
'<input id="qty_ordered'.$suffix.
'" type="hidden" value="'.$objp->qty.
'">';
741 print
'<input id="qty_dispatched'.$suffix.
'" type="hidden" data-dispatched="'.((float) $alreadydispatched).
'" value="'.(float) $alreadydispatched.
'">';
742 print
'<tr class="oddeven">';
744 if (empty(
$conf->cache[
'product'][$objp->fk_product])) {
746 $tmpproduct->fetch($objp->fk_product);
747 $conf->cache[
'product'][$objp->fk_product] = $tmpproduct;
749 $tmpproduct =
$conf->cache[
'product'][$objp->fk_product];
752 $linktoprod =
'<div class="twolinesmax lineheightsmall">';
753 $linktoprod .= $tmpproduct->getNomUrl(1);
754 $linktoprod .=
'<br><span class="opacitymedium small">'.dolPrintHTML($objp->label).
"</span>\n";
755 $linktoprod .=
'</div>';
757 if ($is_mod_batch_enabled) {
758 if ($objp->tobatch) {
760 print
'<td class="tdoverflowbydiv nopaddingtopimp nopaddingbottomimp" id="product_'.$i.
'" data-idproduct="'.$objp->fk_product.
'" data-barcode="'.$objp->barcode.
'">';
763 print
'<td class="dispatch_batch_number"></td>';
764 if ($is_sell_by_enabled) {
765 print
'<td class="dispatch_dlc"></td>';
767 if ($is_eat_by_enabled) {
768 print
'<td class="dispatch_dluo"></td>';
772 print
'<td id="product_'.$i.
'" data-idproduct="'.$objp->fk_product.
'" data-barcode="'.$objp->barcode.
'">';
775 print
'<td class="dispatch_batch_number">';
776 print
'<span class="opacitymedium small">'.$langs->trans(
"ProductDoesNotUseBatchSerial").
'</span>';
778 if ($is_sell_by_enabled) {
779 print
'<td class="dispatch_dlc"></td>';
781 if ($is_eat_by_enabled) {
782 print
'<td class="dispatch_dluo"></td>';
786 print
'<td colspan="4">';
792 $up_ht_disc = $objp->subprice;
793 if (!empty($objp->remise_percent) && !
getDolGlobalString(
'STOCK_EXCLUDE_DISCOUNT_FOR_PMP')) {
794 $up_ht_disc =
price2num($up_ht_disc * (100 - $objp->remise_percent) / 100,
'MU');
798 print
'<td class="right">'.$objp->qty.
'</td>';
801 print
'<td class="right">'.$alreadydispatched.
'</td>';
803 print
'<td class="right">';
809 $sql =
"SELECT ed.rowid, ed.fk_parent";
810 $sql .=
", cd.fk_product";
811 $sql .=
", ".$db->ifsql(
'eb.rowid IS NULL',
'ed.qty',
'eb.qty').
" as qty";
812 $sql .=
", ".$db->ifsql(
'eb.rowid IS NULL OR eb.fk_warehouse IS NULL',
'ed.fk_entrepot',
'eb.fk_warehouse').
" as fk_warehouse";
813 $sql .=
", eb.batch, eb.eatby, eb.sellby";
814 $sql .=
" FROM ".$db->prefix().
"expeditiondet as ed";
815 $sql .=
" LEFT JOIN ".$db->prefix().
"expeditiondet_batch as eb on ed.rowid = eb.fk_expeditiondet";
816 $sql .=
" INNER JOIN ".$db->prefix().
"commandedet as cd on ed.fk_elementdet = cd.rowid";
817 $sql .=
" WHERE ed.fk_elementdet = ".(int) $objp->rowid;
818 $sql .=
" AND ed.fk_expedition = ".(int)
$object->id;
819 $sql .=
" ORDER BY ed.rowid, ed.fk_elementdet";
821 $resultsql =
$db->query($sql);
824 $numd =
$db->num_rows($resultsql);
825 while ($obj_exp =
$db->fetch_object($resultsql)) {
826 $suffix =
"_" . $j .
"_" . $i;
828 $productChildrenNb = 0;
829 $expedition_line_child_list = array();
832 $productChildrenNb = $tmpproduct->hasFatherOrChild(1);
833 if ($productChildrenNb > 0) {
834 $line_id_list = array();
838 $result = $expeditionLine->findAllChild($obj_exp->rowid, $line_id_list, 1);
841 foreach ($line_id_list as $line_id_arr) {
842 foreach ($line_id_arr as $line_obj) {
843 $child_product_id = (int) $line_obj->fk_product;
844 if (empty(
$conf->cache[
'product'][$child_product_id])) {
846 $child_product->fetch($child_product_id);
847 $conf->cache[
'product'][$child_product_id] = $child_product;
849 $child_product =
$conf->cache[
'product'][$child_product_id];
853 $batch_list = array();
854 if ($is_mod_batch_enabled && $child_product->hasbatch()) {
856 $sql_line_batch_search =
"SELECT eb.rowid, eb.qty, eb.batch, eb.sellby, eb.eatby";
857 $sql_line_batch_search .=
" FROM ".$db->prefix().
"expeditiondet_batch as eb";
858 $sql_line_batch_search .=
" WHERE eb.fk_expeditiondet = ".((int) $line_obj->rowid);
859 $res_line_batch_search =
$db->query($sql_line_batch_search);
860 if ($res_line_batch_search) {
861 while ($obj_batch =
$db->fetch_object($res_line_batch_search)) {
863 if ($obj_batch->batch !=
'') {
864 $line_obj->batch = $obj_batch->batch;
868 $batch_list[] = $obj_batch;
870 $db->free($res_line_batch_search);
874 if (empty($batch_list)) {
875 $batch_sort_field_arr = array();
876 $batch_sort_order_arr = array();
877 if ($is_sell_by_enabled) {
878 $batch_sort_field_arr[] =
'pl.sellby';
879 $batch_sort_order_arr[] =
'ASC';
881 if ($is_eat_by_enabled) {
882 $batch_sort_field_arr[] =
'pl.eatby';
883 $batch_sort_order_arr[] =
'ASC';
885 $batch_sort_field_arr[] =
'pb.qty';
886 $batch_sort_order_arr[] =
'ASC';
887 $batch_sort_field_arr[] =
'pl.rowid';
888 $batch_sort_order_arr[] =
'ASC';
890 $product_batch_result = $product_batch->findAllForProduct($child_product_id, $line_obj->fk_warehouse, (
getDolGlobalInt(
'STOCK_DISALLOW_NEGATIVE_TRANSFER') ? 0 : null), implode(
',', $batch_sort_field_arr), implode(
',', $batch_sort_order_arr));
891 if (is_array($product_batch_result)) {
892 foreach ($product_batch_result as $batch_current) {
893 $batch_current->eatby =
dol_print_date($batch_current->eatby,
'day');
894 $batch_current->sellby =
dol_print_date($batch_current->sellby,
'day');
895 $batch_list[] = $batch_current;
900 $line_obj->batch_list = $batch_list;
903 $line_obj->iskit = 0;
904 if ($child_product->stockable_product == Product::ENABLED_STOCK) {
905 $can_manage_stock = 1;
907 $can_manage_stock = 0;
909 $line_obj->incdec = $can_manage_stock;
910 $sql_child =
"SELECT ";
911 $sql_child .=
" SUM(".$db->ifsql(
"pa.rowid IS NOT NULL",
"1",
"0").
") as iskit";
912 $sql_child .=
", ".$db->ifsql(
"pai.incdec IS NULL",
"1",
"pai.incdec").
" as incdec";
913 $sql_child .=
" FROM ".$db->prefix().
"expeditiondet as ed";
914 $sql_child .=
" LEFT JOIN ".$db->prefix().
"expeditiondet as edp ON edp.rowid = ".((int) $line_obj->fk_parent);
915 $sql_child .=
" LEFT JOIN ".$db->prefix().
"product_association as pa ON pa.fk_product_pere = ".((int) $child_product_id);
916 $sql_child .=
" LEFT JOIN ".$db->prefix().
"product_association as pai ON pai.fk_product_pere = edp.fk_product AND pai.fk_product_fils = ".((int) $child_product_id);
917 $sql_child .=
" WHERE ed.rowid = ".((int) $line_obj->rowid);
918 $sql_child .=
" GROUP BY pa.rowid, pai.incdec";
919 $resql_child =
$db->query($sql_child);
921 if ($child_obj =
$db->fetch_object($resql_child)) {
922 if (!
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE')) {
923 $line_obj->iskit = (int) $child_obj->iskit;
925 if ($can_manage_stock) {
926 $line_obj->incdec = (int) $child_obj->incdec;
929 $db->free($resql_child);
931 $line_obj->html_label = str_repeat(
" ", $child_level) .
"→" . $child_product->getNomUrl(1);
932 $expedition_line_child_list[] = $line_obj;
939 if (empty($expedition_line_child_list)) {
942 if ($objp->stockable_product == Product::ENABLED_STOCK) {
943 $obj_exp->incdec = 1;
945 $obj_exp->incdec = 0;
947 $expedition_line_child_list[] = $obj_exp;
950 $child_suffix = $suffix;
951 foreach ($expedition_line_child_list as $objd) {
952 $child_line_id = $objd->rowid;
954 $can_update_stock = empty($objd->iskit) && !empty($objd->incdec);
955 $suffix = $child_line_id.$child_suffix;
958 $dispatch_line_batch_current =
null;
959 if (!empty($objd->batch_list)) {
960 $dispatch_line_batch_count = count($objd->batch_list);
962 if ($dispatch_line_batch_count == 1) {
963 $dispatch_line_batch_current = current($objd->batch_list);
966 if (is_object($dispatch_line_batch_current)) {
967 $objd->batch = $dispatch_line_batch_current->batch;
968 $objd->eatby = $dispatch_line_batch_current->eatby;
969 $objd->sellby = $dispatch_line_batch_current->sellby;
972 if ($is_mod_batch_enabled
975 || (is_null($objd->batch) && $tmpproduct->status_batch > 0)
976 || !empty($objd->batch_list)
984 'is_information_row' =>
true,
989 $reshook = $hookmanager->executeHooks(
990 'printFieldListValue',
998 print $hookmanager->resPrint;
1002 print
'<!-- line for batch ' . $numline .
' -->';
1003 print
'<tr class="oddeven autoresettr" name="' . $type .
'-' . $suffix .
'" data-remove="clear">';
1005 print
'<input id="fk_commandedet' . $suffix .
'" name="fk_commandedet' . $suffix .
'" type="hidden" value="' . $objp->rowid .
'">';
1006 print
'<input id="idline' . $suffix .
'" name="idline' . $suffix .
'" type="hidden" value="' . $objd->rowid .
'">';
1007 print
'<input id="fk_parent' . $suffix .
'" name="fk_parent' . $suffix .
'" type="hidden" value="' . $objd->fk_parent .
'">';
1008 print
'<input name="productbatch' . $suffix .
'" type="hidden" value="' . $objd->fk_product .
'">';
1010 print
'<!-- This is a U.P. (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
1011 print
'<input class="maxwidth75" name="pu' . $suffix .
'" type="hidden" value="' .
price2num($up_ht_disc,
'MU') .
'">';
1012 if (!empty($objd->html_label)) {
1013 print $objd->html_label;
1018 print
'<input type="text" class="inputlotnumber quatrevingtquinzepercent csslotnumber" name="lot_number'.$suffix.
'" value="'.(
GETPOSTISSET(
'lot_number'.$suffix) ?
GETPOST(
'lot_number'.$suffix) : $objd->batch).
'" list="lot_number'.$suffix.
'">';
1019 print $formproduct->selectLotDataList(
'lot_number'.$suffix, 0, $objd->fk_product,
GETPOST(
"entrepot".$suffix) ?
GETPOST(
"entrepot".$suffix) : $objd->fk_warehouse, array());
1022 if ($is_sell_by_enabled) {
1023 print
'<td class="nowraponall">';
1025 print $form->selectDate($dlcdatesuffix,
'dlc'.$suffix, 0, 0, 1,
'');
1028 if ($is_eat_by_enabled) {
1029 print
'<td class="nowraponall">';
1031 print $form->selectDate($dluodatesuffix,
'dluo'.$suffix, 0, 0, 1,
'');
1034 print
'<td colspan="2"> </td>';
1038 $colspan = $is_sell_by_enabled ? $colspan : --$colspan;
1039 $colspan = $is_eat_by_enabled ? $colspan : --$colspan;
1042 $parameters = array(
1044 'is_information_row' =>
true,
1046 'suffix' => $suffix,
1049 $reshook = $hookmanager->executeHooks(
1050 'printFieldListValue',
1058 print $hookmanager->resPrint;
1062 print
'<!-- line no batch '.$numline.
' -->';
1063 print
'<tr class="oddeven autoresettr" name="'.$type.
'-'.$suffix.
'" data-remove="clear">';
1064 print
'<td colspan="'.$colspan.
'">';
1065 print
'<input id="fk_commandedet'.$suffix.
'" name="fk_commandedet'.$suffix.
'" type="hidden" value="'.$objp->rowid.
'">';
1066 print
'<input id="idline'.$suffix.
'" name="idline'.$suffix.
'" type="hidden" value="'.$objd->rowid.
'">';
1067 print
'<input id="fk_parent'.$suffix.
'" name="fk_parent'.$suffix.
'" type="hidden" value="'.$objd->fk_parent.
'">';
1068 print
'<input name="product'.$suffix.
'" type="hidden" value="'.$objd->fk_product.
'">';
1069 print
'<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
1070 print
'<input class="maxwidth75" name="pu'.$suffix.
'" type="hidden" value="'.
price2num($up_ht_disc,
'MU').
'">';
1071 if (!empty($objd->html_label)) {
1072 print $objd->html_label;
1077 print
'<td class="right nowraponall">';
1080 if ($can_update_stock) {
1081 print
'<a href="" id="reset'.$suffix.
'" class="resetline">'.
img_picto($langs->trans(
"Reset"),
'eraser',
'class="pictofixedwidth opacitymedium"').
'</a>';
1082 print
'<input id="qty'.$suffix.
'" onchange="onChangeDispatchLineQty($(this))" name="qty'.$suffix.
'" data-type="'.$type.
'" data-index="'.$i.
'" class="width50 right qtydispatchinput" value="'.$suggestedvalue.
'" data-expected="'.$objd->qty.
'">';
1084 print
'<input type="hidden" id="qty'.$suffix.
'" name="qty'.$suffix.
'" value="">';
1088 if ($can_update_stock) {
1089 print
img_picto($langs->trans(
'AddStockLocationLine'),
'split',
'class="splitbutton" onClick="addDispatchLine('.$i.
', \''.$type.
'-'.$child_line_id.
'\')
"');
1094 print '<td class="right
">';
1095 if ($can_update_stock) {
1096 if (count($listwarehouses) > 1) {
1097 print $formproduct->selectWarehouses(GETPOST("entrepot
".$suffix) ? GETPOST("entrepot
".$suffix) : $objd->fk_warehouse, "entrepot
".$suffix, '', 1, 0, $objd->fk_product, '', 1, 0, array(), 'csswarehouse'.$suffix);
1098 } elseif (count($listwarehouses) == 1) {
1099 print $formproduct->selectWarehouses(GETPOST("entrepot
".$suffix) ? GETPOST("entrepot
".$suffix) : $objd->fk_warehouse, "entrepot
".$suffix, '', 0, 0, $objd->fk_product, '', 1, 0, array(), 'csswarehouse'.$suffix);
1101 $langs->load("errors
");
1102 print $langs->trans("ErrorNoWarehouseDefined
");
1105 // we force the warehouse so we will pass the test to add a line into expedition.class.php
1106 print '<input id="entrepot
'.$suffix.'" name="entrepot
'.$suffix.'" type="hidden
" value="'.$objd->fk_warehouse.'">';
1107 print img_warning().' '.$langs->trans('StockDisabled');
1111 // Enable hooks to append additional columns
1112 $parameters = array(
1113 'is_information_row' => false, // this is a dispatch form row
1115 'suffix' => $suffix,
1119 $reshook = $hookmanager->executeHooks(
1120 'printFieldListValue',
1126 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1128 print $hookmanager->resPrint;
1137 //$suffix = "_
".$j."_
".$i;
1139 $errorMsg = 'Shipment dispatch SQL error : '.$db->lasterror();
1140 setEventMessage($errorMsg, 'errors');
1141 dol_syslog($errorMsg, LOG_ERR);
1146 if ($is_mod_batch_enabled && !empty($objp->tobatch)) {
1149 // Enable hooks to append additional columns
1150 $parameters = array(
1151 // allows hook to distinguish between the rows with information and the rows with dispatch form input
1152 'is_information_row' => true,
1154 'suffix' => $suffix,
1157 $reshook = $hookmanager->executeHooks(
1158 'printFieldListValue',
1164 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1166 print $hookmanager->resPrint;
1170 print '<!-- line for batch '.$numline.' (not dispatched line yet for this order line) -->';
1171 print '<tr class="oddeven autoresettr
" name="'.$type.$suffix.'" data-remove="clear
">';
1173 print '<input id="fk_commandedet
'.$suffix.'" name="fk_commandedet
'.$suffix.'" type="hidden
" value="'.$objp->rowid.'">';
1174 print '<input id="idline
'.$suffix.'" name="idline
'.$suffix.'" type="hidden
" value="-1
">';
1175 print '<input name="productbatch
'.$suffix.'" type="hidden
" value="'.$objp->fk_product.'">';
1177 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
1178 print '<input class="maxwidth75
" name="pu
'.$suffix.'" type="hidden
" value="'.price2num($up_ht_disc, 'MU
').'">';
1182 print '<input type="text
" class="inputlotnumber quatrevingtquinzepercent
" id="lot_number
'.$suffix.'" name="lot_number
'.$suffix.'" value="'.GETPOST('lot_number
'.$suffix).'">';
1184 if ($is_sell_by_enabled) {
1185 print '<td class="nowraponall
">';
1186 $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOSTINT('dlc'.$suffix.'month'), GETPOSTINT('dlc'.$suffix.'day'), GETPOSTINT('dlc'.$suffix.'year'));
1187 print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, 0, 0, 1, '');
1190 if ($is_eat_by_enabled) {
1191 print '<td class="nowraponall
">';
1192 $dluodatesuffix = dol_mktime(0, 0, 0, GETPOSTINT('dluo'.$suffix.'month'), GETPOSTINT('dluo'.$suffix.'day'), GETPOSTINT('dluo'.$suffix.'year'));
1193 print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, 0, 0, 1, '');
1196 print '<td colspan="2
"> </td>'; // Supplier ref + Qty ordered + qty already dispatched
1200 $colspan = $is_sell_by_enabled ? $colspan : --$colspan;
1201 $colspan = $is_eat_by_enabled ? $colspan : --$colspan;
1203 // Enable hooks to append additional columns
1204 $parameters = array(
1205 // allows hook to distinguish between the rows with information and the rows with dispatch form input
1206 'is_information_row' => true,
1208 'suffix' => $suffix,
1211 $reshook = $hookmanager->executeHooks(
1212 'printFieldListValue',
1218 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1220 print $hookmanager->resPrint;
1224 print '<!-- line no batch '.$numline.' (not dispatched line yet for this order line) -->';
1225 print '<tr class="oddeven autoresettr
" name="'.$type.$suffix.'" data-remove="clear
">';
1226 print '<td colspan="'.$colspan.'">';
1227 print '<input id="fk_commandedet
'.$suffix.'" name="fk_commandedet
'.$suffix.'" type="hidden
" value="'.$objp->rowid.'">';
1228 print '<input id="idline
'.$suffix.'" name="idline
'.$suffix.'" type="hidden
" value="-1
">';
1229 print '<input name="product
'.$suffix.'" type="hidden
" value="'.$objp->fk_product.'">';
1231 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
1232 print '<input class="maxwidth75
" name="pu
'.$suffix.'" type="hidden
" value="'.price2num($up_ht_disc, 'MU
').'">';
1236 print '<td class="right
">';
1237 print '<a href="" id="reset
'.$suffix.'" class="resetline
">'.img_picto($langs->trans("Reset
"), 'eraser', 'class="pictofixedwidth opacitymedium
"').'</a>';
1238 $amounttosuggest = (GETPOSTISSET('qty'.$suffix) ? GETPOSTINT('qty'.$suffix) : (!getDolGlobalString('SUPPLIER_ORDER_DISPATCH_FORCE_QTY_INPUT_TO_ZERO') ? $remaintodispatch : 0));
1239 if (count($products_dispatched)) {
1240 // There is already existing lines into llx_expeditiondet, this means a plan for the shipment has already been started.
1241 // In such a case, we do not suggest new values, we suggest the value known.
1242 $amounttosuggest = (GETPOSTISSET('qty'.$suffix) ? GETPOSTINT('qty'.$suffix) : (isset($products_dispatched[$objp->rowid]) ? $products_dispatched[$objp->rowid] : ''));
1244 print '<input id="qty
'.$suffix.'" onchange="onChangeDispatchLineQty($(
this))
" name="qty
'.$suffix.'" data-index="'.$i.'" data-type="text
" class="width50 right qtydispatchinput
" value="'.$amounttosuggest.'" data-expected="'.$amounttosuggest.'">';
1247 if ($is_mod_batch_enabled && $objp->tobatch > 0) {
1249 print img_picto($langs->trans('AddStockLocationLine'), 'split', 'class="splitbutton
" onClick="addDispatchLine(
'.$i.', \
''.$type.
'\')
"');
1252 print img_picto($langs->trans('AddStockLocationLine'), 'split', 'class="splitbutton
" onClick="addDispatchLine(
'.$i.', \
''.$type.
'\')
"');
1258 print '<td class="right
">';
1259 if (count($listwarehouses) > 1) {
1260 print $formproduct->selectWarehouses(GETPOST("entrepot
".$suffix) ? GETPOST("entrepot
".$suffix) : ($objp->fk_default_warehouse ? $objp->fk_default_warehouse : ''), "entrepot
".$suffix, '', 1, 0, $objp->fk_product, '', 1, 0, array(), 'csswarehouse'.$suffix);
1261 } elseif (count($listwarehouses) == 1) {
1262 print $formproduct->selectWarehouses(GETPOST("entrepot
".$suffix) ? GETPOST("entrepot
".$suffix) : ($objp->fk_default_warehouse ? $objp->fk_default_warehouse : ''), "entrepot
".$suffix, '', 0, 0, $objp->fk_product, '', 1, 0, array(), 'csswarehouse'.$suffix);
1264 $langs->load("errors
");
1265 print $langs->trans("ErrorNoWarehouseDefined
");
1269 // Enable hooks to append additional columns
1270 $parameters = array(
1271 'is_information_row' => false, // this is a dispatch form row
1273 'suffix' => $suffix,
1276 $reshook = $hookmanager->executeHooks(
1277 'printFieldListValue',
1283 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1285 print $hookmanager->resPrint;
1294 // reload batch select and warehouse select on change (Ajax)
1295 $out_js_line_list = array();
1296 $out_js_line = 'function updateselectbatchbywarehouse() {';
1297 $out_js_line .= ' jQuery(document).on("change
", "select[
name*=\
"entrepot\"]",
function() {
';
1298 $out_js_line .= ' var selectwarehouse = jQuery(
this);
';
1299 $out_js_line .= ' var selectbatch_name = selectwarehouse.attr(
"name").replace(
"entrepot",
"lot_number");
';
1300 $out_js_line .= ' var selectbatch = jQuery(
"datalist[id*=\""+selectbatch_name+
"\"]");
';
1301 $out_js_line .= ' var selectedbatch = selectbatch.val();
';
1302 $out_js_line .= ' var product_element_name = selectwarehouse.attr(
"name").replace(
"entrepot",
"productbatch");
';
1303 $out_js_line .= ' jQuery.ajax({
';
1304 $out_js_line .= ' type:
"POST",
';
1305 $out_js_line .= ' url:
"'.dol_escape_js(dol_buildpath('/expedition/ajax/interface.php', 1)).'",
';
1306 $out_js_line .= ' data: {
';
1307 $out_js_line .= ' action:
"updateselectbatchbywarehouse",
';
1308 $out_js_line .= ' warehouse_id: jQuery(
this).val(),
';
1309 $out_js_line .= ' token:
"'.currentToken().'",
';
1310 $out_js_line .= ' product_id: jQuery(
"input[name=\""+product_element_name+
"\"]").val()
';
1311 $out_js_line .= ' }
';
1312 $out_js_line .= ' }).done(
function(data) {
';
1313 $out_js_line .= ' selectbatch.empty();
';
1314 $out_js_line .= ' if (typeof data ==
"object") {
';
1315 $out_js_line .= ' console.log(
"data is already type object, no need to parse it");
';
1316 $out_js_line .= ' }
else {
';
1317 $out_js_line .= ' console.log(
"data is type "+(typeof data));
';
1318 $out_js_line .= ' data = JSON.parse(data);
';
1319 $out_js_line .= ' }
';
1320 $out_js_line .= ' selectbatch.append(jQuery(
"<option>", {
';
1321 $out_js_line .= ' value:
"",
';
1322 $out_js_line .= ' }));
';
1323 $out_js_line .= ' jQuery.each(data,
function(key, objBatch) {
';
1324 $out_js_line .= ' var dataEatByDate = objBatch.eatbydate;
';
1325 $out_js_line .= ' var dataSellByDate = objBatch.sellbydate;
';
1326 $out_js_line .= ' var optionLabel = key+
" (";
';
1327 $out_js_line .= ' if (selectwarehouse.val() == -1) {
';
1328 $out_js_line .= ' optionLabel +=
"'.dol_escape_js($langs->trans('TotalStock')).': "+objBatch.qty;
';
1329 $out_js_line .= ' }
else {
';
1330 $out_js_line .= ' optionLabel +=
"'.dol_escape_js($langs->trans('Stock')).': "+objBatch.qty;
';
1331 $out_js_line .= ' }
';
1332 $out_js_line .= ' if (dataEatByDate !=
"") {
';
1333 $out_js_line .= ' optionLabel +=
" - '.dol_escape_js($langs->trans('EatByDate')).': "+dataEatByDate;
';
1334 $out_js_line .= ' }
';
1335 $out_js_line .= ' if (dataSellByDate !=
"") {
';
1336 $out_js_line .= ' optionLabel +=
" - '.dol_escape_js($langs->trans('SellByDate')).': "+dataSellByDate;
';
1337 $out_js_line .= ' }
';
1338 $out_js_line .= ' optionLabel +=
")";
';
1339 $out_js_line .= ' var option =
"<option data-eatbydate=\""+dataEatByDate+
"\" data-sellbydate=\""+dataSellByDate+
"\" value=\""+key+
"\"";
';
1340 $out_js_line .= ' if (key === selectedbatch) {
';
1341 $out_js_line .= ' option +=
" selected";
';
1342 $out_js_line .= ' }
';
1343 $out_js_line .= ' option +=
">"+optionLabel+
"</option>";
';
1344 $out_js_line .= ' selectbatch.append(option);
';
1345 $out_js_line .= ' });
';
1346 $out_js_line .= ' });
';
1347 $out_js_line .= ' });
';
1348 $out_js_line .= '}
';
1350 $out_js_line .= 'function updateselectwarehousebybatch() {
';
1351 $out_js_line .= ' jQuery(document).on(
"change",
"input[name*=lot_number]",
function() {
';
1352 $out_js_line .= ' var selectbatch = jQuery(
this);
';
1353 $out_js_line .= ' var selectwarehouse_name = selectbatch.attr(
"name").replace(
"lot_number",
"entrepot");
';
1354 $out_js_line .= ' var selectwarehouse = jQuery(
"select[name*=\""+selectwarehouse_name+
"\"]");
';
1355 $out_js_line .= ' var selectedwarehouse = selectwarehouse.val();
';
1356 $out_js_line .= ' var inputbatchdlc_name = selectbatch.attr(
"name").replace(
"lot_number",
"dlc");
';
1357 $out_js_line .= ' var inputbatchdlc = jQuery(
"input[name*=\""+inputbatchdlc_name+
"\"]");
';
1358 $out_js_line .= ' var inputbatchdluo_name = selectbatch.attr(
"name").replace(
"lot_number",
"dluo");
';
1359 $out_js_line .= ' var inputbatchdluo = jQuery(
"input[name*=\""+inputbatchdluo_name+
"\"]");
';
1360 $out_js_line .= ' var datalistselectedbatch = jQuery(
"#"+selectbatch.attr(
"name")+
" option[value=\""+selectbatch.val()+
"\"]");
';
1361 $out_js_line .= ' var selectedbatch_dlc = datalistselectedbatch.data(
"sellbydate");
';
1362 $out_js_line .= ' var selectedbatch_dluo = datalistselectedbatch.data(
"eatbydate");
';
1363 $out_js_line .= ' if (typeof selectedbatch_dlc ===
"undefined") {
';
1364 $out_js_line .= ' selectedbatch_dlc =
"";
';
1365 $out_js_line .= ' }
';
1366 $out_js_line .= ' if (typeof selectedbatch_dluo ===
"undefined") {
';
1367 $out_js_line .= ' selectedbatch_dluo =
"";
';
1368 $out_js_line .= ' }
';
1369 $out_js_line .= ' inputbatchdlc.val(selectedbatch_dlc).trigger(
"change");
';
1370 $out_js_line .= ' inputbatchdluo.val(selectedbatch_dluo).trigger(
"change");
';
1371 $out_js_line .= ' if (selectedwarehouse != -1) {
';
1372 $out_js_line .= ' return;
';
1373 $out_js_line .= ' }
';
1374 $out_js_line .= ' var product_element_name = selectbatch.attr(
"name").replace(
"lot_number",
"productbatch");
';
1375 $out_js_line .= ' jQuery.ajax({
';
1376 $out_js_line .= ' type:
"POST",
';
1377 $out_js_line .= ' url:
"'.dol_escape_js(dol_buildpath('/expedition/ajax/interface.php', 1)).'",
';
1378 $out_js_line .= ' data: {
';
1379 $out_js_line .= ' action:
"updateselectwarehousebybatch",
';
1380 $out_js_line .= ' batch: jQuery(
this).val(),
';
1381 $out_js_line .= ' token:
"'.currentToken().'",
';
1382 $out_js_line .= ' product_id: jQuery(
"input[name=\""+product_element_name+
"\"]").val()
';
1383 $out_js_line .= ' }
';
1384 $out_js_line .= ' }).done(
function(data) {
';
1385 $out_js_line .= ' if (typeof data ==
"object") {
';
1386 $out_js_line .= ' console.log(
"data is already type object, no need to parse it");
';
1387 $out_js_line .= ' }
else {
';
1388 $out_js_line .= ' console.log(
"data is type "+(typeof data));
';
1389 $out_js_line .= ' data = JSON.parse(data);
';
1390 $out_js_line .= ' }
';
1391 $out_js_line .= ' if (data != 0) {
';
1392 $out_js_line .= ' selectwarehouse.val(data).change();
';
1393 $out_js_line .= ' }
';
1394 $out_js_line .= ' });
';
1395 $out_js_line .= ' });
';
1396 $out_js_line .= '}
';
1397 $out_js_line_list[] = $out_js_line;
1399 $out_js = '<script
type=
"text/javascript" language=
"javascript">
';
1400 $out_js .= 'jQuery(document).ready(
function() {
';
1401 // when a warehouse is selected, only the lot/serial numbers that are available in it are offered
1402 $out_js .= 'updateselectbatchbywarehouse();
';
1403 // when a lot/serial number is selected and it is only available in one warehouse, the warehouse is automatically selected
1404 $out_js .= 'updateselectwarehousebybatch();
';
1405 $out_js .= implode('', $out_js_line_list);
1407 $out_js .= '</script>
';
1412 dol_print_error($db);
1420 //$checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll
'));
1422 print '<div
class=
"center">
';
1423 $parameters = array();
1424 $reshook = $hookmanager->executeHooks('addMoreActionsButtons
', $parameters, $object, $action); // Note that $action and $object may have been
1426 if (empty($reshook)) {
1427 /*if (empty($conf->reception->enabled)) {
1428 print $langs->trans("Comment").' :
';
1429 print '<input
type=
"text" class=
"minwidth400" maxlength=
"128" name=
"comment" value=
"';
1430 print GETPOSTISSET("comment
") ? GETPOST("comment
") : $langs->trans("DispatchSupplierOrder
", $object->ref);
1431 // print ' / '.$object->ref_supplier; // Not yet available
1432 print '" class=
"flat"><br>
';
1434 print '<input
type=
"checkbox" checked=
"checked" name=
"closeopenorder">
'.$checkboxlabel;
1437 $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
1442 print '<input
type=
"submit" id=
"submitform" class=
"button" name=
"dispatch" value=
"'.$langs->trans("Save
").'"';
1444 if (!$usercancreate) {
1447 if (count($listwarehouses) <= 0) {
1459 // Message if nothing to dispatch
1462 if (!getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED
')) {
1463 print '<div
class=
"opacitymedium">
'.$langs->trans("NoPredefinedProductToDispatch").'</div>
'; // No predefined line at all
1465 print '<div
class=
"opacitymedium">
'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>
'; // No predefined line that remain to be dispatched.
1472 print dol_get_fiche_end();
1474 // Popup for mass barcode scanning
1475 if ($action == 'updatebyscaning
') {
1476 if ($permissiontoadd) {
1477 // Output the javascript to manage the scanner tool.
1481 var duplicatedbatchcode = [];
1487 function barcodescannerjs() {
1488 console.log(
"We catch inputs in scanner box");
1489 jQuery(
"#scantoolmessage").text();
1491 var selectaddorreplace = $(
"select[name=selectaddorreplace]").val();
1492 var barcodemode = $(
"input[name=barcodemode]:checked").val();
1493 var barcodeproductqty = $(
"input[name=barcodeproductqty]").val();
1494 var warehousetouse = $(
"select[name=warehousenew]").val();
1495 var textarea = $(
"textarea[name=barcodelist]").val();
1496 var textarray = textarea.split(/[\s,;]+/);
1497 var tabproduct = [];
1498 duplicatedbatchcode = [];
1504 textarray = textarray.filter(
function(value) {
1507 if (textarray.some((element) => element !=
"")) {
1508 $(
".qtydispatchinput").each(
function() {
1509 id = $(
this).attr(\
'id\');
1510 idarray = id.split(\'_\');
1511 idproduct = idarray[2];
1512 id = idarray[1] + \'_\' + idarray[2];
1513 console.log("Analyze the line "+id+" in inventory, barcodemode="+barcodemode);
1514 warehouse = $("#entrepot_"+id).val();
1515 console.log(warehouse);
1516 productbarcode = $("#product_"+idproduct).attr(\'data-barcode\');
1517 console.log(productbarcode);
1518 productbatchcode = $("#lot_number_"+id).val();
1519 if (productbatchcode == undefined) {
1520 productbatchcode = "";
1522 console.log(productbatchcode);
1524 if (barcodemode != "barcodeforproduct") {
1525 tabproduct.forEach(product=>{
1526 console.log("product.Batch="+product.Batch+" productbatchcode="+productbatchcode);
1527 if (product.Batch != "" && product.Batch == productbatchcode) {
1528 console.log("duplicate batch code found for batch code "+productbatchcode);
1529 duplicatedbatchcode.push(productbatchcode);
1533 productinput = $("#qty_"+id).val();
1534 if (productinput == "") {
1537 tabproduct.push({\'Id\':id,\'Warehouse\':warehouse,\'Barcode\':productbarcode,\'Batch\':productbatchcode,\'Qty\':productinput,\'fetched\':false});
1539 console.log("Loop on each record entered in the textarea");
1541 textarray.forEach(function(element,index) {
1542 console.log("Process record element="+element+" id="+id);
1543 var verify_batch = false;
1544 var verify_barcode = false;
1545 switch(barcodemode) {
1546 case "barcodeforautodetect":
1547 verify_barcode = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"barcode",true);
1548 verify_batch = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"lotserial",true);
1550 case "barcodeforproduct":
1551 verify_barcode = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"barcode");
1553 case "barcodeforlotserial":
1554 verify_batch = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"lotserial");
1557 alert(\''.
dol_escape_js($langs->trans(
"ErrorWrongBarcodemode")).
' "\'+barcodemode+\'"\');
1558 throw \''.
dol_escape_js($langs->trans(
'ErrorWrongBarcodemode')).
' "\'+barcodemode+\'"\';
1561 if (verify_batch == false && verify_barcode == false) { /* If the 2 flags are false, not found error */
1562 errortab2.push(element);
1563 } else if (verify_batch == true && verify_barcode == true) { /* If the 2 flags are true, error: we don t know which one to take */
1564 errortab3.push(element);
1565 } else if (verify_batch == true) {
1566 console.log("element="+element);
1567 console.log(duplicatedbatchcode);
1568 if (duplicatedbatchcode.includes(element)) {
1569 errortab1.push(element);
1574 if (Object.keys(errortab1).length < 1 && Object.keys(errortab2).length < 1 && Object.keys(errortab3).length < 1) {
1575 tabproduct.forEach(product => {
1576 if (product.Qty!=0) {
1577 if (product.hasOwnProperty("reelqty")) {
1578 idprod = $("td[data-idproduct=\'"+product.fk_product+"\']").attr("id");
1579 idproduct = idprod.split("_")[1];
1580 console.log("We create a new line for product_"+idproduct);
1581 if (product.Barcode != null) {
1582 modedispatch = "dispatch";
1584 modedispatch = "batch";
1586 addDispatchLine(idproduct,modedispatch);
1587 console.log($("tr[name^=\'"+modedispatch+"_\'][name$=\'_"+idproduct+"\']"));
1588 nbrTrs = $("tr[name^=\'"+modedispatch+"_\'][name$=\'_"+idproduct+"\']").length;
1590 $("#qty_"+(nbrTrs-1)+"_"+idproduct).val(product.Qty);
1591 $("#entrepot_"+(nbrTrs-1)+"_"+idproduct).val(product.Warehouse);
1593 if (modedispatch == "batch") {
1594 $("#lot_number_"+(nbrTrs-1)+"_"+idproduct).val(product.Batch);
1598 console.log("We change #qty_"+product.Id +" to match input in scanner box");
1599 $("#qty_"+product.Id).val(product.Qty);
1603 jQuery("#scantoolmessage").text("'.
dol_escape_js($langs->transnoentities(
"QtyWasAddedToTheScannedBarcode")).
'\n");
1604 /* document.forms["formrecord"].submit(); */
1606 let stringerror = "";
1607 if (Object.keys(errortab1).length > 0) {
1608 stringerror += "<br>'.
dol_escape_js($langs->transnoentities(
'ErrorSameBatchNumber')).
': ";
1609 errortab1.forEach(element => {
1610 stringerror += (element + ", ")
1612 stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1614 if (Object.keys(errortab2).length > 0) {
1615 stringerror += "<br>'.
dol_escape_js($langs->transnoentities(
'ErrorCantFindCodeInInventory')).
': ";
1616 errortab2.forEach(element => {
1617 stringerror += (element + ", ")
1619 stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1621 if (Object.keys(errortab3).length > 0) {
1622 stringerror += "<br>'.
dol_escape_js($langs->transnoentities(
'ErrorCodeScannedIsBothProductAndSerial')).
': ";
1623 errortab3.forEach(element => {
1624 stringerror += (element + ", ")
1626 stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1628 if (Object.keys(errortab4).length > 0) {
1629 stringerror += "<br>'.
dol_escape_js($langs->transnoentities(
'ErrorBarcodeNotFoundForProductWarehouse')).
': ";
1630 errortab4.forEach(element => {
1631 stringerror += (element + ", ")
1633 stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1636 jQuery("#scantoolmessage").html(\''.
dol_escape_js($langs->transnoentities(
"ErrorOnElementsInventory")).
'\' + stringerror);
1644 function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,mode,autodetect=
false) {
1645 BarcodeIsInProduct=0;
1648 tabproduct.forEach(product => {
1649 $.ajax({ url: \
''.DOL_URL_ROOT.
'/expedition/ajax/searchfrombarcode.php\',
1650 data: { "token":"'.
currentToken().
'", "action":"existbarcode","fk_entrepot": warehousetouse, "barcode":element, "mode":mode},
1653 success: function(response) {
1654 if (response.status == "success") {
1655 console.log(response.message);
1656 if (!newproductrow) {
1657 newproductrow = response.object;
1660 if (mode!="lotserial" && autodetect==false && !errortab4.includes(element)) {
1661 errortab4.push(element);
1662 console.error(response.message);
1666 error : function(output) {
1667 console.error("Error on barcodeserialforproduct function");
1670 console.log("Product "+(index+=1)+": "+element);
1671 if (mode == "barcode") {
1672 testonproduct = product.Barcode
1673 }else if (mode == "lotserial") {
1674 testonproduct = product.Batch
1676 testonwarehouse = product.Warehouse;
1677 if (testonproduct == element && testonwarehouse == warehousetouse) {
1678 if (selectaddorreplace == "add") {
1679 productqty = parseInt(product.Qty,10);
1680 product.Qty = productqty + parseInt(barcodeproductqty,10);
1681 }else if (selectaddorreplace == "replace") {
1682 if (product.fetched == false) {
1683 product.Qty = barcodeproductqty
1684 product.fetched=true
1686 productqty = parseInt(product.Qty,10);
1687 product.Qty = productqty + parseInt(barcodeproductqty,10);
1690 BarcodeIsInProduct+=1;
1693 if (BarcodeIsInProduct==0 && newproductrow!=0) {
1694 tabproduct.push({\'Id\':tabproduct.length-1,\'Warehouse\':newproductrow.fk_warehouse,\'Barcode\':mode=="barcode"?element:null,\'Batch\':mode=="lotserial"?element:null,\'Qty\':barcodeproductqty,\'fetched\':true,\'reelqty\':newproductrow.reelqty,\'fk_product\':newproductrow.fk_product,\'mode\':mode});
1697 if (BarcodeIsInProduct > 0) {
1705 include DOL_DOCUMENT_ROOT.
'/core/class/html.formother.class.php';
1707 print $formother->getHTMLScannerForm(
"barcodescannerjs",
'all', 1);
1711 print
'<script type="text/javascript">
1712 $(document).ready(function () {
1713 $("select[name=fk_default_warehouse]").change(function() {
1714 console.log("warehouse is modified");
1715 var fk_default_warehouse = $("option:selected", this).val();
1716 $("select[name^=entrepot]").val(fk_default_warehouse).change();
1719 $("#autoreset").click(function() {
1720 console.log("we click on autoreset");
1721 $(".autoresettr").each(function() {
1722 id = $(this).attr("name");
1723 idtab = id.split("_");
1724 console.log("we process line "+id+" "+idtab);
1725 if ($(this).data("remove") == "clear") { /* data-remove=clear means that line qty must be cleared but line must not be removed */
1726 console.log("We clear the object to expected value")
1727 var idlinetab = idtab[0].split("-");
1729 if (idlinetab.length > 0) {
1730 idline = idlinetab[1];
1732 $("#qty"+idline+"_"+idtab[1]+"_"+idtab[2]).val("");
1734 qtyexpected = $("#qty_"+idtab[1]+"_"+idtab[2]).data("expected")
1735 console.log(qtyexpected);
1736 $("#qty_"+idtab[1]+"_"+idtab[2]).val(qtyexpected);
1737 qtydispatched = $("#qty_dispatched_0_"+idtab[2]).data("dispatched")
1738 $("#qty_dispatched_0_"+idtab[2]).val(qtydispatched);
1740 } else { /* data-remove=remove means that line must be removed */
1741 console.log("We remove the object")
1743 $("tr[name^=\'"+idtab[0]+"_\'][name$=\'_"+idtab[2]+"\']:last .splitbutton").show();
1749 $("#resetalltoexpected").click(function() {
1750 $(".qtydispatchinput").each(function() {
1751 console.log("We reset to expected "+$(this).attr("id")+" qty to dispatch");
1752 $(this).val($(this).data("expected"));
1757 $(".resetline").on("click", function(event) {
1758 event.preventDefault();
1759 id = $(this).attr("id");
1760 id = id.split("reset");
1761 console.log("Reset trigger for id = qty"+id[1]);
1762 $("#qty"+id[1]).val("");
$id
Support class for third parties, contacts, members, users or resources.
if(! $sortfield) if(! $sortorder) $object
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Class to manage customers orders.
Class to manage warehouses.
const STATUS_DRAFT
Draft status.
Class to manage lines of shipment.
CRUD class for batch number management within shipment.
Class to manage products or services.
Manage record for batch number management.
Class to manage projects.
Class to manage proposals.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
dol_stringtotime($string, $gm=1)
Convert a string date into a GM Timestamps date Warning: YYYY-MM-DDTHH:MM:SS+02:00 (RFC3339) is not s...
dol_now($mode='gmt')
Return date for now.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
currentToken()
Return the value of token currently saved into session with name 'token'.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into JavaScript code.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=0)
Return value of a param into GET or POST supervariable.
GETPOSTFLOAT($paramname, $rounding='', $option=2)
Return the value of a $_GET or $_POST supervariable, converted into float.
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
$conf db name
Only used if Module[ID]Name translation string is not found.
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $nodie=0, $mode='')
Check permissions of a user to show a page and an object.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.
shipping_prepare_head($object)
Prepare array with list of tabs.