[IMP] project : gantt view improvements
Before this commit, the group by in the gantt view of project didn't allow the user to find records for which there were not scheduled tasks. For example, if a Sale Order didn't have a scheduled task, when grouping by Sale Order, the latter was not displayed. And searching for its name was not displaying it either. After this commit, when a user is searching for a sale order, even if the latter does not have any scheduled task, it is displayed in order to facilitate the scheduling of new tasks. In order to do so, a group expand on sale_order_id for the project.task model have been introduced. closes odoo/odoo#121819 Taskid: 3251630 Related: odoo/enterprise#41257 Signed-off-by: Xavier Bol (xbo) <xbo@odoo.com>
This commit is contained in:
@@ -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
|
||||
# ---------------------------------------------------
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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'},
|
||||
))
|
||||
)
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user