From ec9a0417cbe2dc1db1abf7fdddf8c7d48936e0c3 Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Tue, 15 Jan 2019 14:14:38 -0800 Subject: [PATCH] Initial commit of `mrp_bom_add` for 12.0 --- mrp_bom_add/__init__.py | 1 + mrp_bom_add/__manifest__.py | 22 +++++ mrp_bom_add/tests/__init__.py | 1 + mrp_bom_add/tests/test_mrp_bom_add.py | 115 +++++++++++++++++++++++ mrp_bom_add/wizard/__init__.py | 1 + mrp_bom_add/wizard/mrp_bom_add.py | 69 ++++++++++++++ mrp_bom_add/wizard/mrp_bom_add_views.xml | 51 ++++++++++ 7 files changed, 260 insertions(+) create mode 100755 mrp_bom_add/__init__.py create mode 100755 mrp_bom_add/__manifest__.py create mode 100644 mrp_bom_add/tests/__init__.py create mode 100644 mrp_bom_add/tests/test_mrp_bom_add.py create mode 100644 mrp_bom_add/wizard/__init__.py create mode 100644 mrp_bom_add/wizard/mrp_bom_add.py create mode 100644 mrp_bom_add/wizard/mrp_bom_add_views.xml diff --git a/mrp_bom_add/__init__.py b/mrp_bom_add/__init__.py new file mode 100755 index 00000000..40272379 --- /dev/null +++ b/mrp_bom_add/__init__.py @@ -0,0 +1 @@ +from . import wizard diff --git a/mrp_bom_add/__manifest__.py b/mrp_bom_add/__manifest__.py new file mode 100755 index 00000000..cfaf978d --- /dev/null +++ b/mrp_bom_add/__manifest__.py @@ -0,0 +1,22 @@ +{ + 'name': 'BoM Mass Add', + 'author': 'Hibou Corp. ', + 'category': 'Hidden', + 'version': '12.0.1.0.0', + 'description': + """ +Bill of Materials Mass Component Adder +====================================== + +Helper to add all variants of a Product to a BoM filtered by the attributes on that product. +Adds a button under BoM components named "Add Bulk". This lets you configure a product + """, + 'depends': [ + 'mrp', + 'sale', + ], + 'auto_install': False, + 'data': [ + 'wizard/mrp_bom_add_views.xml', + ], +} diff --git a/mrp_bom_add/tests/__init__.py b/mrp_bom_add/tests/__init__.py new file mode 100644 index 00000000..334c6444 --- /dev/null +++ b/mrp_bom_add/tests/__init__.py @@ -0,0 +1 @@ +from . import test_mrp_bom_add diff --git a/mrp_bom_add/tests/test_mrp_bom_add.py b/mrp_bom_add/tests/test_mrp_bom_add.py new file mode 100644 index 00000000..4fa94769 --- /dev/null +++ b/mrp_bom_add/tests/test_mrp_bom_add.py @@ -0,0 +1,115 @@ +from odoo.tests.common import TransactionCase + + +class TestMRPBOMAdd(TransactionCase): + + def setUp(self): + super(TestMRPBOMAdd, self).setUp() + self.attr1 = self.env['product.attribute'].create({ + 'name': 'Test Attr1', + 'create_variant': 'always', + 'type': 'radio', + }) + self.attr1_val1 = self.env['product.attribute.value'].create({ + 'attribute_id': self.attr1.id, + 'name': 'Test Attr1 Val1' + }) + self.attr1_val2 = self.env['product.attribute.value'].create({ + 'attribute_id': self.attr1.id, + 'name': 'Test Attr2 Val1' + }) + + self.attr2 = self.env['product.attribute'].create({ + 'name': 'Test Attr2', + 'create_variant': 'always', + 'type': 'radio', + }) + self.attr2_val1 = self.env['product.attribute.value'].create({ + 'attribute_id': self.attr2.id, + 'name': 'Test Attr2 Val1' + }) + self.attr2_val2 = self.env['product.attribute.value'].create({ + 'attribute_id': self.attr2.id, + 'name': 'Test Attr2 Val2' + }) + + # 2 variant product + self.manufacture = self.env['product.template'].create({ + 'name': 'Test Manufactured', + 'attribute_line_ids': [ + (0, 0, { + 'attribute_id': self.attr1.id, + 'value_ids': [(4, self.attr1_val1.id, 0)], + }), + (0, 0, { + 'attribute_id': self.attr2.id, + 'value_ids': [(4, self.attr2_val1.id, 0), (4, self.attr2_val2.id, 0)], + }), + ] + }) + + # 4 variant component + self.component = self.env['product.template'].create({ + 'name': 'Test Component', + 'attribute_line_ids': [ + (0, 0, { + 'attribute_id': self.attr1.id, + 'value_ids': [(4, self.attr1_val1.id, 0), (4, self.attr1_val2.id, 0)], + }), + (0, 0, { + 'attribute_id': self.attr2.id, + 'value_ids': [(4, self.attr2_val1.id, 0), (4, self.attr2_val2.id, 0)], + }), + ] + }) + self.bom = self.env['mrp.bom'].create({ + 'product_tmpl_id': self.manufacture.id, + 'product_qty': 1.0, + 'product_uom_id': self.manufacture.uom_id.id, + }) + + def test_internals(self): + # Ensure BoM is empty + self.assertEqual(len(self.bom.bom_line_ids), 0) + wizard = self.env['mrp.bom.add'].create({ + 'bom_id': self.bom.id, + }) + wizard.product_tmpl_id = self.component + self.assertEqual(wizard._compute_attribute_value_ids(), + self.component.mapped('product_variant_ids.attribute_value_ids')) + self.assertEqual(wizard._compute_product_ids(), self.component.product_variant_ids) + wizard.limit_possible = True + self.assertEqual(wizard._compute_attribute_value_ids(), + self.manufacture.mapped('product_variant_ids.attribute_value_ids')) + + def test_main(self): + # Ensure BoM is empty + self.assertEqual(len(self.bom.bom_line_ids), 0) + + wizard = self.env['mrp.bom.add'].create({ + 'bom_id': self.bom.id, + }) + self.assertEqual(wizard.product_variant_count, 0) + + wizard.product_tmpl_id = self.component + self.assertEqual(wizard.product_variant_count, 4) + + wizard.add_variants() + self.assertEqual(len(self.bom.bom_line_ids), 4) + + def test_limited(self): + # Ensure BoM is empty + self.assertEqual(len(self.bom.bom_line_ids), 0) + + wizard = self.env['mrp.bom.add'].create({ + 'bom_id': self.bom.id, + }) + self.assertEqual(wizard.product_variant_count, 0) + + wizard.limit_possible = True + wizard.product_tmpl_id = self.component + self.assertEqual(wizard.product_variant_count, 2) + + wizard.add_variants() + self.assertEqual(len(self.bom.bom_line_ids), 2) + diff --git a/mrp_bom_add/wizard/__init__.py b/mrp_bom_add/wizard/__init__.py new file mode 100644 index 00000000..f578190b --- /dev/null +++ b/mrp_bom_add/wizard/__init__.py @@ -0,0 +1 @@ +from . import mrp_bom_add diff --git a/mrp_bom_add/wizard/mrp_bom_add.py b/mrp_bom_add/wizard/mrp_bom_add.py new file mode 100644 index 00000000..2f447584 --- /dev/null +++ b/mrp_bom_add/wizard/mrp_bom_add.py @@ -0,0 +1,69 @@ +from odoo import api, fields, models + + +class ProgramOutputView(models.TransientModel): + _name = 'mrp.bom.add' + _description = 'BoM Add Wizard' + + bom_id = fields.Many2one('mrp.bom', string='Bill of Materials') + bom_product_tmpl_id = fields.Many2one('product.template', string='BoM Product', related='bom_id.product_tmpl_id') + product_tmpl_id = fields.Many2one('product.template', string='Product') + product_variant_count = fields.Integer(string='Variant Count', compute='_compute_variant_count') + limit_possible = fields.Boolean(string='Limit to possible variants', + help='Only add variants that can be selected by BoM Product') + product_qty = fields.Float(string='Quantity to Consume', default=1.0) + product_uom_id = fields.Many2one('uom.uom', string='Consume Unit of Measure') + bom_routing_id = fields.Many2one('mrp.routing', related='bom_id.routing_id') + operation_id = fields.Many2one('mrp.routing.workcenter', 'Consume in Operation') + + @api.multi + @api.depends('product_tmpl_id', 'limit_possible') + def _compute_variant_count(self): + self.ensure_one() + if not self.product_tmpl_id or not self.bom_product_tmpl_id: + self.product_variant_count = 0 + else: + products = self._compute_product_ids() + self.product_variant_count = len(products) + + @api.onchange('product_tmpl_id') + def _onchange_default_product_uom(self): + if self.product_tmpl_id: + self.product_uom_id = self.product_tmpl_id.uom_id + + def _compute_attribute_value_ids(self): + attr_val_ids = self.env['product.attribute.value'] + other_val_ids = self.product_tmpl_id.mapped('attribute_line_ids.value_ids') + if not self.limit_possible: + return other_val_ids + main_product_value_ids = self.bom_product_tmpl_id.mapped('attribute_line_ids.value_ids') + for v in other_val_ids: + if v in main_product_value_ids: + attr_val_ids += v + return attr_val_ids + + def _compute_product_ids(self): + values = self._compute_attribute_value_ids() + products = self.env['product.product'] + for p in self.product_tmpl_id.product_variant_ids: + if not p.attribute_value_ids.filtered(lambda a: a not in values): + # This product's attribute values are in the values set. + products += p + return products + + def add_variants(self): + attribute_values = self._compute_attribute_value_ids() + products = self._compute_product_ids() + if not self.product_uom_id: + self.product_uom_id = self.product_tmpl_id.uom_id + lines = [] + for p in products: + lines.append((0, 0, { + 'bom_id': self.bom_id.id, + 'product_id': p.id, + 'product_qty': self.product_qty, + 'product_uom_id': self.product_uom_id.id, + 'attribute_value_ids': [(4, a.id, 0) for a in p.attribute_value_ids if a in attribute_values], + 'operation_id': self.operation_id.id, + })) + self.bom_id.write({'bom_line_ids': lines}) diff --git a/mrp_bom_add/wizard/mrp_bom_add_views.xml b/mrp_bom_add/wizard/mrp_bom_add_views.xml new file mode 100644 index 00000000..85b24077 --- /dev/null +++ b/mrp_bom_add/wizard/mrp_bom_add_views.xml @@ -0,0 +1,51 @@ + + + + + mrp.bom.add.form + mrp.bom.add + +
+ + + + + + + + + + + + + + + +
+
+
+
+
+ + + Add to Bill of Materials + mrp.bom.add + form + tree,form + + new + + + + mrp.bom.form.inherit + mrp.bom + + + +