[IMP] project: convert onchange to stored-editable computed fields.
The 'stage_id' field is now a stored-editable computed field. The 'company_id' has been converted to a stored-editable computed field. The modification of the 'partner_id' field in the onchange method has been moved and merged into the _compute_partner_id method. Remove the empty 'onchange' method from the project.task model and also remove this method call from the sale_timesheet module, which inherits from the project.task model. Adapt the _compute_partner_id to retrieve exactly the behaviour before the onchange method deletion. Update code and tests of the task/subtask partner_id management after discussion with Alexandra to clarify the behavior. Add the 'multi_edit' attribute to tree views.
This commit is contained in:
committed by
Yannick Tivisse
parent
cd4e854e41
commit
972e097dbe
@@ -520,7 +520,8 @@ class Task(models.Model):
|
||||
], default='0', index=True, string="Priority")
|
||||
sequence = fields.Integer(string='Sequence', index=True, default=10,
|
||||
help="Gives the sequence order when displaying a list of tasks.")
|
||||
stage_id = fields.Many2one('project.task.type', string='Stage', ondelete='restrict', tracking=True, index=True,
|
||||
stage_id = fields.Many2one('project.task.type', string='Stage', compute='_compute_stage_id',
|
||||
store=True, readonly=False, ondelete='restrict', tracking=True, index=True,
|
||||
default=_get_default_stage_id, group_expand='_read_group_stage_ids',
|
||||
domain="[('project_ids', '=', project_id)]", copy=False)
|
||||
tag_ids = fields.Many2many('project.tags', string='Tags')
|
||||
@@ -563,7 +564,9 @@ class Task(models.Model):
|
||||
ribbon_message = fields.Char('Ribbon message', compute='_compute_ribbon_message')
|
||||
partner_city = fields.Char(related='partner_id.city', readonly=False)
|
||||
manager_id = fields.Many2one('res.users', string='Project Manager', related='project_id.user_id', readonly=True)
|
||||
company_id = fields.Many2one('res.company', string='Company', required=True, default=_default_company_id)
|
||||
company_id = fields.Many2one(
|
||||
'res.company', string='Company', compute='_compute_company_id', store=True, readonly=False,
|
||||
required=True, copy=True, default=_default_company_id)
|
||||
color = fields.Integer(string='Color Index')
|
||||
user_email = fields.Char(related='user_id.email', string='User Email', readonly=True, related_sudo=False)
|
||||
attachment_ids = fields.One2many('ir.attachment', compute='_compute_attachment_ids', string="Main Attachments",
|
||||
@@ -722,25 +725,26 @@ class Task(models.Model):
|
||||
for task in self:
|
||||
task.subtask_count = len(self._get_all_subtasks())
|
||||
|
||||
@api.onchange('project_id')
|
||||
def _onchange_project(self):
|
||||
if self.project_id:
|
||||
# find partner
|
||||
if self.project_id.partner_id:
|
||||
self.partner_id = self.project_id.partner_id
|
||||
# find stage
|
||||
if self.project_id not in self.stage_id.project_ids:
|
||||
self.stage_id = self.stage_find(self.project_id.id, [('fold', '=', False), ('is_closed', '=', False)])
|
||||
# keep multi company consistency
|
||||
self.company_id = self.project_id.company_id
|
||||
else:
|
||||
self.stage_id = False
|
||||
|
||||
@api.onchange('company_id')
|
||||
def _onchange_task_company(self):
|
||||
if self.project_id.company_id != self.company_id:
|
||||
self.project_id = False
|
||||
|
||||
@api.depends('project_id.company_id')
|
||||
def _compute_company_id(self):
|
||||
for task in self.filtered(lambda task: task.project_id):
|
||||
task.company_id = task.project_id.company_id
|
||||
|
||||
@api.depends('project_id')
|
||||
def _compute_stage_id(self):
|
||||
for task in self:
|
||||
if task.project_id:
|
||||
if task.project_id not in task.stage_id.project_ids:
|
||||
task.stage_id = task.stage_find(task.project_id.id, [
|
||||
('fold', '=', False), ('is_closed', '=', False)])
|
||||
else:
|
||||
task.stage_id = False
|
||||
|
||||
@api.constrains('parent_id', 'child_ids')
|
||||
def _check_subtask_level(self):
|
||||
for task in self:
|
||||
@@ -865,9 +869,18 @@ class Task(models.Model):
|
||||
|
||||
@api.depends('parent_id.partner_id', 'project_id.partner_id')
|
||||
def _compute_partner_id(self):
|
||||
"""
|
||||
If a task has no partner_id, use the project partner_id if any, or else the parent task partner_id.
|
||||
Once the task partner_id has been set:
|
||||
1) if the project partner_id changes, the task partner_id is automatically changed also.
|
||||
2) if the parent task partner_id changes, the task partner_id remains the same.
|
||||
"""
|
||||
for task in self:
|
||||
if not task.partner_id:
|
||||
task.partner_id = task.parent_id.partner_id or task.project_id.partner_id
|
||||
if task.partner_id:
|
||||
if task.project_id.partner_id:
|
||||
task.partner_id = task.project_id.partner_id
|
||||
else:
|
||||
task.partner_id = task.project_id.partner_id or task.parent_id.partner_id
|
||||
|
||||
@api.depends('partner_id.email', 'parent_id.email_from')
|
||||
def _compute_email_from(self):
|
||||
|
||||
@@ -19,6 +19,9 @@ class TestProjectCommon(SavepointCase):
|
||||
cls.partner_2 = cls.env['res.partner'].create({
|
||||
'name': 'Valid Poilvache',
|
||||
'email': 'valid.other@gmail.com'})
|
||||
cls.partner_3 = cls.env['res.partner'].create({
|
||||
'name': 'Valid Poilboeuf',
|
||||
'email': 'valid.poilboeuf@gmail.com'})
|
||||
|
||||
# Test users to use through the various tests
|
||||
Users = cls.env['res.users'].with_context({'no_reset_password': True})
|
||||
|
||||
@@ -96,8 +96,20 @@ class TestProjectFlow(TestProjectCommon):
|
||||
self.assertEqual(task.stage_id.sequence, 1, "project_task: should have a stage with sequence=1")
|
||||
|
||||
def test_subtask_process(self):
|
||||
""" Check subtask mecanism and change it from project. """
|
||||
"""
|
||||
Check subtask mecanism and change it from project.
|
||||
|
||||
For this test, 2 projects are used:
|
||||
- the 'pigs' project which has a partner_id
|
||||
- the 'goats' project where the partner_id is removed at the beginning of the tests and then restored.
|
||||
|
||||
2 parent tasks are also used to be able to switch the parent task of a sub-task:
|
||||
- 'parent_task' linked to the partner_2
|
||||
- 'another_parent_task' linked to the partner_3
|
||||
"""
|
||||
|
||||
Task = self.env['project.task'].with_context({'tracking_disable': True})
|
||||
|
||||
parent_task = Task.create({
|
||||
'name': 'Mother Task',
|
||||
'user_id': self.user_projectuser.id,
|
||||
@@ -105,23 +117,94 @@ class TestProjectFlow(TestProjectCommon):
|
||||
'partner_id': self.partner_2.id,
|
||||
'planned_hours': 12,
|
||||
})
|
||||
child_task = Task.create({
|
||||
'name': 'Task Child',
|
||||
'parent_id': parent_task.id,
|
||||
|
||||
another_parent_task = Task.create({
|
||||
'name': 'Another Mother Task',
|
||||
'user_id': self.user_projectuser.id,
|
||||
'project_id': self.project_pigs.id,
|
||||
'partner_id': self.partner_3.id,
|
||||
'planned_hours': 0,
|
||||
})
|
||||
|
||||
# remove the partner_id of the 'goats' project
|
||||
goats_partner_id = self.project_goats.partner_id
|
||||
|
||||
self.project_goats.write({
|
||||
'partner_id': False
|
||||
})
|
||||
|
||||
# the child task 1 is linked to a project without partner_id (goats project)
|
||||
child_task_1 = Task.create({
|
||||
'name': 'Task Child with project',
|
||||
'parent_id': parent_task.id,
|
||||
'project_id': self.project_goats.id,
|
||||
'planned_hours': 3,
|
||||
})
|
||||
|
||||
self.assertEqual(parent_task.partner_id, child_task.partner_id, "Subtask should have the same partner than its parent")
|
||||
self.assertEqual(parent_task.subtask_count, 1, "Parent task should have 1 child")
|
||||
self.assertEqual(parent_task.subtask_planned_hours, 3, "Planned hours of subtask should impact parent task")
|
||||
|
||||
# change project
|
||||
child_task.write({
|
||||
'project_id': self.project_goats.id # customer is partner_1
|
||||
# the child task 2 is linked to a project with a partner_id (pigs project)
|
||||
child_task_2 = Task.create({
|
||||
'name': 'Task Child without project',
|
||||
'parent_id': parent_task.id,
|
||||
'project_id': self.project_pigs.id,
|
||||
'planned_hours': 5,
|
||||
})
|
||||
|
||||
self.assertEqual(parent_task.partner_id, child_task.partner_id, "Subtask partner should not change when changing project")
|
||||
self.assertEqual(
|
||||
child_task_1.partner_id, child_task_1.parent_id.partner_id,
|
||||
"When no project partner_id has been set, a subtask should have the same partner than its parent")
|
||||
|
||||
self.assertEqual(
|
||||
child_task_2.partner_id, child_task_2.project_id.partner_id,
|
||||
"When a project partner_id has been set, a subtask should have the same partner than its project")
|
||||
|
||||
self.assertEqual(
|
||||
parent_task.subtask_count, 2,
|
||||
"Parent task should have 2 children")
|
||||
|
||||
self.assertEqual(
|
||||
parent_task.subtask_planned_hours, 8,
|
||||
"Planned hours of subtask should impact parent task")
|
||||
|
||||
# change the parent of a subtask without a project partner_id
|
||||
child_task_1.write({
|
||||
'parent_id': another_parent_task.id
|
||||
})
|
||||
|
||||
self.assertEqual(
|
||||
child_task_1.partner_id, parent_task.partner_id,
|
||||
"When changing the parent task of a subtask with no project partner_id, the partner_id should remain the same.")
|
||||
|
||||
# change the parent of a subtask with a project partner_id
|
||||
child_task_2.write({
|
||||
'parent_id': another_parent_task.id
|
||||
})
|
||||
|
||||
self.assertEqual(
|
||||
child_task_2.partner_id, child_task_2.project_id.partner_id,
|
||||
"When changing the parent task of a subtask with a project, the partner_id should remain the same.")
|
||||
|
||||
# set a project with partner_id to a subtask without project partner_id
|
||||
child_task_1.write({
|
||||
'project_id': self.project_pigs.id
|
||||
})
|
||||
|
||||
self.assertEqual(
|
||||
child_task_1.partner_id, self.project_pigs.partner_id,
|
||||
"When the project changes, the subtask should have the same partner id than the new project.")
|
||||
|
||||
# restore the partner_id of the 'goats' project
|
||||
self.project_goats.write({
|
||||
'partner_id': goats_partner_id
|
||||
})
|
||||
|
||||
# set a project with partner_id to a subtask with a project partner_id
|
||||
child_task_2.write({
|
||||
'project_id': self.project_goats.id
|
||||
})
|
||||
|
||||
self.assertEqual(
|
||||
child_task_2.partner_id, self.project_goats.partner_id,
|
||||
"When the project changes, the subtask should have the same partner id than the new project.")
|
||||
|
||||
def test_rating(self):
|
||||
"""Check if rating works correctly even when task is changed from project A to project B"""
|
||||
|
||||
@@ -856,7 +856,7 @@
|
||||
<field name="name">project.task.tree.activity</field>
|
||||
<field name="model">project.task</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Next Activities" decoration-danger="not is_closed and activity_date_deadline < current_date" default_order="activity_date_deadline">
|
||||
<tree string="Next Activities" decoration-danger="not is_closed and activity_date_deadline < current_date" default_order="activity_date_deadline" multi_edit="1">
|
||||
<field name="is_closed"/>
|
||||
<field name="name"/>
|
||||
<field name="project_id"/>
|
||||
|
||||
@@ -250,7 +250,6 @@ class ProjectTask(models.Model):
|
||||
|
||||
@api.onchange('project_id')
|
||||
def _onchange_project(self):
|
||||
super(ProjectTask, self)._onchange_project()
|
||||
if self.project_id:
|
||||
if self.project_id.billable_type == 'employee_rate':
|
||||
if not self.partner_id:
|
||||
|
||||
Reference in New Issue
Block a user