[FIX] mrp: improve perf of explode
Batch the bom_search of bom_lines in mrp_bom.explode. If we represent the bom hierarchy as a graph, essentially switch from a depth-first to a breadth-first search, allowing to batch search boms for each depth level, hence improving the overall performance. closes odoo/odoo#71137 X-original-commit: 44ae26e4477e1b76b3dbb0f1acd50e8553b14d71 Signed-off-by: William Henrotin <Whenrow@users.noreply.github.com>
This commit is contained in:
@@ -234,14 +234,29 @@ class MrpBom(models.Model):
|
||||
recStack[v] = False
|
||||
return False
|
||||
|
||||
product_ids = set()
|
||||
product_boms = {}
|
||||
def update_product_boms():
|
||||
products = self.env['product.product'].browse(product_ids)
|
||||
product_boms.update(self._bom_find(products, picking_type=picking_type or self.picking_type_id,
|
||||
company_id=self.company_id.id, bom_type='phantom'))
|
||||
# Set missing keys to default value
|
||||
for product in products:
|
||||
product_boms.setdefault(product, self.env['mrp.bom'])
|
||||
|
||||
boms_done = [(self, {'qty': quantity, 'product': product, 'original_qty': quantity, 'parent_line': False})]
|
||||
lines_done = []
|
||||
V |= set([product.product_tmpl_id.id])
|
||||
|
||||
bom_lines = [(bom_line, product, quantity, False) for bom_line in self.bom_line_ids]
|
||||
bom_lines = []
|
||||
for bom_line in self.bom_line_ids:
|
||||
V |= set([bom_line.product_id.product_tmpl_id.id])
|
||||
graph[product.product_tmpl_id.id].append(bom_line.product_id.product_tmpl_id.id)
|
||||
product_id = bom_line.product_id
|
||||
V |= set([product_id.product_tmpl_id.id])
|
||||
graph[product.product_tmpl_id.id].append(product_id.product_tmpl_id.id)
|
||||
bom_lines.append((bom_line, product, quantity, False))
|
||||
product_ids.add(product_id.id)
|
||||
update_product_boms()
|
||||
product_ids.clear()
|
||||
while bom_lines:
|
||||
current_line, current_product, current_qty, parent_line = bom_lines[0]
|
||||
bom_lines = bom_lines[1:]
|
||||
@@ -250,15 +265,20 @@ class MrpBom(models.Model):
|
||||
continue
|
||||
|
||||
line_quantity = current_qty * current_line.product_qty
|
||||
bom = self._bom_find(current_line.product_id, picking_type=picking_type or self.picking_type_id, company_id=self.company_id.id, bom_type='phantom')[current_line.product_id]
|
||||
if not current_line.product_id in product_boms:
|
||||
update_product_boms()
|
||||
product_ids.clear()
|
||||
bom = product_boms.get(current_line.product_id)
|
||||
if bom:
|
||||
converted_line_quantity = current_line.product_uom_id._compute_quantity(line_quantity / bom.product_qty, bom.product_uom_id)
|
||||
bom_lines = [(line, current_line.product_id, converted_line_quantity, current_line) for line in bom.bom_line_ids] + bom_lines
|
||||
bom_lines += [(line, current_line.product_id, converted_line_quantity, current_line) for line in bom.bom_line_ids]
|
||||
for bom_line in bom.bom_line_ids:
|
||||
graph[current_line.product_id.product_tmpl_id.id].append(bom_line.product_id.product_tmpl_id.id)
|
||||
if bom_line.product_id.product_tmpl_id.id in V and check_cycle(bom_line.product_id.product_tmpl_id.id, {key: False for key in V}, {key: False for key in V}, graph):
|
||||
raise UserError(_('Recursion error! A product with a Bill of Material should not have itself in its BoM or child BoMs!'))
|
||||
V |= set([bom_line.product_id.product_tmpl_id.id])
|
||||
if not bom_line.product_id in product_boms:
|
||||
product_ids.add(bom_line.product_id.id)
|
||||
boms_done.append((bom, {'qty': converted_line_quantity, 'product': current_product, 'original_qty': quantity, 'parent_line': current_line}))
|
||||
else:
|
||||
# We round up here because the user expects that if he has to consume a little more, the whole UOM unit
|
||||
|
||||
Reference in New Issue
Block a user