[FIX] mrp: update workcenter with BOM

Before this commit
=================
While updating the Bill of Materials (BOM), the work center and operation name
remained unchanged in the manufacturing order.
When Archiving/Unarchiving the operation doesn't show the "Update BoM" button
in the appropriate MO.

Steps to Produce
================
- Create a BOM1 with operations
- Create a MO with BOM1 and confirm MO
- Goto BOM and change the workcenter and operation name
- In MO Click on the 'update BoM' button
- Now you see the operation name and workcenter are not updated in MO

After this commit
=================
With this commit the work center and operation name get updated with the update
BOM click. For Archiving/Unarchiving the operation results to the display of
the "Update BoM" button in the appropriate MO. Directly editing an
operation will also cause the "Update BoM" button to appear

task-3461985

closes odoo/odoo#138256

X-original-commit: c343ebf0a28f6404f7ad6fc892c4a42edd2bbbe0
Signed-off-by: Tiffany Chang (tic) <tic@odoo.com>
This commit is contained in:
Vraj Panchal
2023-10-11 08:18:51 +00:00
committed by Tiffany Chang (tic)
parent 75858d3509
commit 8852dc2fb9
4 changed files with 88 additions and 15 deletions
+19 -15
View File
@@ -244,22 +244,9 @@ class MrpBom(models.Model):
def write(self, vals):
res = super().write(vals)
relevant_fields = ['bom_line_ids', 'byproduct_ids', 'product_tmpl_id', 'product_id', 'product_qty', 'operation_ids']
relevant_fields = ['bom_line_ids', 'byproduct_ids', 'product_tmpl_id', 'product_id', 'product_qty']
if any(field_name in vals for field_name in relevant_fields):
# Searches for MOs using these BoMs to notify them that their BoM has been updated.
list_of_domain_by_bom = []
for bom in self:
domain_by_products = [('product_id', 'in', bom.product_tmpl_id.product_variant_ids.ids)]
if bom.product_id:
domain_by_products = [('product_id', '=', bom.product_id.id)]
domain_for_confirmed_mo = AND([[('state', '=', 'confirmed')], domain_by_products])
# Avoid confirmed MOs if the BoM's product was changed.
domain_by_states = OR([[('state', '=', 'draft')], domain_for_confirmed_mo])
list_of_domain_by_bom.append(AND([[('bom_id', '=', bom.id)], domain_by_states]))
domain = OR(list_of_domain_by_bom)
productions = self.env['mrp.production'].search(domain)
if productions:
productions.is_outdated_bom = True
self._set_outdated_bom_in_productions()
if 'sequence' in vals and self and self[-1].id == self._prefetch_ids[-1]:
self.browse(self._prefetch_ids)._check_bom_cycle()
return res
@@ -428,6 +415,23 @@ class MrpBom(models.Model):
'template': '/mrp/static/xls/mrp_bom.xls'
}]
def _set_outdated_bom_in_productions(self):
# Searches for MOs using these BoMs to notify them that their BoM has been updated.
list_of_domain_by_bom = []
for bom in self:
domain_by_products = [('product_id', 'in', bom.product_tmpl_id.product_variant_ids.ids)]
if bom.product_id:
domain_by_products = [('product_id', '=', bom.product_id.id)]
domain_for_confirmed_mo = AND([[('state', '=', 'confirmed')], domain_by_products])
# Avoid confirmed MOs if the BoM's product was changed.
domain_by_states = OR([[('state', '=', 'draft')], domain_for_confirmed_mo])
list_of_domain_by_bom.append(AND([[('bom_id', '=', bom.id)], domain_by_states]))
if list_of_domain_by_bom:
domain = OR(list_of_domain_by_bom)
productions = self.env['mrp.production'].search(domain)
if productions:
productions.is_outdated_bom = True
class MrpBomLine(models.Model):
_name = 'mrp.bom.line'
+8
View File
@@ -2314,6 +2314,13 @@ class MrpProduction(models.Model):
break
if operation and workorder.operation_id != operation:
workorder.operation_id = operation
elif operation and workorder.operation_id == operation:
if workorder.workcenter_id != operation.workcenter_id:
workorder.workcenter_id = operation.workcenter_id
if workorder.name != operation.name:
workorder.name = operation.name
elif workorder.operation_id and workorder.operation_id not in operations_by_id:
workorders_to_unlink |= workorder
# Creates a workorder for each remaining operation.
workorders_values = []
for operation in operations_by_id.values():
@@ -2403,6 +2410,7 @@ class MrpProduction(models.Model):
moves_to_unlink._action_cancel()
moves_to_unlink.unlink()
workorders_to_unlink.unlink()
self.bom_id = bom
@api.model
+17
View File
@@ -105,10 +105,27 @@ class MrpRoutingWorkcenter(models.Model):
if not self._check_m2m_recursion('blocked_by_operation_ids'):
raise ValidationError(_("You cannot create cyclic dependency."))
@api.model_create_multi
def create(self, vals_list):
res = super().create(vals_list)
res.bom_id._set_outdated_bom_in_productions()
return res
def write(self, vals):
res = super().write(vals)
self.bom_id._set_outdated_bom_in_productions()
return res
def action_archive(self):
res = super().action_archive()
bom_lines = self.env['mrp.bom.line'].search([('operation_id', 'in', self.ids)])
bom_lines.write({'operation_id': False})
self.bom_id._set_outdated_bom_in_productions()
return res
def action_unarchive(self):
res = super().action_unarchive()
self.bom_id._set_outdated_bom_in_productions()
return res
def copy_to_bom(self):
+44
View File
@@ -1955,3 +1955,47 @@ class TestBoM(TestMrpCommon):
# Check that component 1 is set again and component 2 is removed
self.assertEqual(mo_form.move_raw_ids._records[0]['product_id'], self.product_1.id)
self.assertEqual(len(mo_form.move_raw_ids._records), 1)
def test_update_operations(self):
"""Update the operations in BoM which reflects the changes in Manufacturing Order"""
mo_form = Form(self.env['mrp.production'].with_user(self.user_mrp_user))
mo_form.product_id = self.product_7_1
mo_form.product_qty = 1.0
mo_form.bom_id = self.bom_2
mo = mo_form.save()
mo.action_confirm()
self.bom_2.operation_ids.write({
'name': 'Painting',
'workcenter_id': self.workcenter_2.id
})
self.assertTrue(mo.is_outdated_bom)
mo.action_update_bom()
self.assertEqual(self.bom_2.operation_ids.name, mo.workorder_ids.name)
self.assertEqual(self.bom_2.operation_ids.workcenter_id, mo.workorder_ids.workcenter_id)
def test_archive_operations(self):
"""Archive the operation in BoM and update the BoM in MO
Unarchive the operation which will reflect in BoM and MO"""
mo_form = Form(self.env['mrp.production'].with_user(self.user_mrp_user))
mo_form.product_id = self.product_7_1
mo_form.product_qty = 1.0
mo_form.bom_id = self.bom_2
mo_order = mo_form.save()
mo_order.action_confirm()
operation_ids = self.bom_2.operation_ids.ids
self.bom_2.operation_ids.action_archive()
self.assertTrue(mo_order.is_outdated_bom)
mo_order.action_update_bom()
self.assertEqual(len(mo_order.workorder_ids), 0)
self.env['mrp.routing.workcenter'].browse(operation_ids).action_unarchive()
self.assertTrue(mo_order.is_outdated_bom)
mo_order.action_update_bom()
self.assertEqual(len(mo_order.workorder_ids), 1)