summaryrefslogtreecommitdiff
path: root/addons/mrp/models/mrp_bom.py
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2019-09-13 18:07:59 +0200
committerChristophe Simonis <chs@odoo.com>2019-09-13 18:07:59 +0200
commit6c948c36bbf72dd896e0bff03aa7fbddadcbb0cd (patch)
treef8620905c011735d8a3c340c46d1417a54a75972 /addons/mrp/models/mrp_bom.py
parent48503fcf08eac6fed12e080d4f501f9bbc8d257d (diff)
parent197474e5b9ad43ab2d587a98136a1a809ce9a2e7 (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.py109
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):