[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:
Florian Damhaut
2022-04-30 11:43:52 +02:00
parent 7c9a28d9c4
commit bbfb8cb099
2 changed files with 87 additions and 3 deletions
+16 -3
View File
@@ -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)