FIX - MRP MO Product to Consume (#35424)

* FIX - MRP MO Product to Consume

Fixes MO Product to Consume when recursive BOM's are used, the product
to consume only includes the BOM line items instead of BOM product

* fix php-stan errors

* fix phan analysis errors

* fix phan analysis errors take 2

---------

Co-authored-by: brad <brad@endurotags.com.au>
This commit is contained in:
Bradley Jarvis
2025-09-22 18:18:14 +10:00
committed by GitHub
parent f8376320aa
commit 6c8b4da445
3 changed files with 80 additions and 44 deletions

View File

@@ -777,49 +777,8 @@ class Mo extends CommonObject
if ($this->fk_bom > 0 && is_object($bom)) { // If a BOM is defined, we know what to consume.
if ($bom->id > 0) {
// Lines to consume
if (!$error) {
foreach ($bom->lines as $line) {
$moline = new MoLine($this->db);
$moline->fk_mo = $this->id;
$moline->origin_id = $line->id;
$moline->origin_type = 'bomline';
if (!empty($line->fk_unit)) {
$moline->fk_unit = $line->fk_unit;
}
if ($line->qty_frozen) {
$moline->qty = $line->qty; // Qty to consume does not depends on quantity to produce
} else {
$moline->qty = (float) price2num(($line->qty / (!empty($bom->qty) ? $bom->qty : 1)) * $this->qty / (!empty($line->efficiency) ? $line->efficiency : 1), 'MS'); // Calculate with Qty to produce and more presition
}
if ($moline->qty <= 0) {
$error++;
$this->error = "BadValueForquantityToConsume";
$this->errors[] = $this->error;
break;
} else {
$moline->fk_product = $line->fk_product;
$moline->role = $role;
$moline->position = $line->position;
$moline->qty_frozen = $line->qty_frozen;
$moline->disable_stock_change = $line->disable_stock_change;
if (!empty($line->fk_default_workstation)) {
$moline->fk_default_workstation = $line->fk_default_workstation;
}
$resultline = $moline->create($user, 0); // Never use triggers here
if ($resultline <= 0) {
$error++;
$this->error = $moline->error;
$this->errors[] = $moline->error;
$this->errors = array_merge($this->errors, $moline->errors);
dol_print_error($this->db, $moline->error, $moline->errors);
break;
}
}
}
}
// process lines to consume, this needs to recurse through BOM's
$error += $this->processBOM($user, $role, $bom, $this->qty);
}
}
}
@@ -833,6 +792,69 @@ class Mo extends CommonObject
}
}
/**
* Recurse through BOM only adding products to list to consume/produce
*
* @param User $user User that modifies
* @param string $role MoLine Role that products are added as
* @param BOM $bom BOM to parse lines from
* @param float $quantity Quantity modifier for sub products/BOM
* @return int Return integer <0 if KO, >0 if OK
*/
public function processBOM(User $user, $role, $bom, $quantity)
{
$error = 0;
$quantity /= $bom->qty;
foreach ($bom->lines as $line) {
$quantity_line = !$line->qty_frozen ? $line->qty * $quantity / (!empty($line->efficiency) ? $line->efficiency : 1) : 1;
$tmpproduct = new Product($this->db);
$tmpproduct->fetch($line->fk_product);
if ($line->fk_bom_child > 0) {
$bom = new BOM($this->db);
$bom->fetch((int) $line->fk_bom_child);
$error += $this->processBOM($user, $role, $bom, $quantity_line);
} else {
$moline = new MoLine($this->db);
$moline->fk_mo = $this->id;
$moline->origin_id = $line->id;
$moline->origin_type = 'bomline';
if (!empty($line->fk_unit)) {
$moline->fk_unit = $line->fk_unit;
}
$moline->qty = (float) price2num($quantity_line, 'MS'); // Calculate with Qty to produce and more presition
if ($moline->qty <= 0) {
$error++;
$this->error = "BadValueForquantityToConsume";
$this->errors[] = $this->error;
} else {
$moline->fk_product = $line->fk_product;
$moline->role = $role;
$moline->position = $line->position;
$moline->qty_frozen = $line->qty_frozen;
$moline->disable_stock_change = $line->disable_stock_change;
if (!empty($line->fk_default_workstation)) {
$moline->fk_default_workstation = $line->fk_default_workstation;
}
$resultline = $moline->create($user, 0); // Never use triggers here
if ($resultline <= 0) {
$error++;
$this->error = $moline->error;
$this->errors[] = $moline->error;
$this->errors = array_merge($this->errors, $moline->errors);
dol_print_error($this->db, $moline->error, $moline->errors);
}
}
}
if ($error) break;
}
return $error;
}
/**
* Update quantities in lines to consume and/or lines to produce.
*

View File

@@ -544,6 +544,11 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
}
// Reload BOM to consume and produce
if ($action == 'reload') {
$object->createProduction($user, 0);
}
// Confirmation of validation
if ($action == 'validate') {
// We check that object has a temporary ref
@@ -804,6 +809,15 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
}
}
// Reload BOM
if ($object->status == $object::STATUS_DRAFT && $object->fk_bom > 0) {
if ($permissiontoadd) {
print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=reload&token='.newToken().'">'.$langs->trans("Reload").'</a>';
} else {
print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans('Reload').'</a>'."\n";
}
}
// Validate
if ($object->status == $object::STATUS_DRAFT) {
if ($permissiontoadd) {

View File

@@ -550,7 +550,7 @@ llxHeader('', $title, $help_url, '', 0, 0, $morejs, '', '', 'mod-mrp page-card_p
$newToken = newToken();
// Part to show record
if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) {
if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create' && $action != 'reload'))) {
$res = $object->fetch_thirdparty();
$res = $object->fetch_optionals();