[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:
@@ -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',
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user