[FIX] sale_project: link subtask to sale order line of parent

Steps to reproduce:
-------------------
- create two product of type "service";
- field "Create on Order" is set to "Project & Task";
- create a Sale Order with these two products;
- condirm the Sale Order;

Two tasks are created in a project and each task has its own Sale Order Line Item.

- create a subtask from both tasks respectively;
- select a project for the subtask.

Issue:
------
The same Sale Order Line is selected for the two subtasks.
It always take the first Sale Order line.

Cause:
------
To choose the sale order line, we first look to see if
the subtask belongs to a project.
If so, we take the sale order line which created the project.
Unfortunately, a subtask can belong to a project created with
a sale order line without belonging to the same sale order line
(in the case where a task is added to a project via another product
and therefore another sale order line).

Solution:
---------
- A project without parent --> use project's sale order line
- A parent without project --> no sale order line defined
- A parent in the same project --> use parent's sale order line
- A parent in an other project --> use parent's sale order line

opw-3333936

closes odoo/odoo#124260

X-original-commit: 323d7f631916f5acc5ab34f8531ae59bb0455828
Signed-off-by: Xavier Bol (xbo) <xbo@odoo.com>
Signed-off-by: Lefebvre Thomas (thle) <thle@odoo.com>
This commit is contained in:
Thomas Lefebvre (thle)
2023-06-08 16:10:21 +02:00
parent 491d22e1df
commit 4132408f26
2 changed files with 103 additions and 3 deletions
+5 -3
View File
@@ -738,11 +738,13 @@ class ProjectTask(models.Model):
continue
if not task.sale_line_id:
# if the project_id is set then it means the task is classic task or a subtask with another project than its parent.
# To determine the sale_line_id, we first need to look at the parent before the project to manage the case of subtasks.
# Two sub-tasks in the same project do not necessarily have the same sale_line_id (need to look at the parent task).
sale_line = False
if task.project_id.sale_line_id and task.project_id.partner_id.commercial_partner_id == task.partner_id.commercial_partner_id:
sale_line = task.project_id.sale_line_id
elif task.parent_id.sale_line_id and task.parent_id.partner_id.commercial_partner_id == task.partner_id.commercial_partner_id:
if task.parent_id.sale_line_id and task.parent_id.partner_id.commercial_partner_id == task.partner_id.commercial_partner_id:
sale_line = task.parent_id.sale_line_id
elif task.project_id.sale_line_id and task.project_id.partner_id.commercial_partner_id == task.partner_id.commercial_partner_id:
sale_line = task.project_id.sale_line_id
task.sale_line_id = sale_line or task.milestone_id.sale_line_id
# check sale_line_id and customer are coherent
if task.sale_line_id.order_partner_id.commercial_partner_id != task.partner_id.commercial_partner_id:
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import Command
from odoo.tests.common import new_test_user
from .common import TestSaleProjectCommon
from odoo.tests.common import tagged
@@ -236,6 +237,103 @@ class TestSaleProject(TestSaleProjectCommon):
sale_order.with_context({'disable_cancel_warning': True}).action_cancel()
self.assertFalse(self.project_global.sale_line_id, "The project should not be linked to the SOL anymore")
def test_links_with_sale_order_line(self):
"""
Check that the subtasks are linked to the correct sale order line.
"""
product_A, product_B, product_C = self.env['product.product'].create([
{
'name': 'product_A',
'lst_price': 100.0,
'detailed_type': 'service',
'service_tracking': 'task_in_project',
},
{
'name': 'product_B',
'lst_price': 100.0,
'detailed_type': 'service',
'service_tracking': 'task_in_project',
},
{
'name': 'product_C',
'lst_price': 100.0,
'detailed_type': 'service',
'service_tracking': 'task_in_project',
},
])
sale_order_first, sale_order_second = self.env['sale.order'].create([
{
'partner_id': self.partner.id,
'order_line': [
Command.create({'product_id': product_A.id}),
Command.create({'product_id': product_B.id}),
]
},
{
'partner_id': self.partner.id,
'order_line': [
Command.create({'product_id': product_C.id}),
]
}
])
(sale_order_first + sale_order_second).action_confirm()
sale_order_line_A = sale_order_first.order_line.filtered(lambda sol: sol.product_id == product_A)
sale_order_line_B = sale_order_first.order_line - sale_order_line_A
sale_order_line_C = sale_order_second.order_line
project_first = sale_order_first.project_ids
project_second = sale_order_second.project_ids
task_A = sale_order_first.tasks_ids.filtered(lambda task: task.sale_line_id == sale_order_line_A)
task_B = sale_order_first.tasks_ids - task_A
task_C = sale_order_second.tasks_ids
# [CASE 1] Parent in the same project --> use parent's sale order line
task_A.write({
'child_ids': [
Command.create({'name': 'Sub A in first project', 'project_id': project_first.id}),
]
})
task_B.write({
'child_ids': [
Command.create({'name': 'Sub B in first project', 'project_id': project_first.id}),
]
})
task_C.write({
'child_ids': [
Command.create({'name': 'Sub C in second project', 'project_id': project_second.id}),
]
})
self.assertEqual(task_A.child_ids.sale_line_id, sale_order_line_A)
self.assertEqual(task_B.child_ids.sale_line_id, sale_order_line_B)
self.assertEqual(task_C.child_ids.sale_line_id, sale_order_line_C)
# [CASE 2] Parent in an other project --> use parent's sale_order line
task_B.write({
'child_ids': [
Command.create({'name': 'Sub B in second project', 'project_id': project_second.id}),
]
})
sub_B_second = task_B.child_ids.filtered(lambda sub: sub.name == 'Sub B in second project')
self.assertEqual(sub_B_second.sale_line_id, sale_order_line_B)
# [CASE 3] Without project --> no sale order line defined
task_B.write({
'child_ids': [
Command.create({'name': 'Sub B without project'}),
]
})
sub_B_without = task_B.child_ids.filtered(lambda sub: sub.name == 'Sub B without project')
self.assertEqual(len(sub_B_without.sale_line_id), 0)
# [CASE 4] Without parent --> use sale order line of the project
task_D = self.env['project.task'].create({
'name': 'Task D',
'project_id': project_first.id,
})
self.assertEqual(task_D.sale_line_id, project_first.sale_line_id)
def test_compute_project_and_task_button(self):
"""
Ensures that when a sale order has at least one sol with a service product whose service-policy is either delivered on milestone or ordered prepaid, then the