[IMP] base_name_search_improved: run pre commit again
parent
bebd42a4a2
commit
323645077e
|
@ -1,19 +1,15 @@
|
||||||
# © 2016 Daniel Reis
|
# © 2016 Daniel Reis
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
{
|
{
|
||||||
'name': 'Improved Name Search',
|
"name": "Improved Name Search",
|
||||||
'summary': 'Friendlier search when typing in relation fields',
|
"summary": "Friendlier search when typing in relation fields",
|
||||||
'version': '12.0.1.1.0',
|
"version": "12.0.1.1.0",
|
||||||
'category': 'Uncategorized',
|
"category": "Uncategorized",
|
||||||
'website': 'https://odoo-community.org/',
|
"website": "https://odoo-community.org/",
|
||||||
'author': 'Daniel Reis, Odoo Community Association (OCA), ADHOC SA',
|
"author": "Daniel Reis, Odoo Community Association (OCA), ADHOC SA",
|
||||||
'license': 'AGPL-3',
|
"license": "AGPL-3",
|
||||||
'data': [
|
"data": ["views/ir_model_views.xml",],
|
||||||
'views/ir_model_views.xml',
|
"depends": ["base",],
|
||||||
],
|
"installable": True,
|
||||||
'depends': [
|
|
||||||
'base',
|
|
||||||
],
|
|
||||||
'installable': True,
|
|
||||||
"uninstall_hook": "uninstall_hook",
|
"uninstall_hook": "uninstall_hook",
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from odoo import api, models
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from odoo import api, models
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,34 @@
|
||||||
# © 2016 Daniel Reis
|
# © 2016 Daniel Reis
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
from odoo import models, fields, api, tools, _
|
|
||||||
from lxml import etree
|
|
||||||
from ast import literal_eval
|
|
||||||
from odoo.exceptions import ValidationError
|
|
||||||
import logging
|
import logging
|
||||||
|
from ast import literal_eval
|
||||||
|
|
||||||
|
from lxml import etree
|
||||||
|
|
||||||
|
from odoo import _, api, fields, models, tools
|
||||||
|
from odoo.exceptions import ValidationError
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
# Extended name search is only used on some operators
|
# Extended name search is only used on some operators
|
||||||
ALLOWED_OPS = set(['ilike', 'like'])
|
ALLOWED_OPS = {"ilike", "like"}
|
||||||
|
|
||||||
|
|
||||||
@tools.ormcache(skiparg=0)
|
@tools.ormcache(skiparg=0)
|
||||||
def _get_rec_names(self):
|
def _get_rec_names(self):
|
||||||
"List of fields to search into"
|
"List of fields to search into"
|
||||||
model = self.env['ir.model'].search(
|
model = self.env["ir.model"].search([("model", "=", str(self._name))])
|
||||||
[('model', '=', str(self._name))])
|
|
||||||
rec_name = [self._rec_name] or []
|
rec_name = [self._rec_name] or []
|
||||||
other_names = model.name_search_ids.mapped('name')
|
other_names = model.name_search_ids.mapped("name")
|
||||||
return rec_name + other_names
|
return rec_name + other_names
|
||||||
|
|
||||||
|
|
||||||
@tools.ormcache(skiparg=0)
|
@tools.ormcache(skiparg=0)
|
||||||
def _get_add_smart_search(self):
|
def _get_add_smart_search(self):
|
||||||
"Add Smart Search on search views"
|
"Add Smart Search on search views"
|
||||||
model = self.env['ir.model'].search([('model', '=', str(self._name))])
|
model = self.env["ir.model"].search([("model", "=", str(self._name))])
|
||||||
# Run only if module is installed
|
# Run only if module is installed
|
||||||
if hasattr(model, 'add_smart_search'):
|
if hasattr(model, "add_smart_search"):
|
||||||
return model.add_smart_search
|
return model.add_smart_search
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -34,8 +36,11 @@ def _get_add_smart_search(self):
|
||||||
@tools.ormcache(skiparg=0)
|
@tools.ormcache(skiparg=0)
|
||||||
def _get_name_search_domain(self):
|
def _get_name_search_domain(self):
|
||||||
"Add Smart Search on search views"
|
"Add Smart Search on search views"
|
||||||
name_search_domain = self.env['ir.model'].search(
|
name_search_domain = (
|
||||||
[('model', '=', str(self._name))]).name_search_domain
|
self.env["ir.model"]
|
||||||
|
.search([("model", "=", str(self._name))])
|
||||||
|
.name_search_domain
|
||||||
|
)
|
||||||
if name_search_domain:
|
if name_search_domain:
|
||||||
return literal_eval(name_search_domain)
|
return literal_eval(name_search_domain)
|
||||||
return []
|
return []
|
||||||
|
@ -44,11 +49,12 @@ def _get_name_search_domain(self):
|
||||||
def _extend_name_results(self, domain, results, limit):
|
def _extend_name_results(self, domain, results, limit):
|
||||||
result_count = len(results)
|
result_count = len(results)
|
||||||
if result_count < limit:
|
if result_count < limit:
|
||||||
domain += [('id', 'not in', [x[0] for x in results])]
|
domain += [("id", "not in", [x[0] for x in results])]
|
||||||
recs = self.search(domain, limit=limit - result_count)
|
recs = self.search(domain, limit=limit - result_count)
|
||||||
results.extend(recs.name_get())
|
results.extend(recs.name_get())
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
# TODO move all this to register_hook
|
# TODO move all this to register_hook
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,11 +66,17 @@ def _add_magic_fields(self):
|
||||||
res = _add_magic_fields_original(self)
|
res = _add_magic_fields_original(self)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
'base_name_search_improved' in self.env.registry._init_modules and
|
"base_name_search_improved" in self.env.registry._init_modules
|
||||||
'smart_search' not in self._fields):
|
and "smart_search" not in self._fields
|
||||||
self._add_field('smart_search', fields.Char(
|
):
|
||||||
automatic=True, compute='_compute_smart_search',
|
self._add_field(
|
||||||
search='_search_smart_search'))
|
"smart_search",
|
||||||
|
fields.Char(
|
||||||
|
automatic=True,
|
||||||
|
compute="_compute_smart_search",
|
||||||
|
search="_search_smart_search",
|
||||||
|
),
|
||||||
|
)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,53 +84,44 @@ models.BaseModel._add_magic_fields = _add_magic_fields
|
||||||
|
|
||||||
|
|
||||||
class IrModel(models.Model):
|
class IrModel(models.Model):
|
||||||
_inherit = 'ir.model'
|
_inherit = "ir.model"
|
||||||
|
|
||||||
add_smart_search = fields.Boolean(
|
add_smart_search = fields.Boolean(help="Add Smart Search on search views",)
|
||||||
help="Add Smart Search on search views",
|
name_search_ids = fields.Many2many("ir.model.fields", string="Name Search Fields")
|
||||||
)
|
name_search_domain = fields.Char()
|
||||||
name_search_ids = fields.Many2many(
|
|
||||||
'ir.model.fields',
|
|
||||||
string='Name Search Fields')
|
|
||||||
name_search_domain = fields.Char(
|
|
||||||
)
|
|
||||||
|
|
||||||
@api.constrains(
|
@api.constrains("name_search_ids", "name_search_domain", "add_smart_search")
|
||||||
'name_search_ids', 'name_search_domain', 'add_smart_search')
|
|
||||||
def update_search_wo_restart(self):
|
def update_search_wo_restart(self):
|
||||||
self.clear_caches()
|
self.clear_caches()
|
||||||
|
|
||||||
@api.constrains('name_search_domain')
|
@api.constrains("name_search_domain")
|
||||||
def check_name_search_domain(self):
|
def check_name_search_domain(self):
|
||||||
for rec in self.filtered('name_search_domain'):
|
for rec in self.filtered("name_search_domain"):
|
||||||
name_search_domain = False
|
name_search_domain = False
|
||||||
try:
|
try:
|
||||||
name_search_domain = literal_eval(rec.name_search_domain)
|
name_search_domain = literal_eval(rec.name_search_domain)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
raise ValidationError(_(
|
raise ValidationError(
|
||||||
"Couldn't eval Name Search Domain (%s)") % error)
|
_("Couldn't eval Name Search Domain (%s)") % error
|
||||||
|
)
|
||||||
if not isinstance(name_search_domain, list):
|
if not isinstance(name_search_domain, list):
|
||||||
raise ValidationError(_(
|
raise ValidationError(_("Name Search Domain must be a list of tuples"))
|
||||||
'Name Search Domain must be a list of tuples'))
|
|
||||||
|
|
||||||
@api.model_cr
|
@api.model_cr
|
||||||
def _register_hook(self):
|
def _register_hook(self):
|
||||||
|
|
||||||
def make_name_search():
|
def make_name_search():
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def name_search(self, name='', args=None,
|
def name_search(self, name="", args=None, operator="ilike", limit=100):
|
||||||
operator='ilike', limit=100):
|
|
||||||
limit = limit or 0
|
limit = limit or 0
|
||||||
enabled = self.env.context.get('name_search_extended', True)
|
enabled = self.env.context.get("name_search_extended", True)
|
||||||
superself = self.sudo()
|
superself = self.sudo()
|
||||||
if enabled:
|
if enabled:
|
||||||
# we add domain
|
# we add domain
|
||||||
args = args or [] + _get_name_search_domain(superself)
|
args = args or [] + _get_name_search_domain(superself)
|
||||||
# Perform standard name search
|
# Perform standard name search
|
||||||
res = name_search.origin(
|
res = name_search.origin(
|
||||||
self, name=name, args=args, operator=operator,
|
self, name=name, args=args, operator=operator, limit=limit
|
||||||
limit=limit)
|
)
|
||||||
# Perform extended name search
|
# Perform extended name search
|
||||||
# Note: Empty name causes error on
|
# Note: Empty name causes error on
|
||||||
# Customer->More->Portal Access Management
|
# Customer->More->Portal Access Management
|
||||||
|
@ -130,13 +133,14 @@ class IrModel(models.Model):
|
||||||
for rec_name in all_names[1:]:
|
for rec_name in all_names[1:]:
|
||||||
domain = [(rec_name, operator, name)]
|
domain = [(rec_name, operator, name)]
|
||||||
res = _extend_name_results(
|
res = _extend_name_results(
|
||||||
self, base_domain + domain, res, limit)
|
self, base_domain + domain, res, limit
|
||||||
|
)
|
||||||
# Try ordered word search on each of the search fields
|
# Try ordered word search on each of the search fields
|
||||||
for rec_name in all_names:
|
for rec_name in all_names:
|
||||||
domain = [
|
domain = [(rec_name, operator, name.replace(" ", "%"))]
|
||||||
(rec_name, operator, name.replace(' ', '%'))]
|
|
||||||
res = _extend_name_results(
|
res = _extend_name_results(
|
||||||
self, base_domain + domain, res, limit)
|
self, base_domain + domain, res, limit
|
||||||
|
)
|
||||||
# Try unordered word search on each of the search fields
|
# Try unordered word search on each of the search fields
|
||||||
# we only perform this search if we have at least one
|
# we only perform this search if we have at least one
|
||||||
# separator character
|
# separator character
|
||||||
|
@ -147,39 +151,44 @@ class IrModel(models.Model):
|
||||||
word_domain = []
|
word_domain = []
|
||||||
for rec_name in all_names:
|
for rec_name in all_names:
|
||||||
word_domain = (
|
word_domain = (
|
||||||
word_domain and ['|'] + word_domain or
|
word_domain and ["|"] + word_domain or word_domain
|
||||||
word_domain
|
|
||||||
) + [(rec_name, operator, word)]
|
) + [(rec_name, operator, word)]
|
||||||
domain = (
|
domain = (domain and ["&"] + domain or domain) + word_domain
|
||||||
domain and ['&'] + domain or domain
|
|
||||||
) + word_domain
|
|
||||||
res = _extend_name_results(
|
res = _extend_name_results(
|
||||||
self, base_domain + domain, res, limit)
|
self, base_domain + domain, res, limit
|
||||||
|
)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
return name_search
|
return name_search
|
||||||
|
|
||||||
def patch_fields_view_get():
|
def patch_fields_view_get():
|
||||||
@api.model
|
@api.model
|
||||||
def fields_view_get(
|
def fields_view_get(
|
||||||
self, view_id=None, view_type='form', toolbar=False,
|
self, view_id=None, view_type="form", toolbar=False, submenu=False
|
||||||
submenu=False):
|
):
|
||||||
res = fields_view_get.origin(
|
res = fields_view_get.origin(
|
||||||
self, view_id=view_id, view_type=view_type,
|
self,
|
||||||
toolbar=toolbar, submenu=submenu)
|
view_id=view_id,
|
||||||
if view_type == 'search' and _get_add_smart_search(self):
|
view_type=view_type,
|
||||||
eview = etree.fromstring(res['arch'])
|
toolbar=toolbar,
|
||||||
|
submenu=submenu,
|
||||||
|
)
|
||||||
|
if view_type == "search" and _get_add_smart_search(self):
|
||||||
|
eview = etree.fromstring(res["arch"])
|
||||||
placeholders = eview.xpath("//search/field")
|
placeholders = eview.xpath("//search/field")
|
||||||
if placeholders:
|
if placeholders:
|
||||||
placeholder = placeholders[0]
|
placeholder = placeholders[0]
|
||||||
else:
|
else:
|
||||||
placeholder = eview.xpath("//search")[0]
|
placeholder = eview.xpath("//search")[0]
|
||||||
placeholder.addnext(
|
placeholder.addnext(
|
||||||
etree.Element('field', {'name': 'smart_search'}))
|
etree.Element("field", {"name": "smart_search"})
|
||||||
|
)
|
||||||
eview.remove(placeholder)
|
eview.remove(placeholder)
|
||||||
res['arch'] = etree.tostring(eview)
|
res["arch"] = etree.tostring(eview)
|
||||||
res['fields'].update(self.fields_get(['smart_search']))
|
res["fields"].update(self.fields_get(["smart_search"]))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
return fields_view_get
|
return fields_view_get
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
|
@ -197,7 +206,7 @@ class IrModel(models.Model):
|
||||||
primero los que mejor coinciden, en este caso eso no es necesario
|
primero los que mejor coinciden, en este caso eso no es necesario
|
||||||
Igualmente seguro se puede mejorar y unificar bastante código
|
Igualmente seguro se puede mejorar y unificar bastante código
|
||||||
"""
|
"""
|
||||||
enabled = self.env.context.get('name_search_extended', True)
|
enabled = self.env.context.get("name_search_extended", True)
|
||||||
name = value
|
name = value
|
||||||
if name and enabled and operator in ALLOWED_OPS:
|
if name and enabled and operator in ALLOWED_OPS:
|
||||||
superself = self.sudo()
|
superself = self.sudo()
|
||||||
|
@ -207,29 +216,25 @@ class IrModel(models.Model):
|
||||||
word_domain = []
|
word_domain = []
|
||||||
for rec_name in all_names:
|
for rec_name in all_names:
|
||||||
word_domain = (
|
word_domain = (
|
||||||
word_domain and ['|'] + word_domain or
|
word_domain and ["|"] + word_domain or word_domain
|
||||||
word_domain
|
|
||||||
) + [(rec_name, operator, word)]
|
) + [(rec_name, operator, word)]
|
||||||
domain = (
|
domain = (domain and ["&"] + domain or domain) + word_domain
|
||||||
domain and ['&'] + domain or domain
|
|
||||||
) + word_domain
|
|
||||||
return domain
|
return domain
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# add methods of computed fields
|
# add methods of computed fields
|
||||||
if not hasattr(models.BaseModel, '_compute_smart_search'):
|
if not hasattr(models.BaseModel, "_compute_smart_search"):
|
||||||
models.BaseModel._compute_smart_search = _compute_smart_search
|
models.BaseModel._compute_smart_search = _compute_smart_search
|
||||||
if not hasattr(models.BaseModel, '_search_smart_search'):
|
if not hasattr(models.BaseModel, "_search_smart_search"):
|
||||||
models.BaseModel._search_smart_search = _search_smart_search
|
models.BaseModel._search_smart_search = _search_smart_search
|
||||||
|
|
||||||
_logger.info('Patching fields_view_get on BaseModel')
|
_logger.info("Patching fields_view_get on BaseModel")
|
||||||
models.BaseModel._patch_method(
|
models.BaseModel._patch_method("fields_view_get", patch_fields_view_get())
|
||||||
'fields_view_get', patch_fields_view_get())
|
|
||||||
|
|
||||||
for model in self.sudo().search(self.ids or []):
|
for model in self.sudo().search(self.ids or []):
|
||||||
Model = self.env.get(model.model)
|
Model = self.env.get(model.model)
|
||||||
if Model is not None:
|
if Model is not None:
|
||||||
Model._patch_method('name_search', make_name_search())
|
Model._patch_method("name_search", make_name_search())
|
||||||
|
|
||||||
return super(IrModel, self)._register_hook()
|
return super(IrModel, self)._register_hook()
|
||||||
|
|
||||||
|
|
|
@ -7,62 +7,64 @@ from odoo.tests.common import TransactionCase, at_install, post_install
|
||||||
@at_install(False)
|
@at_install(False)
|
||||||
@post_install(True)
|
@post_install(True)
|
||||||
class NameSearchCase(TransactionCase):
|
class NameSearchCase(TransactionCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(NameSearchCase, self).setUp()
|
super(NameSearchCase, self).setUp()
|
||||||
phone_field = self.env.ref('base.field_res_partner_phone')
|
phone_field = self.env.ref("base.field_res_partner_phone")
|
||||||
model_partner = self.env.ref('base.model_res_partner')
|
model_partner = self.env.ref("base.model_res_partner")
|
||||||
model_partner.name_search_ids = phone_field
|
model_partner.name_search_ids = phone_field
|
||||||
model_partner.add_smart_search = True
|
model_partner.add_smart_search = True
|
||||||
|
|
||||||
# this use does not make muche sense but with base module we dont have
|
# this use does not make muche sense but with base module we dont have
|
||||||
# much models to use for tests
|
# much models to use for tests
|
||||||
model_partner.name_search_domain = "[('parent_id', '=', False)]"
|
model_partner.name_search_domain = "[('parent_id', '=', False)]"
|
||||||
self.Partner = self.env['res.partner']
|
self.Partner = self.env["res.partner"]
|
||||||
self.partner1 = self.Partner.create(
|
self.partner1 = self.Partner.create(
|
||||||
{'name': 'Luigi Verconti',
|
{"name": "Luigi Verconti", "customer": True, "phone": "+351 555 777 333"}
|
||||||
'customer': True,
|
)
|
||||||
'phone': '+351 555 777 333'})
|
|
||||||
self.partner2 = self.Partner.create(
|
self.partner2 = self.Partner.create(
|
||||||
{'name': 'Ken Shabby',
|
{"name": "Ken Shabby", "customer": True, "phone": "+351 555 333 777"}
|
||||||
'customer': True,
|
)
|
||||||
'phone': '+351 555 333 777'})
|
|
||||||
self.partner3 = self.Partner.create(
|
self.partner3 = self.Partner.create(
|
||||||
{'name': 'Johann Gambolputty of Ulm',
|
{
|
||||||
'supplier': True,
|
"name": "Johann Gambolputty of Ulm",
|
||||||
'phone': '+351 777 333 555'})
|
"supplier": True,
|
||||||
|
"phone": "+351 777 333 555",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
def test_RelevanceOrderedResults(self):
|
def test_RelevanceOrderedResults(self):
|
||||||
"""Return results ordered by relevance"""
|
"""Return results ordered by relevance"""
|
||||||
res = self.Partner.name_search('555 777')
|
res = self.Partner.name_search("555 777")
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
res[0][0], self.partner1.id,
|
res[0][0], self.partner1.id, "Match full string honoring spaces"
|
||||||
'Match full string honoring spaces')
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
res[1][0], self.partner2.id,
|
res[1][0], self.partner2.id, "Match words honoring order of appearance"
|
||||||
'Match words honoring order of appearance')
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
res[2][0], self.partner3.id,
|
res[2][0],
|
||||||
'Match all words, regardless of order of appearance')
|
self.partner3.id,
|
||||||
|
"Match all words, regardless of order of appearance",
|
||||||
|
)
|
||||||
|
|
||||||
def test_NameSearchMustMatchAllWords(self):
|
def test_NameSearchMustMatchAllWords(self):
|
||||||
"""Must Match All Words"""
|
"""Must Match All Words"""
|
||||||
res = self.Partner.name_search('ulm aaa 555 777')
|
res = self.Partner.name_search("ulm aaa 555 777")
|
||||||
self.assertFalse(res)
|
self.assertFalse(res)
|
||||||
|
|
||||||
def test_NameSearchDifferentFields(self):
|
def test_NameSearchDifferentFields(self):
|
||||||
"""Must Match All Words"""
|
"""Must Match All Words"""
|
||||||
res = self.Partner.name_search('ulm 555 777')
|
res = self.Partner.name_search("ulm 555 777")
|
||||||
self.assertEqual(len(res), 1)
|
self.assertEqual(len(res), 1)
|
||||||
|
|
||||||
def test_NameSearchDomain(self):
|
def test_NameSearchDomain(self):
|
||||||
"""Must not return a partner with parent"""
|
"""Must not return a partner with parent"""
|
||||||
res = self.Partner.name_search('Edward Foster')
|
res = self.Partner.name_search("Edward Foster")
|
||||||
self.assertFalse(res)
|
self.assertFalse(res)
|
||||||
|
|
||||||
def test_MustHonorDomain(self):
|
def test_MustHonorDomain(self):
|
||||||
"""Must also honor a provided Domain"""
|
"""Must also honor a provided Domain"""
|
||||||
res = self.Partner.name_search('+351', args=[('supplier', '=', True)])
|
res = self.Partner.name_search("+351", args=[("supplier", "=", True)])
|
||||||
gambulputty = self.partner3.id
|
gambulputty = self.partner3.id
|
||||||
self.assertEqual(len(res), 1)
|
self.assertEqual(len(res), 1)
|
||||||
self.assertEqual(res[0][0], gambulputty)
|
self.assertEqual(res[0][0], gambulputty)
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<!-- © 2016 Daniel Reis
|
<!-- © 2016 Daniel Reis
|
||||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
|
||||||
|
|
||||||
<odoo>
|
<odoo>
|
||||||
|
|
||||||
<record id="view_model_form" model="ir.ui.view">
|
<record id="view_model_form" model="ir.ui.view">
|
||||||
<field name="name">Add Name Searchable to Models</field>
|
<field name="name">Add Name Searchable to Models</field>
|
||||||
<field name="model">ir.model</field>
|
<field name="model">ir.model</field>
|
||||||
|
@ -11,7 +9,8 @@
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<field name="state" position="after">
|
<field name="state" position="after">
|
||||||
<field name="add_smart_search" />
|
<field name="add_smart_search" />
|
||||||
<field name="name_search_ids"
|
<field
|
||||||
|
name="name_search_ids"
|
||||||
widget="many2many_tags"
|
widget="many2many_tags"
|
||||||
domain="[('model_id', '=', id), ('store', '=', True)]"
|
domain="[('model_id', '=', id), ('store', '=', True)]"
|
||||||
/>
|
/>
|
||||||
|
@ -19,7 +18,6 @@
|
||||||
</field>
|
</field>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="view_model_form_new" model="ir.ui.view">
|
<record id="view_model_form_new" model="ir.ui.view">
|
||||||
<field name="name">view.model.form</field>
|
<field name="name">view.model.form</field>
|
||||||
<field name="model">ir.model</field>
|
<field name="model">ir.model</field>
|
||||||
|
@ -27,13 +25,22 @@
|
||||||
<form string="Custom Search">
|
<form string="Custom Search">
|
||||||
<sheet>
|
<sheet>
|
||||||
<div class="oe_button_box" name="buttons">
|
<div class="oe_button_box" name="buttons">
|
||||||
<button name="toggle_smart_search" type="object" class="oe_stat_button" icon="fa-archive">
|
<button
|
||||||
<field name="add_smart_search" widget="boolean_button" options="{'terminology': {
|
name="toggle_smart_search"
|
||||||
|
type="object"
|
||||||
|
class="oe_stat_button"
|
||||||
|
icon="fa-archive"
|
||||||
|
>
|
||||||
|
<field
|
||||||
|
name="add_smart_search"
|
||||||
|
widget="boolean_button"
|
||||||
|
options="{'terminology': {
|
||||||
'string_true': 'Smart Active',
|
'string_true': 'Smart Active',
|
||||||
'hover_true': 'Remove Smart Search',
|
'hover_true': 'Remove Smart Search',
|
||||||
'string_false': 'Not Smart Search',
|
'string_false': 'Not Smart Search',
|
||||||
'hover_false': 'Add Smart Search',
|
'hover_false': 'Add Smart Search',
|
||||||
}}"/>
|
}}"
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="oe_title">
|
<div class="oe_title">
|
||||||
|
@ -52,7 +59,12 @@
|
||||||
<notebook colspan="4">
|
<notebook colspan="4">
|
||||||
<page string="Fields">
|
<page string="Fields">
|
||||||
<!-- widget="many2many_tags" -->
|
<!-- widget="many2many_tags" -->
|
||||||
<field name="name_search_ids" colspan="4" nolabel="1" domain="[('model_id', '=', id), ('store', '=', True)]">
|
<field
|
||||||
|
name="name_search_ids"
|
||||||
|
colspan="4"
|
||||||
|
nolabel="1"
|
||||||
|
domain="[('model_id', '=', id), ('store', '=', True)]"
|
||||||
|
>
|
||||||
<tree>
|
<tree>
|
||||||
<field name="name" />
|
<field name="name" />
|
||||||
<field name="field_description" />
|
<field name="field_description" />
|
||||||
|
@ -66,7 +78,6 @@
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="view_model_tree" model="ir.ui.view">
|
<record id="view_model_tree" model="ir.ui.view">
|
||||||
<field name="name">view.model.tree</field>
|
<field name="name">view.model.tree</field>
|
||||||
<field name="model">ir.model</field>
|
<field name="model">ir.model</field>
|
||||||
|
@ -74,13 +85,21 @@
|
||||||
<tree>
|
<tree>
|
||||||
<field name="id" invisible="1" />
|
<field name="id" invisible="1" />
|
||||||
<field name="name" readonly="1" />
|
<field name="name" readonly="1" />
|
||||||
<field name="name_search_ids" widget="many2many_tags" string="Search Fields" domain="[('model_id', '=', id), ('store', '=', True)]"/>
|
<field
|
||||||
|
name="name_search_ids"
|
||||||
|
widget="many2many_tags"
|
||||||
|
string="Search Fields"
|
||||||
|
domain="[('model_id', '=', id), ('store', '=', True)]"
|
||||||
|
/>
|
||||||
<field name="name_search_domain" string="Domain" />
|
<field name="name_search_domain" string="Domain" />
|
||||||
<field name="add_smart_search" string="Smart Search" widget="boolean_toggle"/>
|
<field
|
||||||
|
name="add_smart_search"
|
||||||
|
string="Smart Search"
|
||||||
|
widget="boolean_toggle"
|
||||||
|
/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="view_model_search" model="ir.ui.view">
|
<record id="view_model_search" model="ir.ui.view">
|
||||||
<field name="name">view.model.search</field>
|
<field name="name">view.model.search</field>
|
||||||
<field name="model">ir.model</field>
|
<field name="model">ir.model</field>
|
||||||
|
@ -89,29 +108,40 @@
|
||||||
<field name="id" />
|
<field name="id" />
|
||||||
<field name="name" />
|
<field name="name" />
|
||||||
<field name="model" />
|
<field name="model" />
|
||||||
<filter name="extra_search" string="With Custom Search" domain="[('name_search_ids', '!=', False)]"/>
|
<filter
|
||||||
<filter name="smart_search" string="Smart Search" domain="[('add_smart_search', '=', True)]"/>
|
name="extra_search"
|
||||||
|
string="With Custom Search"
|
||||||
|
domain="[('name_search_ids', '!=', False)]"
|
||||||
|
/>
|
||||||
|
<filter
|
||||||
|
name="smart_search"
|
||||||
|
string="Smart Search"
|
||||||
|
domain="[('add_smart_search', '=', True)]"
|
||||||
|
/>
|
||||||
</search>
|
</search>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="action_improved_name_search" model="ir.actions.act_window">
|
<record id="action_improved_name_search" model="ir.actions.act_window">
|
||||||
<field name="name">Custom Searches</field>
|
<field name="name">Custom Searches</field>
|
||||||
<field name="res_model">ir.model</field>
|
<field name="res_model">ir.model</field>
|
||||||
<field name="view_type">form</field>
|
<field name="view_type">form</field>
|
||||||
<field name="view_mode">tree,form</field>
|
<field name="view_mode">tree,form</field>
|
||||||
<field name="search_view_id" ref="view_model_search" />
|
<field name="search_view_id" ref="view_model_search" />
|
||||||
<field name="view_ids" eval="[(5, 0, 0),
|
<field
|
||||||
|
name="view_ids"
|
||||||
|
eval="[(5, 0, 0),
|
||||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('view_model_tree')}),
|
(0, 0, {'view_mode': 'tree', 'view_id': ref('view_model_tree')}),
|
||||||
(0, 0, {'view_mode': 'form', 'view_id': ref('view_model_form_new')}
|
(0, 0, {'view_mode': 'form', 'view_id': ref('view_model_form_new')}
|
||||||
)]"/>
|
)]"
|
||||||
|
/>
|
||||||
<field name="context">{'search_default_extra_search': 1}</field>
|
<field name="context">{'search_default_extra_search': 1}</field>
|
||||||
<field name="domain">[('transient', '=', False)]</field>
|
<field name="domain">[('transient', '=', False)]</field>
|
||||||
</record>
|
</record>
|
||||||
|
<menuitem
|
||||||
<menuitem id="menu_improved_name_search" name="Custom Searches"
|
id="menu_improved_name_search"
|
||||||
parent="base.menu_administration" sequence="6"
|
name="Custom Searches"
|
||||||
|
parent="base.menu_administration"
|
||||||
|
sequence="6"
|
||||||
action="action_improved_name_search"
|
action="action_improved_name_search"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
Loading…
Reference in New Issue