From 0aab9abe0f5bc6ad30a8ce0fcd5a319a7f038cec Mon Sep 17 00:00:00 2001 From: CarlosRoca13 Date: Mon, 13 Dec 2021 13:32:09 +0100 Subject: [PATCH 1/8] [IMP] product_assortment: Add demo data for product_assortment module --- product_assortment/__manifest__.py | 1 + product_assortment/demo/assortments.xml | 40 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 product_assortment/demo/assortments.xml diff --git a/product_assortment/__manifest__.py b/product_assortment/__manifest__.py index 8cd58360da8..5c8746e197d 100644 --- a/product_assortment/__manifest__.py +++ b/product_assortment/__manifest__.py @@ -18,5 +18,6 @@ "views/product_assortment.xml", "views/res_partner_view.xml", ], + "demo": ["demo/assortments.xml"], "installable": True, } diff --git a/product_assortment/demo/assortments.xml b/product_assortment/demo/assortments.xml new file mode 100644 index 00000000000..f1f02a14419 --- /dev/null +++ b/product_assortment/demo/assortments.xml @@ -0,0 +1,40 @@ + + + + + + product.product + + Assortment Desk + + ["|","|",("default_code","ilike","desk"),("name","ilike","desk"),("barcode","ilike","desk")] + + + + product.product + + Assortment Chair + + ["|","|",("default_code","ilike","chair"),("name","ilike","chair"),("barcode","ilike","chair")] + + + + product.product + + Assortment Service + + + + + From 2563369eb7f58f08fd1491e51c5c38ee418dd5a9 Mon Sep 17 00:00:00 2001 From: Carlos Dauden Date: Fri, 22 Mar 2024 00:40:29 +0100 Subject: [PATCH 2/8] [FIX] product_assortment: All assortments are applied to original partner when partner is duplicated TT48358 --- product_assortment/models/res_partner.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/product_assortment/models/res_partner.py b/product_assortment/models/res_partner.py index dd6721400cd..39947546fdb 100644 --- a/product_assortment/models/res_partner.py +++ b/product_assortment/models/res_partner.py @@ -12,6 +12,7 @@ class ResPartner(models.Model): relation="ir_filter_all_partner_rel", column1="partner_id", column2="filter_id", + copy=False, ) def action_define_product_assortment(self): @@ -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) From ccd2fbcb496bd63eee3b39eed980e382c6b43c64 Mon Sep 17 00:00:00 2001 From: sergio-teruel Date: Mon, 30 Sep 2024 22:48:56 +0200 Subject: [PATCH 3/8] [IMP] product_assortment: Add security group to only show assortments to managers TT51064 --- product_assortment/models/__init__.py | 1 + product_assortment/models/ir_rule.py | 36 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 product_assortment/models/ir_rule.py diff --git a/product_assortment/models/__init__.py b/product_assortment/models/__init__.py index c03968c0074..40f9898560a 100644 --- a/product_assortment/models/__init__.py +++ b/product_assortment/models/__init__.py @@ -1,2 +1,3 @@ from . import ir_filters +from . import ir_rule from . import res_partner diff --git a/product_assortment/models/ir_rule.py b/product_assortment/models/ir_rule.py new file mode 100644 index 00000000000..48c80a52225 --- /dev/null +++ b/product_assortment/models/ir_rule.py @@ -0,0 +1,36 @@ +# Copyright 2024 Tecnativa - Sergio Teruel +# License AGPL-3 - See https://www.gnu.org/licenses/agpl-3.0.html + +from odoo import api, models, tools +from odoo.osv import expression +from odoo.tools import config + + +class IrRule(models.Model): + _inherit = "ir.rule" + + @api.model + @tools.conditional( + "xml" not in config["dev_mode"], + tools.ormcache( + "self.env.uid", + "self.env.su", + "model_name", + "mode", + "tuple(self._compute_domain_context_values())", + ), + ) + def _compute_domain(self, model_name, mode="read"): + """Inject extra domain for restricting filter (Assortments) when the user + has not the group 'Product Assortment Manager'. + """ + res = super()._compute_domain(model_name, mode=mode) + user = self.env.user + if model_name == "ir.filters" and not self.env.su: + if not user.has_group( + "product_assortment.group_product_assortment_manager" + ): + extra_domain = [("is_assortment", "=", False)] + extra_domain = expression.normalize_domain(extra_domain) + res = expression.AND([extra_domain] + [res]) + return res From ced452f6748f0df512f3fd8705c4b8260b14211f Mon Sep 17 00:00:00 2001 From: bosd Date: Sat, 1 Feb 2025 14:41:06 +0100 Subject: [PATCH 4/8] [IMP] product_assortment: Migration leftovers to 18.0 --- product_assortment/README.rst | 39 +++++++----- product_assortment/i18n/ca.po | 2 +- product_assortment/i18n/de.po | 2 +- product_assortment/i18n/fr.po | 2 +- product_assortment/i18n/it.po | 2 +- product_assortment/i18n/nl.po | 2 +- product_assortment/models/ir_filters.py | 12 ++-- product_assortment/readme/HISTORY.md | 12 +++- product_assortment/readme/USAGE.md | 2 +- .../static/description/index.html | 63 ++++++++++--------- .../tests/test_product_assortment.py | 15 +++++ 11 files changed, 95 insertions(+), 58 deletions(-) diff --git a/product_assortment/README.rst b/product_assortment/README.rst index e59527f5e7c..aadb5eb0d72 100644 --- a/product_assortment/README.rst +++ b/product_assortment/README.rst @@ -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 ================== @@ -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 @@ -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 @@ -59,22 +55,33 @@ 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 Bug Tracker =========== @@ -97,13 +104,13 @@ Authors Contributors ------------ -- Denis Roussel -- Cédric Pigeon -- Xavier Bouquiaux -- `Tecnativa `__: +- Denis Roussel +- Cédric Pigeon +- Xavier Bouquiaux +- `Tecnativa `__: - - Carlos Roca - - Sergio Teruel + - Carlos Roca + - Sergio Teruel Maintainers ----------- diff --git a/product_assortment/i18n/ca.po b/product_assortment/i18n/ca.po index acc0fc5d49a..375f25f8d9a 100644 --- a/product_assortment/i18n/ca.po +++ b/product_assortment/i18n/ca.po @@ -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" diff --git a/product_assortment/i18n/de.po b/product_assortment/i18n/de.po index d2680cdcdba..4cdb4bd86df 100644 --- a/product_assortment/i18n/de.po +++ b/product_assortment/i18n/de.po @@ -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" diff --git a/product_assortment/i18n/fr.po b/product_assortment/i18n/fr.po index ebd062220a0..7d3686c522e 100644 --- a/product_assortment/i18n/fr.po +++ b/product_assortment/i18n/fr.po @@ -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" diff --git a/product_assortment/i18n/it.po b/product_assortment/i18n/it.po index ab71abd1bad..5af4acf6e87 100644 --- a/product_assortment/i18n/it.po +++ b/product_assortment/i18n/it.po @@ -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" diff --git a/product_assortment/i18n/nl.po b/product_assortment/i18n/nl.po index 05eb306e293..a82eed0ea15 100644 --- a/product_assortment/i18n/nl.po +++ b/product_assortment/i18n/nl.po @@ -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" diff --git a/product_assortment/models/ir_filters.py b/product_assortment/models/ir_filters.py index 99766efb358..d8651e7bc2a 100644 --- a/product_assortment/models/ir_filters.py +++ b/product_assortment/models/ir_filters.py @@ -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 @@ -52,9 +52,7 @@ class IrFilters(models.Model): @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): @@ -90,10 +88,10 @@ def get_partner_domain_fields(self): @api.depends("partner_ids", "partner_domain") def _compute_all_partner_ids(self): """Summarize selected partners and partners from partner domain field""" - for ir_filter in self: + for ir_filter in self.sudo(): if not ir_filter.is_assortment: ir_filter.all_partner_ids = False - elif ir_filter.partner_domain != "[]": + if ir_filter.partner_domain != []: ir_filter.all_partner_ids = ( self.env["res.partner"].search(ir_filter._get_eval_partner_domain()) + ir_filter.partner_ids @@ -169,7 +167,7 @@ def show_products(self): action.update( { "domain": self._get_eval_domain(), - "name": _("Products"), + "name": self.env._("Products"), "context": self.env.context, "target": "current", } diff --git a/product_assortment/readme/HISTORY.md b/product_assortment/readme/HISTORY.md index 0cc1722371d..9eefcec32b1 100644 --- a/product_assortment/readme/HISTORY.md +++ b/product_assortment/readme/HISTORY.md @@ -12,4 +12,14 @@ ## 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 + diff --git a/product_assortment/readme/USAGE.md b/product_assortment/readme/USAGE.md index dbc0b08586f..dc83a2ad52c 100644 --- a/product_assortment/readme/USAGE.md +++ b/product_assortment/readme/USAGE.md @@ -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 diff --git a/product_assortment/static/description/index.html b/product_assortment/static/description/index.html index f1fef7568d3..42bde133348 100644 --- a/product_assortment/static/description/index.html +++ b/product_assortment/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +Product Assortment -
+
+

