[IMP] base_name_search_improved: black, isort, prettier

pull/2477/head
Juan Jose Scarafia 2020-06-11 09:53:43 -03:00 committed by filoquin
parent 58f6aaa2df
commit 21daec5241
4 changed files with 62 additions and 70 deletions

View File

@ -1,18 +1,14 @@
# Copyright 2016 Daniel Reis # Copyright 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': '11.0.1.0.0', "version": "11.0.1.0.0",
'category': 'Uncategorized', "category": "Uncategorized",
'website': 'https://github.com/OCA/server-tools', "website": "https://github.com/OCA/server-tools",
'author': 'Daniel Reis, Odoo Community Association (OCA)', "author": "Daniel Reis, Odoo Community Association (OCA)",
'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,
} }

View File

@ -1,51 +1,45 @@
# Copyright 2016 Daniel Reis # Copyright 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 odoo import api, fields, models, tools
# Extended name search is only used on some operators # Extended name search is only used on some operators
ALLOWED_OPS = {'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", "=", self._name)])
[('model', '=', self._name)])
rec_name = [self._rec_name] if bool(self._rec_name) else [] rec_name = [self._rec_name] if bool(self._rec_name) else []
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
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
class IrModel(models.Model): class IrModel(models.Model):
_inherit = 'ir.model' _inherit = "ir.model"
name_search_ids = fields.Many2many( name_search_ids = fields.Many2many("ir.model.fields", string="Name Search Fields")
'ir.model.fields',
string='Name Search Fields')
@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):
# 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) )
enabled = self.env.context.get('name_search_extended', True) enabled = self.env.context.get("name_search_extended", True)
# 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
@ -57,24 +51,26 @@ 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
for rec_name in all_names: for rec_name in all_names:
domain = [(rec_name, operator, x) domain = [(rec_name, operator, x) for x in name.split() if x]
for x in name.split() if x]
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
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()

View File

@ -7,47 +7,49 @@ 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
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 555 777') res = self.Partner.name_search("ulm 555 777")
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)

View File

@ -1,21 +1,19 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2016 Daniel Reis <!-- Copyright 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>
<field name="inherit_id" ref="base.view_model_form"/> <field name="inherit_id" ref="base.view_model_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="state" position="after"> <field name="state" position="after">
<field name="name_search_ids" <field
widget="many2many_tags" name="name_search_ids"
domain="[('model_id', '=', id)]" widget="many2many_tags"
/> domain="[('model_id', '=', id)]"
/>
</field> </field>
</field> </field>
</record> </record>
</odoo> </odoo>