From 41ba2c136ae9fdd6098bf6fd3abb06bb0e14435f Mon Sep 17 00:00:00 2001 From: "Mahdi Cheikh Rouhou (macr)" Date: Mon, 5 Jun 2023 07:25:33 +0000 Subject: [PATCH] [FIX] sale_timesheet : allocate hours to different projects with different templates When we create a sale order with multiples services which have different projet templates, the projects created will have the sum of all hours which is not true. Steps to reproduce the error : 1- create at least 2 product with type service and choose create on order : project & task , and create a template for each one on the fly 2- create a sale order with the created services and choose some quantity for each one of them 3- confirm it 4- Click on the smart button projects 5- you will see that the allocated hours for each project have the sum of all the quantities The origin of the problem is that we don't check on the template_id when calculating the allocated hours so we sum the allocated hours of all the services having project & task for each one of them . opw-3341546 closes odoo/odoo#125071 X-original-commit: 537a0093b0467f80aac6b1de2e93bf04c0298e5b Signed-off-by: Nicolas Lempereur (nle) Signed-off-by: Mahdi Cheikh Rouhou (macr) --- addons/sale_timesheet/models/sale_order.py | 2 +- .../tests/test_sale_timesheet.py | 63 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/addons/sale_timesheet/models/sale_order.py b/addons/sale_timesheet/models/sale_order.py index 9a09d2648e7..78d1d2553f7 100644 --- a/addons/sale_timesheet/models/sale_order.py +++ b/addons/sale_timesheet/models/sale_order.py @@ -281,7 +281,7 @@ class SaleOrderLine(models.Model): allocated_hours = 0.0 for line in self.order_id.order_line: product_type = line.product_id.service_tracking - if line.is_service and (product_type == 'task_in_project' or product_type == 'project_only'): + if line.is_service and (product_type == 'task_in_project' or product_type == 'project_only') and line.product_id.project_template_id == self.product_id.project_template_id: if uom_per_id.get(line.product_uom.id) or line.product_uom.id == uom_unit.id: allocated_hours += line.product_uom_qty * uom_per_id.get(line.product_uom.id, project_uom).factor_inv * uom_hour.factor diff --git a/addons/sale_timesheet/tests/test_sale_timesheet.py b/addons/sale_timesheet/tests/test_sale_timesheet.py index 927a03fa2d2..85f95181611 100644 --- a/addons/sale_timesheet/tests/test_sale_timesheet.py +++ b/addons/sale_timesheet/tests/test_sale_timesheet.py @@ -755,6 +755,69 @@ class TestSaleTimesheet(TestCommonSaleTimesheet): items = project._get_profitability_items(with_action=False) self.assertEqual(items['revenues']['data'][0]['to_invoice'], 2*product_price, "The quantity to_invoice should be equal to twice the price of the product") + def test_sale_order_with_multiple_project_templates(self): + """Test when creating multiple projects for one sale order every project has its own allocated hours""" + sale_order = self.env['sale.order'].with_context(tracking_disable=True).create({ + 'partner_id': self.partner_a.id, + 'partner_invoice_id': self.partner_a.id, + 'partner_shipping_id': self.partner_a.id, + }) + + project_template_1, project_template_2 = self.env['project.project'].create([ + {'name': 'Template 1'}, + {'name': 'Template 1'}, + ]) + + product_1, product_2 = self.env['product.product'].create([ + { + 'name': "Service with template 1", + 'standard_price': 10, + 'list_price': 20, + 'type': 'service', + 'invoice_policy': 'order', + 'uom_id': self.uom_hour.id, + 'uom_po_id': self.uom_hour.id, + 'default_code': 'c1', + 'service_tracking': 'task_in_project', + 'project_id': False, # will create a project, + 'project_template_id': project_template_1.id, + }, { + 'name': "Service with template 2", + 'standard_price': 10, + 'list_price': 20, + 'type': 'service', + 'invoice_policy': 'order', + 'uom_id': self.uom_hour.id, + 'uom_po_id': self.uom_hour.id, + 'default_code': 'c2', + 'service_tracking': 'task_in_project', + 'project_id': False, # will create a project, + 'project_template_id': project_template_2.id, + }, + ]) + + sale_order_line_template_1, sale_order_line_template_2 = self.env['sale.order.line'].create([ + { + 'order_id': sale_order.id, + 'name': product_1.name, + 'product_id': product_1.id, + 'product_uom_qty': 10, + 'product_uom': product_1.uom_id.id, + 'price_unit': product_1.list_price, + }, { + 'order_id': sale_order.id, + 'name': product_2.name, + 'product_id': product_2.id, + 'product_uom_qty': 5, + 'product_uom': product_2.uom_id.id, + 'price_unit': product_2.list_price, + }, + ]) + + sale_order.action_confirm() + self.assertEqual(10, sale_order_line_template_1.project_id.allocated_hours) + self.assertEqual(5, sale_order_line_template_2.project_id.allocated_hours) + class TestSaleTimesheetView(TestCommonTimesheet): def test_get_view_timesheet_encode_uom(self):