diff options
| author | Christophe Simonis <chs@odoo.com> | 2019-09-13 18:07:59 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2019-09-13 18:07:59 +0200 |
| commit | 6c948c36bbf72dd896e0bff03aa7fbddadcbb0cd (patch) | |
| tree | f8620905c011735d8a3c340c46d1417a54a75972 /addons/mrp/models/mrp_bom.py | |
| parent | 48503fcf08eac6fed12e080d4f501f9bbc8d257d (diff) | |
| parent | 197474e5b9ad43ab2d587a98136a1a809ce9a2e7 (diff) | |
[MERGE] forward port branch saas-12.5 up to 197474e5b9a
Diffstat (limited to 'addons/mrp/models/mrp_bom.py')
| -rw-r--r-- | addons/mrp/models/mrp_bom.py | 109 |
1 files changed, 67 insertions, 42 deletions
diff --git a/addons/mrp/models/mrp_bom.py b/addons/mrp/models/mrp_bom.py index 0a66b1f04e8..d24ad6d9504 100644 --- a/addons/mrp/models/mrp_bom.py +++ b/addons/mrp/models/mrp_bom.py @@ -15,6 +15,7 @@ class MrpBom(models.Model): _inherit = ['mail.thread'] _rec_name = 'product_tmpl_id' _order = "sequence" + _check_company_auto = True def _get_default_product_uom_id(self): return self.env['uom.uom'].search([], limit=1, order='id').id @@ -29,10 +30,12 @@ class MrpBom(models.Model): default='normal', required=True) product_tmpl_id = fields.Many2one( 'product.template', 'Product', - domain="[('type', 'in', ['product', 'consu'])]", required=True) + check_company=True, + domain="[('type', 'in', ['product', 'consu']), '|', ('company_id', '=', False), ('company_id', '=', company_id)]", required=True) product_id = fields.Many2one( 'product.product', 'Product Variant', - domain="['&', ('product_tmpl_id', '=', product_tmpl_id), ('type', 'in', ['product', 'consu'])]", + check_company=True, + domain="['&', ('product_tmpl_id', '=', product_tmpl_id), ('type', 'in', ['product', 'consu']), '|', ('company_id', '=', False), ('company_id', '=', company_id)]", help="If a product variant is defined the BOM is available only for this product.") bom_line_ids = fields.One2many('mrp.bom.line', 'bom_id', 'BoM Lines', copy=True) byproduct_ids = fields.One2many('mrp.bom.byproduct', 'bom_id', 'By-products', copy=True) @@ -46,7 +49,7 @@ class MrpBom(models.Model): product_uom_category_id = fields.Many2one(related='product_id.uom_id.category_id') sequence = fields.Integer('Sequence', help="Gives the sequence order when displaying a list of bills of material.") routing_id = fields.Many2one( - 'mrp.routing', 'Routing', + 'mrp.routing', 'Routing', check_company=True, help="The operations for producing this BoM. When a routing is specified, the production orders will " " be executed through work orders, otherwise everything is processed in the production order itself. ") ready_to_produce = fields.Selection([ @@ -54,14 +57,14 @@ class MrpBom(models.Model): ('asap', 'When components for 1st operation are available')], string='Manufacturing Readiness', default='asap', help="Defines when a Manufacturing Order is considered as ready to be started", required=True) picking_type_id = fields.Many2one( - 'stock.picking.type', 'Operation Type', domain=[('code', '=', 'mrp_operation')], + 'stock.picking.type', 'Operation Type', domain="[('code', '=', 'mrp_operation'), ('company_id', '=', company_id)]", + check_company=True, help=u"When a procurement has a ‘produce’ route with a operation type set, it will try to create " "a Manufacturing Order for that product using a BoM of the same operation type. That allows " "to define stock rules which trigger different manufacturing orders with different BoMs.") company_id = fields.Many2one( - 'res.company', 'Company', - default=lambda self: self.env.company, - required=True) + 'res.company', 'Company', index=True, + default=lambda self: self.env.company) consumption = fields.Selection([ ('strict', 'Strict'), ('flexible', 'Flexible')], @@ -74,17 +77,25 @@ class MrpBom(models.Model): def onchange_product_id(self): if self.product_id: for line in self.bom_line_ids: - line.attribute_value_ids = False + line.bom_product_template_attribute_value_ids = False @api.constrains('product_id', 'product_tmpl_id', 'bom_line_ids') - def _check_product_recursion(self): + def _check_bom_lines(self): for bom in self: - if bom.product_id: - if bom.bom_line_ids.filtered(lambda x: x.product_id == bom.product_id): - raise ValidationError(_('BoM line product %s should not be same as BoM product.') % bom.display_name) - else: - if bom.bom_line_ids.filtered(lambda x: x.product_id.product_tmpl_id == bom.product_tmpl_id): - raise ValidationError(_('BoM line product %s should not be same as BoM product.') % bom.display_name) + 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_line.product_tmpl_id == bom.product_tmpl_id: + 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]))) + for ptav in bom_line.bom_product_template_attribute_value_ids: + if ptav.product_tmpl_id != bom.product_tmpl_id: + raise ValidationError( + _("The attribute value %s set on product %s does not match the BoM product %s.") % + (ptav.display_name, ptav.product_tmpl_id.display_name, bom_line.parent_product_tmpl_id.display_name) + ) @api.onchange('product_uom_id') def onchange_product_uom_id(self): @@ -103,7 +114,7 @@ class MrpBom(models.Model): if self.product_id.product_tmpl_id != self.product_tmpl_id: self.product_id = False for line in self.bom_line_ids: - line.attribute_value_ids = False + line.bom_product_template_attribute_value_ids = False @api.onchange('routing_id') def onchange_routing_id(self): @@ -132,7 +143,7 @@ class MrpBom(models.Model): if picking_type: domain += ['|', ('picking_type_id', '=', picking_type.id), ('picking_type_id', '=', False)] if company_id or self.env.context.get('company_id'): - domain = domain + [('company_id', '=', company_id or self.env.context.get('company_id'))] + domain = domain + ['|', ('company_id', '=', False), ('company_id', '=', company_id or self.env.context.get('company_id'))] if bom_type: domain += [('type', '=', bom_type)] # order to prioritize bom with product_id over the one without @@ -219,13 +230,15 @@ class MrpBomLine(models.Model): _order = "sequence, id" _rec_name = "product_id" _description = 'Bill of Material Line' + _check_company_auto = True def _get_default_product_uom_id(self): return self.env['uom.uom'].search([], limit=1, order='id').id - product_id = fields.Many2one( - 'product.product', 'Component', required=True) + product_id = fields.Many2one( 'product.product', 'Component', required=True, check_company=True) product_tmpl_id = fields.Many2one('product.template', 'Product Template', related='product_id.product_tmpl_id', readonly=False) + company_id = fields.Many2one( + related='bom_id.company_id', store=True, index=True, readonly=True) product_qty = fields.Float( 'Quantity', default=1.0, digits='Product Unit of Measure', required=True) @@ -248,12 +261,14 @@ class MrpBomLine(models.Model): 'mrp.bom', 'Parent BoM', index=True, ondelete='cascade', required=True) parent_product_tmpl_id = fields.Many2one('product.template', 'Parent Product Template', related='bom_id.product_tmpl_id') - valid_product_attribute_value_ids = fields.Many2many('product.attribute.value', related='bom_id.product_tmpl_id.valid_product_attribute_value_ids') - attribute_value_ids = fields.Many2many( - 'product.attribute.value', string='Apply on Variants', - help="BOM Product Variants needed form apply this line.") + possible_bom_product_template_attribute_value_ids = fields.Many2many('product.template.attribute.value', compute='_compute_possible_bom_product_template_attribute_value_ids') + bom_product_template_attribute_value_ids = fields.Many2many( + 'product.template.attribute.value', string="Apply on Variants", ondelete='restrict', + domain="[('id', 'in', possible_bom_product_template_attribute_value_ids)]", + help="BOM Product Variants needed to apply this line.") operation_id = fields.Many2one( - 'mrp.routing.workcenter', 'Consumed in Operation', + 'mrp.routing.workcenter', 'Consumed in Operation', check_company=True, + domain="[('routing_id', '=', routing_id), '|', ('company_id', '=', company_id), ('company_id', '=', False)]", help="The operation where the components are consumed, or the finished products created.") child_bom_id = fields.Many2one( 'mrp.bom', 'Sub BoM', compute='_compute_child_bom_id') @@ -268,6 +283,15 @@ class MrpBomLine(models.Model): 'You should install the mrp_byproduct module if you want to manage extra products on BoMs !'), ] + @api.depends( + 'parent_product_tmpl_id.attribute_line_ids.value_ids', + 'parent_product_tmpl_id.attribute_line_ids.attribute_id.create_variant', + 'parent_product_tmpl_id.attribute_line_ids.product_template_value_ids.ptav_active', + ) + def _compute_possible_bom_product_template_attribute_value_ids(self): + for line in self: + line.possible_bom_product_template_attribute_value_ids = line.parent_product_tmpl_id.valid_product_template_attribute_line_ids._without_no_variant_attributes().product_template_value_ids._only_active() + @api.depends('product_id', 'bom_id') def _compute_child_bom_id(self): for line in self: @@ -309,15 +333,6 @@ class MrpBomLine(models.Model): if self.product_id: self.product_uom_id = self.product_id.uom_id.id - @api.onchange('parent_product_tmpl_id') - def onchange_parent_product(self): - if not self.parent_product_tmpl_id: - return {} - return {'domain': {'attribute_value_ids': [ - ('id', 'in', self.parent_product_tmpl_id.valid_product_attribute_value_ids.ids), - ('attribute_id.create_variant', '!=', 'no_variant') - ]}} - @api.model_create_multi def create(self, vals_list): for values in vals_list: @@ -326,13 +341,17 @@ class MrpBomLine(models.Model): return super(MrpBomLine, self).create(vals_list) def _skip_bom_line(self, product): - """ Control if a BoM line should be produce, can be inherited for add + """ Control if a BoM line should be produced, can be inherited to add custom control. It currently checks that all variant values are in the - product. """ - if self.attribute_value_ids: - for att, att_values in groupby(self.attribute_value_ids, lambda l: l.attribute_id): - values = self.env['product.attribute.value'].concat(*list(att_values)) - if not (product.attribute_value_ids & values): + product. + + If multiple values are encoded for the same attribute line, only one of + them has to be found on the variant. + """ + self.ensure_one() + if self.bom_product_template_attribute_value_ids: + for ptal, iter_ptav in groupby(self.bom_product_template_attribute_value_ids.sorted('attribute_line_id'), lambda ptav: ptav.attribute_line_id): + if not any([ptav in product.product_template_attribute_value_ids for ptav in iter_ptav]): return True return False @@ -356,21 +375,27 @@ class MrpBomLine(models.Model): Use this feature to store any files, like drawings or specifications. </p>'''), 'limit': 80, - 'context': "{'default_res_model': '%s','default_res_id': %d}" % ('product.product', self.product_id.id) + 'context': "{'default_res_model': '%s','default_res_id': %d, 'default_company_id': %s}" % ('product.product', self.product_id.id, self.company_id.id) } class MrpByProduct(models.Model): _name = 'mrp.bom.byproduct' _description = 'Byproduct' + _check_company_auto = True - product_id = fields.Many2one('product.product', 'By-product', required=True) + product_id = fields.Many2one('product.product', 'By-product', required=True, check_company=True) + company_id = fields.Many2one(related='bom_id.company_id', store=True, index=True, readonly=True) product_qty = fields.Float( 'Quantity', default=1.0, digits='Product Unit of Measure', required=True) product_uom_id = fields.Many2one('uom.uom', 'Unit of Measure', required=True) bom_id = fields.Many2one('mrp.bom', 'BoM', ondelete='cascade') - operation_id = fields.Many2one('mrp.routing.workcenter', 'Produced in Operation') + routing_id = fields.Many2one( + 'mrp.routing', 'Routing', store=True, related='bom_id.routing_id') + operation_id = fields.Many2one( + 'mrp.routing.workcenter', 'Produced in Operation', check_company=True, + domain="[('routing_id', '=', routing_id), '|', ('company_id', '=', company_id), ('company_id', '=', False)]") @api.onchange('product_id') def onchange_product_id(self): |
