diff --git a/base_search_multi_value/README.rst b/base_search_multi_value/README.rst new file mode 100644 index 0000000000..53c39ab4fa --- /dev/null +++ b/base_search_multi_value/README.rst @@ -0,0 +1,100 @@ +======================= +Base Search Multi Value +======================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:2e02cbe72fef34832e26be3ad7f1db4c8bb59ffc6c4da2afe993e4ebd08e6118 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fserver--ux-lightgray.png?logo=github + :target: https://github.com/OCA/server-ux/tree/16.0/base_search_multi_value + :alt: OCA/server-ux +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/server-ux-16-0/server-ux-16-0-base_search_multi_value + :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/server-ux&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows users to search any arbitrary field using +space-separated values. + +For example for sale orders you could search: S00001 S00002 S00003 and +it would return these three records. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Inherit search.multi.value.mixin on your model and implement the search +fields getter + +Known issues / Roadmap +====================== + +- add arbitrary delimiter + +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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Akretion + +Contributors +------------ + +- Kevin Khao kevin.khao@akretion.com + +Other credits +------------- + +This module is heavily inspired by product_search_multi_value, credits +to the creators: + +- Cédric PIGEON cedric.pigeon@acsone.eu +- Xavier Bouquiaux xavier.bouquiaux@acsone.eu + +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/server-ux `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/base_search_multi_value/__init__.py b/base_search_multi_value/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/base_search_multi_value/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/base_search_multi_value/__manifest__.py b/base_search_multi_value/__manifest__.py new file mode 100644 index 0000000000..58ae75182a --- /dev/null +++ b/base_search_multi_value/__manifest__.py @@ -0,0 +1,15 @@ +# Copyright 2024 Akretion +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Base Search Multi Value", + "summary": """ + Search multiple space-separated values""", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "author": "Akretion,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/server-ux", + "depends": ["base"], + "data": [], + "demo": [], +} diff --git a/base_search_multi_value/models/__init__.py b/base_search_multi_value/models/__init__.py new file mode 100644 index 0000000000..ad79756867 --- /dev/null +++ b/base_search_multi_value/models/__init__.py @@ -0,0 +1 @@ +from . import search_multi_value_mixin diff --git a/base_search_multi_value/models/search_multi_value_mixin.py b/base_search_multi_value/models/search_multi_value_mixin.py new file mode 100644 index 0000000000..50b21a873b --- /dev/null +++ b/base_search_multi_value/models/search_multi_value_mixin.py @@ -0,0 +1,40 @@ +# Copyright 2024 Akretion +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import UserError +from odoo.osv.expression import OR + + +class SearchMultiValueMixin(models.AbstractModel): + + _name = "search.multi.value.mixin" + _description = "Mixin to allow delimiter-separated searches" + + search_multi = fields.Char( + "Multiple search", + compute="_compute_search_multi", + search="_search_multi", + ) + + def _compute_search_multi(self): + self.update({"search_multi": False}) + + @api.model + def _get_search_fields_multi_value(self): + raise NotImplementedError + + def _search_multi(self, operator, value): + if operator == "=" or operator == "ilike": + operator = "in" + comparator = OR + else: + raise UserError(_("Operator %s is not usable with multisearch", operator)) + + value_list = value.split(" ") if " " in value else [value] + search_fields = self._get_search_fields_multi_value() + domain_list = [] + for search_field in search_fields: + domain_search_field = [(search_field, operator, tuple(value_list))] + domain_list.append(domain_search_field) + return comparator(domain_list) diff --git a/base_search_multi_value/readme/CONTRIBUTORS.md b/base_search_multi_value/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..06a2116feb --- /dev/null +++ b/base_search_multi_value/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +* Kevin Khao diff --git a/base_search_multi_value/readme/CREDITS.md b/base_search_multi_value/readme/CREDITS.md new file mode 100644 index 0000000000..ed3189ad29 --- /dev/null +++ b/base_search_multi_value/readme/CREDITS.md @@ -0,0 +1,4 @@ +This module is heavily inspired by product_search_multi_value, credits to the creators: + +* Cédric PIGEON +* Xavier Bouquiaux diff --git a/base_search_multi_value/readme/DESCRIPTION.md b/base_search_multi_value/readme/DESCRIPTION.md new file mode 100644 index 0000000000..b756f0eb62 --- /dev/null +++ b/base_search_multi_value/readme/DESCRIPTION.md @@ -0,0 +1,3 @@ +This module allows users to search any arbitrary field using space-separated values. + +For example for sale orders you could search: S00001 S00002 S00003 and it would return these three records. diff --git a/base_search_multi_value/readme/ROADMAP.md b/base_search_multi_value/readme/ROADMAP.md new file mode 100644 index 0000000000..9fa3b0303e --- /dev/null +++ b/base_search_multi_value/readme/ROADMAP.md @@ -0,0 +1 @@ +* add arbitrary delimiter diff --git a/base_search_multi_value/readme/USAGE.md b/base_search_multi_value/readme/USAGE.md new file mode 100644 index 0000000000..659fbce2b3 --- /dev/null +++ b/base_search_multi_value/readme/USAGE.md @@ -0,0 +1 @@ +Inherit search.multi.value.mixin on your model and implement the search fields getter diff --git a/base_search_multi_value/static/description/icon.png b/base_search_multi_value/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/base_search_multi_value/static/description/icon.png differ diff --git a/base_search_multi_value/static/description/index.html b/base_search_multi_value/static/description/index.html new file mode 100644 index 0000000000..64de85c0ce --- /dev/null +++ b/base_search_multi_value/static/description/index.html @@ -0,0 +1,449 @@ + + + + + +Base Search Multi Value + + + +
+

