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'));
85if (GETPOSTISSET(
"projectid")) {
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);
225 setEventMessages($expeditiondispatch->error, $expeditiondispatch->errors,
'errors');
228 $qtystart = $expeditiondispatch->qty;
229 $expeditiondispatch->qty = $newqty;
230 $expeditiondispatch->entrepot_id =
GETPOSTINT($ent);
233 $result = $expeditiondispatch->update($user);
235 $result = $expeditiondispatch->delete($user);
238 setEventMessages($expeditiondispatch->error, $expeditiondispatch->errors,
'errors');
242 if (!$error && $modebatch ==
"batch") {
244 $suffixkeyfordate = preg_replace(
'/^productbatch/',
'', $key);
248 $sqlsearchdet =
"SELECT rowid FROM ".$db->prefix().$expeditionlinebatch->table_element;
249 $sqlsearchdet .=
" WHERE fk_expeditiondet = ".((int) $idline);
250 $resqlsearchdet =
$db->query($sqlsearchdet);
252 $objsearchdet =
null;
253 if ($resqlsearchdet) {
254 $objsearchdet =
$db->fetch_object($resqlsearchdet);
260 $sql =
"UPDATE ".$db->prefix().$expeditionlinebatch->table_element.
" SET";
261 $sql .=
" batch = '".$db->escape($lot).
"'";
262 $sql .=
", eatby = ".($eatby ?
"'".$db->idate($eatby).
"'" :
"null");
263 $sql .=
", sellby = ".($sellby ?
"'".$db->idate($sellby).
"'" :
"null");
264 $sql .=
", qty = ".((float) $newqty);
265 $sql .=
", fk_warehouse = ".((int) $warehouse_id);
266 $sql .=
" WHERE rowid = ".((int) $objsearchdet->rowid);
268 $sql =
"INSERT INTO ".$db->prefix().$expeditionlinebatch->table_element.
" (";
269 $sql .=
"fk_expeditiondet, eatby, sellby, batch, qty, fk_origin_stock, fk_warehouse)";
270 $sql .=
" VALUES (".((int) $idline).
", ".($eatby ?
"'".$db->idate($eatby).
"'" :
"null").
", ".($sellby ?
"'".
$db->idate($sellby).
"'" :
"null").
", ";
271 $sql .=
" '".$db->escape($lot).
"', ".((float) $newqty).
", 0, ".((int) $warehouse_id).
")";
274 $sql =
"DELETE FROM ".$db->prefix().$expeditionlinebatch->table_element;
275 $sql .=
" WHERE fk_expeditiondet = ".((int) $idline);
276 $sql .=
" AND batch = '".$db->escape($lot).
"'";
279 $resql =
$db->query($sql);
287 $expeditiondispatch->fk_expedition =
$object->id;
288 $expeditiondispatch->entrepot_id =
GETPOSTINT($ent);
289 $expeditiondispatch->fk_parent =
GETPOSTINT(
'fk_parent'.$dispatch_line_suffix);
290 $expeditiondispatch->fk_product = $prod_id;
291 if (!($expeditiondispatch->fk_parent > 0)) {
292 $expeditiondispatch->fk_elementdet =
GETPOSTINT($fk_commandedet);
294 $expeditiondispatch->qty = $newqty;
297 $idline = $expeditiondispatch->insert($user);
299 setEventMessages($expeditiondispatch->error, $expeditiondispatch->errors,
'errors');
303 if ($modebatch ==
"batch" && !$error) {
304 $expeditionlinebatch->sellby = $dDLC;
305 $expeditionlinebatch->eatby = $dDLUO;
306 $expeditionlinebatch->batch = $lot;
307 $expeditionlinebatch->qty = $newqty;
308 $expeditionlinebatch->fk_origin_stock = 0;
309 $expeditionlinebatch->fk_warehouse =
GETPOSTINT($ent);
311 $result = $expeditionlinebatch->create($idline);
313 setEventMessages($expeditionlinebatch->error, $expeditionlinebatch->errors,
'errors');
370 header(
"Location: ".DOL_URL_ROOT.
'/expedition/dispatch.php?id='.
$object->id);
373 } elseif ($action ==
'setdate_livraison' && $usercancreate) {
377 $result =
$object->setDeliveryDate($user, $datedelivery);
395$title =
$object->ref.
" - ".$langs->trans(
'ShipmentDistribution');
396$help_url =
'EN:Module_Shipments|FR:Module_Expéditions|ES:Módulo_Expediciones|DE:Modul_Lieferungen';
397$morejs = array(
'/expedition/js/lib_dispatch.js.php');
400llxHeader(
'', $title, $help_url,
'', 0, 0, $morejs,
'',
'',
'mod-expedition page-card_dispatch');
406 $num_prod = count($lines);
419 $author->fetch(
$object->user_author_id);
429 if ($action ==
'ask_deleteline') {
430 $formconfirm = $form->formconfirm($_SERVER[
"PHP_SELF"].
'?id='.
$object->id.
'&lineid='.$lineid, $langs->trans(
'DeleteLine'), $langs->trans(
'ConfirmDeleteLine'),
'confirm_deleteline',
'', 0, 1);
434 $parameters = array(
'lineid' => $lineid);
436 $reshook = $hookmanager->executeHooks(
'formConfirm', $parameters, $object, $action);
437 if (empty($reshook)) {
438 $formconfirm .= $hookmanager->resPrint;
439 } elseif ($reshook > 0) {
440 $formconfirm = $hookmanager->resPrint;
449 $objectsrc->fetch(
$object->origin_object->id);
453 $objectsrc->fetch(
$object->origin_object->id);
457 $linkback =
'<a href="'.DOL_URL_ROOT.
'/expedition/list.php?restore_lastsearch_values=1'.(!empty($socid) ?
'&socid='.$socid :
'').
'">'.$langs->trans(
"BackToList").
'</a>';
458 $morehtmlref =
'<div class="refidno">';
461 $morehtmlref .= $form->editfieldkey(
"RefCustomer",
'ref_customer',
$object->ref_customer, $object, $user->hasRight(
'expedition',
'creer'),
'string',
'', 0, 1);
462 $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);
465 $morehtmlref .=
'<br>'.$object->thirdparty->getNomUrl(1);
468 $langs->load(
"projects");
469 $morehtmlref .=
'<br>';
471 $morehtmlref .=
img_picto($langs->trans(
"Project"),
'project',
'class="pictofixedwidth"');
472 if ($action !=
'classify' && $permissiontoadd) {
473 $morehtmlref .=
'<a class="editfielda" href="'.dolBuildUrl($_SERVER[
'PHP_SELF'], [
'action' =>
'classify',
'id' =>
$object->id],
true).
'">'.
img_edit($langs->transnoentitiesnoconv(
'SetProject')).
'</a> ';
475 $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');
477 if (!empty($objectsrc) && !empty($objectsrc->fk_project)) {
479 $proj->fetch($objectsrc->fk_project);
480 $morehtmlref .= $proj->getNomUrl(1);
482 $morehtmlref .=
'<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).
'</span>';
487 $morehtmlref .=
'</div>';
489 dol_banner_tab($object,
'ref', $linkback, 1,
'ref',
'ref', $morehtmlref);
492 print
'<div class="fichecenter">';
493 print
'<div class="underbanner clearboth"></div>';
495 print
'<table class="border tableforfield centpercent">';
502 print $langs->trans(
"RefOrder").
'</td>';
503 print
'<td colspan="3">';
504 print $objectsrc->getNomUrl(1,
'commande');
511 print $langs->trans(
"RefProposal").
'</td>';
512 print
'<td colspan="3">';
513 print $objectsrc->getNomUrl(1,
'expedition');
519 print
'<tr><td class="titlefield">'.$langs->trans(
"DateCreation").
'</td>';
520 print
'<td colspan="3">'.dol_print_date(
$object->date_creation,
"dayhour",
"tzuserrel").
"</td>\n";
524 print
'<tr><td height="10">';
525 print
'<table class="nobordernopadding" width="100%"><tr><td>';
526 print $langs->trans(
'DateDeliveryPlanned');
528 if ($action !=
'editdate_livraison') {
529 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>';
531 print
'</tr></table>';
532 print
'</td><td colspan="2">';
533 if ($action ==
'editdate_livraison') {
534 print
'<form name="setdate_livraison" action="'.$_SERVER[
"PHP_SELF"].
'?id='.
$object->id.
'" method="post">';
535 print
'<input type="hidden" name="token" value="'.newToken().
'">';
536 print
'<input type="hidden" name="action" value="setdate_livraison">';
537 print $form->selectDate(
$object->date_delivery ?
$object->date_delivery : -1,
'liv_', 1, 1, 0,
"setdate_livraison", 1, 0);
538 print
'<input type="submit" class="button button-edit smallpaddingimp" value="'.$langs->trans(
'Modify').
'">';
544 print
'</tr></table>';
546 print
'<br><br><center>';
548 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>';
550 print
'<a href="#" id="resetalltoexpected" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto(
"",
'autofill',
'class="pictofixedwidth"').$langs->trans(
"RestoreWithCurrentQtySaved").
'</a></td>';
552 print
'<a href="#" id="autoreset" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto(
"",
'eraser',
'class="pictofixedwidth"').$langs->trans(
"ClearQtys").
'</a></td>';
559 require_once DOL_DOCUMENT_ROOT.
'/product/class/html.formproduct.class.php';
561 $formproduct->loadWarehouses();
563 $listwarehouses = $entrepot->list_array(1);
571 print
'<form method="post" action="'.dolBuildUrl($_SERVER[
"PHP_SELF"]).
'">';
573 print
'<input type="hidden" name="token" value="'.newToken().
'">';
574 print
'<input type="hidden" name="action" value="updatelines">';
575 print
'<input type="hidden" name="id" value="'.$object->id.
'">';
577 print
'<div class="div-table-responsive-no-min">';
578 print
'<table class="noborder centpercent">';
581 $products_dispatched = array();
582 $sql =
"SELECT ed.fk_elementdet as rowid, sum(ed.qty) as qty";
583 $sql .=
" FROM ".$db->prefix().
"expeditiondet as ed";
584 $sql .=
" WHERE ed.fk_expedition = ".((int)
$object->id);
585 $sql .=
" GROUP BY ed.fk_elementdet";
587 $resql =
$db->query($sql);
589 $num =
$db->num_rows($resql);
594 $objd =
$db->fetch_object($resql);
595 $products_dispatched[$objd->rowid] =
price2num($objd->qty,
'MS');
602 if ($objectsrc instanceof
Commande) {
604 $sql =
"SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, '' AS sref, l.qty as qty,";
605 $sql .=
" p.ref, p.label, p.tobatch, p.fk_default_warehouse, p.barcode, p.stockable_product";
607 $parameters = array();
608 $reshook = $hookmanager->executeHooks(
609 'printFieldListSelect',
617 $sql .= $hookmanager->resPrint;
619 $sql .=
" FROM ".$db->prefix().
"commandedet as l";
620 $sql .=
" LEFT JOIN ".$db->prefix().
"product as p ON l.fk_product=p.rowid";
621 $sql .=
" WHERE l.fk_commande = ".((int) $objectsrc->id);
623 $sql .=
" AND l.product_type = 0";
626 $parameters = array();
627 $reshook = $hookmanager->executeHooks(
628 'printFieldListWhere',
636 $sql .= $hookmanager->resPrint;
639 $sql .=
" ORDER BY l.rang, p.ref, p.label";
641 $resql =
$db->query($sql);
643 $num =
$db->num_rows($resql);
648 print
'<tr class="liste_titre">';
650 print
'<td>'.$langs->trans(
"Description").
'</td>';
651 if ($is_mod_batch_enabled) {
652 print
'<td class="dispatch_batch_number_title">'.$langs->trans(
"batch_number").
'</td>';
653 if ($is_sell_by_enabled) {
654 print
'<td class="dispatch_dlc_title">'.$langs->trans(
"SellByDate").
'</td>';
656 if ($is_eat_by_enabled) {
657 print
'<td class="dispatch_dluo_title">'.$langs->trans(
"EatByDate").
'</td>';
664 print
'<td class="right">'.$langs->trans(
"QtyOrdered").
'</td>';
666 print
'<td class="right">'.$langs->trans(
"QtyToShip");
668 print
'<td class="right">'.$langs->trans(
"QtyDispatchedShort").
'</td>';
670 print
'<td class="right">'.$langs->trans(
"Details");
671 print
'<td width="32"></td>';
675 print
'<td class="right">'.$langs->trans(
"Price").
'</td>';
676 print
'<td class="right">'.$langs->trans(
"ReductionShort").
' (%)</td>';
677 print
'<td class="right">'.$langs->trans(
"UpdatePrice").
'</td>';
681 print
'<td class="right">'.$langs->trans(
"Warehouse");
684 if (count($listwarehouses) > 1) {
685 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);
686 } elseif (count($listwarehouses) == 1) {
687 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);
693 $parameters = array();
694 $reshook = $hookmanager->executeHooks(
695 'printFieldListTitle',
703 print $hookmanager->resPrint;
708 $conf->cache[
'product'] = array();
712 $objp =
$db->fetch_object($resql);
715 if (!$objp->fk_product > 0) {
718 $alreadydispatched = isset($products_dispatched[$objp->rowid]) ? $products_dispatched[$objp->rowid] : 0;
719 $remaintodispatch =
price2num($objp->qty, 5);
720 if ($remaintodispatch < 0 && !
getDolGlobalString(
'SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN')) {
721 $remaintodispatch = 0;
724 if ($remaintodispatch || !
getDolGlobalString(
'SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
733 print
'<!-- Line to dispatch '.$suffix.
' -->'.
"\n";
735 print
'<input id="qty_ordered'.$suffix.
'" type="hidden" value="'.$objp->qty.
'">';
736 print
'<input id="qty_dispatched'.$suffix.
'" type="hidden" data-dispatched="'.((float) $alreadydispatched).
'" value="'.(float) $alreadydispatched.
'">';
737 print
'<tr class="oddeven">';
739 if (empty(
$conf->cache[
'product'][$objp->fk_product])) {
741 $tmpproduct->fetch($objp->fk_product);
742 $conf->cache[
'product'][$objp->fk_product] = $tmpproduct;
744 $tmpproduct =
$conf->cache[
'product'][$objp->fk_product];
747 $linktoprod =
'<div class="twolinesmax lineheightsmall">';
748 $linktoprod .= $tmpproduct->getNomUrl(1);
749 $linktoprod .=
'<br><span class="opacitymedium small">'.dolPrintHTML($objp->label).
"</span>\n";
750 $linktoprod .=
'</div>';
752 if ($is_mod_batch_enabled) {
753 if ($objp->tobatch) {
755 print
'<td class="tdoverflowbydiv nopaddingtopimp nopaddingbottomimp" id="product_'.$i.
'" data-idproduct="'.$objp->fk_product.
'" data-barcode="'.$objp->barcode.
'">';
758 print
'<td class="dispatch_batch_number"></td>';
759 if ($is_sell_by_enabled) {
760 print
'<td class="dispatch_dlc"></td>';
762 if ($is_eat_by_enabled) {
763 print
'<td class="dispatch_dluo"></td>';
767 print
'<td id="product_'.$i.
'" data-idproduct="'.$objp->fk_product.
'" data-barcode="'.$objp->barcode.
'">';
770 print
'<td class="dispatch_batch_number">';
771 print
'<span class="opacitymedium small">'.$langs->trans(
"ProductDoesNotUseBatchSerial").
'</span>';
773 if ($is_sell_by_enabled) {
774 print
'<td class="dispatch_dlc"></td>';
776 if ($is_eat_by_enabled) {
777 print
'<td class="dispatch_dluo"></td>';
781 print
'<td colspan="4">';
787 $up_ht_disc = $objp->subprice;
788 if (!empty($objp->remise_percent) && !
getDolGlobalString(
'STOCK_EXCLUDE_DISCOUNT_FOR_PMP')) {
789 $up_ht_disc =
price2num($up_ht_disc * (100 - $objp->remise_percent) / 100,
'MU');
793 print
'<td class="right">'.$objp->qty.
'</td>';
796 print
'<td class="right">'.$alreadydispatched.
'</td>';
798 print
'<td class="right">';
804 $sql =
"SELECT ed.rowid, ed.fk_parent";
805 $sql .=
", cd.fk_product";
806 $sql .=
", ".$db->ifsql(
'eb.rowid IS NULL',
'ed.qty',
'eb.qty').
" as qty";
807 $sql .=
", ".$db->ifsql(
'eb.rowid IS NULL OR eb.fk_warehouse IS NULL',
'ed.fk_entrepot',
'eb.fk_warehouse').
" as fk_warehouse";
808 $sql .=
", eb.batch, eb.eatby, eb.sellby";
809 $sql .=
" FROM ".$db->prefix().
"expeditiondet as ed";
810 $sql .=
" LEFT JOIN ".$db->prefix().
"expeditiondet_batch as eb on ed.rowid = eb.fk_expeditiondet";
811 $sql .=
" INNER JOIN ".$db->prefix().
"commandedet as cd on ed.fk_elementdet = cd.rowid";
812 $sql .=
" WHERE ed.fk_elementdet = ".(int) $objp->rowid;
813 $sql .=
" AND ed.fk_expedition = ".(int)
$object->id;
814 $sql .=
" ORDER BY ed.rowid, ed.fk_elementdet";
816 $resultsql =
$db->query($sql);
819 $numd =
$db->num_rows($resultsql);
820 while ($obj_exp =
$db->fetch_object($resultsql)) {
821 $suffix =
"_" . $j .
"_" . $i;
823 $productChildrenNb = 0;
824 $expedition_line_child_list = array();
827 $productChildrenNb = $tmpproduct->hasFatherOrChild(1);
828 if ($productChildrenNb > 0) {
829 $line_id_list = array();
833 $result = $expeditionLine->findAllChild($obj_exp->rowid, $line_id_list, 1);
836 foreach ($line_id_list as $line_id_arr) {
837 foreach ($line_id_arr as $line_obj) {
838 $child_product_id = (int) $line_obj->fk_product;
839 if (empty(
$conf->cache[
'product'][$child_product_id])) {
841 $child_product->fetch($child_product_id);
842 $conf->cache[
'product'][$child_product_id] = $child_product;
844 $child_product =
$conf->cache[
'product'][$child_product_id];
848 $batch_list = array();
849 if ($is_mod_batch_enabled && $child_product->hasbatch()) {
851 $sql_line_batch_search =
"SELECT eb.rowid, eb.qty, eb.batch, eb.sellby, eb.eatby";
852 $sql_line_batch_search .=
" FROM ".$db->prefix().
"expeditiondet_batch as eb";
853 $sql_line_batch_search .=
" WHERE eb.fk_expeditiondet = ".((int) $line_obj->rowid);
854 $res_line_batch_search =
$db->query($sql_line_batch_search);
855 if ($res_line_batch_search) {
856 while ($obj_batch =
$db->fetch_object($res_line_batch_search)) {
858 if ($obj_batch->batch !=
'') {
859 $line_obj->batch = $obj_batch->batch;
863 $batch_list[] = $obj_batch;
865 $db->free($res_line_batch_search);
869 if (empty($batch_list)) {
870 $batch_sort_field_arr = array();
871 $batch_sort_order_arr = array();
872 if ($is_sell_by_enabled) {
873 $batch_sort_field_arr[] =
'pl.sellby';
874 $batch_sort_order_arr[] =
'ASC';
876 if ($is_eat_by_enabled) {
877 $batch_sort_field_arr[] =
'pl.eatby';
878 $batch_sort_order_arr[] =
'ASC';
880 $batch_sort_field_arr[] =
'pb.qty';
881 $batch_sort_order_arr[] =
'ASC';
882 $batch_sort_field_arr[] =
'pl.rowid';
883 $batch_sort_order_arr[] =
'ASC';
885 $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));
886 if (is_array($product_batch_result)) {
887 foreach ($product_batch_result as $batch_current) {
888 $batch_current->eatby =
dol_print_date($batch_current->eatby,
'day');
889 $batch_current->sellby =
dol_print_date($batch_current->sellby,
'day');
890 $batch_list[] = $batch_current;
895 $line_obj->batch_list = $batch_list;
898 $line_obj->iskit = 0;
899 if ($child_product->stockable_product == Product::ENABLED_STOCK) {
900 $can_manage_stock = 1;
902 $can_manage_stock = 0;
904 $line_obj->incdec = $can_manage_stock;
905 $sql_child =
"SELECT ";
906 $sql_child .=
" SUM(".$db->ifsql(
"pa.rowid IS NOT NULL",
"1",
"0").
") as iskit";
907 $sql_child .=
", ".$db->ifsql(
"pai.incdec IS NULL",
"1",
"pai.incdec").
" as incdec";
908 $sql_child .=
" FROM ".$db->prefix().
"expeditiondet as ed";
909 $sql_child .=
" LEFT JOIN ".$db->prefix().
"expeditiondet as edp ON edp.rowid = ".((int) $line_obj->fk_parent);
910 $sql_child .=
" LEFT JOIN ".$db->prefix().
"product_association as pa ON pa.fk_product_pere = ".((int) $child_product_id);
911 $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);
912 $sql_child .=
" WHERE ed.rowid = ".((int) $line_obj->rowid);
913 $sql_child .=
" GROUP BY pa.rowid, pai.incdec";
914 $resql_child =
$db->query($sql_child);
916 if ($child_obj =
$db->fetch_object($resql_child)) {
917 if (!
getDolGlobalInt(
'PRODUIT_SOUSPRODUITS_ALSO_ENABLE_PARENT_STOCK_MOVE')) {
918 $line_obj->iskit = (int) $child_obj->iskit;
920 if ($can_manage_stock) {
921 $line_obj->incdec = (int) $child_obj->incdec;
924 $db->free($resql_child);
926 $line_obj->html_label = str_repeat(
" ", $child_level) .
"→" . $child_product->getNomUrl(1);
927 $expedition_line_child_list[] = $line_obj;
934 if (empty($expedition_line_child_list)) {
937 if ($objp->stockable_product == Product::ENABLED_STOCK) {
938 $obj_exp->incdec = 1;
940 $obj_exp->incdec = 0;
942 $expedition_line_child_list[] = $obj_exp;
945 $child_suffix = $suffix;
946 foreach ($expedition_line_child_list as $objd) {
947 $child_line_id = $objd->rowid;
949 $can_update_stock = empty($objd->iskit) && !empty($objd->incdec);
950 $suffix = $child_line_id.$child_suffix;
953 $dispatch_line_batch_current =
null;
954 if (!empty($objd->batch_list)) {
955 $dispatch_line_batch_count = count($objd->batch_list);
957 if ($dispatch_line_batch_count == 1) {
958 $dispatch_line_batch_current = current($objd->batch_list);
961 if (is_object($dispatch_line_batch_current)) {
962 $objd->batch = $dispatch_line_batch_current->batch;
963 $objd->eatby = $dispatch_line_batch_current->eatby;
964 $objd->sellby = $dispatch_line_batch_current->sellby;
967 if ($is_mod_batch_enabled
970 || (is_null($objd->batch) && $tmpproduct->status_batch > 0)
971 || !empty($objd->batch_list)
979 'is_information_row' =>
true,
984 $reshook = $hookmanager->executeHooks(
985 'printFieldListValue',
993 print $hookmanager->resPrint;
997 print
'<!-- line for batch ' . $numline .
' -->';
998 print
'<tr class="oddeven autoresettr" name="' . $type .
'-' . $suffix .
'" data-remove="clear">';
1000 print
'<input id="fk_commandedet' . $suffix .
'" name="fk_commandedet' . $suffix .
'" type="hidden" value="' . $objp->rowid .
'">';
1001 print
'<input id="idline' . $suffix .
'" name="idline' . $suffix .
'" type="hidden" value="' . $objd->rowid .
'">';
1002 print
'<input id="fk_parent' . $suffix .
'" name="fk_parent' . $suffix .
'" type="hidden" value="' . $objd->fk_parent .
'">';
1003 print
'<input name="productbatch' . $suffix .
'" type="hidden" value="' . $objd->fk_product .
'">';
1005 print
'<!-- This is a U.P. (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
1006 print
'<input class="maxwidth75" name="pu' . $suffix .
'" type="hidden" value="' .
price2num($up_ht_disc,
'MU') .
'">';
1007 if (!empty($objd->html_label)) {
1008 print $objd->html_label;
1013 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.
'">';
1014 print $formproduct->selectLotDataList(
'lot_number'.$suffix, 0, $objd->fk_product,
GETPOST(
"entrepot".$suffix) ?
GETPOST(
"entrepot".$suffix) : $objd->fk_warehouse, array());
1017 if ($is_sell_by_enabled) {
1018 print
'<td class="nowraponall">';
1020 print $form->selectDate($dlcdatesuffix,
'dlc'.$suffix, 0, 0, 1,
'');
1023 if ($is_eat_by_enabled) {
1024 print
'<td class="nowraponall">';
1026 print $form->selectDate($dluodatesuffix,
'dluo'.$suffix, 0, 0, 1,
'');
1029 print
'<td colspan="2"> </td>';
1033 $colspan = $is_sell_by_enabled ? $colspan : --$colspan;
1034 $colspan = $is_eat_by_enabled ? $colspan : --$colspan;
1037 $parameters = array(
1039 'is_information_row' =>
true,
1041 'suffix' => $suffix,
1044 $reshook = $hookmanager->executeHooks(
1045 'printFieldListValue',
1053 print $hookmanager->resPrint;
1057 print
'<!-- line no batch '.$numline.
' -->';
1058 print
'<tr class="oddeven autoresettr" name="'.$type.
'-'.$suffix.
'" data-remove="clear">';
1059 print
'<td colspan="'.$colspan.
'">';
1060 print
'<input id="fk_commandedet'.$suffix.
'" name="fk_commandedet'.$suffix.
'" type="hidden" value="'.$objp->rowid.
'">';
1061 print
'<input id="idline'.$suffix.
'" name="idline'.$suffix.
'" type="hidden" value="'.$objd->rowid.
'">';
1062 print
'<input id="fk_parent'.$suffix.
'" name="fk_parent'.$suffix.
'" type="hidden" value="'.$objd->fk_parent.
'">';
1063 print
'<input name="product'.$suffix.
'" type="hidden" value="'.$objd->fk_product.
'">';
1064 print
'<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
1065 print
'<input class="maxwidth75" name="pu'.$suffix.
'" type="hidden" value="'.
price2num($up_ht_disc,
'MU').
'">';
1066 if (!empty($objd->html_label)) {
1067 print $objd->html_label;
1072 print
'<td class="right nowraponall">';
1073 $suggestedvalue = (GETPOSTISSET(
'qty'.$suffix) ?
GETPOSTFLOAT(
'qty'.$suffix) : $objd->qty);
1075 if ($can_update_stock) {
1076 print
'<a href="" id="reset'.$suffix.
'" class="resetline">'.
img_picto($langs->trans(
"Reset"),
'eraser',
'class="pictofixedwidth opacitymedium"').
'</a>';
1077 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.
'">';
1079 print
'<input type="hidden" id="qty'.$suffix.
'" name="qty'.$suffix.
'" value="">';
1083 if ($can_update_stock) {
1084 print
img_picto($langs->trans(
'AddStockLocationLine'),
'split',
'class="splitbutton" onClick="addDispatchLine('.$i.
', \''.$type.
'-'.$child_line_id.
'\')
"');
1089 print '<td class="right
">';
1090 if ($can_update_stock) {
1091 if (count($listwarehouses) > 1) {
1092 print $formproduct->selectWarehouses(GETPOST("entrepot
".$suffix) ? GETPOST("entrepot
".$suffix) : $objd->fk_warehouse, "entrepot
".$suffix, '', 1, 0, $objd->fk_product, '', 1, 0, array(), 'csswarehouse'.$suffix);
1093 } elseif (count($listwarehouses) == 1) {
1094 print $formproduct->selectWarehouses(GETPOST("entrepot
".$suffix) ? GETPOST("entrepot
".$suffix) : $objd->fk_warehouse, "entrepot
".$suffix, '', 0, 0, $objd->fk_product, '', 1, 0, array(), 'csswarehouse'.$suffix);
1096 $langs->load("errors
");
1097 print $langs->trans("ErrorNoWarehouseDefined
");
1100 // we force the warehouse so we will pass the test to add a line into expedition.class.php
1101 print '<input id="entrepot
'.$suffix.'" name="entrepot
'.$suffix.'" type="hidden
" value="'.$objd->fk_warehouse.'">';
1102 print img_warning().' '.$langs->trans('StockDisabled');
1106 // Enable hooks to append additional columns
1107 $parameters = array(
1108 'is_information_row' => false, // this is a dispatch form row
1110 'suffix' => $suffix,
1114 $reshook = $hookmanager->executeHooks(
1115 'printFieldListValue',
1121 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1123 print $hookmanager->resPrint;
1132 //$suffix = "_
".$j."_
".$i;
1134 $errorMsg = 'Shipment dispatch SQL error : '.$db->lasterror();
1135 setEventMessage($errorMsg, 'errors');
1136 dol_syslog($errorMsg, LOG_ERR);
1141 if ($is_mod_batch_enabled && !empty($objp->tobatch)) {
1144 // Enable hooks to append additional columns
1145 $parameters = array(
1146 // allows hook to distinguish between the rows with information and the rows with dispatch form input
1147 'is_information_row' => true,
1149 'suffix' => $suffix,
1152 $reshook = $hookmanager->executeHooks(
1153 'printFieldListValue',
1159 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1161 print $hookmanager->resPrint;
1165 print '<!-- line for batch '.$numline.' (not dispatched line yet for this order line) -->';
1166 print '<tr class="oddeven autoresettr
" name="'.$type.$suffix.'" data-remove="clear
">';
1168 print '<input id="fk_commandedet
'.$suffix.'" name="fk_commandedet
'.$suffix.'" type="hidden
" value="'.$objp->rowid.'">';
1169 print '<input id="idline
'.$suffix.'" name="idline
'.$suffix.'" type="hidden
" value="-1
">';
1170 print '<input name="productbatch
'.$suffix.'" type="hidden
" value="'.$objp->fk_product.'">';
1172 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
1173 print '<input class="maxwidth75
" name="pu
'.$suffix.'" type="hidden
" value="'.price2num($up_ht_disc, 'MU
').'">';
1177 print '<input type="text
" class="inputlotnumber quatrevingtquinzepercent
" id="lot_number
'.$suffix.'" name="lot_number
'.$suffix.'" value="'.GETPOST('lot_number
'.$suffix).'">';
1179 if ($is_sell_by_enabled) {
1180 print '<td class="nowraponall
">';
1181 $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOSTINT('dlc'.$suffix.'month'), GETPOSTINT('dlc'.$suffix.'day'), GETPOSTINT('dlc'.$suffix.'year'));
1182 print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, 0, 0, 1, '');
1185 if ($is_eat_by_enabled) {
1186 print '<td class="nowraponall
">';
1187 $dluodatesuffix = dol_mktime(0, 0, 0, GETPOSTINT('dluo'.$suffix.'month'), GETPOSTINT('dluo'.$suffix.'day'), GETPOSTINT('dluo'.$suffix.'year'));
1188 print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, 0, 0, 1, '');
1191 print '<td colspan="2
"> </td>'; // Supplier ref + Qty ordered + qty already dispatched
1195 $colspan = $is_sell_by_enabled ? $colspan : --$colspan;
1196 $colspan = $is_eat_by_enabled ? $colspan : --$colspan;
1198 // Enable hooks to append additional columns
1199 $parameters = array(
1200 // allows hook to distinguish between the rows with information and the rows with dispatch form input
1201 'is_information_row' => true,
1203 'suffix' => $suffix,
1206 $reshook = $hookmanager->executeHooks(
1207 'printFieldListValue',
1213 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1215 print $hookmanager->resPrint;
1219 print '<!-- line no batch '.$numline.' (not dispatched line yet for this order line) -->';
1220 print '<tr class="oddeven autoresettr
" name="'.$type.$suffix.'" data-remove="clear
">';
1221 print '<td colspan="'.$colspan.'">';
1222 print '<input id="fk_commandedet
'.$suffix.'" name="fk_commandedet
'.$suffix.'" type="hidden
" value="'.$objp->rowid.'">';
1223 print '<input id="idline
'.$suffix.'" name="idline
'.$suffix.'" type="hidden
" value="-1
">';
1224 print '<input name="product
'.$suffix.'" type="hidden
" value="'.$objp->fk_product.'">';
1226 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
1227 print '<input class="maxwidth75
" name="pu
'.$suffix.'" type="hidden
" value="'.price2num($up_ht_disc, 'MU
').'">';
1231 print '<td class="right
">';
1232 print '<a href="" id="reset
'.$suffix.'" class="resetline
">'.img_picto($langs->trans("Reset
"), 'eraser', 'class="pictofixedwidth opacitymedium
"').'</a>';
1233 $amounttosuggest = (GETPOSTISSET('qty'.$suffix) ? GETPOSTINT('qty'.$suffix) : (!getDolGlobalString('SUPPLIER_ORDER_DISPATCH_FORCE_QTY_INPUT_TO_ZERO') ? $remaintodispatch : 0));
1234 if (count($products_dispatched)) {
1235 // There is already existing lines into llx_expeditiondet, this means a plan for the shipment has already been started.
1236 // In such a case, we do not suggest new values, we suggest the value known.
1237 $amounttosuggest = (GETPOSTISSET('qty'.$suffix) ? GETPOSTINT('qty'.$suffix) : (isset($products_dispatched[$objp->rowid]) ? $products_dispatched[$objp->rowid] : ''));
1239 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.'">';
1242 if ($is_mod_batch_enabled && $objp->tobatch > 0) {
1244 print img_picto($langs->trans('AddStockLocationLine'), 'split', 'class="splitbutton
" onClick="addDispatchLine(
'.$i.', \
''.$type.
'\')
"');
1247 print img_picto($langs->trans('AddStockLocationLine'), 'split', 'class="splitbutton
" onClick="addDispatchLine(
'.$i.', \
''.$type.
'\')
"');
1253 print '<td class="right
">';
1254 if (count($listwarehouses) > 1) {
1255 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);
1256 } elseif (count($listwarehouses) == 1) {
1257 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);
1259 $langs->load("errors
");
1260 print $langs->trans("ErrorNoWarehouseDefined
");
1264 // Enable hooks to append additional columns
1265 $parameters = array(
1266 'is_information_row' => false, // this is a dispatch form row
1268 'suffix' => $suffix,
1271 $reshook = $hookmanager->executeHooks(
1272 'printFieldListValue',
1278 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1280 print $hookmanager->resPrint;
1289 // reload batch select and warehouse select on change (Ajax)
1290 $out_js_line_list = array();
1291 $out_js_line = 'function updateselectbatchbywarehouse() {';
1292 $out_js_line .= ' jQuery(document).on("change
", "select[
name*=\
"entrepot\"]",
function() {
';
1293 $out_js_line .= ' var selectwarehouse = jQuery(
this);
';
1294 $out_js_line .= ' var selectbatch_name = selectwarehouse.attr(
"name").replace(
"entrepot",
"lot_number");
';
1295 $out_js_line .= ' var selectbatch = jQuery(
"datalist[id*=\""+selectbatch_name+
"\"]");
';
1296 $out_js_line .= ' var selectedbatch = selectbatch.val();
';
1297 $out_js_line .= ' var product_element_name = selectwarehouse.attr(
"name").replace(
"entrepot",
"productbatch");
';
1298 $out_js_line .= ' jQuery.ajax({
';
1299 $out_js_line .= ' type:
"POST",
';
1300 $out_js_line .= ' url:
"'.dol_escape_js(dol_buildpath('/expedition/ajax/interface.php', 1)).'",
';
1301 $out_js_line .= ' data: {
';
1302 $out_js_line .= ' action:
"updateselectbatchbywarehouse",
';
1303 $out_js_line .= ' warehouse_id: jQuery(
this).val(),
';
1304 $out_js_line .= ' token:
"'.currentToken().'",
';
1305 $out_js_line .= ' product_id: jQuery(
"input[name=\""+product_element_name+
"\"]").val()
';
1306 $out_js_line .= ' }
';
1307 $out_js_line .= ' }).done(
function(data) {
';
1308 $out_js_line .= ' selectbatch.empty();
';
1309 $out_js_line .= ' if (typeof data ==
"object") {
';
1310 $out_js_line .= ' console.log(
"data is already type object, no need to parse it");
';
1311 $out_js_line .= ' }
else {
';
1312 $out_js_line .= ' console.log(
"data is type "+(typeof data));
';
1313 $out_js_line .= ' data = JSON.parse(data);
';
1314 $out_js_line .= ' }
';
1315 $out_js_line .= ' selectbatch.append(jQuery(
"<option>", {
';
1316 $out_js_line .= ' value:
"",
';
1317 $out_js_line .= ' }));
';
1318 $out_js_line .= ' jQuery.each(data,
function(key, objBatch) {
';
1319 $out_js_line .= ' var dataEatByDate = objBatch.eatbydate;
';
1320 $out_js_line .= ' var dataSellByDate = objBatch.sellbydate;
';
1321 $out_js_line .= ' var optionLabel = key+
" (";
';
1322 $out_js_line .= ' if (selectwarehouse.val() == -1) {
';
1323 $out_js_line .= ' optionLabel +=
"'.dol_escape_js($langs->trans('TotalStock')).': "+objBatch.qty;
';
1324 $out_js_line .= ' }
else {
';
1325 $out_js_line .= ' optionLabel +=
"'.dol_escape_js($langs->trans('Stock')).': "+objBatch.qty;
';
1326 $out_js_line .= ' }
';
1327 $out_js_line .= ' if (dataEatByDate !=
"") {
';
1328 $out_js_line .= ' optionLabel +=
" - '.dol_escape_js($langs->trans('EatByDate')).': "+dataEatByDate;
';
1329 $out_js_line .= ' }
';
1330 $out_js_line .= ' if (dataSellByDate !=
"") {
';
1331 $out_js_line .= ' optionLabel +=
" - '.dol_escape_js($langs->trans('SellByDate')).': "+dataSellByDate;
';
1332 $out_js_line .= ' }
';
1333 $out_js_line .= ' optionLabel +=
")";
';
1334 $out_js_line .= ' var option =
"<option data-eatbydate=\""+dataEatByDate+
"\" data-sellbydate=\""+dataSellByDate+
"\" value=\""+key+
"\"";
';
1335 $out_js_line .= ' if (key === selectedbatch) {
';
1336 $out_js_line .= ' option +=
" selected";
';
1337 $out_js_line .= ' }
';
1338 $out_js_line .= ' option +=
">"+optionLabel+
"</option>";
';
1339 $out_js_line .= ' selectbatch.append(option);
';
1340 $out_js_line .= ' });
';
1341 $out_js_line .= ' });
';
1342 $out_js_line .= ' });
';
1343 $out_js_line .= '}
';
1345 $out_js_line .= 'function updateselectwarehousebybatch() {
';
1346 $out_js_line .= ' jQuery(document).on(
"change",
"input[name*=lot_number]",
function() {
';
1347 $out_js_line .= ' var selectbatch = jQuery(
this);
';
1348 $out_js_line .= ' var selectwarehouse_name = selectbatch.attr(
"name").replace(
"lot_number",
"entrepot");
';
1349 $out_js_line .= ' var selectwarehouse = jQuery(
"select[name*=\""+selectwarehouse_name+
"\"]");
';
1350 $out_js_line .= ' var selectedwarehouse = selectwarehouse.val();
';
1351 $out_js_line .= ' var inputbatchdlc_name = selectbatch.attr(
"name").replace(
"lot_number",
"dlc");
';
1352 $out_js_line .= ' var inputbatchdlc = jQuery(
"input[name*=\""+inputbatchdlc_name+
"\"]");
';
1353 $out_js_line .= ' var inputbatchdluo_name = selectbatch.attr(
"name").replace(
"lot_number",
"dluo");
';
1354 $out_js_line .= ' var inputbatchdluo = jQuery(
"input[name*=\""+inputbatchdluo_name+
"\"]");
';
1355 $out_js_line .= ' var datalistselectedbatch = jQuery(
"#"+selectbatch.attr(
"name")+
" option[value=\""+selectbatch.val()+
"\"]");
';
1356 $out_js_line .= ' var selectedbatch_dlc = datalistselectedbatch.data(
"sellbydate");
';
1357 $out_js_line .= ' var selectedbatch_dluo = datalistselectedbatch.data(
"eatbydate");
';
1358 $out_js_line .= ' if (typeof selectedbatch_dlc ===
"undefined") {
';
1359 $out_js_line .= ' selectedbatch_dlc =
"";
';
1360 $out_js_line .= ' }
';
1361 $out_js_line .= ' if (typeof selectedbatch_dluo ===
"undefined") {
';
1362 $out_js_line .= ' selectedbatch_dluo =
"";
';
1363 $out_js_line .= ' }
';
1364 $out_js_line .= ' inputbatchdlc.val(selectedbatch_dlc).trigger(
"change");
';
1365 $out_js_line .= ' inputbatchdluo.val(selectedbatch_dluo).trigger(
"change");
';
1366 $out_js_line .= ' if (selectedwarehouse != -1) {
';
1367 $out_js_line .= ' return;
';
1368 $out_js_line .= ' }
';
1369 $out_js_line .= ' var product_element_name = selectbatch.attr(
"name").replace(
"lot_number",
"productbatch");
';
1370 $out_js_line .= ' jQuery.ajax({
';
1371 $out_js_line .= ' type:
"POST",
';
1372 $out_js_line .= ' url:
"'.dol_escape_js(dol_buildpath('/expedition/ajax/interface.php', 1)).'",
';
1373 $out_js_line .= ' data: {
';
1374 $out_js_line .= ' action:
"updateselectwarehousebybatch",
';
1375 $out_js_line .= ' batch: jQuery(
this).val(),
';
1376 $out_js_line .= ' token:
"'.currentToken().'",
';
1377 $out_js_line .= ' product_id: jQuery(
"input[name=\""+product_element_name+
"\"]").val()
';
1378 $out_js_line .= ' }
';
1379 $out_js_line .= ' }).done(
function(data) {
';
1380 $out_js_line .= ' if (typeof data ==
"object") {
';
1381 $out_js_line .= ' console.log(
"data is already type object, no need to parse it");
';
1382 $out_js_line .= ' }
else {
';
1383 $out_js_line .= ' console.log(
"data is type "+(typeof data));
';
1384 $out_js_line .= ' data = JSON.parse(data);
';
1385 $out_js_line .= ' }
';
1386 $out_js_line .= ' if (data != 0) {
';
1387 $out_js_line .= ' selectwarehouse.val(data).change();
';
1388 $out_js_line .= ' }
';
1389 $out_js_line .= ' });
';
1390 $out_js_line .= ' });
';
1391 $out_js_line .= '}
';
1392 $out_js_line_list[] = $out_js_line;
1394 $out_js = '<script
type=
"text/javascript" language=
"javascript">
';
1395 $out_js .= 'jQuery(document).ready(
function() {
';
1396 // when a warehouse is selected, only the lot/serial numbers that are available in it are offered
1397 $out_js .= 'updateselectbatchbywarehouse();
';
1398 // when a lot/serial number is selected and it is only available in one warehouse, the warehouse is automatically selected
1399 $out_js .= 'updateselectwarehousebybatch();
';
1400 $out_js .= implode('', $out_js_line_list);
1402 $out_js .= '</script>
';
1407 dol_print_error($db);
1415 //$checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll
'));
1417 print '<div
class=
"center">
';
1418 $parameters = array();
1419 $reshook = $hookmanager->executeHooks('addMoreActionsButtons
', $parameters, $object, $action); // Note that $action and $object may have been
1421 if (empty($reshook)) {
1422 /*if (empty($conf->reception->enabled)) {
1423 print $langs->trans("Comment").' :
';
1424 print '<input
type=
"text" class=
"minwidth400" maxlength=
"128" name=
"comment" value=
"';
1425 print GETPOSTISSET("comment
") ? GETPOST("comment
") : $langs->trans("DispatchSupplierOrder
", $object->ref);
1426 // print ' / '.$object->ref_supplier; // Not yet available
1427 print '" class=
"flat"><br>
';
1429 print '<input
type=
"checkbox" checked=
"checked" name=
"closeopenorder">
'.$checkboxlabel;
1432 $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
1437 print '<input
type=
"submit" id=
"submitform" class=
"button" name=
"dispatch" value=
"'.$langs->trans("Save
").'"';
1439 if (!$usercancreate) {
1442 if (count($listwarehouses) <= 0) {
1454 // Message if nothing to dispatch
1457 if (!getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED
')) {
1458 print '<div
class=
"opacitymedium">
'.$langs->trans("NoPredefinedProductToDispatch").'</div>
'; // No predefined line at all
1460 print '<div
class=
"opacitymedium">
'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>
'; // No predefined line that remain to be dispatched.
1467 print dol_get_fiche_end();
1469 // Popup for mass barcode scanning
1470 if ($action == 'updatebyscaning
') {
1471 if ($permissiontoadd) {
1472 // Output the javascript to manage the scanner tool.
1476 var duplicatedbatchcode = [];
1482 function barcodescannerjs() {
1483 console.log(
"We catch inputs in scanner box");
1484 jQuery(
"#scantoolmessage").text();
1486 var selectaddorreplace = $(
"select[name=selectaddorreplace]").val();
1487 var barcodemode = $(
"input[name=barcodemode]:checked").val();
1488 var barcodeproductqty = $(
"input[name=barcodeproductqty]").val();
1489 var warehousetouse = $(
"select[name=warehousenew]").val();
1490 var textarea = $(
"textarea[name=barcodelist]").val();
1491 var textarray = textarea.split(/[\s,;]+/);
1492 var tabproduct = [];
1493 duplicatedbatchcode = [];
1499 textarray = textarray.filter(
function(value) {
1502 if (textarray.some((element) => element !=
"")) {
1503 $(
".qtydispatchinput").each(
function() {
1504 id = $(
this).attr(\
'id\');
1505 idarray = id.split(\'_\');
1506 idproduct = idarray[2];
1507 id = idarray[1] + \'_\' + idarray[2];
1508 console.log("Analyze the line "+id+" in inventory, barcodemode="+barcodemode);
1509 warehouse = $("#entrepot_"+id).val();
1510 console.log(warehouse);
1511 productbarcode = $("#product_"+idproduct).attr(\'data-barcode\');
1512 console.log(productbarcode);
1513 productbatchcode = $("#lot_number_"+id).val();
1514 if (productbatchcode == undefined) {
1515 productbatchcode = "";
1517 console.log(productbatchcode);
1519 if (barcodemode != "barcodeforproduct") {
1520 tabproduct.forEach(product=>{
1521 console.log("product.Batch="+product.Batch+" productbatchcode="+productbatchcode);
1522 if (product.Batch != "" && product.Batch == productbatchcode) {
1523 console.log("duplicate batch code found for batch code "+productbatchcode);
1524 duplicatedbatchcode.push(productbatchcode);
1528 productinput = $("#qty_"+id).val();
1529 if (productinput == "") {
1532 tabproduct.push({\'Id\':id,\'Warehouse\':warehouse,\'Barcode\':productbarcode,\'Batch\':productbatchcode,\'Qty\':productinput,\'fetched\':false});
1534 console.log("Loop on each record entered in the textarea");
1536 textarray.forEach(function(element,index) {
1537 console.log("Process record element="+element+" id="+id);
1538 var verify_batch = false;
1539 var verify_barcode = false;
1540 switch(barcodemode) {
1541 case "barcodeforautodetect":
1542 verify_barcode = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"barcode",true);
1543 verify_batch = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"lotserial",true);
1545 case "barcodeforproduct":
1546 verify_barcode = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"barcode");
1548 case "barcodeforlotserial":
1549 verify_batch = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"lotserial");
1552 alert(\''.
dol_escape_js($langs->trans(
"ErrorWrongBarcodemode")).
' "\'+barcodemode+\'"\');
1553 throw \''.
dol_escape_js($langs->trans(
'ErrorWrongBarcodemode')).
' "\'+barcodemode+\'"\';
1556 if (verify_batch == false && verify_barcode == false) { /* If the 2 flags are false, not found error */
1557 errortab2.push(element);
1558 } else if (verify_batch == true && verify_barcode == true) { /* If the 2 flags are true, error: we don t know which one to take */
1559 errortab3.push(element);
1560 } else if (verify_batch == true) {
1561 console.log("element="+element);
1562 console.log(duplicatedbatchcode);
1563 if (duplicatedbatchcode.includes(element)) {
1564 errortab1.push(element);
1569 if (Object.keys(errortab1).length < 1 && Object.keys(errortab2).length < 1 && Object.keys(errortab3).length < 1) {
1570 tabproduct.forEach(product => {
1571 if (product.Qty!=0) {
1572 if (product.hasOwnProperty("reelqty")) {
1573 idprod = $("td[data-idproduct=\'"+product.fk_product+"\']").attr("id");
1574 idproduct = idprod.split("_")[1];
1575 console.log("We create a new line for product_"+idproduct);
1576 if (product.Barcode != null) {
1577 modedispatch = "dispatch";
1579 modedispatch = "batch";
1581 addDispatchLine(idproduct,modedispatch);
1582 console.log($("tr[name^=\'"+modedispatch+"_\'][name$=\'_"+idproduct+"\']"));
1583 nbrTrs = $("tr[name^=\'"+modedispatch+"_\'][name$=\'_"+idproduct+"\']").length;
1585 $("#qty_"+(nbrTrs-1)+"_"+idproduct).val(product.Qty);
1586 $("#entrepot_"+(nbrTrs-1)+"_"+idproduct).val(product.Warehouse);
1588 if (modedispatch == "batch") {
1589 $("#lot_number_"+(nbrTrs-1)+"_"+idproduct).val(product.Batch);
1593 console.log("We change #qty_"+product.Id +" to match input in scanner box");
1594 $("#qty_"+product.Id).val(product.Qty);
1598 jQuery("#scantoolmessage").text("'.
dol_escape_js($langs->transnoentities(
"QtyWasAddedToTheScannedBarcode")).
'\n");
1599 /* document.forms["formrecord"].submit(); */
1601 let stringerror = "";
1602 if (Object.keys(errortab1).length > 0) {
1603 stringerror += "<br>'.
dol_escape_js($langs->transnoentities(
'ErrorSameBatchNumber')).
': ";
1604 errortab1.forEach(element => {
1605 stringerror += (element + ", ")
1607 stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1609 if (Object.keys(errortab2).length > 0) {
1610 stringerror += "<br>'.
dol_escape_js($langs->transnoentities(
'ErrorCantFindCodeInInventory')).
': ";
1611 errortab2.forEach(element => {
1612 stringerror += (element + ", ")
1614 stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1616 if (Object.keys(errortab3).length > 0) {
1617 stringerror += "<br>'.
dol_escape_js($langs->transnoentities(
'ErrorCodeScannedIsBothProductAndSerial')).
': ";
1618 errortab3.forEach(element => {
1619 stringerror += (element + ", ")
1621 stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1623 if (Object.keys(errortab4).length > 0) {
1624 stringerror += "<br>'.
dol_escape_js($langs->transnoentities(
'ErrorBarcodeNotFoundForProductWarehouse')).
': ";
1625 errortab4.forEach(element => {
1626 stringerror += (element + ", ")
1628 stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1631 jQuery("#scantoolmessage").html(\''.
dol_escape_js($langs->transnoentities(
"ErrorOnElementsInventory")).
'\' + stringerror);
1639 function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,mode,autodetect=
false) {
1640 BarcodeIsInProduct=0;
1643 tabproduct.forEach(product => {
1644 $.ajax({ url: \
''.DOL_URL_ROOT.
'/expedition/ajax/searchfrombarcode.php\',
1645 data: { "token":"'.newToken().
'", "action":"existbarcode","fk_entrepot": warehousetouse, "barcode":element, "mode":mode},
1648 success: function(response) {
1649 if (response.status == "success") {
1650 console.log(response.message);
1651 if (!newproductrow) {
1652 newproductrow = response.object;
1655 if (mode!="lotserial" && autodetect==false && !errortab4.includes(element)) {
1656 errortab4.push(element);
1657 console.error(response.message);
1661 error : function(output) {
1662 console.error("Error on barcodeserialforproduct function");
1665 console.log("Product "+(index+=1)+": "+element);
1666 if (mode == "barcode") {
1667 testonproduct = product.Barcode
1668 }else if (mode == "lotserial") {
1669 testonproduct = product.Batch
1671 testonwarehouse = product.Warehouse;
1672 if (testonproduct == element && testonwarehouse == warehousetouse) {
1673 if (selectaddorreplace == "add") {
1674 productqty = parseInt(product.Qty,10);
1675 product.Qty = productqty + parseInt(barcodeproductqty,10);
1676 }else if (selectaddorreplace == "replace") {
1677 if (product.fetched == false) {
1678 product.Qty = barcodeproductqty
1679 product.fetched=true
1681 productqty = parseInt(product.Qty,10);
1682 product.Qty = productqty + parseInt(barcodeproductqty,10);
1685 BarcodeIsInProduct+=1;
1688 if (BarcodeIsInProduct==0 && newproductrow!=0) {
1689 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});
1692 if (BarcodeIsInProduct > 0) {
1700 include DOL_DOCUMENT_ROOT.
'/core/class/html.formother.class.php';
1702 print $formother->getHTMLScannerForm(
"barcodescannerjs",
'all', 1);
1706 print
'<script type="text/javascript">
1707 $(document).ready(function () {
1708 $("select[name=fk_default_warehouse]").change(function() {
1709 console.log("warehouse is modified");
1710 var fk_default_warehouse = $("option:selected", this).val();
1711 $("select[name^=entrepot]").val(fk_default_warehouse).change();
1714 $("#autoreset").click(function() {
1715 console.log("we click on autoreset");
1716 $(".autoresettr").each(function() {
1717 id = $(this).attr("name");
1718 idtab = id.split("_");
1719 console.log("we process line "+id+" "+idtab);
1720 if ($(this).data("remove") == "clear") { /* data-remove=clear means that line qty must be cleared but line must not be removed */
1721 console.log("We clear the object to expected value")
1722 var idlinetab = idtab[0].split("-");
1724 if (idlinetab.length > 0) {
1725 idline = idlinetab[1];
1727 $("#qty"+idline+"_"+idtab[1]+"_"+idtab[2]).val("");
1729 qtyexpected = $("#qty_"+idtab[1]+"_"+idtab[2]).data("expected")
1730 console.log(qtyexpected);
1731 $("#qty_"+idtab[1]+"_"+idtab[2]).val(qtyexpected);
1732 qtydispatched = $("#qty_dispatched_0_"+idtab[2]).data("dispatched")
1733 $("#qty_dispatched_0_"+idtab[2]).val(qtydispatched);
1735 } else { /* data-remove=remove means that line must be removed */
1736 console.log("We remove the object")
1738 $("tr[name^=\'"+idtab[0]+"_\'][name$=\'_"+idtab[2]+"\']:last .splitbutton").show();
1744 $("#resetalltoexpected").click(function() {
1745 $(".qtydispatchinput").each(function() {
1746 console.log("We reset to expected "+$(this).attr("id")+" qty to dispatch");
1747 $(this).val($(this).data("expected"));
1752 $(".resetline").on("click", function(event) {
1753 event.preventDefault();
1754 id = $(this).attr("id");
1755 id = id.split("reset");
1756 console.log("Reset trigger for id = qty"+id[1]);
1757 $("#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)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
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 '.
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.
GETPOSTFLOAT($paramname, $rounding='', $option=2)
Return the value of a $_GET or $_POST supervariable, converted into float.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
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...
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'))
Abort invoice creation with a given error message.
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, $mode=0)
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.