From 4c2a03aa8f422fce5f86e3a5c394d0b5992c920d Mon Sep 17 00:00:00 2001 From: Nicolas Galler Date: Mon, 5 Oct 2020 17:26:49 +0000 Subject: [PATCH] [FIX] mrp: validate BOM lines with same product as BOM Current behavior before PR: It is possible to create a BOM that has a BOM line that reference the same product as the BOM itself. This is undesirable as when we create a manufacturing order for this product we will have an error. It is a regression bug that was introduced in commit 575353e251a0cce3bbff759edaeb56b5718beb11 between v12 and v13. Behavior after PR is merged: When saving a BOM it will validate that no product line references the same product, or the same product variant, as the BOM itself. Note that it is allowed to have a BOM for a product variant that references another variant of the same product. opw-2347941 closes odoo/odoo#59633 X-original-commit: 917e4c67b4aa14ca71ec6cba4bc6d20a86459f42 Signed-off-by: Nicolas Martinelli (nim) --- addons/mrp/models/mrp_bom.py | 8 +++-- addons/mrp/tests/test_bom.py | 69 ++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) 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()