diff --git a/mrp_bom_attribute_match/__init__.py b/mrp_bom_attribute_match/__init__.py index 0650744f6..55ec7fc9a 100644 --- a/mrp_bom_attribute_match/__init__.py +++ b/mrp_bom_attribute_match/__init__.py @@ -1 +1,2 @@ from . import models +from . import reports diff --git a/mrp_bom_attribute_match/reports/__init__.py b/mrp_bom_attribute_match/reports/__init__.py new file mode 100644 index 000000000..d5f0e0470 --- /dev/null +++ b/mrp_bom_attribute_match/reports/__init__.py @@ -0,0 +1 @@ +from . import mrp_report_bom_structure diff --git a/mrp_bom_attribute_match/reports/mrp_report_bom_structure.py b/mrp_bom_attribute_match/reports/mrp_report_bom_structure.py new file mode 100644 index 000000000..3cb228911 --- /dev/null +++ b/mrp_bom_attribute_match/reports/mrp_report_bom_structure.py @@ -0,0 +1,44 @@ +# Copyright 2023 Camptocamp SA (https://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import Command, models + + +class ReportBomStructure(models.AbstractModel): + _inherit = "report.mrp.report_bom_structure" + + def _get_bom_lines(self, bom, bom_quantity, product, line_id, level): + # OVERRIDE to fill in the `line.product_id` if a component template is used. + # To avoid a complete override, we HACK the bom by replacing it with a virtual + # record, and modifying it's lines on-the-fly. + has_template_lines = any( + line.component_template_id for line in bom.bom_line_ids + ) + if has_template_lines: + bom = bom.new(origin=bom) + to_ignore_line_ids = [] + for line in bom.bom_line_ids: + if line._skip_bom_line(product) or not line.component_template_id: + continue + line_product = bom._get_component_template_product( + line, product, line.product_id + ) + if not line_product: + to_ignore_line_ids.append(line.id) + continue + else: + line.product_id = line_product + if to_ignore_line_ids: + bom.bom_line_ids = [Command.unlink(id) for id in to_ignore_line_ids] + components, total = super()._get_bom_lines( + bom, bom_quantity, product, line_id, level + ) + # Replace any NewId value by the real record id + # Otherwise it's evaluated as False in some situations, and it may cause issues + if has_template_lines: + for component in components: + for key, value in component.items(): + if isinstance(value, models.NewId): + component[key] = value.origin + return components, total diff --git a/mrp_bom_attribute_match/tests/test_mrp_bom_attribute_match.py b/mrp_bom_attribute_match/tests/test_mrp_bom_attribute_match.py index b2efabaaf..f91f56b37 100644 --- a/mrp_bom_attribute_match/tests/test_mrp_bom_attribute_match.py +++ b/mrp_bom_attribute_match/tests/test_mrp_bom_attribute_match.py @@ -4,7 +4,7 @@ from odoo.tests import Form from .common import TestMrpBomAttributeMatchBase -class TestMrpAttachmentMgmt(TestMrpBomAttributeMatchBase): +class TestMrpBomAttributeMatch(TestMrpBomAttributeMatchBase): def test_bom_1(self): mrp_bom_form = Form(self.env["mrp.bom"]) mrp_bom_form.product_tmpl_id = self.product_sword @@ -170,3 +170,18 @@ class TestMrpAttachmentMgmt(TestMrpBomAttributeMatchBase): ) with self.assertRaisesRegex(UserError, r"Recursion error! .+"): test_bom_3.explode(self.product_9, 1) + + def test_mrp_report_bom_structure(self): + sword_cyan = self.product_sword.product_variant_ids[0] + BomStructureReport = self.env["report.mrp.report_bom_structure"] + res = BomStructureReport._get_report_data(self.bom_id.id) + self.assertTrue(res["is_variant_applied"]) + self.assertEqual(res["lines"]["product"], sword_cyan) + self.assertEqual( + res["lines"]["components"][0]["line_id"], + self.bom_id.bom_line_ids.id, + ) + self.assertEqual( + res["lines"]["components"][0]["parent_id"], + self.bom_id.id, + )