Base Search Multi Value

+ + +

Beta License: AGPL-3 OCA/server-ux Translate me on Weblate Try me on Runboat

+

This module allows users to search any arbitrary field using +space-separated values.

+

For example for sale orders you could search: S00001 S00002 S00003 and +it would return these three records.

+

Table of contents

+ +
+

Usage

+

Inherit search.multi.value.mixin on your model and implement the search +fields getter

+
+
+

Known issues / Roadmap

+
    +
  • add arbitrary delimiter
  • +
+
+
+

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.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Akretion
  • +
+
+ +
+

Other credits

+

This module is heavily inspired by product_search_multi_value, credits +to the creators:

+ +
+
+

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

+

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

+
+
+
+ + diff --git a/base_search_multi_value/tests/__init__.py b/base_search_multi_value/tests/__init__.py new file mode 100644 index 0000000000..f7a5c09e31 --- /dev/null +++ b/base_search_multi_value/tests/__init__.py @@ -0,0 +1 @@ +from . import test_search_multi_value diff --git a/base_search_multi_value/tests/models.py b/base_search_multi_value/tests/models.py new file mode 100644 index 0000000000..e8bb280975 --- /dev/null +++ b/base_search_multi_value/tests/models.py @@ -0,0 +1,10 @@ +from odoo import api, models + + +class ResPartner(models.Model): + _inherit = ["res.partner", "search.multi.value.mixin"] + _name = "res.partner" + + @api.model + def _get_search_fields(self): + return ["name", "email"] diff --git a/base_search_multi_value/tests/test_search_multi_value.py b/base_search_multi_value/tests/test_search_multi_value.py new file mode 100644 index 0000000000..17efaeb45c --- /dev/null +++ b/base_search_multi_value/tests/test_search_multi_value.py @@ -0,0 +1,47 @@ +# Copyright 2024 Akretion +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo_test_helper import FakeModelLoader + +from odoo.tests.common import TransactionCase + + +class TestSearchMultiValue(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.loader = FakeModelLoader(cls.env, cls.__module__) + cls.loader.backup_registry() + from .test_models import ResPartner + + cls.loader.update_registry((ResPartner,)) + + @classmethod + def tearDownClass(cls): + super().tearDownClass() + cls.loader.restore_registry() + return super().tearDownClass() + + def setUp(self): + super().setUp() + self.partners = self.env["res.partner"] + for i in range(1, 10): + self.partners += self.env["res.partner"].create( + {"name": f"Testpartner{i}", "email": f"email@test{i}"} + ) + self.names = self.partners.mapped("name") + self.emails = self.partners.mapped("email") + + def test_multi_search(self): + self.assertEqual( + self.partners, + self.env["res.partner"].search( + [("search_multi", "=", " ".join(self.names))] + ), + ) + self.assertEqual( + self.partners, + self.env["res.partner"].search( + [("search_multi", "=", " ".join(self.emails))] + ), + ) diff --git a/setup/base_search_multi_value/odoo/addons/base_search_multi_value b/setup/base_search_multi_value/odoo/addons/base_search_multi_value new file mode 120000 index 0000000000..8c999e7029 --- /dev/null +++ b/setup/base_search_multi_value/odoo/addons/base_search_multi_value @@ -0,0 +1 @@ +../../../../base_search_multi_value \ No newline at end of file diff --git a/setup/base_search_multi_value/setup.py b/setup/base_search_multi_value/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/base_search_multi_value/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)