Product Assortment

- - -Odoo Community Association - -
-

Product Assortment

-

Production/Stable License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

+

Production/Stable License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

This addon intends to manage product assortment. In Odoo you can only define some filters defined by a domain but it can be sometimes really complicated. With this addon you will be able to define a domain but @@ -390,55 +385,68 @@

Product Assortment

  • 12.0.1.0.0 (2019-06-03)
  • 14.0.1.0.0 (2019-06-03)
  • 16.0.1.0.0 (2022-09-15)
  • +
  • 18.0.1.0.0 (2025-03-06)
  • -
  • Bug Tracker
  • -
  • Credits
  • -

    Usage

    +

    Usage

    To use this module, you need to:

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

    Changelog

    +

    Changelog

    -

    10.0.1.0.0 (2018-08-27)

    +

    10.0.1.0.0 (2018-08-27)

    • [10.0][ADD] productassortment
    -

    12.0.1.0.0 (2019-06-03)

    +

    12.0.1.0.0 (2019-06-03)

    • [12.0][MIG] productassortment
    -

    14.0.1.0.0 (2019-06-03)

    +

    14.0.1.0.0 (2019-06-03)

    • [14.0][MIG] productassortment
    -

    16.0.1.0.0 (2022-09-15)

    +

    16.0.1.0.0 (2022-09-15)

    +
      +
    • [16.0][MIG] product_assortment
    • +
    +
    +
    +

    18.0.1.0.0 (2025-03-06)

      -
    • [16.0][MIG] productassortment
    • +
    • [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
    -

    Bug Tracker

    +

    Bug Tracker

    Bugs are tracked on GitHub 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 @@ -446,15 +454,15 @@

    Bug Tracker

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

    -

    Credits

    +

    Credits

    -

    Authors

    +

    Authors

    • ACSONE SA/NV
    -

    Contributors

    +

    Contributors

    -

    Maintainers

    +

    Maintainers

    This module is maintained by the OCA.

    Odoo Community Association @@ -480,6 +488,5 @@

    Maintainers

    -
    diff --git a/product_assortment/tests/test_product_assortment.py b/product_assortment/tests/test_product_assortment.py index 083f400fdca..483c38146f3 100644 --- a/product_assortment/tests/test_product_assortment.py +++ b/product_assortment/tests/test_product_assortment.py @@ -115,6 +115,21 @@ def test_product_assortment_mixed_view(self): res = self.assortment.show_products() self.assertEqual(res["domain"], [("id", "not in", excluded_product.ids)]) + def test_product_assortment_filter_combination(self): + """Combine a whitelisted and a blacklisted product in order + to validate the combination of both filters. The result should be a + simple domain with the excluded product. + """ + # Add a default no product filter to the assortment + self.assortment.write({"domain": [("id", "=", 0)]}) + included_product = self.env.ref("product.product_product_7") + self.assortment.write({"whitelist_product_ids": [(4, included_product.id)]}) + excluded_product = self.env.ref("product.product_product_2") + self.assortment.write({"blacklist_product_ids": [(4, excluded_product.id)]}) + res = self.assortment.show_products() + self.assertIn(("id", "not in", [excluded_product.id]), res["domain"]) + self.assertIn(("id", "in", [included_product.id]), res["domain"]) + def test_record_count(self): products = self.product_obj.search([]) self.assertEqual(self.assortment.record_count, len(products)) From ad5eae7ce4f0065ccac12c2e2cfdec449ba21157 Mon Sep 17 00:00:00 2001 From: bosd Date: Sat, 1 Feb 2025 21:27:53 +0100 Subject: [PATCH 5/8] [FIX] product_assortment: Show all applied assortments from partner smartbutton. Before this commit, the assortments which where applied to the partner using the partner domain, where not shown. --- product_assortment/README.rst | 3 +++ product_assortment/models/res_partner.py | 2 +- product_assortment/readme/HISTORY.md | 2 ++ product_assortment/static/description/index.html | 3 +++ product_assortment/tests/test_product_assortment.py | 5 ++++- 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/product_assortment/README.rst b/product_assortment/README.rst index aadb5eb0d72..5c8ab343727 100644 --- a/product_assortment/README.rst +++ b/product_assortment/README.rst @@ -82,6 +82,9 @@ Changelog 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 =========== diff --git a/product_assortment/models/res_partner.py b/product_assortment/models/res_partner.py index 39947546fdb..812011ddd2a 100644 --- a/product_assortment/models/res_partner.py +++ b/product_assortment/models/res_partner.py @@ -20,7 +20,7 @@ def action_define_product_assortment(self): 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() diff --git a/product_assortment/readme/HISTORY.md b/product_assortment/readme/HISTORY.md index 9eefcec32b1..589bbea5c99 100644 --- a/product_assortment/readme/HISTORY.md +++ b/product_assortment/readme/HISTORY.md @@ -22,4 +22,6 @@ - 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.) diff --git a/product_assortment/static/description/index.html b/product_assortment/static/description/index.html index 42bde133348..ce178c6db58 100644 --- a/product_assortment/static/description/index.html +++ b/product_assortment/static/description/index.html @@ -442,6 +442,9 @@

    18.0.1.0.0 (2025-03-06)

    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.)
  • diff --git a/product_assortment/tests/test_product_assortment.py b/product_assortment/tests/test_product_assortment.py index 483c38146f3..367ad9a89dd 100644 --- a/product_assortment/tests/test_product_assortment.py +++ b/product_assortment/tests/test_product_assortment.py @@ -84,7 +84,10 @@ def test_search_assortment_with_partner(self): search_domain = self.partner.action_define_product_assortment()["domain"] self.assertEqual( search_domain, - [("partner_ids", "in", [self.partner.id]), ("is_assortment", "=", True)], + [ + ("all_partner_ids", "in", [self.partner.id]), + ("is_assortment", "=", True), + ], ) def test_product_assortment_view(self): From cf2c0792e0e2927ca9b0c34f543876a05765d6f3 Mon Sep 17 00:00:00 2001 From: bosd <11499387+bosd@users.noreply.github.com> Date: Sat, 24 Jan 2026 12:41:13 +0100 Subject: [PATCH 6/8] Update product_assortment/models/ir_rule.py Co-authored-by: BizzAppDev --- product_assortment/models/ir_rule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/product_assortment/models/ir_rule.py b/product_assortment/models/ir_rule.py index 48c80a52225..99684c82040 100644 --- a/product_assortment/models/ir_rule.py +++ b/product_assortment/models/ir_rule.py @@ -26,7 +26,7 @@ def _compute_domain(self, model_name, mode="read"): """ res = super()._compute_domain(model_name, mode=mode) user = self.env.user - if model_name == "ir.filters" and not self.env.su: + if model_name == "ir.filters" and not self.env.is_superuser(): if not user.has_group( "product_assortment.group_product_assortment_manager" ): From 1502fd5dcb53859eafa072bc9dac4271c4a007ab Mon Sep 17 00:00:00 2001 From: bosd <11499387+bosd@users.noreply.github.com> Date: Sat, 24 Jan 2026 13:13:21 +0100 Subject: [PATCH 7/8] [IMP] product_assortment: Refactor partner ID computation in ir_filters.py --- product_assortment/models/ir_filters.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/product_assortment/models/ir_filters.py b/product_assortment/models/ir_filters.py index d8651e7bc2a..7da000b9a01 100644 --- a/product_assortment/models/ir_filters.py +++ b/product_assortment/models/ir_filters.py @@ -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", @@ -88,13 +89,14 @@ def get_partner_domain_fields(self): @api.depends("partner_ids", "partner_domain") def _compute_all_partner_ids(self): """Summarize selected partners and partners from partner domain field""" - for ir_filter in self.sudo(): + for ir_filter in self: if not ir_filter.is_assortment: ir_filter.all_partner_ids = False - if 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 From 9f799daef2797d8c4893688c198a3051422c8564 Mon Sep 17 00:00:00 2001 From: bosd <11499387+bosd@users.noreply.github.com> Date: Sat, 24 Jan 2026 13:37:08 +0100 Subject: [PATCH 8/8] [REF] Restrict search for non-manager users in ir_filters --- product_assortment/models/__init__.py | 1 - product_assortment/models/ir_filters.py | 40 +++++++++++++++++++++++++ product_assortment/models/ir_rule.py | 36 ---------------------- 3 files changed, 40 insertions(+), 37 deletions(-) delete mode 100644 product_assortment/models/ir_rule.py diff --git a/product_assortment/models/__init__.py b/product_assortment/models/__init__.py index 40f9898560a..c03968c0074 100644 --- a/product_assortment/models/__init__.py +++ b/product_assortment/models/__init__.py @@ -1,3 +1,2 @@ from . import ir_filters -from . import ir_rule from . import res_partner diff --git a/product_assortment/models/ir_filters.py b/product_assortment/models/ir_filters.py index 7da000b9a01..1c6e909a6f4 100644 --- a/product_assortment/models/ir_filters.py +++ b/product_assortment/models/ir_filters.py @@ -51,6 +51,46 @@ 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): return self.env.context.get("product_assortment", False) diff --git a/product_assortment/models/ir_rule.py b/product_assortment/models/ir_rule.py deleted file mode 100644 index 99684c82040..00000000000 --- a/product_assortment/models/ir_rule.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2024 Tecnativa - Sergio Teruel -# License AGPL-3 - See https://www.gnu.org/licenses/agpl-3.0.html - -from odoo import api, models, tools -from odoo.osv import expression -from odoo.tools import config - - -class IrRule(models.Model): - _inherit = "ir.rule" - - @api.model - @tools.conditional( - "xml" not in config["dev_mode"], - tools.ormcache( - "self.env.uid", - "self.env.su", - "model_name", - "mode", - "tuple(self._compute_domain_context_values())", - ), - ) - def _compute_domain(self, model_name, mode="read"): - """Inject extra domain for restricting filter (Assortments) when the user - has not the group 'Product Assortment Manager'. - """ - res = super()._compute_domain(model_name, mode=mode) - user = self.env.user - if model_name == "ir.filters" and not self.env.is_superuser(): - if not user.has_group( - "product_assortment.group_product_assortment_manager" - ): - extra_domain = [("is_assortment", "=", False)] - extra_domain = expression.normalize_domain(extra_domain) - res = expression.AND([extra_domain] + [res]) - return res