diff --git a/web_advanced_search/README.rst b/web_advanced_search/README.rst new file mode 100644 index 00000000..d8624a43 --- /dev/null +++ b/web_advanced_search/README.rst @@ -0,0 +1,162 @@ +=============== +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/12.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-12-0/web-12-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/12.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. + +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 + +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 + +Contributors +~~~~~~~~~~~~ + +* Holger Brunn +* Vicent Cubells +* Jairo Llopis +* Rami Alwafaie +* Jose Mª Bernet +* Simone Orsi + +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/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 00000000..e69de29b diff --git a/web_advanced_search/__manifest__.py b/web_advanced_search/__manifest__.py new file mode 100644 index 00000000..645de4f9 --- /dev/null +++ b/web_advanced_search/__manifest__.py @@ -0,0 +1,27 @@ +# 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", + "version": "12.0.1.0.0", + "author": "Therp BV, " + "Tecnativa, " + "Odoo Community Association (OCA)", + "license": "AGPL-3", + "category": "Usability", + "summary": "Easier and more powerful searching tools", + "website": "https://github.com/OCA/web", + "depends": [ + 'web', + ], + "data": [ + 'views/templates.xml', + ], + "qweb": [ + 'static/src/xml/web_advanced_search.xml', + ], + "installable": True, + "application": False, +} diff --git a/web_advanced_search/i18n/da.po b/web_advanced_search/i18n/da.po new file mode 100644 index 00000000..67a3aae1 --- /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:9 +#, 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 00000000..2105b6a7 --- /dev/null +++ b/web_advanced_search/i18n/de.po @@ -0,0 +1,29 @@ +# 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: 2018-01-03 03:49+0000\n" +"Last-Translator: Rudolf Schnapka , 2018\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" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:9 +#, python-format +msgid "Add Advanced Filter" +msgstr "" + +#~ 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 00000000..8ae0ceba --- /dev/null +++ b/web_advanced_search/i18n/es.po @@ -0,0 +1,29 @@ +# 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: 2018-01-03 03:49+0000\n" +"Last-Translator: OCA Transbot , 2017\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" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:9 +#, python-format +msgid "Add Advanced Filter" +msgstr "" + +#~ 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 00000000..dfdf9338 --- /dev/null +++ b/web_advanced_search/i18n/fr.po @@ -0,0 +1,29 @@ +# 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: 2018-01-03 03:49+0000\n" +"Last-Translator: OCA Transbot , 2017\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" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:9 +#, python-format +msgid "Add Advanced Filter" +msgstr "" + +#~ 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 00000000..82f42916 --- /dev/null +++ b/web_advanced_search/i18n/hr.po @@ -0,0 +1,30 @@ +# 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: 2018-01-03 03:49+0000\n" +"Last-Translator: Bole , 2017\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" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:9 +#, python-format +msgid "Add Advanced Filter" +msgstr "" + +#~ msgid "is in selection" +#~ msgstr "je u odabiru" diff --git a/web_advanced_search/i18n/nl.po b/web_advanced_search/i18n/nl.po new file mode 100644 index 00000000..cae5e1aa --- /dev/null +++ b/web_advanced_search/i18n/nl.po @@ -0,0 +1,29 @@ +# 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: 2018-01-03 03:49+0000\n" +"Last-Translator: OCA Transbot , 2017\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" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:9 +#, python-format +msgid "Add Advanced Filter" +msgstr "" + +#~ 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 00000000..949c83a9 --- /dev/null +++ b/web_advanced_search/i18n/nl_NL.po @@ -0,0 +1,30 @@ +# 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: 2018-01-03 03:49+0000\n" +"Last-Translator: Peter Hageman , 2017\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" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:9 +#, python-format +msgid "Add Advanced Filter" +msgstr "" + +#~ msgid "is in selection" +#~ msgstr "Is in selectie" diff --git a/web_advanced_search/i18n/pt_BR.po b/web_advanced_search/i18n/pt_BR.po new file mode 100644 index 00000000..a2d187ee --- /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: 2018-01-03 03:49+0000\n" +"Last-Translator: Rodrigo de Almeida Sottomaior Macedo " +", 2017\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" + +#. module: web_advanced_search +#. openerp-web +#: code:addons/web_advanced_search/static/src/xml/web_advanced_search.xml:9 +#, python-format +msgid "Add Advanced Filter" +msgstr "" + +#~ 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 00000000..51844650 --- /dev/null +++ b/web_advanced_search/i18n/web_advanced_search.pot @@ -0,0 +1,22 @@ +# 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" +"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/xml/web_advanced_search.xml:9 +#, 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 00000000..ed3dc10c --- /dev/null +++ b/web_advanced_search/readme/CONTRIBUTORS.rst @@ -0,0 +1,6 @@ +* Holger Brunn +* Vicent Cubells +* Jairo Llopis +* Rami Alwafaie +* Jose Mª Bernet +* Simone Orsi diff --git a/web_advanced_search/readme/DESCRIPTION.rst b/web_advanced_search/readme/DESCRIPTION.rst new file mode 100644 index 00000000..bd4c29fd --- /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 00000000..7b791ed9 --- /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 00000000..8a0a6871 --- /dev/null +++ b/web_advanced_search/readme/ROADMAP.rst @@ -0,0 +1,10 @@ +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 diff --git a/web_advanced_search/readme/USAGE.rst b/web_advanced_search/readme/USAGE.rst new file mode 100644 index 00000000..b8e6f277 --- /dev/null +++ b/web_advanced_search/readme/USAGE.rst @@ -0,0 +1,21 @@ +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. diff --git a/web_advanced_search/static/description/icon.png b/web_advanced_search/static/description/icon.png new file mode 100644 index 00000000..1ab5d1e1 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 00000000..016003dd --- /dev/null +++ b/web_advanced_search/static/description/index.html @@ -0,0 +1,512 @@ + + + + + + +Advanced search + + + + + + diff --git a/web_advanced_search/static/src/js/human_domain.js b/web_advanced_search/static/src/js/human_domain.js new file mode 100644 index 00000000..82aefc5c --- /dev/null +++ b/web_advanced_search/static/src/js/human_domain.js @@ -0,0 +1,86 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */ + + odoo.define("web_advanced_search.human_domain", function (require) { + "use strict"; + + var DomainSelector = require("web.DomainSelector"); + + var join_mapping = { + "&": _(" and "), + "|": _(" or "), + "!": _(" is not "), + }; + + // HACK I should extend classes, but they are not exposed + // TODO Remove file when merged https://github.com/odoo/odoo/pull/25922 + var human_domain_methods = { + DomainTree: function () { + var human_domains = []; + _.each(this.children, function (child) { + human_domains.push( + human_domain_methods[child.template].apply(child) + ); + }); + return _.str.sprintf( + "(%s)", + human_domains.join(join_mapping[this.operator]) + ); + }, + + DomainSelector: function () { + var result = human_domain_methods.DomainTree.apply(this, arguments); + // Remove surrounding parenthesis + return result.slice(1, -1); + }, + + DomainLeaf: function () { + var chain = [], + operator = this.operator_mapping[this.operator], + value = _.str.sprintf('"%s"', this.value); + // Humanize chain + this.chain.split(".").forEach(function (element, index) { + chain.push( + _.findWhere( + this.fieldSelector.pages[index], + {name: element} + ).string || element + ); + }, this); + // 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 = _.str.sprintf('["%s"]', this.value.join('", "')); + } + return _.str.sprintf( + "%s %s %s", + chain.join("→"), + operator || this.operator, + value + ).trim(); + }, + }; + + function getHumanDomain (parent, model, domain, options) { + var domain_selector = new DomainSelector( + parent, + model, + domain, + options + ); + var dummy_parent = $("
"); + domain_selector.appendTo(dummy_parent); + var result = human_domain_methods.DomainSelector.apply( + domain_selector + ); + domain_selector.destroy(); + dummy_parent.destroy(); + return result; + } + + return { + getHumanDomain: getHumanDomain, + }; +}); diff --git a/web_advanced_search/static/src/js/web_advanced_search.js b/web_advanced_search/static/src/js/web_advanced_search.js new file mode 100644 index 00000000..35ca25bb --- /dev/null +++ b/web_advanced_search/static/src/js/web_advanced_search.js @@ -0,0 +1,348 @@ +/* Copyright 2015 Therp BV + * Copyright 2017-2018 Jairo Llopis + * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */ + +odoo.define("web_advanced_search", function (require) { + "use strict"; + + var core = require("web.core"); + var Domain = require("web.Domain"); + var DomainSelectorDialog = require("web.DomainSelectorDialog"); + var field_registry = require("web.field_registry"); + var FieldManagerMixin = require("web.FieldManagerMixin"); + var FiltersMenu = require("web.FiltersMenu"); + var human_domain = require("web_advanced_search.human_domain"); + var SearchView = require("web.SearchView"); + var Widget = require("web.Widget"); + var Char = core.search_filters_registry.get("char"); + + SearchView.include({ + custom_events: _.extend({}, SearchView.prototype.custom_events, { + "get_dataset": "_on_get_dataset", + }), + + /** + * Add or update a `dataset` attribute in event target + * + * The search view dataset includes things such as the model, which + * is required to make some parts of search views smarter. + * + * @param {OdooEvent} event The target will get the dataset. + */ + _on_get_dataset: function (event) { + event.target.dataset = this.dataset; + event.stopPropagation(); + }, + }); + + /** + * An almost dummy search proposition, to use with domain widget + */ + var AdvancedSearchProposition = Widget.extend({ + + /** + * @override + */ + init: function (parent, model, domain) { + this._super(parent); + this.model = model; + this.domain = new Domain(domain); + }, + + /** + * Produce a filter descriptor for advanced searches. + * + * @returns {Object} In the format expected by `web.FiltersMenu`. + */ + get_filter: function () { + var domain_array = this.domain.toArray(); + return { + attrs: { + domain: domain_array, + // TODO Remove when merged + // https://github.com/odoo/odoo/pull/25922 + string: human_domain.getHumanDomain( + this, + this.model, + domain_array + ), + }, + children: [], + tag: "filter", + }; + }, + }); + + // Add advanced search features + FiltersMenu.include({ + custom_events: _.extend({}, FiltersMenu.prototype.custom_events, { + "domain_selected": "advanced_search_commit", + }), + + events: _.extend({}, FiltersMenu.prototype.events, { + "click .o_add_advanced_search": "advanced_search_open", + }), + + /** + * @override + */ + init: function () { + this._super.apply(this, arguments); + this.trigger_up("get_dataset"); + }, + + /** + * Open advanced search dialog + * + * @returns {$.Deferred} The opening dialog itself. + */ + advanced_search_open: function () { + var domain_selector_dialog = new DomainSelectorDialog( + this, + this.dataset.model, + "[]", + { + debugMode: core.debug, + readonly: false, + } + ); + domain_selector_dialog.opened(function () { + // Add 1st domain node by default + domain_selector_dialog.domainSelector._onAddFirstButtonClick(); + }); + return domain_selector_dialog.open(); + }, + + /** + * Apply advanced search on dialog save + * + * @param {OdooEvent} event A `domain_selected` event from the dialog. + */ + advanced_search_commit: function (event) { + _.invoke(this.propositions, "destroy"); + var proposition = new AdvancedSearchProposition( + this, + this.dataset.model, + event.data.domain + ); + this.propositions = [proposition]; + this._commitSearch(); + }, + }); + + /** + * A search field for relational fields. + * + * 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. + */ + var Relational = Char.extend(FieldManagerMixin, { + tagName: "div", + className: "x2x_container", + attributes: {}, + + /** + * @override + */ + init: function () { + this._super.apply(this, arguments); + // To make widgets work, we need a model and an empty record + FieldManagerMixin.init.call(this); + this.trigger_up("get_dataset"); + // Make equal and not equal appear 1st and 2nd + this.operators = _.sortBy( + this.operators, + function (op) { + switch (op.value) { + case "=": + return -2; + case "!=": + return -1; + default: + return 0; + } + }); + // Create dummy record with only the field the user is searching + var params = { + fieldNames: [this.field.name], + modelName: this.dataset.model, + context: this.dataset.context, + fields: {}, + type: "record", + viewType: "default", + fieldsInfo: { + default: {}, + }, + }; + // See https://stackoverflow.com/a/11508530/1468388 + // to know how to include this in the previous step in ES6 + params.fields[this.field.name] = _.omit( + this.field, + // User needs all records, to actually produce a new domain + "domain", + // Onchanges make no sense in this context, there's no record + "onChange" + ); + if (this.field.type.endsWith("2many")) { + // X2many fields behave like m2o in the search context + params.fields[this.field.name].type = "many2one"; + } + params.fieldsInfo.default[this.field.name] = {}; + // Emulate `model.load()`, without RPC-calling `default_get()` + this.datapoint_id = this.model._makeDataPoint(params).id; + this.model.applyDefaultValues( + this.datapoint_id, + {}, + params.fieldNames + ); + // To generate a new fake ID + this._fake_id = -1; + }, + + /** + * @override + */ + start: function () { + var result = this._super.apply(this, arguments); + // Render the initial widget + result.done($.proxy(this, "show_inputs", $(""))); + return result; + }, + + /** + * @override + */ + destroy: function () { + if (this._field_widget) { + this._field_widget.destroy(); + } + this.model.destroy(); + delete this.record; + return this._super.apply(this, arguments); + }, + + /** + * Get record object for current datapoint. + * + * @returns {Object} + */ + _get_record: function () { + return this.model.get(this.datapoint_id); + }, + + /** + * @override + */ + show_inputs: function ($operator) { + // Get widget class to be used + switch ($operator.val()) { + case "=": + case "!=": + this._field_widget_name = "many2one"; + break; + default: + this._field_widget_name = "char"; + } + var _Widget = field_registry.get(this._field_widget_name); + // Destroy previous widget, if any + if (this._field_widget) { + this._field_widget.destroy(); + delete this._field_widget; + } + // Create new widget + var options = { + mode: "edit", + attrs: { + options: { + no_create_edit: true, + no_create: true, + no_open: true, + no_quick_create: true, + }, + }, + }; + this._field_widget = new _Widget( + this, + this.field.name, + this._get_record(), + options + ); + this._field_widget.appendTo(this.$el); + return this._super.apply(this, arguments); + }, + + /** + * @override + */ + _applyChanges: function (dataPointID, changes, event) { + // Make char updates look like valid x2one updates + if (_.isNaN(changes[this.field.name].id)) { + changes[this.field.name] = { + id: this._fake_id--, + display_name: event.target.lastSetValue, + }; + } + return FieldManagerMixin._applyChanges.apply(this, arguments); + }, + + /** + * @override + */ + _confirmChange: function (id, fields, event) { + this.datapoint_id = id; + return this._field_widget.reset(this._get_record(), event); + }, + + /** + * @override + */ + get_value: function () { + try { + switch (this._field_widget_name) { + case "many2one": + return this._field_widget.value.res_id; + default: + return this._field_widget.value.data.display_name; + } + } catch (error) { + if (error.name === "TypeError") { + return false; + } + } + }, + + /** + * Extract the field's value in a human-readable format. + * + * @override + */ + toString: function () { + try { + switch (this._field_widget_name) { + case "many2one": + return this._field_widget.value.data.display_name; + } + return this._super.apply(this, arguments); + } catch (error) { + if (error.name === "TypeError") { + return ""; + } + } + }, + }); + + // Register search filter widgets + core.search_filters_registry + .add("many2many", Relational) + .add("many2one", Relational) + .add("one2many", Relational); + + return { + AdvancedSearchProposition: AdvancedSearchProposition, + Relational: Relational, + }; +}); diff --git a/web_advanced_search/static/src/xml/web_advanced_search.xml b/web_advanced_search/static/src/xml/web_advanced_search.xml new file mode 100644 index 00000000..8d791eaa --- /dev/null +++ b/web_advanced_search/static/src/xml/web_advanced_search.xml @@ -0,0 +1,11 @@ + + + + + +