[FIX] mrp: reordering rules for BoM product

When running the scheduler, if one of the concerned product  is a
kit, it will always generate a RfQ for the components, even if there
are already enough of them.

To reproduce the error:
(Need purchase)
1. Create 2 products P and P_compo
	- Both must be storable products
	- P_compo must have at least one vendor
2. Go on P-product page
3. Add a reordering rule (e.g., min: 5 and max: 10)
4. Add a BoM
	- Must be a Kit
	- Add P_compo to components
5. Inventory > Operations > Run Scheduler
6. Go to Purchase, find the generated RfQ
7. Confirm the order, Receive Products, Validate
8. Go on P-product's page
	- As you can see, you have enough P-products on hand
9. Repeat steps 5-6

=> You should not find any RfQ since you already have enough P-products.

When checking the P-product's page, you can see the correct quantity on
hand because it uses the `_compute_quantities` method and this one has been
overridden in the mrp-module so a kit will be correctly computed.

However, when running the scheduler, it uses another method to get the
current quantities: `_compute_quantities_dict`. Since this method has
not been overridden in mrp-module, it will use the basic implementation
and this one does not consider the possibility for a product to be a
kit.

This fix creates an override of `_compute_quantities_dict` so it can
compute the correct quantities of products with 'phantom' as BoM type.
Moreover, for the code to be simpler and clearer, thix fix also merges
`_compute_quantities` and the new `_compute_quantities_dict`.

OPW-2421841

closes odoo/odoo#64326

X-original-commit: 609e2f4427082431b56aa8f999d74ed9d39db653
Signed-off-by: Nicolas Lempereur (nle) <nle@odoo.com>
Signed-off-by: Adrien Widart <adwid@users.noreply.github.com>
This commit is contained in:
Adrien Widart
2021-01-11 11:46:01 +00:00
parent 23233a7051
commit 31bf2fd446
+22 -40
View File
@@ -56,34 +56,6 @@ class ProductTemplate(models.Model):
}
return action
def _compute_quantities(self):
""" When the product template is a kit, this override computes the fields :
- 'virtual_available'
- 'qty_available'
- 'incoming_qty'
- 'outgoing_qty'
"""
product_without_bom = self.browse([])
for product_template in self:
if not self.env['mrp.bom']._bom_find(product_tmpl=product_template, bom_type='phantom'):
product_without_bom |= product_template
continue
virtual_available = 0
qty_available = 0
incoming_qty = 0
outgoing_qty = 0
for product in product_template.product_variant_ids:
if self.env['mrp.bom']._bom_find(product=product, bom_type='phantom'):
qty_available += product.qty_available
virtual_available += product.virtual_available
incoming_qty += product.incoming_qty
outgoing_qty += product.outgoing_qty
product_template.qty_available = qty_available
product_template.virtual_available = virtual_available
product_template.incoming_qty = incoming_qty
product_template.outgoing_qty = outgoing_qty
super(ProductTemplate, product_without_bom)._compute_quantities()
class ProductProduct(models.Model):
_inherit = "product.product"
@@ -141,19 +113,17 @@ class ProductProduct(models.Model):
continue
product.mrp_product_qty = float_round(mapped_data.get(product.id, 0), precision_rounding=product.uom_id.rounding)
def _compute_quantities(self):
def _compute_quantities_dict(self, lot_id, owner_id, package_id, from_date=False, to_date=False):
""" When the product is a kit, this override computes the fields :
- 'virtual_available'
- 'qty_available'
- 'incoming_qty'
- 'outgoing_qty'
- 'free_qty'
This override is used to get the correct quantities of products
with 'phantom' as BoM type.
"""
self.virtual_available = 0
self.qty_available = 0
self.incoming_qty = 0
self.outgoing_qty = 0
self.free_qty = 0
bom_kits = {
product: bom
for product in self
@@ -161,7 +131,7 @@ class ProductProduct(models.Model):
if bom
}
kits = self.filtered(lambda p: bom_kits.get(p))
super(ProductProduct, self.filtered(lambda p: p not in bom_kits))._compute_quantities()
res = super(ProductProduct, self - kits)._compute_quantities_dict(lot_id, owner_id, package_id, from_date=from_date, to_date=to_date)
for product in bom_kits:
boms, bom_sub_lines = bom_kits[product].explode(product, 1)
ratios_virtual_available = []
@@ -186,11 +156,23 @@ class ProductProduct(models.Model):
ratios_outgoing_qty.append(component.outgoing_qty / qty_per_kit)
ratios_free_qty.append(component.free_qty / qty_per_kit)
if bom_sub_lines and ratios_virtual_available: # Guard against all cnsumable bom: at least one ratio should be present.
product.virtual_available = min(ratios_virtual_available) // 1
product.qty_available = min(ratios_qty_available) // 1
product.incoming_qty = min(ratios_incoming_qty) // 1
product.outgoing_qty = min(ratios_outgoing_qty) // 1
product.free_qty = min(ratios_free_qty) // 1
res[product.id] = {
'virtual_available': min(ratios_virtual_available) // 1,
'qty_available': min(ratios_qty_available) // 1,
'incoming_qty': min(ratios_incoming_qty) // 1,
'outgoing_qty': min(ratios_outgoing_qty) // 1,
'free_qty': min(ratios_free_qty) // 1,
}
else:
res[product.id] = {
'virtual_available': 0,
'qty_available': 0,
'incoming_qty': 0,
'outgoing_qty': 0,
'free_qty': 0,
}
return res
def action_view_bom(self):
action = self.env["ir.actions.actions"]._for_xml_id("mrp.product_open_bom")