[FIX] hr_timesheet: correctly propagates project
Steps to reproduce: - Create 2 projects: 'Project1' and 'Project2' - Enable sub-tasks - In Project1 create a task, name it '1'. - In task 1 add a subtask, name it '1:1'. - In task 1:1 add another subtask, name it '1:1:1'. - Go to Timesheet app > add lines for each task. - The lines display name are "Project1 / 1", ... - Go back to task 1, edit the task project to Project2 and save. - The subtasks will have their project_id also set to Project2. - Go to Timesheet app. Issue: Tasks 1 and 1:1 will have their display names updated to "Project2 / 1" and "Project2 / 1:1". However, task 1:1:1 is displayed as "Project1 / 1:1:1", meaning it's project_id was never updated. This happens because of the way changed fields propagate to immediate children, but not to grandchildren, which is intended behaviour. Solution: `_compute_project_id` is also called onchange, meaning that we can use it to update account lines with an outdated project value with the new value. opw-3018301 closes odoo/odoo#109352 X-original-commit: 91b42c806ce2029d9ef678d145ced3138e35bec0 Signed-off-by: Xavier Bol (xbo) <xbo@odoo.com> Signed-off-by: Stefan-Calin Crainiciuc (stcc) <stcc@odoo.com>
This commit is contained in:
@@ -95,7 +95,9 @@ class AccountAnalyticLine(models.Model):
|
||||
|
||||
@api.depends('task_id', 'task_id.project_id')
|
||||
def _compute_project_id(self):
|
||||
for line in self.filtered(lambda line: not line.project_id):
|
||||
for line in self:
|
||||
if not line.task_id.project_id or line.project_id == line.task_id.project_id:
|
||||
continue
|
||||
line.project_id = line.task_id.project_id
|
||||
|
||||
@api.depends('project_id')
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
from lxml import etree
|
||||
|
||||
from odoo.fields import Command
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.tests.common import TransactionCase, Form
|
||||
from odoo.exceptions import AccessError, UserError, ValidationError
|
||||
|
||||
|
||||
@@ -238,36 +238,63 @@ class TestTimesheet(TestCommonTimesheet):
|
||||
def test_transfert_project(self):
|
||||
""" Transfert task with timesheet to another project. """
|
||||
Timesheet = self.env['account.analytic.line']
|
||||
|
||||
# create nested subtasks
|
||||
task_child = self.env['project.task'].create({
|
||||
'name': 'Task Child',
|
||||
'parent_id': self.task1.id,
|
||||
})
|
||||
|
||||
task_grandchild = self.env['project.task'].create({
|
||||
'name': 'Task Grandchild',
|
||||
'parent_id': task_child.id,
|
||||
})
|
||||
|
||||
# create a second project
|
||||
self.project_customer2 = self.env['project.project'].create({
|
||||
'name': 'Project NUMBER DEUX',
|
||||
'allow_timesheets': True,
|
||||
})
|
||||
# employee 1 log some timesheet on task 1
|
||||
Timesheet.create({
|
||||
# employee 1 log some timesheet on task 1 and its subtasks
|
||||
Timesheet.create([{
|
||||
'project_id': self.project_customer.id,
|
||||
'task_id': self.task1.id,
|
||||
'name': 'my first timesheet',
|
||||
'unit_amount': 4,
|
||||
'user_id': self.user_employee.id,
|
||||
})
|
||||
'employee_id': self.empl_employee.id,
|
||||
}, {
|
||||
'project_id': self.project_customer.id,
|
||||
'task_id': task_child.id,
|
||||
'name': 'my second timesheet',
|
||||
'unit_amount': 4,
|
||||
'employee_id': self.empl_employee.id,
|
||||
}, {
|
||||
'project_id': self.project_customer.id,
|
||||
'task_id': task_grandchild.id,
|
||||
'name': 'my third timesheet',
|
||||
'unit_amount': 4,
|
||||
'employee_id': self.empl_employee.id,
|
||||
}])
|
||||
|
||||
timesheet_count1 = Timesheet.search_count([('project_id', '=', self.project_customer.id)])
|
||||
timesheet_count2 = Timesheet.search_count([('project_id', '=', self.project_customer2.id)])
|
||||
self.assertEqual(timesheet_count1, 1, "One timesheet in project 1")
|
||||
self.assertEqual(timesheet_count2, 0, "No timesheet in project 2")
|
||||
self.assertEqual(len(self.task1.timesheet_ids), 1, "The timesheet should be linked to task 1")
|
||||
self.assertEqual(timesheet_count1, 3, "3 timesheets should be linked to Project1")
|
||||
self.assertEqual(timesheet_count2, 0, "No timesheets should be linked to Project2")
|
||||
self.assertEqual(len(self.task1.timesheet_ids), 1, "The timesheet should be linked to task1")
|
||||
self.assertEqual(len(task_child.timesheet_ids), 1, "The timesheet should be linked to task_child")
|
||||
self.assertEqual(len(task_grandchild.timesheet_ids), 1, "The timesheet should be linked to task_grandchild")
|
||||
|
||||
# change project of task 1
|
||||
self.task1.write({
|
||||
'project_id': self.project_customer2.id
|
||||
})
|
||||
# change project of task 1 from form to trigger onchange
|
||||
with Form(self.task1) as task_form:
|
||||
task_form.project_id = self.project_customer2
|
||||
|
||||
timesheet_count1 = Timesheet.search_count([('project_id', '=', self.project_customer.id)])
|
||||
timesheet_count2 = Timesheet.search_count([('project_id', '=', self.project_customer2.id)])
|
||||
self.assertEqual(timesheet_count1, 0, "No timesheet in project 1")
|
||||
self.assertEqual(timesheet_count2, 1, "Still one timesheet in project 2")
|
||||
self.assertEqual(len(self.task1.timesheet_ids), 1, "The timesheet still should be linked to task 1")
|
||||
self.assertEqual(timesheet_count1, 0, "There are still timesheets linked to Project1")
|
||||
self.assertEqual(timesheet_count2, 3, "3 timesheets should be linked to Project2")
|
||||
self.assertEqual(len(self.task1.timesheet_ids), 1, "The timesheet still should be linked to task1")
|
||||
self.assertEqual(len(task_child.timesheet_ids), 1, "The timesheet still should be linked to task_child")
|
||||
self.assertEqual(len(task_grandchild.timesheet_ids), 1, "The timesheet still should be linked to task_grandchild")
|
||||
|
||||
# it is forbidden to set a task with timesheet without project
|
||||
with self.assertRaises(UserError):
|
||||
|
||||
@@ -75,6 +75,10 @@ class AccountAnalyticLine(models.Model):
|
||||
def _compute_partner_id(self):
|
||||
super(AccountAnalyticLine, self.filtered(lambda t: t._is_not_billed()))._compute_partner_id()
|
||||
|
||||
@api.depends('timesheet_invoice_id.state')
|
||||
def _compute_project_id(self):
|
||||
super(AccountAnalyticLine, self.filtered(lambda t: t._is_not_billed()))._compute_project_id()
|
||||
|
||||
def _is_not_billed(self):
|
||||
self.ensure_one()
|
||||
return not self.timesheet_invoice_id or self.timesheet_invoice_id.state == 'cancel'
|
||||
|
||||
Reference in New Issue
Block a user