diff --git a/addons/project/models/project_task.py b/addons/project/models/project_task.py index 657a4158dca..f23d8661e5b 100644 --- a/addons/project/models/project_task.py +++ b/addons/project/models/project_task.py @@ -12,6 +12,7 @@ from odoo.addons.web_editor.controllers.main import handle_history_divergence from odoo.exceptions import UserError, ValidationError, AccessError from odoo.osv import expression from odoo.tools.misc import get_lang +from odoo.addons.resource.models.utils import filter_domain_leaf PROJECT_TASK_READABLE_FIELDS = { @@ -1122,6 +1123,39 @@ class Task(models.Model): return {'date_end': fields.Datetime.now()} return {'date_end': False} + def _search_on_comodel(self, domain, field, comodel, order=None, additional_domain=None): + + def _change_operator(domain): + new_domain = [] + for dom in domain: + if len(dom) == 3: + _, op, value = dom + op = "ilike" if op == "child_of" else op + if isinstance(value, list) and all(isinstance(val, int) for val in value): + new_domain.append(("id", op, value)) + if isinstance(value, str) or (isinstance(value, list) and not all(isinstance(val, str) for val in value)): + new_domain.append(("name", op, value)) + if isinstance(value, int): + new_domain.append(("id", op, [value])) + else: + new_domain.append(dom) + return new_domain + + filtered_domain = filter_domain_leaf(domain, lambda field_to_check: field_to_check in [ + field, + f"{field}.id", + f"{field}.name", + ], { + field: "name", + f"{field}.id": "id", + f"{field}.name": "name", + }) + if not filtered_domain: + return False + if additional_domain: + filtered_domain = expression.AND([filtered_domain, additional_domain]) + return self.env[comodel].search(_change_operator(filtered_domain), order=order) + # --------------------------------------------------- # Subtasks # --------------------------------------------------- diff --git a/addons/resource/models/utils.py b/addons/resource/models/utils.py index fe435f6395d..8f643fea389 100644 --- a/addons/resource/models/utils.py +++ b/addons/resource/models/utils.py @@ -84,8 +84,8 @@ def filter_domain_leaf(domain, field_check, field_name_mapping=None): next_elem = domain.pop() # Browsing the domain backward simplifies the filtering if is_leaf(next_elem): field_name, op, value = next_elem - field_name = field_name_mapping.get(field_name, field_name) if field_check(field_name): + field_name = field_name_mapping.get(field_name, field_name) stack.append((field_name, op, value)) ignored_elems.append(False) else: diff --git a/addons/resource/tests/test_utils.py b/addons/resource/tests/test_utils.py index 2c5db580d6c..e262061d0e7 100644 --- a/addons/resource/tests/test_utils.py +++ b/addons/resource/tests/test_utils.py @@ -50,10 +50,10 @@ class TestExpression(TransactionCase): # Testing field mapping 1 self.assertEqual( - ['&', '!', ('field3', '=', False), ('field3', '!=', 'test')], + [('field4', '!=', 'test')], normalize_domain(utils.filter_domain_leaf( ['|', ('field1', 'in', [1, 2]), '!', ('field2', '=', False), ('field3', '!=', 'test')], lambda field: field == 'field3', - field_name_mapping={'field2': 'field3'}, + field_name_mapping={'field3': 'field4'}, )) ) diff --git a/addons/sale_project/models/project.py b/addons/sale_project/models/project.py index 665dc07ddbf..90ffd9ed39d 100755 --- a/addons/sale_project/models/project.py +++ b/addons/sale_project/models/project.py @@ -9,6 +9,7 @@ from odoo import api, fields, models, _, _lt from odoo.exceptions import ValidationError, AccessError from odoo.osv import expression from odoo.tools import Query + from functools import reduce from odoo.addons.project.models.project_task import CLOSED_STATES @@ -752,7 +753,7 @@ class Project(models.Model): class ProjectTask(models.Model): _inherit = "project.task" - sale_order_id = fields.Many2one('sale.order', 'Sales Order', compute='_compute_sale_order_id', store=True, help="Sales order to which the task is linked.") + sale_order_id = fields.Many2one('sale.order', 'Sales Order', compute='_compute_sale_order_id', store=True, help="Sales order to which the task is linked.", group_expand="_group_expand_sales_order") sale_line_id = fields.Many2one( 'sale.order.line', 'Sales Order Item', copy=True, tracking=True, index='btree_not_null', recursive=True, @@ -776,6 +777,17 @@ class ProjectTask(models.Model): def SELF_READABLE_FIELDS(self): return super().SELF_READABLE_FIELDS | {'allow_billable', 'sale_order_id', 'sale_line_id', 'display_sale_order_button'} + @api.model + def _group_expand_sales_order(self, sales_orders, domain, order): + start_date = self._context.get('gantt_start_date') + scale = self._context.get('gantt_scale') + if not (start_date and scale): + return sales_orders + search_on_comodel = self._search_on_comodel(domain, "sale_order_id", "sale.order", order) + if search_on_comodel: + return search_on_comodel + return sales_orders + @api.depends('sale_line_id', 'project_id', 'partner_id.commercial_partner_id', 'allow_billable') def _compute_sale_order_id(self): for task in self: