diff --git a/htdocs/fourn/commande/dispatch.php b/htdocs/fourn/commande/dispatch.php index 014b7f20ced..cc38abfc935 100644 --- a/htdocs/fourn/commande/dispatch.php +++ b/htdocs/fourn/commande/dispatch.php @@ -807,7 +807,6 @@ if ($id > 0 || !empty($ref)) { print ''; if (! empty($conf->productbatch->enabled) && $objp->tobatch == 1) { $type = 'batch'; - //print img_picto($langs->trans('AddDispatchBatchLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine(' . $i . ',\'' . $type . '\')"'); print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"'); } else @@ -815,7 +814,6 @@ if ($id > 0 || !empty($ref)) { $type = 'dispatch'; print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"'); } - print ''; if (! empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) { diff --git a/htdocs/fourn/js/lib_dispatch.js.php b/htdocs/fourn/js/lib_dispatch.js.php index 8dfb3369cd8..dda12313bc9 100644 --- a/htdocs/fourn/js/lib_dispatch.js.php +++ b/htdocs/fourn/js/lib_dispatch.js.php @@ -17,7 +17,7 @@ // or see https://www.gnu.org/ /** - * \file htdocs/core/js/lib_dispatch.js.php + * \file htdocs/fourn/js/lib_dispatch.js.php * \brief File that include javascript functions used for dispatching qty/stock/lot */ @@ -53,11 +53,11 @@ function addDispatchLine(index, type, mode) mode = mode || 'qtymissing' console.log("fourn/js/lib_dispatch.js.php Split line type="+type+" index="+index+" mode="+mode); - var $row = $("tr[name='"+type+'_0_'+index+"']").clone(true), // clone first batch line to jQuery object - nbrTrs = $("tr[name^='"+type+"_'][name$='_"+index+"']").length, // position of line for batch - qtyOrdered = parseFloat($("#qty_ordered_0_"+index).val()), // Qty ordered is same for all rows - qty = parseFloat($("#qty_"+(nbrTrs - 1)+"_"+index).val()), - qtyDispatched; + var $row = $("tr[name='"+type+'_0_'+index+"']").clone(true); // clone first batch line to jQuery object + var nbrTrs = $("tr[name^='"+type+"_'][name$='_"+index+"']").length; // position of line for batch + var qtyOrdered = parseFloat($("#qty_ordered_0_"+index).val()); // Qty ordered is same for all rows + var qty = parseFloat($("#qty_"+(nbrTrs - 1)+"_"+index).val()); + var qtyDispatched; if (mode === 'lessone') { @@ -126,7 +126,7 @@ function addDispatchLine(index, type, mode) * * Change event handler for dispatch qty input field, * recalculate qty dispatched when qty input has changed. - * If qty is more then qty ordered reset input qty to max qty to dispatch. + * If qty is more than qty ordered reset input qty to max qty to dispatch. * * element requires arbitrary data qty (value before change), type (type of dispatch) and index (index of product line) */ diff --git a/htdocs/install/mysql/migration/11.0.0-12.0.0.sql b/htdocs/install/mysql/migration/11.0.0-12.0.0.sql index b2d0b9b0bd1..b367091c3a0 100644 --- a/htdocs/install/mysql/migration/11.0.0-12.0.0.sql +++ b/htdocs/install/mysql/migration/11.0.0-12.0.0.sql @@ -193,8 +193,8 @@ ALTER TABLE llx_accounting_account DROP COLUMN pcg_subtype; ALTER TABLE llx_product ADD COLUMN accountancy_code_buy_intra varchar(32) AFTER accountancy_code_buy; ALTER TABLE llx_product ADD COLUMN accountancy_code_buy_export varchar(32) AFTER accountancy_code_buy_intra; -ALTER TABLE llx_entrepot ADD COLUMN fax varchar(20) DEFAULT NULL AFTER fk_pays; -ALTER TABLE llx_entrepot ADD COLUMN phone varchar(20) DEFAULT NULL AFTER fk_pays; +ALTER TABLE llx_entrepot ADD COLUMN fax varchar(20) DEFAULT NULL; +ALTER TABLE llx_entrepot ADD COLUMN phone varchar(20) DEFAULT NULL; ALTER TABLE llx_accounting_account ADD COLUMN reconcilable tinyint DEFAULT 0 NOT NULL after active; diff --git a/htdocs/mrp/js/lib_dispatch.js.php b/htdocs/mrp/js/lib_dispatch.js.php new file mode 100644 index 00000000000..dc7c079a024 --- /dev/null +++ b/htdocs/mrp/js/lib_dispatch.js.php @@ -0,0 +1,136 @@ + +// Copyright (C) 2017 Francis Appels +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// or see https://www.gnu.org/ + +/** + * \file htdocs/mrp/js/lib_dispatch.js.php + * \brief File that include javascript functions used for dispatching qty/stock/lot + */ + +if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); +if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', 1); +if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', 1); +if (! defined('NOLOGIN')) define('NOLOGIN', 1); +if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', 1); +if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', 1); +if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); + +session_cache_limiter('public'); + +require_once '../../main.inc.php'; + +// Define javascript type +top_httphead('text/javascript; charset=UTF-8'); +// Important: Following code is to avoid page request by browser and PHP CPU at each Dolibarr page access. +if (empty($dolibarr_nocache)) header('Cache-Control: max-age=10800, public, must-revalidate'); +else header('Cache-Control: no-cache'); + +?> +/** + * addDispatchLine + * Adds new table row for dispatching to multiple stock locations or multiple lot/serial + * + * @param index int index of product line. 0 = first product line + * @param type string type of dispatch (batch = batch dispatch, dispatch = non batch dispatch) + * @param mode string 'qtymissing' will create new line with qty missing, 'lessone' will keep 1 in old line and the rest in new one + */ +function addDispatchLine(index, type, mode) +{ + mode = mode || 'qtymissing' + + console.log("fourn/js/lib_dispatch.js.php Split line type="+type+" index="+index+" mode="+mode); + var nbrTrs = $("tr[name^='"+type+"_"+index+"']").length; // position of line for batch + var $row = $("tr[name='"+type+'_'+index+"_1']").clone(true); // clone last batch line to jQuery object + var qtyOrdered = parseFloat($("#qty_ordered_"+index).val()); // Qty ordered is same for all rows + var qty = parseFloat($("#qtytoproduce-"+index+"-"+nbrTrs).val()); + var qtyDispatched; + + if (mode === 'lessone') + { + qtyDispatched = parseFloat($("#qty_dispatched_"+index).val()) + 1; + } + else + { + qtyDispatched = parseFloat($("#qty_dispatched_"+index).val()) + qty; + console.log(qty); + // If user did not reduced the qty to dispatch on old line, we keep only 1 on old line and the rest on new line + if (qtyDispatched == qtyOrdered && qtyDispatched > 1) { + qtyDispatched = parseFloat($("#qty_dispatched_"+index).val()) + 1; + mode = 'lessone'; + } + } + console.log("qtyDispatched="+qtyDispatched+" qtyOrdered="+qtyOrdered); + + if (qtyOrdered <= 1) { + window.alert("Quantity can't be split"); + } + if (qtyDispatched < qtyOrdered) + { + //replace tr suffix nbr + var re1 = new RegExp('_'+index+'_1', 'g'); + var re2 = new RegExp('-'+index+'-1', 'g'); + $row.html($row.html().replace(re1, '_'+index+'_'+(nbrTrs+1))); + $row.html($row.html().replace(re2, '-'+index+'-'+(nbrTrs+1))); + //create new select2 to avoid duplicate id of cloned one + $row.find("select[name='"+'idwarehousetoproduce-'+index+'-'+(nbrTrs+1)+"']").select2(); + // TODO find solution to copy selected option to new select + // TODO find solution to keep new tr's after page refresh + //clear value + $row.find("input[name^='qtytoproduce']").val(''); + //change name of new row + $row.attr('name',type+'_'+index+'_'+(nbrTrs+1)); + //insert new row before last row + $("tr[name^='"+type+"_"+index+"_"+nbrTrs+"']:last").after($row); + + //remove cloned select2 with duplicate id. + $("#s2id_entrepot_"+nbrTrs+'_'+index).detach(); // old way to find duplicated select2 component + $(".csswarehouse_"+index+"_"+(nbrTrs+1)+":first-child").parent("span.selection").parent(".select2").detach(); + + /* Suffix of lines are: index _ trs.length */ + $("#qtytoproduce-"+index+"-"+(nbrTrs+1)).focus(); + if ($("#qtytoproduce-"+index+"-"+(nbrTrs)).val() == 0) { + $("#qtytoproduce-"+index+"-"+(nbrTrs)).val(1); + } + var totalonallines = 0; + for (let i = 1; i <= nbrTrs; i++) { + console.log(i+" = "+parseFloat($("#qtytoproduce-"+index+"-"+i).val())); + totalonallines = totalonallines + parseFloat($("#qtytoproduce-"+index+"-"+i).val()); + } + console.log("totalonallines="+totalonallines); + if (totalonallines == qtyOrdered && qtyOrdered > 1) { + var prevouslineqty = $("#qtytoproduce-"+index+"-"+nbrTrs).val(); + $("#qtytoproduce-"+index+"-"+(nbrTrs)).val(1); + $("#qtytoproduce-"+index+"-"+(nbrTrs+1)).val(prevouslineqty - 1); + } + $("#qty_dispatched_"+index).val(qtyDispatched); + + //hide all buttons then show only the last one + $("tr[name^='"+type+"_'][name$='_"+index+"'] .splitbutton").hide(); + $("tr[name^='"+type+"_'][name$='_"+index+"']:last .splitbutton").show(); + + if (mode === 'lessone') + { + qty = 1; // keep 1 in old line + $("#qty_"+(nbrTrs-1)+"_"+index).val(qty); + } + // Store arbitrary data for dispatch qty input field change event + $("#qtytoproduce-"+index+(nbrTrs)).data('qty', qty); + $("#qtytoproduce-"+index+(nbrTrs)).data('type', type); + $("#qtytoproduce-"+index+(nbrTrs)).data('index', index); + } +} + diff --git a/htdocs/mrp/mo_production.php b/htdocs/mrp/mo_production.php index c8c7ec0e624..b25f5093cb9 100644 --- a/htdocs/mrp/mo_production.php +++ b/htdocs/mrp/mo_production.php @@ -397,7 +397,8 @@ $formproduct = new FormProduct($db); $tmpwarehouse = new Entrepot($db); $tmpbatch = new Productlot($db); -llxHeader('', $langs->trans('Mo'), ''); +$help_url = 'EN:Module_Manufacturing_Orders|FR:Module_Ordres_de_Fabrication'; +llxHeader('', $langs->trans('Mo'), $help_url, '', 0, 0, array('/mrp/js/lib_dispatch.js.php')); // Part to show record if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) @@ -687,7 +688,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''; print $form->select_produits('', 'productidtoadd', '', 0, 0, -1, 2, '', 0, array(), 0, '1', 0, 'maxwidth300'); print ''; - print ''; + print ''; print ''; print ''; print ''; @@ -774,8 +775,8 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''.$line2['qty'].''; print ''; if ($line2['fk_warehouse'] > 0) { - $tmpwarehouse->fetch($line2['fk_warehouse']); - print $tmpwarehouse->getNomUrl(1); + $result = $tmpwarehouse->fetch($line2['fk_warehouse']); + if ($result > 0) print $tmpwarehouse->getNomUrl(1); } print ''; // Lot Batch @@ -846,6 +847,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''; if ($collapse || in_array($action, array('consumeorproduce', 'consumeandproduceall'))) print $langs->trans("Batch"); print ''; + print ''; } print ''; @@ -861,6 +863,8 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea $nblinetoproducecursor = 0; foreach ($object->lines as $line) { if ($line->role == 'toproduce') { + $i=1; + $nblinetoproducecursor++; $tmpproduct = new Product($db); @@ -872,6 +876,12 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea $alreadyproduced += $line2['qty']; } + $suffix = '_'.$line->id; + print ''."\n"; + // hidden fields for js function + print ''; + print ''; + print ''; print ''.$tmpproduct->getNomUrl(1).''; print ''.$line->qty.''; @@ -899,6 +909,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''; if ($conf->productbatch->enabled) { print ''; // Lot + print ''; } print ''; @@ -912,30 +923,33 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''.$line2['qty'].''; print ''; if ($line2['fk_warehouse'] > 0) { - $tmpwarehouse->fetch($line2['fk_warehouse']); - print $tmpwarehouse->getNomUrl(1); + $result = $tmpwarehouse->fetch($line2['fk_warehouse']); + if ($result > 0) print $tmpwarehouse->getNomUrl(1); } print ''; - print ''; - if ($line2['batch'] != '') { - $tmpbatch->fetch(0, $line2['fk_product'], $line2['batch']); - print $tmpbatch->getNomUrl(1); + if ($conf->productbatch->enabled) { + print ''; + if ($line2['batch'] != '') { + $tmpbatch->fetch(0, $line2['fk_product'], $line2['batch']); + print $tmpbatch->getNomUrl(1); + } + print ''; + print ''; } - print ''; print ''; } if (in_array($action, array('consumeorproduce', 'consumeandproduceall'))) { - print ''; + print ''; print ''.$langs->trans("ToProduce").''; $preselected = (GETPOSTISSET('qtytoproduce-'.$line->id.'-'.$i) ? GETPOST('qtytoproduce-'.$line->id.'-'.$i) : max(0, $line->qty - $alreadyproduced)); if ($action == 'consumeorproduce' && !GETPOSTISSET('qtytoproduce-'.$line->id.'-'.$i)) $preselected = 0; - print ''; + print ''; print ''; print ''; if ($tmpproduct->type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) { $preselected = (GETPOSTISSET('idwarehousetoproduce-'.$line->id.'-'.$i) ? GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i) : ($object->fk_warehouse > 0 ? $object->fk_warehouse : 'ifone')); - print $formproduct->selectWarehouses($preselected, 'idwarehousetoproduce-'.$line->id.'-'.$i, '', 1, 0, $line->fk_product, '', 1); + print $formproduct->selectWarehouses($preselected, 'idwarehousetoproduce-'.$line->id.'-'.$i, '', 1, 0, $line->fk_product, '', 1, 0, null, 'csswarehouse_'.$line->id.'_'.$i); } else { print ''.$langs->trans("NoStockChangeOnServices").''; } @@ -947,6 +961,12 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''; } print ''; + print ''; + if ($tmpproduct->status_batch) { + $type = 'batch'; + print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$line->id.', \''.$type.'\', \'qtymissing\')"'); + } + print ''; } print ''; }