From 407deb5985ce9f4e538262fed5917c8d2cf9b79d Mon Sep 17 00:00:00 2001 From: Denis Roussel Date: Mon, 27 Aug 2018 13:47:15 +0200 Subject: [PATCH 01/65] [10.0][ADD] product_assortment --- product_assortment/README.rst | 88 ++++ product_assortment/__init__.py | 1 + product_assortment/__manifest__.py | 21 + .../i18n/product_assortment.pot | 88 ++++ product_assortment/models/__init__.py | 1 + product_assortment/models/ir_filters.py | 86 ++++ product_assortment/readme/CONTRIBUTORS.rst | 2 + product_assortment/readme/DESCRIPTION.rst | 6 + product_assortment/readme/USAGE.rst | 5 + .../static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 434 ++++++++++++++++++ product_assortment/tests/__init__.py | 1 + .../tests/test_product_assortment.py | 66 +++ .../views/product_assortment.xml | 88 ++++ 14 files changed, 887 insertions(+) create mode 100644 product_assortment/README.rst create mode 100644 product_assortment/__init__.py create mode 100644 product_assortment/__manifest__.py create mode 100644 product_assortment/i18n/product_assortment.pot create mode 100644 product_assortment/models/__init__.py create mode 100644 product_assortment/models/ir_filters.py create mode 100644 product_assortment/readme/CONTRIBUTORS.rst create mode 100644 product_assortment/readme/DESCRIPTION.rst create mode 100644 product_assortment/readme/USAGE.rst create mode 100644 product_assortment/static/description/icon.png create mode 100644 product_assortment/static/description/index.html create mode 100644 product_assortment/tests/__init__.py create mode 100644 product_assortment/tests/test_product_assortment.py create mode 100644 product_assortment/views/product_assortment.xml diff --git a/product_assortment/README.rst b/product_assortment/README.rst new file mode 100644 index 00000000000..a0e93c720ea --- /dev/null +++ b/product_assortment/README.rst @@ -0,0 +1,88 @@ +================== +Product Assortment +================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/10.0/product_assortment + :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-10-0/product-attribute-10-0-product_assortment + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/135/10.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +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 also add some +products to include or to exclude through a white list and a black list. +This is done by overriding ir.capability but without influencing its standard +behaviour. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + + +To use this module, you need to: + +#. Enter the menu through Product Assortment Icon +#. Create a new filter where you can define your domain and add whitelisted and blacklisted products + +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 smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* ACSONE SA/NV + +Contributors +~~~~~~~~~~~~ + +* Denis Roussel +* Cédric Pigeon + +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 `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_assortment/__init__.py b/product_assortment/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/product_assortment/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/product_assortment/__manifest__.py b/product_assortment/__manifest__.py new file mode 100644 index 00000000000..fbc3fe66a25 --- /dev/null +++ b/product_assortment/__manifest__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + 'name': 'Product Assortment', + 'summary': """ + Adds the ability to manage products assortment""", + 'version': '10.0.1.0.0', + 'license': 'AGPL-3', + 'author': 'ACSONE SA/NV,Odoo Community Association (OCA)', + 'website': 'https://acsone.eu', + 'depends': [ + 'base', + 'product', + 'web_widget_domain_v11', + ], + 'data': [ + 'views/product_assortment.xml', + ], +} diff --git a/product_assortment/i18n/product_assortment.pot b/product_assortment/i18n/product_assortment.pot new file mode 100644 index 00000000000..9083bb8ea21 --- /dev/null +++ b/product_assortment/i18n/product_assortment.pot @@ -0,0 +1,88 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_assortment +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: product_assortment +#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_form +msgid "Products" +msgstr "" + +#. module: product_assortment +#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_form +#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_search +msgid "Assortment Name" +msgstr "" + +#. module: product_assortment +#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_search +msgid "Assortments" +msgstr "" + +#. module: product_assortment +#: model:ir.model.fields,field_description:product_assortment.field_ir_filters_blacklist_product_ids +msgid "Blacklist product ids" +msgstr "" + +#. module: product_assortment +#: model:ir.model,name:product_assortment.model_ir_filters +#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_form +msgid "Filters" +msgstr "" + +#. module: product_assortment +#: model:ir.model.fields,field_description:product_assortment.field_ir_filters_is_assortment +msgid "Is assortment" +msgstr "" + +#. module: product_assortment +#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_form +msgid "Product" +msgstr "" + +#. module: product_assortment +#: model:ir.ui.menu,name:product_assortment.menu_product_assortments +msgid "Product Assortment" +msgstr "" + +#. module: product_assortment +#: model:ir.actions.act_window,name:product_assortment.actions_product_assortment_view +msgid "Product assortment" +msgstr "" + +#. module: product_assortment +#: code:addons/product_assortment/models/ir_filters.py:79 +#, python-format +msgid "Products" +msgstr "" + +#. module: product_assortment +#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_form +msgid "Products to exclude" +msgstr "" + +#. module: product_assortment +#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_form +msgid "Products to include" +msgstr "" + +#. module: product_assortment +#: model:ir.model.fields,field_description:product_assortment.field_ir_filters_record_count +msgid "Record count" +msgstr "" + +#. module: product_assortment +#: model:ir.model.fields,field_description:product_assortment.field_ir_filters_whitelist_product_ids +msgid "Whitelist product ids" +msgstr "" + diff --git a/product_assortment/models/__init__.py b/product_assortment/models/__init__.py new file mode 100644 index 00000000000..4c520abbe48 --- /dev/null +++ b/product_assortment/models/__init__.py @@ -0,0 +1 @@ +from . import ir_filters diff --git a/product_assortment/models/ir_filters.py b/product_assortment/models/ir_filters.py new file mode 100644 index 00000000000..8096173af24 --- /dev/null +++ b/product_assortment/models/ir_filters.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import api, fields, models, _ +from odoo.osv import expression + + +class ProductAssortment(models.Model): + _inherit = 'ir.filters' + + @api.model + def _get_default_model(self): + if self.env.context.get('product_assortment', False): + model = self.env.ref('product.model_product_product') + return model.model + return '' + + @api.model + def _get_default_is_assortment(self): + if self.env.context.get('product_assortment', False): + return True + return False + + model_id = fields.Selection( + default=lambda x: x._get_default_model()) + + blacklist_product_ids = fields.Many2many( + comodel_name='product.product', + relation='assortment_product_blacklisted') + + whitelist_product_ids = fields.Many2many( + comodel_name='product.product', + relation='assortment_product_whitelisted') + + record_count = fields.Integer(compute='_compute_record_count') + + is_assortment = fields.Boolean( + default=lambda x: x._get_default_is_assortment()) + + @api.multi + def _get_eval_domain(self): + res = super(ProductAssortment, self)._get_eval_domain() + + if self.whitelist_product_ids and res: + result_domain = [('id', 'in', self.whitelist_product_ids.ids)] + res = expression.OR([result_domain, res]) + + if self.blacklist_product_ids: + result_domain = [('id', 'not in', self.blacklist_product_ids.ids)] + res = expression.AND([result_domain, res]) + + return res + + @api.multi + def _compute_record_count(self): + for record in self: + domain = record._get_eval_domain() + record.record_count = self.env[ + record.model_id].search_count(domain) + + @api.model + def _get_action_domain(self, action_id=None): + # tricky way to act on get_filter method to prevent returning + # assortment in search view filters + domain = super(ProductAssortment, + self)._get_action_domain(action_id=action_id) + domain = expression.AND([ + [('is_assortment', '=', False)], + domain, + ]) + + return domain + + @api.multi + def show_products(self): + self.ensure_one() + return { + 'type': 'ir.actions.act_window', + 'name': _("Products"), + 'res_model': 'product.product', + 'domain': self._get_eval_domain(), + 'view_type': 'form', + 'view_mode': 'tree, form', + 'context': self.env.context, + 'target': 'current', + } diff --git a/product_assortment/readme/CONTRIBUTORS.rst b/product_assortment/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..3e696282f39 --- /dev/null +++ b/product_assortment/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Denis Roussel +* Cédric Pigeon diff --git a/product_assortment/readme/DESCRIPTION.rst b/product_assortment/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..6a94b870f58 --- /dev/null +++ b/product_assortment/readme/DESCRIPTION.rst @@ -0,0 +1,6 @@ +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 also add some +products to include or to exclude through a white list and a black list. +This is done by overriding ir.capability but without influencing its standard +behaviour. diff --git a/product_assortment/readme/USAGE.rst b/product_assortment/readme/USAGE.rst new file mode 100644 index 00000000000..9791683313b --- /dev/null +++ b/product_assortment/readme/USAGE.rst @@ -0,0 +1,5 @@ + +To use this module, you need to: + +#. Enter the menu through Product Assortment Icon +#. Create a new filter where you can define your domain and add whitelisted and blacklisted products diff --git a/product_assortment/static/description/icon.png b/product_assortment/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/product_assortment/static/description/index.html b/product_assortment/static/description/index.html new file mode 100644 index 00000000000..6ab1cab3ef5 --- /dev/null +++ b/product_assortment/static/description/index.html @@ -0,0 +1,434 @@ + + + + + + +Product Assortment + + + +
+

