diff --git a/setup/web_advanced_search/odoo/addons/web_advanced_search b/setup/web_advanced_search/odoo/addons/web_advanced_search new file mode 120000 index 000000000000..77a1d3db86cc --- /dev/null +++ b/setup/web_advanced_search/odoo/addons/web_advanced_search @@ -0,0 +1 @@ +../../../../web_advanced_search \ No newline at end of file diff --git a/setup/web_advanced_search/setup.py b/setup/web_advanced_search/setup.py new file mode 100644 index 000000000000..28c57bb64031 --- /dev/null +++ b/setup/web_advanced_search/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/web_advanced_search/README.rst b/web_advanced_search/README.rst new file mode 100644 index 000000000000..1284d8606089 --- /dev/null +++ b/web_advanced_search/README.rst @@ -0,0 +1,190 @@ +=============== +Advanced search +=============== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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%2Fweb-lightgray.png?logo=github + :target: https://github.com/OCA/web/tree/15.0/web_advanced_search + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-15-0/web-15-0-web_advanced_search + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/162/15.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +More powerful and easy to use search, especially for related fields. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module, you need to: + +* Open *Filters* in a search view +* Select any relational field +* Select operator `is equal to` or `is not equal to` +* The text field changes to a relational selection field where you + can search for the record in question +* Click *Apply* + +To search for properties of linked records (ie invoices for customers +with a credit limit higher than X): + +* Open *Filters* in a search view +* Select *Add Advanced Filter* +* Edit the advanced filter +* Click *Save* + +Note that you can stack searching for properties: Simply add another +advanced search in the selection search window. You can do +this indefinetely, so it is possible to search for moves belonging +to a journal which has a user who is member of a certain group etc. + +Note also the domain dialog offers an editable preview in debug mode: + .. image:: https://raw.githubusercontent.com/OCA/web/15.0/web_advanced_search/static/img/debug_mode.png + +Known issues / Roadmap +====================== + +Improvements to the ``domain`` widget, not exclusively related to this addon: + +* Use relational widgets when filtering a relational field +* Allow to filter field names + +Improvements to the search view in this addon: + +* Use widgets ``one2many_tags`` when searching ``one2many`` fields +* Use widgets ``many2many_tags`` when searching ``many2many`` fields +* Allow to edit current full search using the advanced domain editor + +Issues: + +* Grouped totals can show incorrect values. See https://github.com/odoo/odoo/issues/47950 + +Changelog +========= + +11.0.1.0.2 (2018-10-31) +~~~~~~~~~~~~~~~~~~~~~~~ + +* Fix initialization of 1st domain node + + Sometime the dialog is not ready yet, like on EE version. + Hence when you inject the 1st domain node + the dialog must be already opened. + + [simahawk] + + +11.0.1.0.1 (2018-09-18) +~~~~~~~~~~~~~~~~~~~~~~~ + +* Fix `undefined` in x2m fields + + Before this patch, when searching with the "equals to" operator in any + x2many field, the searched parameter was always `undefined`. + + The problem was that the underlying field manager implementation was + treating those fields as x2many, while the widget used was the `one2many` + one. + + This patch simply mocks the underlying fake record to make think that + any relational field is always a `one2many`. This sets all pieces in + place and makes the field manager work as expected, and thus you can + search as expected too. + +* Make linter happy + + [Yajo] + + +11.0.1.0.0 (2018-07-20) +~~~~~~~~~~~~~~~~~~~~~~~ + +* Rename, refactor, migrate to v11 + + [Yajo] + +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 +~~~~~~~ + +* Therp BV +* Tecnativa +* Camptocamp + +Contributors +~~~~~~~~~~~~ + +* Holger Brunn +* Rami Alwafaie +* Jose Mª Bernet +* Simone Orsi +* Dennis Sluijk +* `Tecnativa `_: + + * Vicent Cubells + * Jairo Llopis + * Alexandre Díaz + +* `DynApps NV `_: + + * Raf Ven + +* `Camptocamp `_ + + * Iván Todorovich + +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. + +.. |maintainer-ivantodorovich| image:: https://github.com/ivantodorovich.png?size=40px + :target: https://github.com/ivantodorovich + :alt: ivantodorovich + +Current `maintainer `__: + +|maintainer-ivantodorovich| + +This module is part of the `OCA/web `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/web_advanced_search/__init__.py b/web_advanced_search/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web_advanced_search/__manifest__.py b/web_advanced_search/__manifest__.py new file mode 100644 index 000000000000..67e63975290d --- /dev/null +++ b/web_advanced_search/__manifest__.py @@ -0,0 +1,22 @@ +# Copyright 2015 Therp BV +# Copyright 2017 Tecnativa - Vicent Cubells +# Copyright 2018 Tecnativa - Jairo Llopis +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Advanced search", + "summary": "Easier and more powerful searching tools", + "version": "16.0.1.0.0", + "author": "Therp BV, Tecnativa, Camptocamp, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/web", + "maintainers": ["ivantodorovich"], + "license": "AGPL-3", + "category": "Usability", + "depends": ["web"], + "assets": { + "web.assets_backend": [ + "web_advanced_search/static/src/js/**/*.js", + "web_advanced_search/static/src/xml/**/*.xml", + ] + }, +} diff --git a/web_advanced_search/i18n/da.po b/web_advanced_search/i18n/da.po new file mode 100644 index 000000000000..116ce354c3de --- /dev/null +++ b/web_advanced_search/i18n/da.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_advanced_search +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2018-09-01 05:03+0000\n" +"Last-Translator: Hans Henrik Gabelgaard \n" +"Language-Team: none\n" +"Language: da\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.1.1\n" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:0 +#, python-format +msgid "Add Advanced Filter" +msgstr "Tilføj avanceret filter" diff --git a/web_advanced_search/i18n/de.po b/web_advanced_search/i18n/de.po new file mode 100644 index 000000000000..c85dc8b2385d --- /dev/null +++ b/web_advanced_search/i18n/de.po @@ -0,0 +1,30 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_advanced_search_x2x +# +# Translators: +# Rudolf Schnapka , 2018 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-03 03:49+0000\n" +"PO-Revision-Date: 2020-07-21 18:19+0000\n" +"Last-Translator: c2cdidier \n" +"Language-Team: German (https://www.transifex.com/oca/teams/23907/de/)\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.10\n" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:0 +#, python-format +msgid "Add Advanced Filter" +msgstr "Erweitertes Filter hinzufügen" + +#~ msgid "is in selection" +#~ msgstr "Ist in Auswahl" diff --git a/web_advanced_search/i18n/es.po b/web_advanced_search/i18n/es.po new file mode 100644 index 000000000000..ed4c6b362ee5 --- /dev/null +++ b/web_advanced_search/i18n/es.po @@ -0,0 +1,30 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_advanced_search_x2x +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-03 03:49+0000\n" +"PO-Revision-Date: 2019-08-04 17:44+0000\n" +"Last-Translator: eduardgm \n" +"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.7.1\n" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:0 +#, python-format +msgid "Add Advanced Filter" +msgstr "Añadir un Filtro Avanzado" + +#~ msgid "is in selection" +#~ msgstr "está en la selección" diff --git a/web_advanced_search/i18n/fr.po b/web_advanced_search/i18n/fr.po new file mode 100644 index 000000000000..afc868a8d1f8 --- /dev/null +++ b/web_advanced_search/i18n/fr.po @@ -0,0 +1,30 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_advanced_search_x2x +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-03 03:49+0000\n" +"PO-Revision-Date: 2019-05-27 13:20+0000\n" +"Last-Translator: Kévin Allard \n" +"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.6.1\n" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:0 +#, python-format +msgid "Add Advanced Filter" +msgstr "Ajouter un filtre avancé" + +#~ msgid "is in selection" +#~ msgstr "parmi la sélection" diff --git a/web_advanced_search/i18n/hr.po b/web_advanced_search/i18n/hr.po new file mode 100644 index 000000000000..9f5f34b873aa --- /dev/null +++ b/web_advanced_search/i18n/hr.po @@ -0,0 +1,31 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_advanced_search_x2x +# +# Translators: +# Bole , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-03 03:49+0000\n" +"PO-Revision-Date: 2019-11-14 10:34+0000\n" +"Last-Translator: Bole \n" +"Language-Team: Croatian (https://www.transifex.com/oca/teams/23907/hr/)\n" +"Language: hr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 3.8\n" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:0 +#, python-format +msgid "Add Advanced Filter" +msgstr "Dodaj napredni filter" + +#~ msgid "is in selection" +#~ msgstr "je u odabiru" diff --git a/web_advanced_search/i18n/it.po b/web_advanced_search/i18n/it.po new file mode 100644 index 000000000000..e4d30ccc4b56 --- /dev/null +++ b/web_advanced_search/i18n/it.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_advanced_search +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-10-03 00:43+0000\n" +"Last-Translator: Alessandro Fiorino \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:0 +#, python-format +msgid "Add Advanced Filter" +msgstr "Aggiungi Filtro Avanzato" diff --git a/web_advanced_search/i18n/nl.po b/web_advanced_search/i18n/nl.po new file mode 100644 index 000000000000..2896da2781ef --- /dev/null +++ b/web_advanced_search/i18n/nl.po @@ -0,0 +1,30 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_advanced_search_x2x +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-03 03:49+0000\n" +"PO-Revision-Date: 2020-11-11 13:08+0000\n" +"Last-Translator: Dennis Sluijk \n" +"Language-Team: Dutch (https://www.transifex.com/oca/teams/23907/nl/)\n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.10\n" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:0 +#, python-format +msgid "Add Advanced Filter" +msgstr "Voeg Geavanceerde Filter Toe" + +#~ msgid "is in selection" +#~ msgstr "is in selectie" diff --git a/web_advanced_search/i18n/nl_NL.po b/web_advanced_search/i18n/nl_NL.po new file mode 100644 index 000000000000..173a67ad5bfe --- /dev/null +++ b/web_advanced_search/i18n/nl_NL.po @@ -0,0 +1,31 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_advanced_search_x2x +# +# Translators: +# Peter Hageman , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-03 03:49+0000\n" +"PO-Revision-Date: 2020-12-10 13:36+0000\n" +"Last-Translator: Dennis Sluijk \n" +"Language-Team: Dutch (Netherlands) (https://www.transifex.com/oca/teams/" +"23907/nl_NL/)\n" +"Language: nl_NL\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.10\n" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:0 +#, python-format +msgid "Add Advanced Filter" +msgstr "Voeg geavanceerde filter toe" + +#~ msgid "is in selection" +#~ msgstr "Is in selectie" diff --git a/web_advanced_search/i18n/pl.po b/web_advanced_search/i18n/pl.po new file mode 100644 index 000000000000..2416f61747e2 --- /dev/null +++ b/web_advanced_search/i18n/pl.po @@ -0,0 +1,46 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_advanced_search +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2022-08-11 13:07+0000\n" +"Last-Translator: Jacek Michalski \n" +"Language-Team: none\n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/js/utils.esm.js:0 +#, python-format +msgid " and " +msgstr " oraz " + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/js/utils.esm.js:0 +#, python-format +msgid " is not " +msgstr " nie jest " + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/js/utils.esm.js:0 +#, python-format +msgid " or " +msgstr " lub " + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/AdvancedFilterItem.xml:0 +#, python-format +msgid "Add Advanced Filter" +msgstr "Dodaj Filtr Zaawansowany" diff --git a/web_advanced_search/i18n/pt.po b/web_advanced_search/i18n/pt.po new file mode 100644 index 000000000000..426bbf533a57 --- /dev/null +++ b/web_advanced_search/i18n/pt.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_advanced_search +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2019-08-12 11:44+0000\n" +"Last-Translator: Pedro Castro Silva \n" +"Language-Team: none\n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.7.1\n" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:0 +#, python-format +msgid "Add Advanced Filter" +msgstr "Adicionar Filtro Avançado" diff --git a/web_advanced_search/i18n/pt_BR.po b/web_advanced_search/i18n/pt_BR.po new file mode 100644 index 000000000000..08da1be3b23c --- /dev/null +++ b/web_advanced_search/i18n/pt_BR.po @@ -0,0 +1,31 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_advanced_search_x2x +# +# Translators: +# Rodrigo de Almeida Sottomaior Macedo , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-03 03:49+0000\n" +"PO-Revision-Date: 2019-08-30 15:23+0000\n" +"Last-Translator: Rodrigo Macedo \n" +"Language-Team: Portuguese (Brazil) (https://www.transifex.com/oca/" +"teams/23907/pt_BR/)\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.8\n" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:0 +#, python-format +msgid "Add Advanced Filter" +msgstr "Adicionar filtro avançado" + +#~ msgid "is in selection" +#~ msgstr "Está em seleção" diff --git a/web_advanced_search/i18n/web_advanced_search.pot b/web_advanced_search/i18n/web_advanced_search.pot new file mode 100644 index 000000000000..990a5a7bb9e4 --- /dev/null +++ b/web_advanced_search/i18n/web_advanced_search.pot @@ -0,0 +1,42 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_advanced_search +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.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: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/js/utils.esm.js:0 +#, python-format +msgid " and " +msgstr "" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/js/utils.esm.js:0 +#, python-format +msgid " is not " +msgstr "" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/js/utils.esm.js:0 +#, python-format +msgid " or " +msgstr "" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/AdvancedFilterItem.xml:0 +#, python-format +msgid "Add Advanced Filter" +msgstr "" diff --git a/web_advanced_search/i18n/zh_CN.po b/web_advanced_search/i18n/zh_CN.po new file mode 100644 index 000000000000..7c703ca6266f --- /dev/null +++ b/web_advanced_search/i18n/zh_CN.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_advanced_search +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2019-09-01 12:52+0000\n" +"Last-Translator: 黎伟杰 <674416404@qq.com>\n" +"Language-Team: none\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 3.8\n" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:0 +#, python-format +msgid "Add Advanced Filter" +msgstr "添加高级过滤器" diff --git a/web_advanced_search/readme/CONTRIBUTORS.rst b/web_advanced_search/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..07528e22a5da --- /dev/null +++ b/web_advanced_search/readme/CONTRIBUTORS.rst @@ -0,0 +1,18 @@ +* Holger Brunn +* Rami Alwafaie +* Jose Mª Bernet +* Simone Orsi +* Dennis Sluijk +* `Tecnativa `_: + + * Vicent Cubells + * Jairo Llopis + * Alexandre Díaz + +* `DynApps NV `_: + + * Raf Ven + +* `Camptocamp `_ + + * Iván Todorovich diff --git a/web_advanced_search/readme/DESCRIPTION.rst b/web_advanced_search/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..bd4c29fdd20b --- /dev/null +++ b/web_advanced_search/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +More powerful and easy to use search, especially for related fields. diff --git a/web_advanced_search/readme/HISTORY.rst b/web_advanced_search/readme/HISTORY.rst new file mode 100644 index 000000000000..7b791ed951d7 --- /dev/null +++ b/web_advanced_search/readme/HISTORY.rst @@ -0,0 +1,40 @@ +11.0.1.0.2 (2018-10-31) +~~~~~~~~~~~~~~~~~~~~~~~ + +* Fix initialization of 1st domain node + + Sometime the dialog is not ready yet, like on EE version. + Hence when you inject the 1st domain node + the dialog must be already opened. + + [simahawk] + + +11.0.1.0.1 (2018-09-18) +~~~~~~~~~~~~~~~~~~~~~~~ + +* Fix `undefined` in x2m fields + + Before this patch, when searching with the "equals to" operator in any + x2many field, the searched parameter was always `undefined`. + + The problem was that the underlying field manager implementation was + treating those fields as x2many, while the widget used was the `one2many` + one. + + This patch simply mocks the underlying fake record to make think that + any relational field is always a `one2many`. This sets all pieces in + place and makes the field manager work as expected, and thus you can + search as expected too. + +* Make linter happy + + [Yajo] + + +11.0.1.0.0 (2018-07-20) +~~~~~~~~~~~~~~~~~~~~~~~ + +* Rename, refactor, migrate to v11 + + [Yajo] diff --git a/web_advanced_search/readme/ROADMAP.rst b/web_advanced_search/readme/ROADMAP.rst new file mode 100644 index 000000000000..b71b3c344ff9 --- /dev/null +++ b/web_advanced_search/readme/ROADMAP.rst @@ -0,0 +1,14 @@ +Improvements to the ``domain`` widget, not exclusively related to this addon: + +* Use relational widgets when filtering a relational field +* Allow to filter field names + +Improvements to the search view in this addon: + +* Use widgets ``one2many_tags`` when searching ``one2many`` fields +* Use widgets ``many2many_tags`` when searching ``many2many`` fields +* Allow to edit current full search using the advanced domain editor + +Issues: + +* Grouped totals can show incorrect values. See https://github.com/odoo/odoo/issues/47950 diff --git a/web_advanced_search/readme/USAGE.rst b/web_advanced_search/readme/USAGE.rst new file mode 100644 index 000000000000..76f224a0d992 --- /dev/null +++ b/web_advanced_search/readme/USAGE.rst @@ -0,0 +1,24 @@ +To use this module, you need to: + +* Open *Filters* in a search view +* Select any relational field +* Select operator `is equal to` or `is not equal to` +* The text field changes to a relational selection field where you + can search for the record in question +* Click *Apply* + +To search for properties of linked records (ie invoices for customers +with a credit limit higher than X): + +* Open *Filters* in a search view +* Select *Add Advanced Filter* +* Edit the advanced filter +* Click *Save* + +Note that you can stack searching for properties: Simply add another +advanced search in the selection search window. You can do +this indefinetely, so it is possible to search for moves belonging +to a journal which has a user who is member of a certain group etc. + +Note also the domain dialog offers an editable preview in debug mode: + .. image:: ../static/img/debug_mode.png diff --git a/web_advanced_search/static/description/icon.png b/web_advanced_search/static/description/icon.png new file mode 100644 index 000000000000..1ab5d1e10173 Binary files /dev/null and b/web_advanced_search/static/description/icon.png differ diff --git a/web_advanced_search/static/description/index.html b/web_advanced_search/static/description/index.html new file mode 100644 index 000000000000..7adfb5d00126 --- /dev/null +++ b/web_advanced_search/static/description/index.html @@ -0,0 +1,547 @@ + + + + + + +Advanced search + + + + + + diff --git a/web_advanced_search/static/img/debug_mode.png b/web_advanced_search/static/img/debug_mode.png new file mode 100644 index 000000000000..e9a4b46ff294 Binary files /dev/null and b/web_advanced_search/static/img/debug_mode.png differ diff --git a/web_advanced_search/static/src/js/RecordPicker.esm.js b/web_advanced_search/static/src/js/RecordPicker.esm.js new file mode 100644 index 000000000000..cefbcd7c92a2 --- /dev/null +++ b/web_advanced_search/static/src/js/RecordPicker.esm.js @@ -0,0 +1,197 @@ +/** @odoo-module **/ + +import BasicModel from "web.BasicModel"; +import {ComponentAdapter} from "web.OwlCompatibility"; +import {Dropdown} from "@web/core/dropdown/dropdown"; +import FieldManagerMixin from "web.FieldManagerMixin"; +import {FieldMany2One} from "web.relational_fields"; +import {SelectCreateDialog} from "web.view_dialogs"; +import {patch} from "@web/core/utils/patch"; +import {session} from "@web/session"; + +const {Component, xml} = owl; + +patch(Dropdown.prototype, "dropdown", { + onWindowClicked(ev) { + // This patch is created to prevent the closing of the Filter menu + // when a selection is made in the RecordPicker + if ( + $(ev.target.closest("ul.dropdown-menu")).attr("id") !== undefined && + $(ev.target.closest("ul.dropdown-menu")).attr("id") === + $("body > ul.dropdown-menu").attr("id") + ) { + return; + } + this._super(ev); + }, +}); + +export const FakeMany2oneFieldWidget = FieldMany2One.extend(FieldManagerMixin, { + /** + * @override + */ + init: function (parent) { + this.componentAdapter = parent; + const options = this.componentAdapter.props.attrs; + // Create a dummy record with only a dummy m2o field to search on + const model = new BasicModel("dummy"); + const params = { + fieldNames: ["dummy"], + modelName: "dummy", + context: {}, + type: "record", + viewType: "default", + fieldsInfo: {default: {dummy: {}}}, + fields: { + dummy: { + string: options.string, + relation: options.model, + context: options.context, + domain: options.domain, + type: "many2one", + }, + }, + }; + // Emulate `model.load()`, without RPC-calling `default_get()` + this.dataPointID = model._makeDataPoint(params).id; + model.generateDefaultValues(this.dataPointID, {}); + this._super(this.componentAdapter, "dummy", this._get_record(model), { + mode: "edit", + attrs: { + options: { + no_create_edit: true, + no_create: true, + no_open: true, + no_quick_create: true, + }, + }, + }); + FieldManagerMixin.init.call(this, model); + }, + /** + * Get record + * + * @param {BasicModel} model + * @returns {String} + */ + _get_record: function (model) { + return model.get(this.dataPointID); + }, + /** + * @override + */ + _confirmChange: function (id, fields, event) { + this.componentAdapter.trigger("change", event.data.changes[fields[0]]); + this.dataPointID = id; + return this.reset(this._get_record(this.model), event); + }, + /** + * Stop propagation of the 'Search more..' dialog click event. + * Otherwise, the filter's dropdown will be closed after a selection. + * + * @override + */ + _searchCreatePopup: function (view, ids, context, dynamicFilters) { + const options = this._getSearchCreatePopupOptions( + view, + ids, + context, + dynamicFilters + ); + const dialog = new SelectCreateDialog( + this, + _.extend({}, this.nodeOptions, options) + ); + // Hack to stop click event propagation + dialog._opened.then(() => + dialog.$el + .get(0) + .addEventListener("click", (event) => event.stopPropagation()) + ); + return dialog.open(); + }, + _onFieldChanged: function (event) { + const self = this; + event.stopPropagation(); + if (event.data.changes.dummy.display_name === undefined) { + return this._rpc({ + model: this.field.relation, + method: "name_get", + args: [event.data.changes.dummy.id], + context: session.user_context, + }).then(function (result) { + event.data.changes.dummy.display_name = result[0][1]; + return ( + self + ._applyChanges( + event.data.dataPointID, + event.data.changes, + event + ) + // eslint-disable-next-line no-empty-function + .then(event.data.onSuccess || function () {}) + // eslint-disable-next-line no-empty-function + .guardedCatch(event.data.onFailure || function () {}) + ); + }); + } + return ( + this._applyChanges(event.data.dataPointID, event.data.changes, event) + // eslint-disable-next-line no-empty-function + .then(event.data.onSuccess || function () {}) + // eslint-disable-next-line no-empty-function + .guardedCatch(event.data.onFailure || function () {}) + ); + }, +}); + +export class FakeMany2oneFieldWidgetAdapter extends ComponentAdapter { + constructor() { + super(...arguments); + this.env = Component.env; + } + + renderWidget() { + this.widget._render(); + } + + get widgetArgs() { + if (this.props.widgetArgs) { + return this.props.widgetArgs; + } + return [this.props.attrs]; + } +} + +/** + * A record selector widget. + * + * Underneath, it implements and extends the `FieldManagerMixin`, and acts as if it + * were a reduced dummy controller. Some actions "mock" the underlying model, since + * sometimes we use a char widget to fill related fields (which is not supported by + * that widget), and fields need an underlying model implementation, which can only + * hold fake data, given a search view has no data on it by definition. + * + * @extends Component + */ +export class RecordPicker extends Component { + setup() { + this.attrs = { + string: this.props.string, + model: this.props.model, + domain: this.props.domain, + context: this.props.context, + }; + this.FakeMany2oneFieldWidget = FakeMany2oneFieldWidget; + } +} + +RecordPicker.template = xml` +
+ +
`; +RecordPicker.components = {FakeMany2oneFieldWidgetAdapter}; diff --git a/web_advanced_search/static/src/js/owl/AdvancedFilterItem.esm.js b/web_advanced_search/static/src/js/owl/AdvancedFilterItem.esm.js new file mode 100644 index 000000000000..87fad1e8fcc8 --- /dev/null +++ b/web_advanced_search/static/src/js/owl/AdvancedFilterItem.esm.js @@ -0,0 +1,56 @@ +/** @odoo-module **/ + +import Domain from "web.Domain"; +import DomainSelectorDialog from "web.DomainSelectorDialog"; +import config from "web.config"; +import {getHumanDomain} from "../utils.esm"; +import {standaloneAdapter} from "web.OwlCompatibility"; +const {Component, useRef} = owl; +class AdvancedFilterItem extends Component { + setup() { + this.itemRef = useRef("dropdown-item"); + } + /** + * Prevent propagation of dropdown-item-selected event, so that it + * doesn't reaches the FilterMenu onFilterSelected event handler. + */ + mounted() { + $(this.itemRef.el).on("dropdown-item-selected", (event) => + event.stopPropagation() + ); + } + /** + * Open advanced search dialog + * + * @returns {DomainSelectorDialog} The opened dialog itself. + */ + onClick() { + const adapterParent = standaloneAdapter({Component}); + const dialog = new DomainSelectorDialog( + adapterParent, + this.env.searchModel.resModel, + "[]", + { + debugMode: config.isDebug(), + readonly: false, + } + ); + // Add 1st domain node by default + dialog.opened(() => dialog.domainSelector._onAddFirstButtonClick()); + // Configure handler + dialog.on("domain_selected", this, function (e) { + const preFilter = { + description: getHumanDomain(dialog.domainSelector), + domain: Domain.prototype.arrayToString(e.data.domain), + type: "filter", + }; + this.env.searchModel.createNewFilters([preFilter]); + }); + return dialog.open(); + } +} + +AdvancedFilterItem.components = {AdvancedFilterItem}; + +AdvancedFilterItem.template = "web_advanced_search.AdvancedFilterItem"; +export default AdvancedFilterItem; diff --git a/web_advanced_search/static/src/js/owl/CustomFilterItem.esm.js b/web_advanced_search/static/src/js/owl/CustomFilterItem.esm.js new file mode 100644 index 000000000000..13adefdb6a47 --- /dev/null +++ b/web_advanced_search/static/src/js/owl/CustomFilterItem.esm.js @@ -0,0 +1,103 @@ +/** @odoo-module **/ + +import {CustomFilterItem} from "@web/search/filter_menu/custom_filter_item"; +import {RecordPicker} from "../RecordPicker.esm"; +import {patch} from "@web/core/utils/patch"; + +/** + * Patches the CustomFilterItem for owl widgets. + */ +patch(CustomFilterItem.prototype, "web_advanced_search.CustomFilterItem", { + /** + * @override + */ + setup() { + this._super.apply(this, arguments); + this.OPERATORS.relational = this.OPERATORS.char; + this.FIELD_TYPES.many2one = "relational"; + }, + /** + * @override + */ + setDefaultValue(condition) { + const res = this._super.apply(this, arguments); + const fieldType = this.fields[condition.field].type; + const genericType = this.FIELD_TYPES[fieldType]; + if (genericType === "relational") { + condition.value = 0; + condition.displayedValue = ""; + } + return res; + }, + /** + * Add displayed value to preFilters for "relational" types. + * + * @override + */ + onApply() { + // To avoid the complete override, we patch this.conditions.map() + const originalMapFn = this.conditions.map; + const self = this; + this.conditions.map = function () { + const preFilters = originalMapFn.apply(this, arguments); + for (const condition of this) { + const field = self.fields[condition.field]; + const type = self.FIELD_TYPES[field.type]; + if (type === "relational") { + const idx = this.indexOf(condition); + const preFilter = preFilters[idx]; + const operator = self.OPERATORS[type][condition.operator]; + if ( + ["=", "!="].includes(operator.symbol) && + operator.value === undefined + ) { + const descriptionArray = [ + field.string, + operator.description, + `"${condition.displayedValue}"`, + ]; + preFilter.description = descriptionArray.join(" "); + } + } + } + return preFilters; + }; + const res = this._super.apply(this, arguments); + // Restore original map() + this.conditions.map = originalMapFn; + return res; + }, + /** + * @private + * @param {Object} condition + * @param {OwlEvent} ev + */ + onRelationalChanged(condition, ev) { + if (ev.detail) { + condition.value = ev.detail.id; + condition.displayedValue = ev.detail.display_name; + } + }, + onValueChange(condition, ev) { + if (!ev.target.value) { + return this.setDefaultValue(condition); + } + const field = this.fields[condition.field]; + const type = this.FIELD_TYPES[field.type]; + if (type === "relational") { + condition.value = ev.target.value; + condition.displayedValue = ev.target.value; + } else { + this._super.apply(this, arguments); + } + }, +}); + +patch(CustomFilterItem, "web_advanced_search.CustomFilterItem", { + components: { + ...CustomFilterItem.components, + RecordPicker, + }, +}); + +export default CustomFilterItem; diff --git a/web_advanced_search/static/src/js/owl/FilterMenu.esm.js b/web_advanced_search/static/src/js/owl/FilterMenu.esm.js new file mode 100644 index 000000000000..ca7a71d5d171 --- /dev/null +++ b/web_advanced_search/static/src/js/owl/FilterMenu.esm.js @@ -0,0 +1,16 @@ +/** @odoo-module **/ + +import AdvancedFilterItem from "./AdvancedFilterItem.esm"; +import {FilterMenu} from "@web/search/filter_menu/filter_menu"; +import {patch} from "@web/core/utils/patch"; +/** + * Patches the FilterMenu for owl widgets. + */ +patch(FilterMenu, "web_advanced_search.FilterMenu", { + components: { + ...FilterMenu.components, + AdvancedFilterItem, + }, +}); + +export default FilterMenu; diff --git a/web_advanced_search/static/src/js/utils.esm.js b/web_advanced_search/static/src/js/utils.esm.js new file mode 100644 index 000000000000..f3f3d88bb9d9 --- /dev/null +++ b/web_advanced_search/static/src/js/utils.esm.js @@ -0,0 +1,58 @@ +/** @odoo-module **/ +/* + Copyright 2018 Tecnativa - Jairo Llopis + Copyright 2020 Tecnativa - Alexandre Díaz + Copyright 2022 Camptocamp SA - Iván Todorovich + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +*/ + +import {_t} from "web.core"; +const JOIN_MAPPING = { + "&": _t(" and "), + "|": _t(" or "), + "!": _t(" is not "), +}; + +const HUMAN_DOMAIN_METHODS = { + DomainTree: function () { + const human_domains = []; + _.each(this.children, (child) => { + human_domains.push(HUMAN_DOMAIN_METHODS[child.template].apply(child)); + }); + return `(${human_domains.join(JOIN_MAPPING[this.operator])})`; + }, + + DomainSelector: function () { + const result = HUMAN_DOMAIN_METHODS.DomainTree.apply(this, arguments); + // Remove surrounding parenthesis + return result.slice(1, -1); + }, + + DomainLeaf: function () { + const chain = []; + let operator = this.operator_mapping[this.operator], + value = `"${this.value}"`; + // Humanize chain + const chain_splitted = this.chain.split("."); + const len = chain_splitted.length; + for (let x = 0; x < len; ++x) { + const element = chain_splitted[x]; + chain.push( + _.findWhere(this.fieldSelector.popover.pages[x], {name: element}) + .string || element + ); + } + // Special beautiness for some values + if (this.operator === "=" && _.isBoolean(this.value)) { + operator = this.operator_mapping[this.value ? "set" : "not set"]; + value = ""; + } else if (_.isArray(this.value)) { + value = `["${this.value.join('", "')}"]`; + } + return `${chain.join("→")} ${operator || this.operator} ${value}`.trim(); + }, +}; + +export function getHumanDomain(domainSelector) { + return HUMAN_DOMAIN_METHODS.DomainSelector.apply(domainSelector); +} diff --git a/web_advanced_search/static/src/xml/AdvancedFilterItem.xml b/web_advanced_search/static/src/xml/AdvancedFilterItem.xml new file mode 100644 index 000000000000..86559e7f34b0 --- /dev/null +++ b/web_advanced_search/static/src/xml/AdvancedFilterItem.xml @@ -0,0 +1,15 @@ + + + + + Add Advanced Filter + + diff --git a/web_advanced_search/static/src/xml/CustomFilterItem.xml b/web_advanced_search/static/src/xml/CustomFilterItem.xml new file mode 100644 index 000000000000..ca0554adac6f --- /dev/null +++ b/web_advanced_search/static/src/xml/CustomFilterItem.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/web_advanced_search/static/src/xml/FilterMenu.xml b/web_advanced_search/static/src/xml/FilterMenu.xml new file mode 100644 index 000000000000..058a9b17befb --- /dev/null +++ b/web_advanced_search/static/src/xml/FilterMenu.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + +