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') replace_existing = fields.Boolean(string='Replace existing BoM lines for this template.') existing_line_count = fields.Integer(string='Existing Lines', help='Remove any existing lines for this Product Template.', compute='_compute_variant_count') product_qty = fields.Float(string='Quantity to Consume', default=1.0) product_uom_id = fields.Many2one('uom.uom', string='Consume Unit of Measure') @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 self.existing_line_count = 0 else: products = self._compute_product_ids() lines = self._compute_existing_line_ids() self.product_variant_count = len(products) self.existing_line_count = len(lines) @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') return main_product_value_ids.filtered(lambda v: v in other_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.product_template_attribute_value_ids.mapped('product_attribute_value_id').filtered(lambda a: a not in values): # This product's attribute values are in the values set. products += p return products def _compute_existing_line_ids(self): return self.bom_id.bom_line_ids.filtered(lambda l: l.product_id.product_tmpl_id == self.product_tmpl_id) def add_variants(self): if self.replace_existing: lines = self._compute_existing_line_ids() lines.unlink() 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: bom_product_template_attribute_values = self.bom_product_tmpl_id.attribute_line_ids\ .mapped('product_template_value_ids') p_values = p.product_template_attribute_value_ids.mapped('product_attribute_value_id') bom_product_template_attribute_value_ids = bom_product_template_attribute_values \ .filtered(lambda v: v.product_attribute_value_id in attribute_values and v.product_attribute_value_id in p_values) 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, 'bom_product_template_attribute_value_ids': [(4, a.id, 0) for a in bom_product_template_attribute_value_ids], })) self.bom_id.write({'bom_line_ids': lines})