Product Assortment

+ + +

Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runbot

+

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 also add some +products to include or to exclude through a white list and a black list. +This is done by overriding ir.capability but without influencing its standard +behaviour.

+

Table of contents

+ +
+

Usage

+

To use this module, you need to:

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

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 smashing it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • ACSONE SA/NV
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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 project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/product_assortment/tests/__init__.py b/product_assortment/tests/__init__.py new file mode 100644 index 00000000000..7c6e5f94694 --- /dev/null +++ b/product_assortment/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_assortment diff --git a/product_assortment/tests/test_product_assortment.py b/product_assortment/tests/test_product_assortment.py new file mode 100644 index 00000000000..0e5d7daff0e --- /dev/null +++ b/product_assortment/tests/test_product_assortment.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import TransactionCase + + +class TestProductAssortment(TransactionCase): + + def setUp(self): + super(TestProductAssortment, self).setUp() + self.filter_obj = self.env['ir.filters'] + self.product_obj = self.env['product.product'] + self.assortment = self.filter_obj.create({ + 'name': 'Test Assortment', + 'model_id': 'product.product', + 'is_assortment': True, + 'domain': [], + }) + + def test_assortment(self): + products = self.product_obj.search([]) + domain = self.assortment._get_eval_domain() + products_filtered = self.product_obj.search(domain) + self.assertEqual(products.ids, products_filtered.ids) + + # reduce assortment to services products + domain = [('type', '=', 'service')] + self.assortment.domain = domain + + products = self.product_obj.search(domain) + domain = self.assortment._get_eval_domain() + products_filtered = self.product_obj.search(domain) + self.assertEqual(products.ids, products_filtered.ids) + + # include one product not in initial filter + included_product = self.env.ref('product.product_product_7') + self.assortment.write({ + 'whitelist_product_ids': [(4, included_product.id)]}) + domain = self.assortment._get_eval_domain() + products_filtered = self.product_obj.search(domain) + self.assertIn(included_product.id, products_filtered.ids) + + # exclude one product not in initial filter + excluded_product = self.env.ref('product.service_delivery') + domain = self.assortment._get_eval_domain() + products_filtered = self.product_obj.search(domain) + self.assertIn(excluded_product.id, products_filtered.ids) + self.assortment.write({ + 'blacklist_product_ids': [(4, excluded_product.id)]}) + domain = self.assortment._get_eval_domain() + products_filtered = self.product_obj.search(domain) + self.assertNotIn(excluded_product.id, products_filtered.ids) + + def test_assortment_not_available_search_view(self): + model = self.env.ref('product.model_product_product') + filters = self.filter_obj.get_filters(model.id) + self.assertFalse(filters) + + def test_create_assortment_with_context(self): + assortment = self.filter_obj.with_context( + product_assortment=True).create({ + 'name': 'Test Assortment Context', + 'domain': []}) + self.assertTrue(assortment.is_assortment) + self.assertEqual(assortment.model_id, 'product.product') diff --git a/product_assortment/views/product_assortment.xml b/product_assortment/views/product_assortment.xml new file mode 100644 index 00000000000..e70f8e0424f --- /dev/null +++ b/product_assortment/views/product_assortment.xml @@ -0,0 +1,88 @@ + + + + + + product.assortment.search + ir.filters + + + + + + + + + + ir.filters + + + + + + + + + ir.filters + +
+ +
+ +
+ + + + + + + + + + +
+ + + + + + +
+
+ + + + + + +
+
+
+
+
+
+ + + Product assortment + ir.actions.act_window + ir.filters + [('is_assortment', '=', True)] + {'product_assortment': True, + 'default_is_assortment': 1} + + + + +
\ No newline at end of file From 81b7790c5178d82463cca301b89eb5b6772502db Mon Sep 17 00:00:00 2001 From: tbaden Date: Sat, 4 May 2019 19:50:11 +0200 Subject: [PATCH 02/65] [FIX][10.0] product_assortment travis warning --- product_assortment/views/product_assortment.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/product_assortment/views/product_assortment.xml b/product_assortment/views/product_assortment.xml index e70f8e0424f..ccb355d9781 100644 --- a/product_assortment/views/product_assortment.xml +++ b/product_assortment/views/product_assortment.xml @@ -85,4 +85,4 @@ - \ No newline at end of file + From e39bf5ac38306efb0844a00b65de514f51245283 Mon Sep 17 00:00:00 2001 From: Denis Roussel Date: Mon, 3 Jun 2019 16:12:01 +0200 Subject: [PATCH 03/65] [12.0][MIG] product_assortment --- product_assortment/README.rst | 36 ++++++++----- product_assortment/__manifest__.py | 10 ++-- .../i18n/product_assortment.pot | 41 ++++++++------- product_assortment/models/ir_filters.py | 3 +- product_assortment/readme/HISTORY.rst | 9 ++++ .../static/description/index.html | 52 +++++++++++++------ .../tests/test_product_assortment.py | 5 +- 7 files changed, 99 insertions(+), 57 deletions(-) create mode 100644 product_assortment/readme/HISTORY.rst diff --git a/product_assortment/README.rst b/product_assortment/README.rst index a0e93c720ea..a45f47b7a44 100644 --- a/product_assortment/README.rst +++ b/product_assortment/README.rst @@ -7,23 +7,20 @@ Product Assortment !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -.. |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 +.. |badge1| 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/10.0/product_assortment +.. |badge2| image:: https://img.shields.io/badge/github-OCA%2Fproduct--attribute-lightgray.png?logo=github + :target: https://github.com/OCA/product-attribute/tree/12.0/product_assortment :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-10-0/product-attribute-10-0-product_assortment +.. |badge3| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/product-attribute-12-0/product-attribute-12-0-product_assortment :alt: Translate me on Weblate -.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/135/10.0 +.. |badge4| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/135/12.0 :alt: Try me on Runbot -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| 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. @@ -46,13 +43,26 @@ To use this module, you need to: #. Enter the menu through Product Assortment Icon #. Create a new filter where you can define your domain and add whitelisted and blacklisted products +Changelog +========= + +10.0.1.0.0 (2018-08-27) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [10.0][ADD] product_assortment + +12.0.1.0.0 (2019-06-03) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [12.0][MIG] product_assortment + 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 smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -83,6 +93,6 @@ 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 `_ project on GitHub. +This module is part of the `OCA/product-attribute `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_assortment/__manifest__.py b/product_assortment/__manifest__.py index fbc3fe66a25..4f1790c3708 100644 --- a/product_assortment/__manifest__.py +++ b/product_assortment/__manifest__.py @@ -1,21 +1,21 @@ -# -*- coding: utf-8 -*- -# Copyright 2018 ACSONE SA/NV +# Copyright 2018-2019 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { 'name': 'Product Assortment', 'summary': """ Adds the ability to manage products assortment""", - 'version': '10.0.1.0.0', + 'version': '12.0.1.0.0', 'license': 'AGPL-3', + 'development_status': 'Stable/Production', 'author': 'ACSONE SA/NV,Odoo Community Association (OCA)', - 'website': 'https://acsone.eu', + 'website': 'https://github.com/OCA/product-attribute', 'depends': [ 'base', 'product', - 'web_widget_domain_v11', ], 'data': [ 'views/product_assortment.xml', ], + 'installable': True, } diff --git a/product_assortment/i18n/product_assortment.pot b/product_assortment/i18n/product_assortment.pot index 9083bb8ea21..d04407c9445 100644 --- a/product_assortment/i18n/product_assortment.pot +++ b/product_assortment/i18n/product_assortment.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 10.0\n" +"Project-Id-Version: Odoo Server 12.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: <>\n" "Language-Team: \n" @@ -14,39 +14,44 @@ msgstr "" "Plural-Forms: \n" #. module: product_assortment -#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_form +#: model_terms:ir.ui.view,arch_db:product_assortment.product_assortment_view_form msgid "Products" msgstr "" #. module: product_assortment -#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_form -#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_search +#: model_terms:ir.ui.view,arch_db:product_assortment.product_assortment_view_form +#: model_terms:ir.ui.view,arch_db:product_assortment.product_assortment_view_search msgid "Assortment Name" msgstr "" #. module: product_assortment -#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_search +#: model_terms:ir.ui.view,arch_db:product_assortment.product_assortment_view_search msgid "Assortments" msgstr "" #. module: product_assortment -#: model:ir.model.fields,field_description:product_assortment.field_ir_filters_blacklist_product_ids -msgid "Blacklist product ids" +#: model:ir.model.fields,field_description:product_assortment.field_ir_filters__blacklist_product_ids +msgid "Blacklist Product" msgstr "" #. module: product_assortment #: model:ir.model,name:product_assortment.model_ir_filters -#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_form +#: model_terms:ir.ui.view,arch_db:product_assortment.product_assortment_view_form msgid "Filters" msgstr "" #. module: product_assortment -#: model:ir.model.fields,field_description:product_assortment.field_ir_filters_is_assortment -msgid "Is assortment" +#: model:ir.model.fields,field_description:product_assortment.field_ir_filters__is_assortment +msgid "Is Assortment" msgstr "" #. module: product_assortment -#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_form +#: model:ir.model.fields,field_description:product_assortment.field_ir_filters__model_id +msgid "Model" +msgstr "" + +#. module: product_assortment +#: model_terms:ir.ui.view,arch_db:product_assortment.product_assortment_view_form msgid "Product" msgstr "" @@ -61,28 +66,28 @@ msgid "Product assortment" msgstr "" #. module: product_assortment -#: code:addons/product_assortment/models/ir_filters.py:79 +#: code:addons/product_assortment/models/ir_filters.py:78 #, python-format msgid "Products" msgstr "" #. module: product_assortment -#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_form +#: model_terms:ir.ui.view,arch_db:product_assortment.product_assortment_view_form msgid "Products to exclude" msgstr "" #. module: product_assortment -#: model:ir.ui.view,arch_db:product_assortment.product_assortment_view_form +#: model_terms:ir.ui.view,arch_db:product_assortment.product_assortment_view_form msgid "Products to include" msgstr "" #. module: product_assortment -#: model:ir.model.fields,field_description:product_assortment.field_ir_filters_record_count -msgid "Record count" +#: model:ir.model.fields,field_description:product_assortment.field_ir_filters__record_count +msgid "Record Count" msgstr "" #. module: product_assortment -#: model:ir.model.fields,field_description:product_assortment.field_ir_filters_whitelist_product_ids -msgid "Whitelist product ids" +#: model:ir.model.fields,field_description:product_assortment.field_ir_filters__whitelist_product_ids +msgid "Whitelist Product" msgstr "" diff --git a/product_assortment/models/ir_filters.py b/product_assortment/models/ir_filters.py index 8096173af24..92824568508 100644 --- a/product_assortment/models/ir_filters.py +++ b/product_assortment/models/ir_filters.py @@ -1,5 +1,4 @@ -# -*- coding: utf-8 -*- -# Copyright 2018 ACSONE SA/NV +# Copyright 2018-2019 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import api, fields, models, _ from odoo.osv import expression diff --git a/product_assortment/readme/HISTORY.rst b/product_assortment/readme/HISTORY.rst new file mode 100644 index 00000000000..13f4794e2e0 --- /dev/null +++ b/product_assortment/readme/HISTORY.rst @@ -0,0 +1,9 @@ +10.0.1.0.0 (2018-08-27) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [10.0][ADD] product_assortment + +12.0.1.0.0 (2019-06-03) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [12.0][MIG] product_assortment diff --git a/product_assortment/static/description/index.html b/product_assortment/static/description/index.html index 6ab1cab3ef5..3c96edbcff3 100644 --- a/product_assortment/static/description/index.html +++ b/product_assortment/static/description/index.html @@ -3,7 +3,7 @@ - + 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 @@ -397,7 +402,7 @@

