diff --git a/addons/mrp/models/mrp_bom.py b/addons/mrp/models/mrp_bom.py index b21998d3cc2..fc01dfb1ade 100644 --- a/addons/mrp/models/mrp_bom.py +++ b/addons/mrp/models/mrp_bom.py @@ -89,8 +89,12 @@ class MrpBom(models.Model): def _check_bom_lines(self): for bom in self: for bom_line in bom.bom_line_ids: - if bom.product_id and bom_line.product_id == bom.product_id: - raise ValidationError(_("BoM line product %s should not be the same as BoM product.", bom.display_name)) + if bom.product_id: + same_product = bom.product_id == bom_line.product_id + else: + same_product = bom.product_tmpl_id == bom_line.product_id.product_tmpl_id + if same_product: + raise ValidationError(_("BoM line product %s should not be the same as BoM product.") % bom.display_name) if bom.product_id and bom_line.bom_product_template_attribute_value_ids: raise ValidationError(_("BoM cannot concern product %s and have a line with attributes (%s) at the same time.") % (bom.product_id.display_name, ", ".join([ptav.display_name for ptav in bom_line.bom_product_template_attribute_value_ids]))) diff --git a/addons/mrp/tests/test_bom.py b/addons/mrp/tests/test_bom.py index 8a26d960935..9ec7c2bee42 100644 --- a/addons/mrp/tests/test_bom.py +++ b/addons/mrp/tests/test_bom.py @@ -729,3 +729,72 @@ class TestBoM(TestMrpCommon): report_values = self.env['report.mrp.report_bom_structure']._get_report_data(bom_id=bom_finished.id, searchQty=80) self.assertAlmostEqual(report_values['lines']['total'], 2.92) + + def test_validate_no_bom_line_with_same_product(self): + """ + Cannot set a BOM line on a BOM with the same product as the BOM itself + """ + uom_unit = self.env.ref('uom.product_uom_unit') + finished = self.env['product.product'].create({ + 'name': 'Finished', + 'type': 'product', + 'uom_id': uom_unit.id, + 'uom_po_id': uom_unit.id, + }) + bom_finished = Form(self.env['mrp.bom']) + bom_finished.product_tmpl_id = finished.product_tmpl_id + bom_finished.product_qty = 100 + with bom_finished.bom_line_ids.new() as line: + line.product_id = finished + line.product_uom_id = uom_unit + line.product_qty = 5 + with self.assertRaises(exceptions.ValidationError), self.cr.savepoint(): + bom_finished = bom_finished.save() + + def test_validate_no_bom_line_with_same_product_variant(self): + """ + Cannot set a BOM line on a BOM with the same product variant as the BOM itself + """ + uom_unit = self.env.ref('uom.product_uom_unit') + bom_finished = Form(self.env['mrp.bom']) + bom_finished.product_tmpl_id = self.product_7_template + bom_finished.product_id = self.product_7_3 + bom_finished.product_qty = 100 + with bom_finished.bom_line_ids.new() as line: + line.product_id = self.product_7_3 + line.product_uom_id = uom_unit + line.product_qty = 5 + with self.assertRaises(exceptions.ValidationError), self.cr.savepoint(): + bom_finished = bom_finished.save() + + def test_validate_bom_line_with_different_product_variant(self): + """ + Can set a BOM line on a BOM with a different product variant as the BOM itself (same product) + Usecase for example A black T-shirt made from a white T-shirt and + black color. + """ + uom_unit = self.env.ref('uom.product_uom_unit') + bom_finished = Form(self.env['mrp.bom']) + bom_finished.product_tmpl_id = self.product_7_template + bom_finished.product_id = self.product_7_3 + bom_finished.product_qty = 100 + with bom_finished.bom_line_ids.new() as line: + line.product_id = self.product_7_2 + line.product_uom_id = uom_unit + line.product_qty = 5 + bom_finished = bom_finished.save() + + def test_validate_bom_line_with_variant_of_bom_product(self): + """ + Can set a BOM line on a BOM with a product variant when the BOM has no variant selected + """ + uom_unit = self.env.ref('uom.product_uom_unit') + bom_finished = Form(self.env['mrp.bom']) + bom_finished.product_tmpl_id = self.product_6.product_tmpl_id + # no product_id + bom_finished.product_qty = 100 + with bom_finished.bom_line_ids.new() as line: + line.product_id = self.product_7_2 + line.product_uom_id = uom_unit + line.product_qty = 5 + bom_finished = bom_finished.save()