Skip to content
Open
42 changes: 26 additions & 16 deletions product_assortment/README.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

==================
Product Assortment
==================
Expand All @@ -17,7 +13,7 @@ Product Assortment
.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png
:target: https://odoo-community.org/page/development-status
:alt: Production/Stable
.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
.. |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
Expand Down Expand Up @@ -49,7 +45,7 @@ Usage

To use this module, you need to:

1. Enter the menu through Product Assortment Icon
1. Enter the menu through the Product Assortment Icon
2. Create a new filter where you can define your domain and add allowed
and restricted products

Expand All @@ -59,22 +55,36 @@ Changelog
10.0.1.0.0 (2018-08-27)
-----------------------

- [10.0][ADD] productassortment
- [10.0][ADD] productassortment

12.0.1.0.0 (2019-06-03)
-----------------------

- [12.0][MIG] productassortment
- [12.0][MIG] productassortment

14.0.1.0.0 (2019-06-03)
-----------------------

- [14.0][MIG] productassortment
- [14.0][MIG] productassortment

16.0.1.0.0 (2022-09-15)
-----------------------

- [16.0][MIG] productassortment
- [16.0][MIG] product_assortment

18.0.1.0.0 (2025-03-06)
-----------------------

- [18.0][MIG] product_assortment
- Forward port demo data
- Forward port Only Show assortments to managers
- Forward port Fix All assortments are applied to original partner when
partner is duplicated
- Adjust test code to new API behavior, for info: odoo/odoo@450f5c9
- added test for combined black list and whitelisted product
- Fix: Navigating to the product assortment using the smartbutton on
the partner does not show all applicable assortments. (The
assortments with the partner defined as a domain where missing.)

Bug Tracker
===========
Expand All @@ -97,13 +107,13 @@ Authors
Contributors
------------

- Denis Roussel <denis.roussel@acsone.eu>
- Cédric Pigeon <cedric.pigeon@acsone.eu>
- Xavier Bouquiaux <xavier.bouquiaux@acsone.eu>
- `Tecnativa <https://www.tecnativa.com>`__:
- Denis Roussel <denis.roussel@acsone.eu>
- Cédric Pigeon <cedric.pigeon@acsone.eu>
- Xavier Bouquiaux <xavier.bouquiaux@acsone.eu>
- `Tecnativa <https://www.tecnativa.com>`__:

- Carlos Roca
- Sergio Teruel
- Carlos Roca
- Sergio Teruel

Maintainers
-----------
Expand Down
1 change: 1 addition & 0 deletions product_assortment/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
"views/product_assortment.xml",
"views/res_partner_view.xml",
],
"demo": ["demo/assortments.xml"],
"installable": True,
}
40 changes: 40 additions & 0 deletions product_assortment/demo/assortments.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version='1.0' encoding='utf-8' ?>
<!-- Copyright 2021 Tecnativa - Carlos Roca
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<!-- oca-hooks:disable=xml-dangerous-filter-wo-user -->
<odoo>
<record id="product_assortment_1" model="ir.filters">
<field name="model_id">product.product</field>
<field name="is_assortment" eval="True" />
<field name="name">Assortment Desk</field>
<field name="active" eval="True" />
<field
name="domain"
>["|","|",("default_code","ilike","desk"),("name","ilike","desk"),("barcode","ilike","desk")]</field>
<field name="partner_domain" eval="[('id', '=', ref('base.partner_admin'))]" />
</record>
<record id="product_assortment_2" model="ir.filters">
<field name="model_id">product.product</field>
<field name="is_assortment" eval="True" />
<field name="name">Assortment Chair</field>
<field name="active" eval="True" />
<field
name="domain"
>["|","|",("default_code","ilike","chair"),("name","ilike","chair"),("barcode","ilike","chair")]</field>
<field name="partner_domain" eval="[('id', '=', ref('base.partner_demo'))]" />
</record>
<record id="product_assortment_3" model="ir.filters">
<field name="model_id">product.product</field>
<field name="is_assortment" eval="True" />
<field name="name">Assortment Service</field>
<field name="active" eval="True" />
<field
name="domain"
eval="[('categ_id', 'child_of', ref('product.product_category_3'))]"
/>
<field
name="partner_domain"
eval="[('id', '=', ref('base.partner_demo_portal'))]"
/>
</record>
</odoo>
2 changes: 1 addition & 1 deletion product_assortment/i18n/ca.po
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ msgid "Partners to apply"
msgstr "Socis a aplicar"

#. module: product_assortment
#: model_terms:ir.ui.view,arch_db:product_assortment.product_product_view_tree
#: model_terms:ir.ui.view,arch_db:product_assortment.product_product_view_list
msgid "Product"
msgstr "Producte"

Expand Down
2 changes: 1 addition & 1 deletion product_assortment/i18n/de.po
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ msgid "Partners to apply"
msgstr ""

#. module: product_assortment
#: model_terms:ir.ui.view,arch_db:product_assortment.product_product_view_tree
#: model_terms:ir.ui.view,arch_db:product_assortment.product_product_view_list
msgid "Product"
msgstr "Produkt"

Expand Down
2 changes: 1 addition & 1 deletion product_assortment/i18n/fr.po
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ msgid "Partners to apply"
msgstr "Appliquer aux partenaires"

#. module: product_assortment
#: model_terms:ir.ui.view,arch_db:product_assortment.product_product_view_tree
#: model_terms:ir.ui.view,arch_db:product_assortment.product_product_view_list
msgid "Product"
msgstr "Produit"

Expand Down
2 changes: 1 addition & 1 deletion product_assortment/i18n/it.po
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ msgid "Partners to apply"
msgstr "Partner da applicare"

