diff --git a/mrp_bom_attribute_match/models/mrp_bom.py b/mrp_bom_attribute_match/models/mrp_bom.py
index 4469178c5..ccb7f4160 100644
--- a/mrp_bom_attribute_match/models/mrp_bom.py
+++ b/mrp_bom_attribute_match/models/mrp_bom.py
@@ -18,7 +18,10 @@ class MrpBomLine(models.Model):
"product.template", "Component (product template)"
)
match_on_attribute_ids = fields.Many2many(
- "product.attribute", string="Match on Attributes", readonly=True
+ "product.attribute",
+ string="Match on Attributes",
+ compute="_compute_match_on_attribute_ids",
+ store=True,
)
product_uom_category_id = fields.Many2one(
"uom.category",
@@ -56,84 +59,93 @@ class MrpBomLine(models.Model):
@api.onchange("component_template_id")
def _onchange_component_template_id(self):
if self.component_template_id:
+ if self.product_id:
+ self.product_backup_id = self.product_id
+ self.product_id = False
if (
self.product_uom_id.category_id
!= self.component_template_id.uom_id.category_id
):
self.product_uom_id = self.component_template_id.uom_id
else:
+ if self.product_backup_id:
+ self.product_id = self.product_backup_id
+ self.product_backup_id = False
if self.product_uom_id.category_id != self.product_id.uom_id.category_id:
self.product_uom_id = self.product_id.uom_id
- self._update_component_attributes()
- def _update_component_attributes(self):
- if self.component_template_id:
- self._check_component_attributes()
- self.product_backup_id = self.product_id.id
- self.match_on_attribute_ids = (
- self.component_template_id.attribute_line_ids.mapped("attribute_id")
- .filtered(lambda x: x.create_variant != "no_variant")
- .ids
- )
- self.product_id = False
- self._check_variants_validity()
- else:
- self.match_on_attribute_ids = False
- if self.product_backup_id and not self.product_id:
- self.product_id = self.product_backup_id.id
- self.product_backup_id = False
+ @api.depends("component_template_id")
+ def _compute_match_on_attribute_ids(self):
+ for rec in self:
+ if rec.component_template_id:
+ rec.match_on_attribute_ids = (
+ rec.component_template_id.attribute_line_ids.attribute_id.filtered(
+ lambda x: x.create_variant != "no_variant"
+ )
+ )
+ else:
+ rec.match_on_attribute_ids = False
+ @api.constrains("component_template_id")
def _check_component_attributes(self):
- comp_attr_ids = (
- self.component_template_id.valid_product_template_attribute_line_ids.attribute_id.ids
- )
- prod_attr_ids = (
- self.bom_id.product_tmpl_id.valid_product_template_attribute_line_ids.attribute_id.ids
- )
- if len(comp_attr_ids) == 0:
- raise ValidationError(
- _(
- "No match on attribute has been detected for Component "
- "(Product Template) %s",
- self.component_template_id.display_name,
- )
+ for rec in self:
+ if not rec.component_template_id:
+ continue
+ comp_attrs = (
+ rec.component_template_id.valid_product_template_attribute_line_ids.attribute_id
)
- if not all(item in prod_attr_ids for item in comp_attr_ids):
- raise ValidationError(
- _(
- "Some attributes of the dynamic component are not included into "
- "production product attributes."
- )
+ prod_attrs = (
+ rec.bom_id.product_tmpl_id.valid_product_template_attribute_line_ids.attribute_id
)
+ if not comp_attrs:
+ raise ValidationError(
+ _(
+ "No match on attribute has been detected for Component "
+ "(Product Template) %s",
+ rec.component_template_id.display_name,
+ )
+ )
+ if not all(attr in prod_attrs for attr in comp_attrs):
+ raise ValidationError(
+ _(
+ "Some attributes of the dynamic component are not included into "
+ "production product attributes."
+ )
+ )
+
+ @api.constrains("component_template_id", "bom_product_template_attribute_value_ids")
+ def _check_variants_validity(self):
+ for rec in self:
+ if (
+ not rec.bom_product_template_attribute_value_ids
+ or not rec.component_template_id
+ ):
+ continue
+ variant_attrs = rec.bom_product_template_attribute_value_ids.attribute_id
+ same_attr_ids = set(rec.match_on_attribute_ids.ids) & set(variant_attrs.ids)
+ same_attrs = self.env["product.attribute"].browse(same_attr_ids)
+ if same_attrs:
+ raise ValidationError(
+ _(
+ "You cannot use an attribute value for attribute(s) %(attributes)s "
+ "in the field “Apply on Variants” as it's the same attribute used "
+ "in the field “Match on Attribute” related to the component "
+ "%(component)s.",
+ attributes=", ".join(same_attrs.mapped("name")),
+ component=rec.component_template_id.name,
+ )
+ )
+
+ @api.onchange("match_on_attribute_ids")
+ def _onchange_match_on_attribute_ids_check_component_attributes(self):
+ if self.match_on_attribute_ids:
+ self._check_component_attributes()
@api.onchange("bom_product_template_attribute_value_ids")
- def _onchange_attribute_value_ids(self):
+ def _onchange_bom_product_template_attribute_value_ids_check_variants(self):
if self.bom_product_template_attribute_value_ids:
self._check_variants_validity()
- def _check_variants_validity(self):
- if (
- not self.bom_product_template_attribute_value_ids
- or not self.component_template_id
- ):
- return
- variant_attr_ids = self.bom_product_template_attribute_value_ids.mapped(
- "attribute_id"
- )
- same_attrs = set(self.match_on_attribute_ids.ids) & set(variant_attr_ids.ids)
- if len(same_attrs) > 0:
- attr_recs = self.env["product.attribute"].browse(same_attrs)
- raise ValidationError(
- _(
- "You cannot use an attribute value for attribute(s) %(attributes)s "
- "in the field “Apply on Variants” as it's the same attribute used "
- "in the field “Match on Attribute” related to the component "
- "%(component)s.",
- attributes=", ".join(attr_recs.mapped("name")),
- component=self.component_template_id.name,
- )
- )
-
class MrpBom(models.Model):
_inherit = "mrp.bom"
@@ -333,8 +345,10 @@ class MrpBom(models.Model):
else:
return line_product_id
- def write(self, vals):
- res = super().write(vals)
- for line in self.bom_line_ids:
- line._update_component_attributes()
- return res
+ @api.constrains("product_tmpl_id", "product_id")
+ def _check_component_attributes(self):
+ return self.bom_line_ids._check_component_attributes()
+
+ @api.constrains("product_tmpl_id", "product_id")
+ def _check_variants_validity(self):
+ return self.bom_line_ids._check_variants_validity()
diff --git a/mrp_bom_attribute_match/models/mrp_production.py b/mrp_bom_attribute_match/models/mrp_production.py
index ed2467915..076604e1b 100644
--- a/mrp_bom_attribute_match/models/mrp_production.py
+++ b/mrp_bom_attribute_match/models/mrp_production.py
@@ -1,4 +1,4 @@
-from odoo import models
+from odoo import api, models
class MrpProduction(models.Model):
@@ -12,7 +12,6 @@ class MrpProduction(models.Model):
bom_line.product_id = False
return res
- def write(self, vals):
- for bl in self.bom_id.bom_line_ids.filtered("component_template_id"):
- bl._check_component_attributes()
- return super().write(vals)
+ @api.constrains("bom_id")
+ def _check_component_attributes(self):
+ self.bom_id._check_component_attributes()
diff --git a/mrp_bom_attribute_match/models/product.py b/mrp_bom_attribute_match/models/product.py
index d2e238a4f..7c9088c09 100644
--- a/mrp_bom_attribute_match/models/product.py
+++ b/mrp_bom_attribute_match/models/product.py
@@ -1,31 +1,24 @@
-from odoo import _, models
+from odoo import _, api, models
from odoo.exceptions import UserError
class ProductTemplate(models.Model):
_inherit = "product.template"
- def write(self, vals):
- res = super().write(vals)
- for rec in self:
- rec._check_product_with_component_change_allowed()
- rec._check_component_change_allowed()
- return res
-
+ @api.constrains("attribute_line_ids")
def _check_product_with_component_change_allowed(self):
- self.ensure_one()
- if len(self.attribute_line_ids) > 0 and len(self.bom_ids) > 0:
- for bom in self.bom_ids:
- for line in bom.bom_line_ids.filtered(
- lambda x: x.match_on_attribute_ids
- ):
- prod_attr_ids = self.attribute_line_ids.attribute_id.filtered(
+ for rec in self:
+ if not rec.attribute_line_ids:
+ continue
+ for bom in rec.bom_ids:
+ for line in bom.bom_line_ids.filtered("match_on_attribute_ids"):
+ prod_attr_ids = rec.attribute_line_ids.attribute_id.filtered(
lambda x: x.create_variant != "no_variant"
).ids
comp_attr_ids = line.match_on_attribute_ids.ids
- diff = list(set(comp_attr_ids) - set(prod_attr_ids))
- if len(diff) > 0:
- attr_recs = self.env["product.attribute"].browse(diff)
+ diff_ids = list(set(comp_attr_ids) - set(prod_attr_ids))
+ diff = rec.env["product.attribute"].browse(diff_ids)
+ if diff:
raise UserError(
_(
"The attributes you're trying to remove are used in "
@@ -33,33 +26,36 @@ class ProductTemplate(models.Model):
"To remove these attributes, first remove the BOM line "
"with the matching component.\n"
"Attributes: %(attributes)s\nBoM: %(bom)s",
- attributes=", ".join(attr_recs.mapped("name")),
+ attributes=", ".join(diff.mapped("name")),
bom=bom.display_name,
)
)
+ @api.constrains("attribute_line_ids")
def _check_component_change_allowed(self):
- self.ensure_one()
- if len(self.attribute_line_ids) > 0:
+ for rec in self:
+ if not rec.attribute_line_ids:
+ continue
boms = self._get_component_boms()
- if boms:
- for bom in boms:
- vpa = bom.product_tmpl_id.valid_product_template_attribute_line_ids
- prod_attr_ids = vpa.attribute_id.ids
- comp_attr_ids = self.attribute_line_ids.attribute_id.ids
- diff = list(set(comp_attr_ids) - set(prod_attr_ids))
- if len(diff) > 0:
- attr_recs = self.env["product.attribute"].browse(diff)
- raise UserError(
- _(
- "This product template is used as a component in the "
- "BOMs for %(bom)s and attribute(s) %(attributes)s is "
- "not present in all such product(s), and this would "
- "break the BOM behavior.",
- attributes=", ".join(attr_recs.mapped("name")),
- bom=bom.display_name,
- )
+ if not boms:
+ continue
+ for bom in boms:
+ vpa = bom.product_tmpl_id.valid_product_template_attribute_line_ids
+ prod_attr_ids = vpa.attribute_id.ids
+ comp_attr_ids = self.attribute_line_ids.attribute_id.ids
+ diff = list(set(comp_attr_ids) - set(prod_attr_ids))
+ if len(diff) > 0:
+ attr_recs = self.env["product.attribute"].browse(diff)
+ raise UserError(
+ _(
+ "This product template is used as a component in the "
+ "BOMs for %(bom)s and attribute(s) %(attributes)s is "
+ "not present in all such product(s), and this would "
+ "break the BOM behavior.",
+ attributes=", ".join(attr_recs.mapped("name")),
+ bom=bom.display_name,
)
+ )
def _get_component_boms(self):
self.ensure_one()
diff --git a/mrp_bom_attribute_match/views/mrp_bom_views.xml b/mrp_bom_attribute_match/views/mrp_bom_views.xml
index ca482aae7..3ba95fb69 100644
--- a/mrp_bom_attribute_match/views/mrp_bom_views.xml
+++ b/mrp_bom_attribute_match/views/mrp_bom_views.xml
@@ -5,12 +5,7 @@
-
+