[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:
Aurélien (avd)
2021-05-21 10:46:46 +00:00
parent a1f45aab0e
commit 2e527b4cac
+25 -5
View File
@@ -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