#. module: product_assortment
#: model_terms:ir.ui.view,arch_db:product_assortment.product_product_view_tree
#: model_terms:ir.ui.view,arch_db:product_assortment.product_product_view_list
msgid "Product"
msgstr "Prodotto"

Expand Down
2 changes: 1 addition & 1 deletion product_assortment/i18n/nl.po
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ msgid "Partners to apply"
msgstr "Partners om toe te passen"

#. module: product_assortment
#: model_terms:ir.ui.view,arch_db:product_assortment.product_product_view_tree
#: model_terms:ir.ui.view,arch_db:product_assortment.product_product_view_list
msgid "Product"
msgstr "Product"

Expand Down
56 changes: 48 additions & 8 deletions product_assortment/models/ir_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Copyright 2023 Tecnativa - Carlos Dauden
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import _, api, fields, models
from odoo import api, fields, models
from odoo.osv import expression
from odoo.tools import ormcache
from odoo.tools.safe_eval import datetime, safe_eval
Expand Down Expand Up @@ -38,6 +38,7 @@ class IrFilters(models.Model):
compute="_compute_all_partner_ids",
# Make it store=True because we will need this field to search by involved
# partners
compute_sudo=True,
store=True,
relation="ir_filter_all_partner_rel",
column1="filter_id",
Expand All @@ -50,11 +51,49 @@ class IrFilters(models.Model):
string="Restricted product domain", default="[]", required=True
)

@api.model
def _search(self, args, offset=0, limit=None, order=None, count=False):
# Check if user is NOT a manager and NOT a superuser
if not self.env.is_superuser() and not self.env.user.has_group(
"product_assortment.group_product_assortment_manager"
):
# Inject the domain directly into the search arguments
args = expression.AND([args, [("is_assortment", "=", False)]])

# Call the parent _search method without the count parameter
result = super()._search(args, offset=offset, limit=limit, order=order)

# If count is requested, return the count of the result
if count:
# The result of _search is typically a list of IDs
if isinstance(result, list):
return len(result)
# If result is not a list, it might be a query object,
# so we need to handle differently
# In most cases, we should return the length of the result
try:
return len(result)
except TypeError:
# If we can't get the length, fall back to calling search_count
# with the modified args
return self.search_count(args)

return result

@api.model
def search_count(self, args):
# Apply the same access control as in _search
if not self.env.is_superuser() and not self.env.user.has_group(
"product_assortment.group_product_assortment_manager"
):
# Inject the domain directly into the search arguments
args = expression.AND([args, [("is_assortment", "=", False)]])

return super().search_count(args)

@api.model
def _get_default_is_assortment(self):
if self.env.context.get("product_assortment", False):
return True
return False
return self.env.context.get("product_assortment", False)

@api.model
def _update_assortment_default_values(self, vals_list):
Expand Down Expand Up @@ -93,10 +132,11 @@ def _compute_all_partner_ids(self):
for ir_filter in self:
if not ir_filter.is_assortment:
ir_filter.all_partner_ids = False
elif ir_filter.partner_domain != "[]":
continue
if ir_filter.partner_domain and ir_filter.partner_domain != []:
domain = ir_filter._get_eval_partner_domain()
ir_filter.all_partner_ids = (
self.env["res.partner"].search(ir_filter._get_eval_partner_domain())
+ ir_filter.partner_ids
self.env["res.partner"].search(domain) + ir_filter.partner_ids
)
else:
ir_filter.all_partner_ids = ir_filter.partner_ids
Expand Down Expand Up @@ -169,7 +209,7 @@ def show_products(self):
action.update(
{
"domain": self._get_eval_domain(),
"name": _("Products"),
"name": self.env._("Products"),
"context": self.env.context,
"target": "current",
}
Expand Down
7 changes: 3 additions & 4 deletions product_assortment/models/res_partner.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ class ResPartner(models.Model):
relation="ir_filter_all_partner_rel",
column1="partner_id",
column2="filter_id",
copy=False,
)

def action_define_product_assortment(self):
self.ensure_one()
xmlid = "product_assortment.actions_product_assortment_view"
action = self.env["ir.actions.act_window"]._for_xml_id(xmlid)
action["domain"] = [
("partner_ids", "in", self.ids),
("all_partner_ids", "in", self.ids),
("is_assortment", "=", True),
]
ctx = self.env.context.copy()
Expand All @@ -41,9 +42,7 @@ def _update_partner_assortments(self):
# Use ids instead of record to improve performance (Remove in next versions)
partner_assortment_ids = []
for assortment in assortments:
if partner in assortment.partner_ids or partner.filtered_domain(
assortment._get_eval_partner_domain()
):
if partner in assortment.all_partner_ids:
partner_assortment_ids.append(assortment.id)
partner.applied_assortment_ids = assortments.browse(partner_assortment_ids)

Expand Down
14 changes: 13 additions & 1 deletion product_assortment/readme/HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,16 @@

## 16.0.1.0.0 (2022-09-15)

- \[16.0\]\[MIG\] productassortment
- \[16.0\]\[MIG\] product_assortment

## 18.0.1.0.0 (2025-03-06)

- \[18.0\]\[MIG\] product_assortment
- Forward port demo data
- Forward port Only Show assortments to managers
- Forward port Fix All assortments are applied to original partner when partner is duplicated
- Adjust test code to new API behavior, for info: odoo/odoo@450f5c9
- added test for combined black list and whitelisted product
- Fix: Navigating to the product assortment using the smartbutton on the partner does not show all applicable assortments.
(The assortments with the partner defined as a domain where missing.)

2 changes: 1 addition & 1 deletion product_assortment/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
To use this module, you need to:

1. Enter the menu through Product Assortment Icon
1. Enter the menu through the Product Assortment Icon
2. Create a new filter where you can define your domain and add allowed
and restricted products
Loading