From 85a75d2d828467137cf9eb503abd016c8c8511da Mon Sep 17 00:00:00 2001 From: "lase@odoo.com" Date: Thu, 4 Apr 2024 17:07:42 +0200 Subject: [PATCH] [FIX] project: assign copied task to copied project Steps to reproduce: - Create a project with a task with a sub-task - Assign manually the sub-task to the project - Create a product that creates a project based on this product template - Create an SO with that product > A copy of your project template will be created and assigned to the SO Expected Behavior: Just as in 16.4, the copy of the subtask created during this process should be associated with the copy of your project template. Current Behavior: The subtask is associated with the original project template. Cause of the issue/Fix: Confirming the SO will call the copy method on your project template. During this call copies of its task and sub-task will be created and should then be remapped to the correct project/task using by the `map_tasks` method call: https://github.com/odoo/odoo/blob/f31174e02157e612650e77ebba3ed1fe54b96776/addons/project/models/project_project.py#L436-L437 This use to do the job correctly in 16.4 because of these lines: https://github.com/odoo/odoo/blob/ce28edbaae5a9af0a8c6e1f2addf4285ec56e9e1/addons/project/models/project_project.py#L415-L419 However, these were removed by Commit 62e53fa, probably because the new write method of the "project.project" model introduced by this commit sometimes relies on the "project_id" of these tasks and this information should be consistent with the future value of the "project_id" of these tasks. However, the "project_id" of these tasks should still be remapped to the copied project at some point and in my opinion this should be done before the new write method is called, so that this method can be used correctly. opw-3823013 closes odoo/odoo#160625 Signed-off-by: Xavier Bol (xbo) --- addons/project/models/project_project.py | 5 +++ addons/sale_project/tests/test_child_tasks.py | 39 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/addons/project/models/project_project.py b/addons/project/models/project_project.py index b42283eee6c..80008568879 100644 --- a/addons/project/models/project_project.py +++ b/addons/project/models/project_project.py @@ -413,6 +413,11 @@ class Project(models.Model): subtasks_not_displayed = all_subtasks.filtered( lambda task: not task.display_in_project ) + all_subtasks.filtered( + lambda child: child.project_id == self + ).write({ + 'project_id': project.id + }) project.write({'tasks': [Command.set(new_tasks.ids)]}) subtasks_not_displayed.write({ 'display_in_project': False diff --git a/addons/sale_project/tests/test_child_tasks.py b/addons/sale_project/tests/test_child_tasks.py index e9c5b4c7df8..7921c0c9502 100644 --- a/addons/sale_project/tests/test_child_tasks.py +++ b/addons/sale_project/tests/test_child_tasks.py @@ -246,3 +246,42 @@ class TestNestedTaskUpdate(TransactionCase): subtask2.project_id = project_non_billable self.assertFalse(subtask2.allow_billable) self.assertFalse(subsubtask.allow_billable) + + # ---------------------------------- + # + # When copying a project template, some values go on the child + # + # ---------------------------------- + + def test_associate_copied_task_to_copied_project(self): + """ + When confirming an SO with a product generating a project from a template, + check that the copied task and subtask are correctly assigned to the copied + project rather than its template. + """ + project_tempalte = self.env['project.project'].create({'name': 'Super Project'}) + parent = self.env['project.task'].create({'name': 'parent task', 'project_id': project_tempalte.id}) + child = self.env['project.task'].create({'name': 'child task', 'parent_id': parent.id, 'project_id': project_tempalte.id}) + super_product = self.env['product.product'].create({ + 'name': 'Super product', + 'detailed_type': 'service', + 'service_tracking': 'project_only', + 'project_template_id': project_tempalte.id, + }) + sale_order = self.env['sale.order'].create({ + 'partner_id': self.partner.id, + 'order_line': [ + Command.create({ + 'name': super_product.name, + 'product_id': super_product.id, + 'product_uom_qty': 1, + 'price_unit': 100, + }) + ] + }) + sale_order.action_confirm() + self.assertEqual(project_tempalte.tasks, parent | child) + super_project = sale_order.order_line.project_id + self.assertFalse(super_project.tasks & project_tempalte.tasks) + self.assertEqual(len(super_project.tasks), 2) + self.assertEqual(super_project.tasks.parent_id, super_project.tasks.child_ids.parent_id)