[FIX] project: Copy task dependency on project copy
Step to reproduce: - Create a project with 2 task A and B - Set task A blocked by task B - Duplicate Project Current behaviour: - Duplicate project is also blocked by original project's task - Original project's tasks are blocked by new duplicate project's task Behaviour after PR: - Original project's tasks are not changed - Duplicate project's tasks are blocked by duplicate project's task if they were blocked by the original project. - Tasks are still blocked by tasks not linked to the original project opw-2818476 closes odoo/odoo#90256 X-original-commit: 5c184628b2278814d2b28366587c8e4b813d0374 Signed-off-by: Laurent Stukkens (ltu) <ltu@odoo.com>
This commit is contained in:
@@ -471,6 +471,8 @@ class Project(models.Model):
|
||||
new_subtasks = self.env['project.task']
|
||||
# We want to copy archived task, but do not propagate an active_test context key
|
||||
task_ids = self.env['project.task'].with_context(active_test=False).search([('project_id', '=', self.id), ('parent_id', '=', False)]).ids
|
||||
if self.allow_task_dependencies and 'task_mapping' not in self.env.context:
|
||||
self = self.with_context(task_mapping=dict())
|
||||
for task in self.env['project.task'].browse(task_ids):
|
||||
# preserve task name and stage, normally altered during copy
|
||||
defaults = self._map_tasks_default_valeus(task, project)
|
||||
@@ -1084,10 +1086,10 @@ class Task(models.Model):
|
||||
allow_task_dependencies = fields.Boolean(related='project_id.allow_task_dependencies')
|
||||
# Tracking of this field is done in the write function
|
||||
depend_on_ids = fields.Many2many('project.task', relation="task_dependencies_rel", column1="task_id",
|
||||
column2="depends_on_id", string="Blocked By", tracking=True,
|
||||
column2="depends_on_id", string="Blocked By", tracking=True, copy=False,
|
||||
domain="[('allow_task_dependencies', '=', True), ('id', '!=', id)]")
|
||||
dependent_ids = fields.Many2many('project.task', relation="task_dependencies_rel", column1="depends_on_id",
|
||||
column2="task_id", string="Block",
|
||||
column2="task_id", string="Block", copy=False,
|
||||
domain="[('allow_task_dependencies', '=', True), ('id', '!=', id)]")
|
||||
dependent_tasks_count = fields.Integer(string="Dependent Tasks", compute='_compute_dependent_tasks_count')
|
||||
|
||||
@@ -1540,6 +1542,8 @@ class Task(models.Model):
|
||||
def copy(self, default=None):
|
||||
if default is None:
|
||||
default = {}
|
||||
if self.allow_task_dependencies and 'task_mapping' not in self.env.context:
|
||||
self = self.with_context(task_mapping=dict())
|
||||
has_default_name = bool(default.get('name', ''))
|
||||
if not has_default_name:
|
||||
default['name'] = _("%s (copy)", self.name)
|
||||
@@ -1547,7 +1551,16 @@ class Task(models.Model):
|
||||
default['recurrence_id'] = self.recurrence_id.copy().id
|
||||
if self.allow_subtasks:
|
||||
default['child_ids'] = [child.copy({'name': child.name} if has_default_name else None).id for child in self.child_ids]
|
||||
return super(Task, self).copy(default)
|
||||
task_copy = super(Task, self).copy(default)
|
||||
if self.allow_task_dependencies:
|
||||
task_mapping = self.env.context.get('task_mapping')
|
||||
task_mapping[self.id] = task_copy.id
|
||||
new_tasks = task_mapping.values()
|
||||
self.write({'depend_on_ids': [Command.unlink(t.id) for t in self.depend_on_ids if t.id in new_tasks]})
|
||||
self.write({'dependent_ids': [Command.unlink(t.id) for t in self.dependent_ids if t.id in new_tasks]})
|
||||
task_copy.write({'depend_on_ids': [Command.link(task_mapping.get(t.id, t.id)) for t in self.depend_on_ids]})
|
||||
task_copy.write({'dependent_ids': [Command.link(task_mapping.get(t.id, t.id)) for t in self.dependent_ids]})
|
||||
return task_copy
|
||||
|
||||
@api.model
|
||||
def get_empty_list_help(self, help):
|
||||
|
||||
@@ -159,3 +159,74 @@ class TestTaskDependencies(TestProjectCommon):
|
||||
'name': 'My Ducks Project'
|
||||
})
|
||||
self.assertFalse(self.project_ducks.allow_task_dependencies, "New Projects allow_task_dependencies should default to group_project_task_dependencies")
|
||||
|
||||
def test_duplicate_project_with_task_dependencies(self):
|
||||
self.project_pigs.allow_task_dependencies = True
|
||||
self.task_1.depend_on_ids = self.task_2
|
||||
pigs_copy = self.project_pigs.copy()
|
||||
|
||||
task1_copy = pigs_copy.task_ids.filtered(lambda t: t.name == 'Pigs UserTask')
|
||||
task2_copy = pigs_copy.task_ids.filtered(lambda t: t.name == 'Pigs ManagerTask')
|
||||
|
||||
self.assertEqual(len(task1_copy), 1, "Should only contain 1 copy of UserTask")
|
||||
self.assertEqual(len(task2_copy), 1, "Should only contain 1 copy of ManagerTask")
|
||||
|
||||
self.assertEqual(task1_copy.depend_on_ids.ids, [task2_copy.id],
|
||||
"Copy should only create a relation between both copy if they are both part of the project")
|
||||
|
||||
task1_copy.depend_on_ids = self.task_1
|
||||
|
||||
pigs_copy_copy = pigs_copy.copy()
|
||||
task1_copy_copy = pigs_copy_copy.task_ids.filtered(lambda t: t.name == 'Pigs UserTask')
|
||||
|
||||
self.assertEqual(task1_copy_copy.depend_on_ids.ids, [self.task_1.id],
|
||||
"Copy should not alter the relation if the other task is in a different project")
|
||||
|
||||
def test_duplicate_project_with_subtask_dependencies(self):
|
||||
parent_task = self.env['project.task'].with_context({'mail_create_nolog': True}).create({
|
||||
'name': 'Parent Task',
|
||||
'project_id': self.project_goats.id,
|
||||
'child_ids': [
|
||||
Command.create({'name': 'Node 1'}),
|
||||
Command.create({'name': 'SuperNode 2', 'child_ids': [Command.create({'name': 'Node 2'})]}),
|
||||
Command.create({'name': 'Node 3'}),
|
||||
],
|
||||
})
|
||||
|
||||
node1 = parent_task.child_ids[0]
|
||||
node2 = parent_task.child_ids[1].child_ids
|
||||
node3 = parent_task.child_ids[2]
|
||||
|
||||
node1.dependent_ids = node2
|
||||
node2.dependent_ids = node3
|
||||
|
||||
# Test copying the whole Node tree
|
||||
parent_task_copy = parent_task.copy()
|
||||
parent_copy_node1 = parent_task_copy.child_ids[0]
|
||||
parent_copy_node2 = parent_task_copy.child_ids[1].child_ids
|
||||
parent_copy_node3 = parent_task_copy.child_ids[2]
|
||||
|
||||
# Relation should only be copied between the newly created node
|
||||
self.assertEqual(len(parent_copy_node1.dependent_ids), 1)
|
||||
self.assertEqual(parent_copy_node1.dependent_ids.ids, parent_copy_node2.ids, 'Node1copy - Node2copy relation should be present')
|
||||
self.assertEqual(len(parent_copy_node2.dependent_ids), 1)
|
||||
self.assertEqual(parent_copy_node2.dependent_ids.ids, parent_copy_node3.ids, 'Node2copy - Node3copy relation should be present')
|
||||
|
||||
# Original Node should not have new relation
|
||||
self.assertEqual(len(node1.dependent_ids), 1)
|
||||
self.assertEqual(node1.dependent_ids.ids, node2.ids, 'Only Node1 - Node2 relation should be present')
|
||||
self.assertEqual(len(node2.dependent_ids), 1)
|
||||
self.assertEqual(node2.dependent_ids.ids, node3.ids, 'Only Node2 - Node3 relation should be present')
|
||||
|
||||
# Test copying Node inside the chain
|
||||
single_copy_node2 = node2.copy()
|
||||
|
||||
# Relation should be present between the other original node and the newly copied node
|
||||
self.assertEqual(len(single_copy_node2.depend_on_ids), 1)
|
||||
self.assertEqual(single_copy_node2.depend_on_ids.ids, node1.ids, 'Node1 - Node2copy relation should be present')
|
||||
self.assertEqual(len(single_copy_node2.dependent_ids), 1)
|
||||
self.assertEqual(single_copy_node2.dependent_ids.ids, node3.ids, 'Node2copy - Node3 relation should be present')
|
||||
|
||||
# Original Node should have new relations
|
||||
self.assertEqual(len(node1.dependent_ids), 2)
|
||||
self.assertEqual(len(node3.depend_on_ids), 2)
|
||||
|
||||
Reference in New Issue
Block a user