Product Assortment

-

Usage

+

Usage

To use this module, you need to:

  1. Enter the menu through Product Assortment Icon
  2. @@ -406,34 +411,34 @@

    Usage

-

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] productassortment
-

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 @@ -441,15 +446,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 @@ -475,5 +480,6 @@

Maintainers

+
From 161a9ee57064227fbd733f15ed4f9e637e0f1e52 Mon Sep 17 00:00:00 2001 From: CarlosRoca13 Date: Mon, 13 Dec 2021 13:32:09 +0100 Subject: [PATCH 60/65] [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 6e94d675b2368125d14395c6c71b25475cc0b5fc Mon Sep 17 00:00:00 2001 From: Carlos Dauden Date: Fri, 22 Mar 2024 00:40:29 +0100 Subject: [PATCH 61/65] [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 3da6ee8c8e1d535aacd5032888cfa073450f4827 Mon Sep 17 00:00:00 2001 From: sergio-teruel Date: Mon, 30 Sep 2024 22:48:56 +0200 Subject: [PATCH 62/65] [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 bc1c997ad794b4309c77bb73da3676fd9281e4e6 Mon Sep 17 00:00:00 2001 From: bosd Date: Sat, 1 Feb 2025 14:41:06 +0100 Subject: [PATCH 63/65] [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 4658a4da9c56aad422f41d0f5147f5c7d69a2c31 Mon Sep 17 00:00:00 2001 From: bosd Date: Sat, 1 Feb 2025 21:27:53 +0100 Subject: [PATCH 64/65] [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 80d4b8562c712b813d037276fdb4a1d4e4de6835 Mon Sep 17 00:00:00 2001 From: Ruchir Shukla Date: Tue, 13 Jan 2026 14:12:20 +0530 Subject: [PATCH 65/65] [MIG] product_assortment: Migration to 19.0 --- product_assortment/README.rst | 24 ++++++-- product_assortment/__manifest__.py | 2 +- .../migrations/18.0.1.0.0/pre-migrate.py | 37 ------------ product_assortment/models/ir_filters.py | 15 +++-- product_assortment/models/ir_rule.py | 7 +-- .../static/description/index.html | 42 +++++++------ .../tests/test_product_assortment.py | 60 +++++++++++++------ .../views/product_assortment.xml | 7 --- 8 files changed, 94 insertions(+), 100 deletions(-) delete mode 100644 product_assortment/migrations/18.0.1.0.0/pre-migrate.py diff --git a/product_assortment/README.rst b/product_assortment/README.rst index 5c8ab343727..29ace043841 100644 --- a/product_assortment/README.rst +++ b/product_assortment/README.rst @@ -1,3 +1,7 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + ================== Product Assortment ================== @@ -13,17 +17,17 @@ 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/licence-AGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/license-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/18.0/product_assortment + :target: https://github.com/OCA/product-attribute/tree/19.0/product_assortment :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-18-0/product-attribute-18-0-product_assortment + :target: https://translation.odoo-community.org/projects/product-attribute-19-0/product-attribute-19-0-product_assortment :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=18.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/product-attribute&target_branch=19.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -57,21 +61,29 @@ Changelog - [10.0][ADD] productassortment +.. _section-1: + 12.0.1.0.0 (2019-06-03) ----------------------- - [12.0][MIG] productassortment +.. _section-2: + 14.0.1.0.0 (2019-06-03) ----------------------- - [14.0][MIG] productassortment +.. _section-3: + 16.0.1.0.0 (2022-09-15) ----------------------- - [16.0][MIG] product_assortment +.. _section-4: + 18.0.1.0.0 (2025-03-06) ----------------------- @@ -92,7 +104,7 @@ 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 -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -128,6 +140,6 @@ 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 `_ project on GitHub. +This module is part of the `OCA/product-attribute `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_assortment/__manifest__.py b/product_assortment/__manifest__.py index 5c8746e197d..e5c6bab5775 100644 --- a/product_assortment/__manifest__.py +++ b/product_assortment/__manifest__.py @@ -6,7 +6,7 @@ "name": "Product Assortment", "summary": """ Adds the ability to manage products assortment""", - "version": "18.0.1.0.1", + "version": "19.0.1.0.0", "license": "AGPL-3", "development_status": "Production/Stable", "author": "ACSONE SA/NV,Odoo Community Association (OCA)", diff --git a/product_assortment/migrations/18.0.1.0.0/pre-migrate.py b/product_assortment/migrations/18.0.1.0.0/pre-migrate.py deleted file mode 100644 index 94354337fbe..00000000000 --- a/product_assortment/migrations/18.0.1.0.0/pre-migrate.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (C) 2025 The O-team -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from openupgradelib import openupgrade - - -def migrate(cr, version): - """Update the `domain` value to `[(1, "=", 0)]`. - - This is needed to retain the behavior of the module available in older versions of - the module. In older versions, the `whitelist_product_ids` field was not required - to be set explicitly to a void domain when used in combination with the - 'whitelisted_product_ids' field. When the `whitelist_product_ids` field was empty, - the `domain` field was ignored. - - However, due to a change in the ORM, the `domain` field is now always applied, - even if the `whitelist_product_ids` field is empty. This change has caused the - behavior to differ from previous versions of the module. - - To restore the previous behavior, we need to set the `domain` field to a - non-empty domain, such as `[(1, "=", 0)]`, which will always return False and - effectively ignore the `domain` field. - """ - openupgrade.logged_query( - cr, - """ - UPDATE ir_filters irf - SET domain = '[("id", "=", 0)]' - WHERE irf.is_assortment = True - AND irf.domain = '[]' - AND EXISTS( - SELECT 1 - FROM assortment_product_whitelisted apw - WHERE apw.ir_filters_id = irf.id - ) - """, - ) diff --git a/product_assortment/models/ir_filters.py b/product_assortment/models/ir_filters.py index d8651e7bc2a..315571ffb9b 100644 --- a/product_assortment/models/ir_filters.py +++ b/product_assortment/models/ir_filters.py @@ -3,7 +3,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import api, fields, models -from odoo.osv import expression +from odoo.fields import Domain from odoo.tools import ormcache from odoo.tools.safe_eval import datetime, safe_eval @@ -103,17 +103,15 @@ def _get_eval_domain(self): res = super()._get_eval_domain() if self.apply_black_list_product_domain: black_list_domain = self._get_eval_black_list_domain() - res = expression.AND( - [expression.distribute_not(["!"] + black_list_domain), res] - ) + res = Domain.AND([~Domain(black_list_domain), Domain(res)]) if self.whitelist_product_ids: result_domain = [("id", "in", self.whitelist_product_ids.ids)] - res = expression.OR([result_domain, res]) + res = Domain.OR([result_domain, Domain(res)]) if self.blacklist_product_ids: result_domain = [("id", "not in", self.blacklist_product_ids.ids)] - res = expression.AND([result_domain, res]) + res = Domain.AND([result_domain, Domain(res)]) return res @@ -133,7 +131,8 @@ def _get_eval_partner_domain(self): def _compute_record_count(self): for record in self: - if not record.is_assortment: + # model_id may be unset on new records, skip count to prevent errors + if not record.is_assortment or not record.model_id: record.record_count = 0 continue domain = record._get_eval_domain() @@ -150,7 +149,7 @@ def _get_action_domain( embedded_action_id=embedded_action_id, embedded_parent_res_id=embedded_parent_res_id, ) - domain = expression.AND([[("is_assortment", "=", False)], domain]) + domain = Domain.AND([Domain([("is_assortment", "=", False)]), Domain(domain)]) return domain diff --git a/product_assortment/models/ir_rule.py b/product_assortment/models/ir_rule.py index 48c80a52225..e077978cb42 100644 --- a/product_assortment/models/ir_rule.py +++ b/product_assortment/models/ir_rule.py @@ -2,7 +2,7 @@ # 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.fields import Domain from odoo.tools import config @@ -30,7 +30,6 @@ def _compute_domain(self, model_name, mode="read"): 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]) + extra_domain = Domain([("is_assortment", "=", False)]) + res = Domain.AND([extra_domain] + [res]) return res diff --git a/product_assortment/static/description/index.html b/product_assortment/static/description/index.html index ce178c6db58..e12b3d47927 100644 --- a/product_assortment/static/description/index.html +++ b/product_assortment/static/description/index.html @@ -3,7 +3,7 @@ -Product Assortment +README.rst -
    -

    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 @@ -398,7 +403,7 @@

    Product Assortment

    -

    Usage

    +

    Usage

    To use this module, you need to:

    1. Enter the menu through the Product Assortment Icon
    2. @@ -407,33 +412,33 @@

      Usage

    -

    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)

    +

    18.0.1.0.0 (2025-03-06)

    -

    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 -feedback.

    +feedback.

    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 @@ -486,10 +491,11 @@

    Maintainers

    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 project on GitHub.

    +

    This module is part of the OCA/product-attribute project on GitHub.

    You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

    +
    diff --git a/product_assortment/tests/test_product_assortment.py b/product_assortment/tests/test_product_assortment.py index 367ad9a89dd..88df4e9131e 100644 --- a/product_assortment/tests/test_product_assortment.py +++ b/product_assortment/tests/test_product_assortment.py @@ -7,11 +7,30 @@ class TestProductAssortment(TransactionCase): - def setUp(self): - super().setUp() - self.filter_obj = self.env["ir.filters"] - self.product_obj = self.env["product.product"] - self.assortment = self.filter_obj.create( + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.filter_obj = cls.env["ir.filters"] + cls.product_obj = cls.env["product.product"] + cls.product_storage_box = cls.product_obj.create( + { + "name": "Storage Box", + "type": "consu", + "standard_price": 14.0, + "list_price": 15.8, + "default_code": "E-COM08", + } + ) + cls.product_virtual_home_staging = cls.product_obj.create( + { + "name": "Virtual Home Staging", + "type": "service", + "standard_price": 25.5, + "list_price": 38.25, + } + ) + cls.assortment = cls.filter_obj.create( { "name": "Test Assortment", "model_id": "product.product", @@ -19,8 +38,8 @@ def setUp(self): "domain": [], } ) - self.partner = self.env["res.partner"].create({"name": "Test partner"}) - self.partner2 = self.env["res.partner"].create({"name": "Test partner 2"}) + cls.partner = cls.env["res.partner"].create({"name": "Test partner"}) + cls.partner2 = cls.env["res.partner"].create({"name": "Test partner 2"}) def test_assortment(self): products = self.product_obj.search([]) @@ -38,14 +57,14 @@ def test_assortment(self): self.assertEqual(products.ids, products_filtered.ids) # include one product not in initial filter - included_product = self.env.ref("product.product_product_7") + included_product = self.product_storage_box self.assortment.write({"whitelist_product_ids": [(4, included_product.id)]}) domain = self.assortment._get_eval_domain() products_filtered = self.product_obj.search(domain) self.assertIn(included_product.id, products_filtered.ids) # exclude one product not in initial filter - excluded_product = self.env.ref("product.product_product_2") + excluded_product = self.product_virtual_home_staging domain = self.assortment._get_eval_domain() products_filtered = self.product_obj.search(domain) self.assertIn(excluded_product.id, products_filtered.ids) @@ -91,24 +110,26 @@ def test_search_assortment_with_partner(self): ) def test_product_assortment_view(self): - included_product = self.env.ref("product.product_product_7") + included_product = self.product_storage_box self.assortment.write({"whitelist_product_ids": [(4, included_product.id)]}) res = self.assortment.show_products() - self.assertEqual(res["domain"], [(1, "=", 1)]) + domain = [tuple(condition) for condition in res["domain"]] + self.assertEqual(domain, [(1, "=", 1)]) def test_product_assortment_view_with_black_list(self): - excluded_product = self.env.ref("product.product_product_7") + excluded_product = self.product_virtual_home_staging self.assortment.write( { "blacklist_product_ids": [(4, excluded_product.id)], } ) res = self.assortment.show_products() - self.assertEqual(res["domain"], [("id", "not in", excluded_product.ids)]) + domain = [tuple(condition) for condition in res["domain"]] + self.assertEqual(domain, [("id", "not in", excluded_product.ids)]) def test_product_assortment_mixed_view(self): - included_product = self.env.ref("product.product_product_7") - excluded_product = self.env.ref("product.product_product_2") + included_product = self.product_storage_box + excluded_product = self.product_virtual_home_staging self.assortment.write( { "whitelist_product_ids": [(4, included_product.id)], @@ -116,7 +137,8 @@ def test_product_assortment_mixed_view(self): } ) res = self.assortment.show_products() - self.assertEqual(res["domain"], [("id", "not in", excluded_product.ids)]) + domain = [tuple(condition) for condition in res["domain"]] + self.assertEqual(domain, [("id", "not in", excluded_product.ids)]) def test_product_assortment_filter_combination(self): """Combine a whitelisted and a blacklisted product in order @@ -125,9 +147,9 @@ def test_product_assortment_filter_combination(self): """ # Add a default no product filter to the assortment self.assortment.write({"domain": [("id", "=", 0)]}) - included_product = self.env.ref("product.product_product_7") + included_product = self.product_storage_box self.assortment.write({"whitelist_product_ids": [(4, included_product.id)]}) - excluded_product = self.env.ref("product.product_product_2") + excluded_product = self.product_virtual_home_staging 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"]) @@ -170,7 +192,7 @@ def test_assortment_update_with_multiple_partner(self): self.assertEqual(assortment.all_partner_ids, self.partner + self.partner2) def test_assortment_with_black_list_product_domain(self): - excluded_product = self.env.ref("product.product_product_7") + excluded_product = self.product_virtual_home_staging assortment = self.filter_obj.with_context(product_assortment=True).create( { "name": "Test Assortment black product domain", diff --git a/product_assortment/views/product_assortment.xml b/product_assortment/views/product_assortment.xml index 6b298911f48..1336c65c5ea 100644 --- a/product_assortment/views/product_assortment.xml +++ b/product_assortment/views/product_assortment.xml @@ -60,13 +60,6 @@ - - - - - - -