[FIX] project: avoid warning when selecting tags of a task

Currently, when selecting tags for a task with no project (private
task) on mobile, a warning is displayed. On top of that, the amount
available tags is way more limited than in classical view and the
selection of some exesting tags is impossible.

Steps
=====
1. Warning when selecting tags
- Install module project
- In mobile view, go to the view "Tasks -> My Tasks"
- Open or create a private task (task with no project)
- Click on the tags field

A warning is displayed (on the server logs) stating:
"The domain term '('project_ids', 'in', False)' should use the '=' or
'!=' operator."

2. Limited tag choice
- Install module project
- In mobile view, go to the view "Tasks -> My Tasks"
- Open or create a private task (task with no project)
- Click on the tags field
- The tags that are only related to project(s) are not displayed in this
  view
- Try to create a tag with the same name than an existing tag that does
  not appear.
- A traceback is displayed because this tag already exists.

Cause
=====
As noted from the test of expression.py, M2M fields in the domain should
be compared to list of elements. It is not the case here. When a
project_id exits in the context, nothing happens, but there exists a
check in the ORM to ensure that '=' or '!=' operator is used if the
second element of the domain leaf is a boolean. In this case, there is
not project_id set in the context for private task, resulting in
the previous warning (False used instead of project_id).

Fix
===
We use the improved implementation of _name_search to get the ordered
list of id of records project.tags to display. This list has the
advantage to not be restricted to the current project, while still
presenting the tags of the current project at the top of the list. The
mobile view uses the method search_read to get the list of project.tags
record values, therefore we call the _name_search in this method and use
an optimized sorting function to sort the resulting records accordingly.

task-3302370

closes odoo/odoo#126091

X-original-commit: a03a93aa8cf5567f79dd66ced5911721b82a3802
Signed-off-by: Xavier Bol (xbo) <xbo@odoo.com>
This commit is contained in:
Hugo Carlier (Huca)
2023-06-22 21:07:39 +02:00
parent 4d7da09779
commit 1e57df85ad
+21 -5
View File
@@ -27,22 +27,38 @@ class ProjectTags(models.Model):
]
def _get_project_tags_domain(self, domain, project_id):
tag_ids = list(self.with_user(SUPERUSER_ID)._search(
['|', ('task_ids.project_id', '=', project_id), ('project_ids', 'in', project_id)]))
return expression.AND([domain, [('id', 'in', tag_ids)]])
# TODO: Remove in master
return domain
@api.model
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
if 'project_id' in self.env.context:
domain = self._get_project_tags_domain(domain, self.env.context.get('project_id'))
tag_ids = self._name_search('')
domain = expression.AND([domain, [('id', 'in', tag_ids)]])
return super().read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
@api.model
def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None):
if 'project_id' in self.env.context:
domain = self._get_project_tags_domain(domain, self.env.context.get('project_id'))
tag_ids = self._name_search('')
domain = expression.AND([domain, [('id', 'in', tag_ids)]])
return self.arrange_tag_list_by_id(super().search_read(domain=domain, fields=fields, offset=offset, limit=limit), tag_ids)
return super().search_read(domain=domain, fields=fields, offset=offset, limit=limit, order=order)
@api.model
def arrange_tag_list_by_id(self, tag_list, id_order):
"""arrange_tag_list_by_id re-order a list of record values (dict) following a given id sequence
complexity: O(n)
param:
- tag_list: ordered (by id) list of record values, each record being a dict
containing at least an 'id' key
- id_order: list of value (int) corresponding to the id of the records to re-arrange
result:
- Sorted list of record values (dict)
"""
tags_by_id = {tag['id']: tag for tag in tag_list}
return [tags_by_id[id] for id in id_order if id in tags_by_id]
@api.model
def _name_search(self, name, domain=None, operator='ilike', limit=None, order=None):
if self.env.context.get('project_id') and operator == 'ilike':