[FIX] mrp: find child/source MO

When a MO is generated in order to supply another one, the smart buttons
"Source MO"/"Child MO" are still invisible.

To reproduce the issue:
1. In Settings, enable "Multi-Step Routes"
2. Enable MTO route
3. Edit the warehouse: 3-steps manufacturing
4. Create 3 stored products Super, Sub and Compo:
    - Sub has two routes: MTO and Manufacture
5. Create two BoMs:
    - For 1 x Super:
        - 1 x Sub
    - For 1 x Sub:
        - 1 x Compo
6. Create and confirm a MO with 1 x Super

Error: On confirmation, a second MO is created to produce one Sub, which
is correct. However, neither the first MO nor the generated one has a
link with the other one (through the smart button "Source MO"/"Child
MO")

When confirming the MO, a SM is created to bring one Sub to the
pre-production location. Thanks to MTO route, this will generate another
SM that brings one Sub from post-production to stock location (this will
lead to the creation of the second MO). However, the other SM (1 x Sub
from Post to Stock) doesn't have the same procurement group. This is the
reason why it is not found by the `_compute` methods.

OPW-2730830

closes odoo/odoo#94334

X-original-commit: 81e5ce05f2f79eb19489f00fb867143189fb38df
Signed-off-by: Arnold Moyaux (arm) <arm@odoo.com>
Signed-off-by: Adrien Widart <awt@odoo.com>
This commit is contained in:
Adrien Widart
2022-06-23 10:15:01 +02:00
parent a6a83b6d62
commit 92a049ecff
2 changed files with 77 additions and 6 deletions
+20 -6
View File
@@ -247,15 +247,17 @@ class MrpProduction(models.Model):
('qty_positive', 'check (product_qty > 0)', 'The quantity to produce must be positive!'),
]
@api.depends('procurement_group_id.stock_move_ids.created_production_id.procurement_group_id.mrp_production_ids')
@api.depends('procurement_group_id.stock_move_ids.created_production_id.procurement_group_id.mrp_production_ids',
'procurement_group_id.stock_move_ids.move_orig_ids.created_production_id.procurement_group_id.mrp_production_ids')
def _compute_mrp_production_child_count(self):
for production in self:
production.mrp_production_child_count = len(production.procurement_group_id.stock_move_ids.created_production_id.procurement_group_id.mrp_production_ids - production)
production.mrp_production_child_count = len(production._get_children())
@api.depends('move_dest_ids.group_id.mrp_production_ids')
@api.depends('procurement_group_id.mrp_production_ids.move_dest_ids.group_id.mrp_production_ids',
'procurement_group_id.stock_move_ids.move_dest_ids.group_id.mrp_production_ids')
def _compute_mrp_production_source_count(self):
for production in self:
production.mrp_production_source_count = len(production.procurement_group_id.mrp_production_ids.move_dest_ids.group_id.mrp_production_ids - production)
production.mrp_production_source_count = len(production._get_sources())
@api.depends('procurement_group_id.mrp_production_ids')
def _compute_mrp_production_backorder(self):
@@ -1125,9 +1127,21 @@ class MrpProduction(models.Model):
self.workorder_ids.filtered(lambda w: w.state not in ['done', 'cancel'])._action_confirm()
def _get_children(self):
self.ensure_one()
procurement_moves = self.procurement_group_id.stock_move_ids
child_moves = procurement_moves.move_orig_ids
return (procurement_moves | child_moves).created_production_id.procurement_group_id.mrp_production_ids - self
def _get_sources(self):
self.ensure_one()
dest_moves = self.procurement_group_id.mrp_production_ids.move_dest_ids
parent_moves = self.procurement_group_id.stock_move_ids.move_dest_ids
return (dest_moves | parent_moves).group_id.mrp_production_ids - self
def action_view_mrp_production_childs(self):
self.ensure_one()
mrp_production_ids = self.procurement_group_id.stock_move_ids.created_production_id.procurement_group_id.mrp_production_ids.ids
mrp_production_ids = self._get_children().ids
action = {
'res_model': 'mrp.production',
'type': 'ir.actions.act_window',
@@ -1147,7 +1161,7 @@ class MrpProduction(models.Model):
def action_view_mrp_production_sources(self):
self.ensure_one()
mrp_production_ids = self.procurement_group_id.mrp_production_ids.move_dest_ids.group_id.mrp_production_ids.ids
mrp_production_ids = self._get_sources().ids
action = {
'res_model': 'mrp.production',
'type': 'ir.actions.act_window',
+57
View File
@@ -2802,3 +2802,60 @@ class TestMrpOrder(TestMrpCommon):
wizard.change_prod_qty()
self.assertFalse(mo.move_raw_ids.move_line_ids)
def test_source_and_child_mo(self):
"""
Suppose three manufactured products A, B and C. C is a component of B
and B is a component of A. If B and C have the routes MTO + Manufacture,
when producing one A, it should generate a MO for B and C. Moreover,
starting from one of the MOs, we should be able to find the source/child
MO.
(The test checks the flow in 1-step, 2-steps and 3-steps manufacturing)
"""
warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.env.company.id)], limit=1)
mto_route = warehouse.mto_pull_id.route_id
manufacture_route = warehouse.manufacture_pull_id.route_id
mto_route.active = True
grandparent, parent, child = self.env['product.product'].create([{
'name': n,
'type': 'product',
'route_ids': [(6, 0, mto_route.ids + manufacture_route.ids)],
} for n in ['grandparent', 'parent', 'child']])
component = self.env['product.product'].create({
'name': 'component',
'type': 'consu',
})
self.env['mrp.bom'].create([{
'product_tmpl_id': finished_product.product_tmpl_id.id,
'product_qty': 1,
'type': 'normal',
'bom_line_ids': [
(0, 0, {'product_id': compo.id, 'product_qty': 1}),
],
} for finished_product, compo in [(grandparent, parent), (parent, child), (child, component)]])
none_production = self.env['mrp.production']
for steps, case_description, in [('mrp_one_step', '1-step Manufacturing'), ('pbm', '2-steps Manufacturing'), ('pbm_sam', '3-steps Manufacturing')]:
warehouse.manufacture_steps = steps
grandparent_production_form = Form(self.env['mrp.production'])
grandparent_production_form.product_id = grandparent
grandparent_production = grandparent_production_form.save()
grandparent_production.action_confirm()
child_production, parent_production = self.env['mrp.production'].search([('product_id', 'in', (parent + child).ids)], order='id desc', limit=2)
for source_mo, mo, product, child_mo in [(none_production, grandparent_production, grandparent, parent_production),
(grandparent_production, parent_production, parent, child_production),
(parent_production, child_production, child, none_production)]:
self.assertEqual(mo.product_id, product, '[%s] There should be a MO for product %s' % (case_description, product.display_name))
self.assertEqual(mo.mrp_production_source_count, len(source_mo), '[%s] Incorrect value for product %s' % (case_description, product.display_name))
self.assertEqual(mo.mrp_production_child_count, len(child_mo), '[%s] Incorrect value for product %s' % (case_description, product.display_name))
source_action = mo.action_view_mrp_production_sources()
child_action = mo.action_view_mrp_production_childs()
self.assertEqual(source_action.get('res_id', False), source_mo.id, '[%s] Incorrect value for product %s' % (case_description, product.display_name))
self.assertEqual(child_action.get('res_id', False), child_mo.id, '[%s] Incorrect value for product %s' % (case_description, product.display_name))