Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions product_attribute_value_dependent_mixin/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
=======================================
Product Attribute Value Dependent Mixin
=======================================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:ba5d1efad0e1d29166513c1a23b430a0477e8fc7f44fe2afe6dfea4f6718ea82
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproduct--attribute-lightgray.png?logo=github
:target: https://github.com/OCA/product-attribute/tree/16.0/product_attribute_value_dependent_mixin
:alt: OCA/product-attribute
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/product-attribute-16-0/product-attribute-16-0-product_attribute_value_dependent_mixin
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/product-attribute&target_branch=16.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This technical module introduces a reusable mixin designed to enable any model to establish dependencies on specific product attribute values.
By inheriting from this mixin, developers can easily link business rules, configurations, or records to precise product variants without duplicating complex filtering logic.

- Automatically computes available products and attribute values based on the selected product.template.
- Supports domain construction to filter attribute values based on context.
- Matching Logic: Includes a is_matching_product(product) method to validate whether a specific product variant satisfies the configured attribute constraints.

**Table of contents**

.. contents::
:local:

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/product-attribute/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/product-attribute/issues/new?body=module:%20product_attribute_value_dependent_mixin%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
~~~~~~~

* Akretion

Contributors
~~~~~~~~~~~~

* `Akretion <https://www.akretion.com>`_

* Chafique Delli <chafique.delli@akretion.com>

Maintainers
~~~~~~~~~~~

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/product-attribute <https://github.com/OCA/product-attribute/tree/16.0/product_attribute_value_dependent_mixin>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
3 changes: 3 additions & 0 deletions product_attribute_value_dependent_mixin/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import models
16 changes: 16 additions & 0 deletions product_attribute_value_dependent_mixin/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2023 Akretion
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
"name": "Product Attribute Value Dependent Mixin",
"summary": "Mixin to make product attribute values fields on models",
"author": "Akretion,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/product-attribute",
"license": "AGPL-3",
"application": False,
"installable": True,
"category": "Product",
"version": "16.0.1.0.0",
"depends": ["product"],
"data": [],
}
2 changes: 2 additions & 0 deletions product_attribute_value_dependent_mixin/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not necessary

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @rousseldenis

Do you mean the file init.py itself is not necessary or the License statement ? Sorry, I don't understand why...

from . import product_attribute_value_dependent_mixin
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Copyright 2023-2026 Akretion
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https is better


import itertools
import json

from odoo import api, fields, models


class AttributeValueDependantMixin(models.AbstractModel):
_name = "attribute.value.dependant.mixin"
_description = "Attribute Value Dependant Mixin"

product_tmpl_id = fields.Many2one(
comodel_name="product.template",
string="Product Template",
)
product_id = fields.Many2one(
comodel_name="product.product",
string="Product",
domain="[('id', 'in', available_product_ids)]",
)
available_product_ids = fields.Many2many(
comodel_name="product.product",
string="Available Products",
compute="_compute_available_product_ids",
)

attribute_value_ids = fields.Many2many(
comodel_name="product.attribute.value",
string="Attribute Values",
)

available_attribute_value_domain = fields.Char(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In v16 and later, you can use fields.Binary() to avoid json.dumps()

compute="_compute_available_attribute_value_domain",
)

@api.depends("product_tmpl_id")
def _compute_available_product_ids(self):
for rec in self:
rec.available_product_ids = self.env["product.product"].search(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, this should be avoided at all for performances reasons.

Why using _origin ?

I would have done the search before the loop

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moreover, why not having used a One2many field using the direct field product_tmpl_id instead ?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moreover, this One2many field already exists on product.template, it is the product_variant_ids field defined in the product module... (it was already there in 14.0 too)
See https://github.com/odoo/odoo/blob/f28eb1478fe47c4627fc3377fa505c78a6a7ea82/addons/product/models/product_template.py#L122

@chafique-delli or @Kev-Roche Do you remember a reason for using self instead of rec and _origin in the search to get a Many2many instead of the One2many field ? I can't find where the field is used... not in sale_warehouse_rule at least...

[("product_tmpl_id", "=", self.product_tmpl_id._origin.id)]
)

@api.depends(
"product_tmpl_id",
"product_tmpl_id.attribute_line_ids.value_ids",
"available_attribute_value_domain",
)
def _compute_available_attribute_value_ids(self):
for rec in self:
if rec.product_tmpl_id:
rec.available_attribute_value_ids = rec.product_tmpl_id.mapped(
"attribute_line_ids.value_ids"
).filtered_domain(json.loads(rec.available_attribute_value_domain))
else:
rec.available_attribute_value_ids = None

@api.depends("product_tmpl_id", "product_tmpl_id.attribute_line_ids.value_ids")
def _compute_available_attribute_value_domain(self):
for rec in self:
domain = []
if rec.product_tmpl_id:
domain = [
("id", "in", rec.product_tmpl_id.attribute_line_ids.value_ids.ids)
]
rec.available_attribute_value_domain = json.dumps(domain)

def is_matching_product(self, product):
self.ensure_one()
if self.product_tmpl_id != product.product_tmpl_id:
return False
elif self.product_id:
if self.product_id == product:
return True
else:
return False
elif self.attribute_value_ids:
ptav = product.product_template_attribute_value_ids
attr2vals = {
attribute: set(values)
for attribute, values in itertools.groupby(
self.attribute_value_ids, lambda pav: pav.attribute_id
)
}
for attribute in attr2vals:
if attribute not in ptav.attribute_id:
return False
elif not attr2vals[attribute] & set(ptav.product_attribute_value_id):
return False
return True
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* `Akretion <https://www.akretion.com>`_

* Chafique Delli <chafique.delli@akretion.com>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
This technical module introduces a reusable mixin designed to enable any model to establish dependencies on specific product attribute values.
By inheriting from this mixin, developers can easily link business rules, configurations, or records to precise product variants without duplicating complex filtering logic.

- Automatically computes available products and attribute values based on the selected product.template.
- Supports domain construction to filter attribute values based on context.
- Matching Logic: Includes a is_matching_product(product) method to validate whether a specific product variant satisfies the configured attribute constraints.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading