Browse Source

Merge pull request #1197 from Tecnativa/12.0-web_advanced_search

[MIG] web_advanced_search: Migrate to v12
pull/1204/head
Pedro M. Baeza 6 years ago
committed by GitHub
parent
commit
760a9047b2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 162
      web_advanced_search/README.rst
  2. 0
      web_advanced_search/__init__.py
  3. 27
      web_advanced_search/__manifest__.py
  4. 24
      web_advanced_search/i18n/da.po
  5. 29
      web_advanced_search/i18n/de.po
  6. 29
      web_advanced_search/i18n/es.po
  7. 29
      web_advanced_search/i18n/fr.po
  8. 30
      web_advanced_search/i18n/hr.po
  9. 29
      web_advanced_search/i18n/nl.po
  10. 30
      web_advanced_search/i18n/nl_NL.po
  11. 31
      web_advanced_search/i18n/pt_BR.po
  12. 22
      web_advanced_search/i18n/web_advanced_search.pot
  13. 6
      web_advanced_search/readme/CONTRIBUTORS.rst
  14. 1
      web_advanced_search/readme/DESCRIPTION.rst
  15. 40
      web_advanced_search/readme/HISTORY.rst
  16. 10
      web_advanced_search/readme/ROADMAP.rst
  17. 21
      web_advanced_search/readme/USAGE.rst
  18. BIN
      web_advanced_search/static/description/icon.png
  19. 512
      web_advanced_search/static/description/index.html
  20. 86
      web_advanced_search/static/src/js/human_domain.js
  21. 348
      web_advanced_search/static/src/js/web_advanced_search.js
  22. 11
      web_advanced_search/static/src/xml/web_advanced_search.xml
  23. 13
      web_advanced_search/views/templates.xml

162
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 <https://github.com/OCA/web/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 <https://github.com/OCA/web/issues/new?body=module:%20web_advanced_search%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* Therp BV
* Tecnativa
Contributors
~~~~~~~~~~~~
* Holger Brunn <hbrunn@therp.nl>
* Vicent Cubells <vicent.cubells@tecnativa.com>
* Jairo Llopis <jairo.llopis@tecnativa.com>
* Rami Alwafaie <rami.alwafaie@initos.com>
* Jose Mª Bernet <josemaria.bernet@guadaltech.es>
* Simone Orsi <simone.orsi@camptocamp.com>
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 <https://github.com/OCA/web/tree/12.0/web_advanced_search>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

0
web_advanced_search/__init__.py

27
web_advanced_search/__manifest__.py

@ -0,0 +1,27 @@
# Copyright 2015 Therp BV <http://therp.nl>
# 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,
}

24
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 <hhg@gabelgaard.org>\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"

29
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 <rs@techno-flex.de>, 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 <rs@techno-flex.de>, 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"

29
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 <transbot@odoo-community.org>, 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 <transbot@odoo-community.org>, 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"

29
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 <transbot@odoo-community.org>, 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 <transbot@odoo-community.org>, 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"

30
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 <bole@dajmi5.com>, 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 <bole@dajmi5.com>, 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"

29
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 <transbot@odoo-community.org>, 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 <transbot@odoo-community.org>, 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"

30
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 <hageman.p@gmail.com>, 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 <hageman.p@gmail.com>, 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"

31
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 <rmsolucoeseminformatic4@gmail.com>, 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 "
"<rmsolucoeseminformatic4@gmail.com>, 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"

22
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 ""

6
web_advanced_search/readme/CONTRIBUTORS.rst

@ -0,0 +1,6 @@
* Holger Brunn <hbrunn@therp.nl>
* Vicent Cubells <vicent.cubells@tecnativa.com>
* Jairo Llopis <jairo.llopis@tecnativa.com>
* Rami Alwafaie <rami.alwafaie@initos.com>
* Jose Mª Bernet <josemaria.bernet@guadaltech.es>
* Simone Orsi <simone.orsi@camptocamp.com>

1
web_advanced_search/readme/DESCRIPTION.rst

@ -0,0 +1 @@
More powerful and easy to use search, especially for related fields.

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

10
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

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

BIN
web_advanced_search/static/description/icon.png

After

Width: 100  |  Height: 100  |  Size: 2.0 KiB

512
web_advanced_search/static/description/index.html

@ -0,0 +1,512 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.14: http://docutils.sourceforge.net/" />
<title>Advanced search</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="advanced-search">
<h1 class="title">Advanced search</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/web/tree/12.0/web_advanced_search"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/web-12-0/web-12-0-web_advanced_search"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/162/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>More powerful and easy to use search, especially for related fields.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="id4">Usage</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="id5">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#changelog" id="id6">Changelog</a><ul>
<li><a class="reference internal" href="#id1" id="id7">11.0.1.0.2 (2018-10-31)</a></li>
<li><a class="reference internal" href="#id2" id="id8">11.0.1.0.1 (2018-09-18)</a></li>
<li><a class="reference internal" href="#id3" id="id9">11.0.1.0.0 (2018-07-20)</a></li>
</ul>
</li>
<li><a class="reference internal" href="#bug-tracker" id="id10">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id11">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id12">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id13">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id14">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id4">Usage</a></h1>
<p>To use this module, you need to:</p>
<ul class="simple">
<li>Open <em>Filters</em> in a search view</li>
<li>Select any relational field</li>
<li>Select operator <cite>is equal to</cite> or <cite>is not equal to</cite></li>
<li>The text field changes to a relational selection field where you
can search for the record in question</li>
<li>Click <em>Apply</em></li>
</ul>
<p>To search for properties of linked records (ie invoices for customers
with a credit limit higher than X):</p>
<ul class="simple">
<li>Open <em>Filters</em> in a search view</li>
<li>Select <em>Add Advanced Filter</em></li>
<li>Edit the advanced filter</li>
<li>Click <em>Save</em></li>
</ul>
<p>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.</p>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#id5">Known issues / Roadmap</a></h1>
<p>Improvements to the <tt class="docutils literal">domain</tt> widget, not exclusively related to this addon:</p>
<ul class="simple">
<li>Use relational widgets when filtering a relational field</li>
<li>Allow to filter field names</li>
</ul>
<p>Improvements to the search view in this addon:</p>
<ul class="simple">
<li>Use widgets <tt class="docutils literal">one2many_tags</tt> when searching <tt class="docutils literal">one2many</tt> fields</li>
<li>Use widgets <tt class="docutils literal">many2many_tags</tt> when searching <tt class="docutils literal">many2many</tt> fields</li>
<li>Allow to edit current full search using the advanced domain editor</li>
</ul>
</div>
<div class="section" id="changelog">
<h1><a class="toc-backref" href="#id6">Changelog</a></h1>
<div class="section" id="id1">
<h2><a class="toc-backref" href="#id7">11.0.1.0.2 (2018-10-31)</a></h2>
<ul>
<li><p class="first">Fix initialization of 1st domain node</p>
<p>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.</p>
<p>[simahawk]</p>
</li>
</ul>
</div>
<div class="section" id="id2">
<h2><a class="toc-backref" href="#id8">11.0.1.0.1 (2018-09-18)</a></h2>
<ul>
<li><p class="first">Fix <cite>undefined</cite> in x2m fields</p>
<p>Before this patch, when searching with the “equals to” operator in any
x2many field, the searched parameter was always <cite>undefined</cite>.</p>
<p>The problem was that the underlying field manager implementation was
treating those fields as x2many, while the widget used was the <cite>one2many</cite>
one.</p>
<p>This patch simply mocks the underlying fake record to make think that
any relational field is always a <cite>one2many</cite>. This sets all pieces in
place and makes the field manager work as expected, and thus you can
search as expected too.</p>
</li>
<li><p class="first">Make linter happy</p>
<p>[Yajo]</p>
</li>
</ul>
</div>
<div class="section" id="id3">
<h2><a class="toc-backref" href="#id9">11.0.1.0.0 (2018-07-20)</a></h2>
<ul>
<li><p class="first">Rename, refactor, migrate to v11</p>
<p>[Yajo]</p>
</li>
</ul>
</div>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id10">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/web/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/web/issues/new?body=module:%20web_advanced_search%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id11">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id12">Authors</a></h2>
<ul class="simple">
<li>Therp BV</li>
<li>Tecnativa</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id13">Contributors</a></h2>
<ul class="simple">
<li>Holger Brunn &lt;<a class="reference external" href="mailto:hbrunn&#64;therp.nl">hbrunn&#64;therp.nl</a>&gt;</li>
<li>Vicent Cubells &lt;<a class="reference external" href="mailto:vicent.cubells&#64;tecnativa.com">vicent.cubells&#64;tecnativa.com</a>&gt;</li>
<li>Jairo Llopis &lt;<a class="reference external" href="mailto:jairo.llopis&#64;tecnativa.com">jairo.llopis&#64;tecnativa.com</a>&gt;</li>
<li>Rami Alwafaie &lt;<a class="reference external" href="mailto:rami.alwafaie&#64;initos.com">rami.alwafaie&#64;initos.com</a>&gt;</li>
<li>Jose Mª Bernet &lt;<a class="reference external" href="mailto:josemaria.bernet&#64;guadaltech.es">josemaria.bernet&#64;guadaltech.es</a>&gt;</li>
<li>Simone Orsi &lt;<a class="reference external" href="mailto:simone.orsi&#64;camptocamp.com">simone.orsi&#64;camptocamp.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id14">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/web/tree/12.0/web_advanced_search">OCA/web</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

86
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 = $("<div>");
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,
};
});

348
web_advanced_search/static/src/js/web_advanced_search.js

@ -0,0 +1,348 @@
/* Copyright 2015 Therp BV <http://therp.nl>
* Copyright 2017-2018 Jairo Llopis <jairo.llopis@tecnativa.com>
* 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", $("<input value='='/>")));
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,
};
});

11
web_advanced_search/static/src/xml/web_advanced_search.xml

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2017-2018 Jairo Llopis <jairo.llopis@tecnativa.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<templates>
<t t-extend="FiltersMenuGenerator">
<t t-jquery=".o_add_filter_menu" t-operation="after">
<div role="separator" class="dropdown-divider"/>
<a class="dropdown-item o_add_advanced_search">Add Advanced Filter</a>
</t>
</t>
</templates>

13
web_advanced_search/views/templates.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2017-2018 Jairo Llopis <jairo.llopis@tecnativa.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<template id="assets_backend" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/web_advanced_search/static/src/js/human_domain.js"/>
<script type="text/javascript" src="/web_advanced_search/static/src/js/web_advanced_search.js"/>
</xpath>
</template>
</odoo>
Loading…
Cancel
Save