diff --git a/htdocs/cron/class/cronjob.class.php b/htdocs/cron/class/cronjob.class.php index a84fa3109df..714622e8014 100644 --- a/htdocs/cron/class/cronjob.class.php +++ b/htdocs/cron/class/cronjob.class.php @@ -137,6 +137,11 @@ class Cronjob extends CommonObject */ public $processing; + /** + * @var int The job current PID + */ + public $pid; + /** * @var int ID */ @@ -422,6 +427,7 @@ class Cronjob extends CommonObject $sql .= " t.frequency,"; $sql .= " t.status,"; $sql .= " t.processing,"; + $sql .= " t.pid,"; $sql .= " t.fk_user_author,"; $sql .= " t.fk_user_mod,"; $sql .= " t.note as note_private,"; @@ -470,6 +476,7 @@ class Cronjob extends CommonObject $this->frequency = $obj->frequency; $this->status = $obj->status; $this->processing = $obj->processing; + $this->pid = $obj->pid; $this->fk_user_author = $obj->fk_user_author; $this->fk_user_mod = $obj->fk_user_mod; $this->note_private = $obj->note_private; @@ -530,6 +537,7 @@ class Cronjob extends CommonObject $sql .= " t.frequency,"; $sql .= " t.status,"; $sql .= " t.processing,"; + $sql .= " t.pid,"; $sql .= " t.fk_user_author,"; $sql .= " t.fk_user_mod,"; $sql .= " t.note as note_private,"; @@ -606,6 +614,7 @@ class Cronjob extends CommonObject $line->frequency = $obj->frequency; $line->status = $obj->status; $line->processing = $obj->processing; + $line->pid = $obj->pid; $line->fk_user_author = $obj->fk_user_author; $line->fk_user_mod = $obj->fk_user_mod; $line->note_private = $obj->note_private; @@ -708,6 +717,10 @@ class Cronjob extends CommonObject $this->processing = 0; } + if (empty($this->pid)) { + $this->pid = null; + } + // Check parameters // Put here code to add a control on parameters values if (dol_strlen($this->datenextrun) == 0) { @@ -773,6 +786,7 @@ class Cronjob extends CommonObject $sql .= " frequency=".(isset($this->frequency) ? $this->frequency : "null").","; $sql .= " status=".(isset($this->status) ? $this->status : "null").","; $sql .= " processing=".((isset($this->processing) && $this->processing > 0) ? $this->processing : "0").","; + $sql .= " pid=".(isset($this->pid) ? $this->pid : "null").","; $sql .= " fk_user_mod=".$user->id.","; $sql .= " note=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").","; $sql .= " nbrun=".((isset($this->nbrun) && $this->nbrun > 0) ? $this->nbrun : "null").","; @@ -925,6 +939,7 @@ class Cronjob extends CommonObject $this->frequency = ''; $this->status = 0; $this->processing = 0; + $this->pid = null; $this->fk_user_author = 0; $this->fk_user_mod = 0; $this->note_private = ''; @@ -1125,6 +1140,7 @@ class Cronjob extends CommonObject $this->lastoutput = ''; $this->lastresult = ''; $this->processing = 1; // To know job was started + $this->pid = dol_getmypid(); $this->nbrun = $this->nbrun + 1; $result = $this->update($user); // This include begin/commit if ($result < 0) { @@ -1316,6 +1332,7 @@ class Cronjob extends CommonObject $this->datelastresult = dol_now(); $this->processing = 0; + $this->pid = null; $result = $this->update($user); // This include begin/commit if ($result < 0) { dol_syslog(get_class($this)."::run_jobs ".$this->error, LOG_ERR); diff --git a/htdocs/mrp/js/lib_dispatch.js.php b/htdocs/mrp/js/lib_dispatch.js.php index e8ca84d7a4e..8470716ce8f 100644 --- a/htdocs/mrp/js/lib_dispatch.js.php +++ b/htdocs/mrp/js/lib_dispatch.js.php @@ -70,7 +70,7 @@ function addDispatchLine(index, type, mode) mode = mode || 'qtymissing' console.log("fourn/js/lib_dispatch.js.php Split line type="+type+" index="+index+" mode="+mode); - if(mode == 'qtymissingconsume') { + if(mode == 'qtymissingconsume' || mode == 'allmissingconsume') { var inputId = 'qtytoconsume'; var warehouseId = 'idwarehouse'; } @@ -94,16 +94,70 @@ function addDispatchLine(index, type, mode) console.log($("#qty_dispatched_"+index).val()); // 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'; + qtyDispatched = parseFloat($("#qty_dispatched_" + index).val()) + 1; + + } + if(mode == 'allmissingconsume' || mode == 'alltoproduce') { + var qtymax = parseFloat($($row).data('max-qty')); + if(qtymax === 'undefined') qtymax = 1; } } - console.log("qtyDispatched="+qtyDispatched+" qtyOrdered="+qtyOrdered); + + if(mode == 'allmissingconsume' || mode == 'alltoproduce') { + var count = 0; + var qtyalreadyused = 0; + var error = 0; + + while (qtyalreadyused < qty) { + //If remaining qty needed is inferior to qty asked, qtymax = qty asked - qty already used + if ((qtyalreadyused + qtymax) > qty) qtymax = qty - qtyalreadyused; + //If first line, we replace value, not add line + if(count === 0){ + $("#"+inputId+"-"+index+"-"+nbrTrs).val(qtymax); + } else { + var res = addDispatchTR(qtyOrdered, qtyDispatched, index, nbrTrs, warehouseId, inputId, type, qtymax, mode, $row); + if(res === -1){ + error = 1; + break; + } + nbrTrs++; + } + qtyalreadyused = qtyalreadyused + qtymax; + count++; + $row = $("tr[name='" + type + '_' + index + "_1']").clone(true); + } + + if(error === 0) { + addDispatchTR(qtyOrdered, qtyDispatched, index, nbrTrs, warehouseId, inputId, type, '', mode, $row); + } + } + else addDispatchTR(qtyOrdered, qtyDispatched, index, nbrTrs, warehouseId, inputId, type, qty, mode, $row) + +} + +/** + * addDispatchTR + * Adds new table row for dispatching to multiple stock locations or multiple lot/serial + * + * @param qtyOrdered double + * @param qtyDispatched double + * @param index int + * @param nbrTrs int + * @param warehouseId int + * @param inputId int + * @param type string + * @param qty double + * @param mode string + * @param $row object + */ +function addDispatchTR(qtyOrdered, qtyDispatched, index, nbrTrs, warehouseId, inputId, type, qty, mode, $row) { if (qtyOrdered <= 1) { window.alert("Quantity can't be split"); + return -1; } else if (qtyDispatched >= qtyOrdered) { window.alert("No remain qty to dispatch"); + return -1; } else if (qtyDispatched < qtyOrdered) { //replace tr suffix nbr var re1 = new RegExp('_'+index+'_1', 'g'); @@ -128,24 +182,27 @@ function addDispatchLine(index, type, mode) /* Suffix of lines are: index _ trs.length */ $("#"+inputId+"-"+index+"-"+(nbrTrs+1)).focus(); if ($("#"+inputId+"-"+index+"-"+(nbrTrs)).val() == 0) { - $("#"+inputId+"-"+index+"-"+(nbrTrs)).val(1); + if(mode == 'allmissingconsume' || mode == 'alltoproduce') $("#"+inputId+"-"+index+"-"+(nbrTrs)).val(qty); + else $("#"+inputId+"-"+index+"-"+(nbrTrs)).val(1); } var totalonallines = 0; for (let i = 1; i <= nbrTrs; i++) { console.log(i+" = "+parseFloat($("#"+inputId+"-"+index+"-"+i).val())); totalonallines = totalonallines + parseFloat($("#"+inputId+"-"+index+"-"+i).val()); } - console.log("totalonallines="+totalonallines); - if (totalonallines == qtyOrdered && qtyOrdered > 1) { - var prevouslineqty = $("#"+inputId+"-"+index+"-"+nbrTrs).val(); - $("#"+inputId+"-"+index+"-"+(nbrTrs)).val(1); - $("#"+inputId+"-"+index+"-"+(nbrTrs+1)).val(prevouslineqty - 1); + + if(mode != 'allmissingconsume' && mode != 'alltoproduce') { + if (totalonallines == qtyOrdered && qtyOrdered > 1) { + var prevouslineqty = $("#" + inputId + "-" + index + "-" + nbrTrs).val(); + $("#" + inputId + "-" + index + "-" + (nbrTrs)).val(1); + $("#" + inputId + "-" + 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(); + $("tr[name^='"+type+"_"+index+"_'] .splitbutton").hide(); + $("tr[name^='"+type+"_"+index+"_']:last .splitbutton").show(); if (mode === 'lessone') { @@ -156,6 +213,10 @@ function addDispatchLine(index, type, mode) $("#"+inputId+"-"+index+(nbrTrs)).data('qty', qty); $("#"+inputId+"-"+index+(nbrTrs)).data('type', type); $("#"+inputId+"-"+index+(nbrTrs)).data('index', index); + if(mode == 'allmissingconsume' || mode == 'alltoproduce') { + let currentQtyDispatched = qtyDispatched+qty; + $row.find("input[id^='"+inputId+"']").val(qty); + } } } diff --git a/htdocs/mrp/mo_production.php b/htdocs/mrp/mo_production.php index 6584c80cc37..d6fc14b33ae 100644 --- a/htdocs/mrp/mo_production.php +++ b/htdocs/mrp/mo_production.php @@ -772,6 +772,13 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea if ($permissiontodelete) { print ''; } + + // Split + print ''; + + // SplitAll + print ''; + print ''; if ($action == 'addconsumeline') { @@ -855,7 +862,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''; print ''; - print ''; + print ''; // Product print ''.$tmpproduct->getNomUrl(1); print '
'.$tmpproduct->label.''; @@ -935,6 +942,13 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''; print ''; } + + // Split + print ''; + + // Split All + print ''; + print ''; // Show detailed of already consumed with js code to collapse @@ -1000,7 +1014,8 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea if (in_array($action, array('consumeorproduce', 'consumeandproduceall'))) { $i = 1; print ''."\n"; - print ''; + $maxQty = 1; + print ''; // Ref print ''.$langs->trans("ToConsume").''; $preselected = (GETPOSTISSET('qty-'.$line->id.'-'.$i) ? GETPOST('qty-'.$line->id.'-'.$i) : max(0, $line->qty - $alreadyconsumed)); @@ -1052,7 +1067,12 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print $formproduct->selectLotDataList('batch-'.$line->id.'-'.$i, 0, $line->fk_product, '', ''); $type = 'batch'; + print ''; print ' '.img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.((int) $line->id).', \''.dol_escape_js($type).'\', \'qtymissingconsume\')"'); + print ''; + print ''; + if (($action == 'consumeorproduce' || $action == 'consumeandproduceall')) print img_picto($langs->trans('SplitAllQuantity'), 'split.png', 'class="splitbutton splitallbutton field-error-icon" data-max-qty="1" onClick="addDispatchLine('.$line->id.', \'batch\', \'allmissingconsume\')"'); + print ''; } print ''; } @@ -1130,6 +1150,12 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''; if ($collapse || in_array($action, array('consumeorproduce', 'consumeandproduceall'))) { print $langs->trans("Batch"); + + // Split + print ''; + + // Split All + print ''; } print ''; print ''; @@ -1293,13 +1319,20 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea } print ''; print ''; + + // Split + print ''; + + // Split All + print ''; } print ''; } if (in_array($action, array('consumeorproduce', 'consumeandproduceall'))) { print ''."\n"; - print ''; + $maxQty = 1; + 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)) { @@ -1346,7 +1379,13 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea print ''; if ($tmpproduct->status_batch) { $type = 'batch'; + print ''; print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$line->id.', \''.$type.'\', \'qtymissing\')"'); + print ''; + + print ''; + if (($action == 'consumeorproduce' || $action == 'consumeandproduceall') && $tmpproduct->status_batch == 2) print img_picto($langs->trans('SplitAllQuantity'), 'split.png', 'class="splitbutton splitallbutton field-error-icon" onClick="addDispatchLine('.$line->id.', \'batch\', \'alltoproduce\')"'); // + print ''; } print ''; }