From c3c5c5ae72ccbca41091dc590fe16ac4135d9f8d Mon Sep 17 00:00:00 2001 From: "Audric Onockx (auon)" Date: Wed, 20 Apr 2022 13:28:33 +0000 Subject: [PATCH] [FIX] sale_project : set project's aa on sol Steps : Create a Project (P) : > Analytic Account : AA Create a Product (A) : > Product Type : Service > Create on Order : Task > Project : P Create a Product (B) : > Product Type : Consumable Create and confirm a Quotation : > SOL > Product : A Go to the Task consequently created. Add B to the products. Go back to the Quotation and create invoice. Issue : See Invoice Lines: > INVL(A)'s analytic account is AA. > INVL(B)'s is not set. Cause : To set the aa on the SOL, we use SOL.task_id._get_task_analytic_account_id(), which returns the task's aa or its project's. Yet we do that only if the task has an aa. Fix : Call the method. If it returns something, set it on SOL. opw-2817811 closes odoo/odoo#89660 X-original-commit: 9e7bf074c346c35325e14e14422f2d860d0db74e Signed-off-by: Laurent Stukkens (ltu) Signed-off-by: Xavier --- addons/sale_project/models/sale_order_line.py | 5 ++- .../sale_timesheet/tests/test_sale_service.py | 45 +++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/addons/sale_project/models/sale_order_line.py b/addons/sale_project/models/sale_order_line.py index d0607e0aa49..8043255c354 100644 --- a/addons/sale_project/models/sale_order_line.py +++ b/addons/sale_project/models/sale_order_line.py @@ -307,8 +307,9 @@ class SaleOrderLine(models.Model): """ values = super(SaleOrderLine, self)._prepare_invoice_line(**optional_values) if not values.get('analytic_account_id'): - if self.task_id.analytic_account_id: - values['analytic_account_id'] = self.task_id._get_task_analytic_account_id().id + task_analytic_account = self.task_id._get_task_analytic_account_id() if self.task_id else False + if task_analytic_account: + values['analytic_account_id'] = task_analytic_account.id elif self.project_id.analytic_account_id: values['analytic_account_id'] = self.project_id.analytic_account_id.id elif self.is_service and not self.is_expense: diff --git a/addons/sale_timesheet/tests/test_sale_service.py b/addons/sale_timesheet/tests/test_sale_service.py index 60d89e1dacd..54937a5dbb5 100644 --- a/addons/sale_timesheet/tests/test_sale_service.py +++ b/addons/sale_timesheet/tests/test_sale_service.py @@ -640,3 +640,48 @@ class TestSaleService(TestCommonSaleTimesheet): tasks = self.project_global.task_ids for task in tasks: self.assertEqual(task.planned_hours, planned_hours_for_uom[task.sale_line_id.name]) + + def test_add_product_analytic_account(self): + """ When we have a project with an analytic account and we add a product to the task, + the consequent invoice line should have the same analytic account as the project. + """ + # Ensure the SO has no analytic account to give to its SOLs + self.assertFalse(self.sale_order.analytic_account_id) + Product = self.env['product.product'] + SaleOrderLine = self.env['sale.order.line'] + + # Create a SO with a service that creates a task + product_create = Product.create({ + 'name': 'Product that creates the task', + 'type': 'service', + 'service_type': 'timesheet', + 'project_id': self.project_global.id, + 'service_tracking': 'task_global_project', + }) + sale_order_line_create = SaleOrderLine.create({ + 'order_id': self.sale_order.id, + 'name': product_create.name, + 'product_id': product_create.id, + 'product_uom_qty': 5, + 'product_uom': product_create.uom_id.id, + 'price_unit': product_create.list_price, + }) + self.sale_order.action_confirm() + + # Add a SOL with a task_id to mimmic the "Add a product" flow on the task + product_add = Product.create({'name': 'Product added on task'}) + SaleOrderLine.create({ + 'order_id': self.sale_order.id, + 'name': product_add.name, + 'product_id': product_add.id, + 'product_uom_qty': 5, + 'product_uom': product_add.uom_id.id, + 'price_unit': product_add.list_price, + 'task_id': sale_order_line_create.task_id.id, + }) + self.sale_order._create_invoices() + + # Check that the resulting invoice line and the project have the same analytic account + invoice_line = self.sale_order.invoice_ids.line_ids.filtered(lambda line: line.product_id == product_add) + self.assertEqual(invoice_line.analytic_account_id, self.project_global.analytic_account_id, + "SOL's analytic account should be the same as the project's")