mirror of
https://github.com/OCA/web.git
synced 2025-02-22 13:21:25 +02:00
Description
-----------
This commit fixes incorrect bechavior (error thrown) in case when
additional `domain` provided to action (`ir.actions.act_window`)
that displays view with search panel enabled.
Before this commit
------------------
For example we have following models:
- My Category
- My Model
And in category view, we have stat-button that display number of records
of records in this category. On click, it have to open view for My
Model, with domain like `[('category_id', '=', 42)]`.
In this case, following error will be raised:
```tracaback
Error:
Odoo Server Error
Traceback (most recent call last):
...
File "/opt/odoo/custom_addons/web_view_searchpanel/models/base.py", line 60, in search_panel_select_range
hierarchical_naming=False).search_read(model_domain, fields),
File "/opt/odoo/odoo/odoo/models.py", line 4615, in search_read
records = self.search(domain or [], offset=offset, limit=limit, order=order)
File "/opt/odoo/odoo/odoo/models.py", line 1581, in search
res = self._search(args, offset=offset, limit=limit, order=order, count=count)
File "/opt/odoo/odoo/odoo/models.py", line 4147, in _search
query = self._where_calc(args)
File "/opt/odoo/odoo/odoo/models.py", line 3939, in _where_calc
e = expression.expression(domain, self)
File "/opt/odoo/odoo/odoo/osv/expression.py", line 673, in __init__
self.parse()
File "/opt/odoo/odoo/odoo/osv/expression.py", line 854, in parse
raise ValueError("Invalid field %r in leaf %r" % (left, str(leaf)))
ValueError: Invalid field 'category_id' in leaf "<osv.ExtendedLeaf: ('category_id', '=', 26) on bureaucrat_knowledge_category (ctx: )>"
```
Diagnostics
-----------
It seems that model domain was passed to comodel, thus system cannot
find field related to model in comodel. See code
(web_view_searchpanel/models/base.py", line 60, in
search_panel_select_range)
As tested, the `search_domain` causes this bug.
But if we look at implementation of same method
(`search_panel_select_range`) in Odoo 13.0 (see
[code](https://github.com/odoo/odoo/blob/13.0/addons/web/models/models.py#L214))
then we can see, that there is only empty domain applied for search.
Solution
--------
It seems, that variable `model_domain` could be simply removed, and
we could do the search in comodel without any extra domain in this case.
So, this commit, only makes imlementation of this method look same as in
Odoo 13.0
After this commit
-----------------
Everything is working fine.
193 lines
7.3 KiB
Python
193 lines
7.3 KiB
Python
# Copyright 2017-2019 MuK IT GmbH.
|
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
|
|
|
import logging
|
|
|
|
from odoo import _, api, models
|
|
from odoo.exceptions import UserError
|
|
from odoo.osv import expression
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class Base(models.AbstractModel):
|
|
|
|
_inherit = 'base'
|
|
|
|
@api.model
|
|
def search_panel_select_range(self, field_name, **kwargs):
|
|
"""
|
|
Return possible values of the field field_name (case select="one")
|
|
and the parent field (if any) used to hierarchize them.
|
|
|
|
:param field_name: the name of a many2one category field
|
|
:return: {
|
|
'parent_field': parent field on the comodel of field, or False
|
|
'values': array of dictionaries containing some info on the
|
|
records available on the comodel of the field 'field_name'.
|
|
The display name (and possibly parent_field) are fetched.
|
|
}
|
|
"""
|
|
field = self._fields[field_name]
|
|
supported_types = ['many2one']
|
|
if field.type not in supported_types:
|
|
raise UserError(_(
|
|
'Only types %(supported_types)s are supported for category'
|
|
'(found type %(field_type)s)'
|
|
) % ({
|
|
'supported_types': supported_types,
|
|
'field_type': field.type
|
|
}))
|
|
|
|
Comodel = self.env[field.comodel_name]
|
|
fields = ['display_name']
|
|
parent_name = (
|
|
Comodel._parent_name if Comodel._parent_name
|
|
in Comodel._fields else False
|
|
)
|
|
if parent_name:
|
|
fields.append(parent_name)
|
|
|
|
return {
|
|
'parent_field': parent_name,
|
|
'values': Comodel.with_context(
|
|
hierarchical_naming=False).search_read([], fields),
|
|
}
|
|
|
|
@api.model
|
|
def search_panel_select_multi_range(self, field_name, **kwargs):
|
|
"""
|
|
Return possible values of the field field_name (case select="multi"),
|
|
possibly with counters and groups.
|
|
|
|
:param field_name: the name of a filter field;
|
|
possible types are many2one, many2many, selection.
|
|
:param search_domain: base domain of search
|
|
:param category_domain: domain generated by categories
|
|
:param filter_domain: domain generated by filters
|
|
:param comodel_domain: domain of field values (if relational)
|
|
:param group_by: extra field to read on comodel, to group comodel
|
|
records
|
|
:param disable_counters: whether to count records by value
|
|
:return: a list of possible values, each being a dict with keys
|
|
'id' (value),
|
|
'name' (value label),
|
|
'count' (how many records with that value),
|
|
'group_id' (value of group),
|
|
'group_name' (label of group).
|
|
"""
|
|
field = self._fields[field_name]
|
|
supported_types = ['many2one', 'many2many', 'selection']
|
|
if field.type not in supported_types:
|
|
raise UserError(_(
|
|
'Only types %(supported_types)s are supported for '
|
|
'filter (found type %(field_type)s)'
|
|
) % ({
|
|
'supported_types': supported_types, 'field_type': field.type}))
|
|
|
|
Comodel = self.env.get(field.comodel_name)
|
|
|
|
model_domain = expression.AND([
|
|
kwargs.get('search_domain', []),
|
|
kwargs.get('category_domain', []),
|
|
kwargs.get('filter_domain', []),
|
|
[(field_name, '!=', False)],
|
|
])
|
|
comodel_domain = kwargs.get('comodel_domain', [])
|
|
disable_counters = kwargs.get('disable_counters', False)
|
|
|
|
group_by = kwargs.get('group_by', False)
|
|
if group_by:
|
|
# determine the labeling of values returned by the group_by field
|
|
group_by_field = Comodel._fields[group_by]
|
|
|
|
if group_by_field.type == 'many2one':
|
|
def group_id_name(value):
|
|
return value or (False, _("Not Set"))
|
|
|
|
elif group_by_field.type == 'selection':
|
|
desc = Comodel.fields_get([group_by])[group_by]
|
|
group_by_selection = dict(desc['selection'])
|
|
group_by_selection[False] = _("Not Set")
|
|
|
|
def group_id_name(value):
|
|
return value, group_by_selection[value]
|
|
|
|
else:
|
|
def group_id_name(value):
|
|
return (value, value) if value else (False, _("Not Set"))
|
|
|
|
# get filter_values
|
|
filter_values = []
|
|
|
|
if field.type == 'many2one':
|
|
counters = {}
|
|
if not disable_counters:
|
|
groups = self.read_group(
|
|
model_domain, [field_name], [field_name])
|
|
counters = {
|
|
group[field_name][0]: group[field_name + '_count']
|
|
for group in groups
|
|
}
|
|
# retrieve all possible values, and return them with their label
|
|
# and counter
|
|
field_names = ['display_name']
|
|
if group_by:
|
|
field_names.append(group_by)
|
|
records = Comodel.search_read(comodel_domain, field_names)
|
|
for record in records:
|
|
record_id = record['id']
|
|
values = {
|
|
'id': record_id,
|
|
'name': record['display_name'],
|
|
'count': counters.get(record_id, 0),
|
|
}
|
|
if group_by:
|
|
values['group_id'], values['group_name'] = group_id_name(
|
|
record[group_by])
|
|
filter_values.append(values)
|
|
|
|
elif field.type == 'many2many':
|
|
# retrieve all possible values, and return them with their label
|
|
# and counter
|
|
field_names = ['display_name']
|
|
if group_by:
|
|
field_names.append(group_by)
|
|
records = Comodel.search_read(comodel_domain, field_names)
|
|
for record in records:
|
|
record_id = record['id']
|
|
values = {
|
|
'id': record_id,
|
|
'name': record['display_name'],
|
|
'count': 0,
|
|
}
|
|
if not disable_counters:
|
|
count_domain = expression.AND([
|
|
model_domain, [(field_name, 'in', record_id)]])
|
|
values['count'] = self.search_count(count_domain)
|
|
if group_by:
|
|
values['group_id'], values['group_name'] = group_id_name(
|
|
record[group_by])
|
|
filter_values.append(values)
|
|
|
|
elif field.type == 'selection':
|
|
counters = {}
|
|
if not disable_counters:
|
|
groups = self.read_group(
|
|
model_domain, [field_name], [field_name])
|
|
counters = {
|
|
group[field_name]: group[field_name + '_count']
|
|
for group in groups
|
|
}
|
|
# retrieve all possible values, and return them with their label
|
|
# and counter
|
|
selection = self.fields_get([field_name])[field_name]['selection']
|
|
for value, label in selection:
|
|
filter_values.append({
|
|
'id': value,
|
|
'name': label,
|
|
'count': counters.get(value, 0),
|
|
})
|
|
|
|
return filter_values
|