From 173cc43ca222a8a3e4eddb8c8a8c21782848dd7e Mon Sep 17 00:00:00 2001 From: prro-odoo Date: Fri, 9 Jul 2021 13:44:40 +0000 Subject: [PATCH] [FIX] sale_timesheet: fix amount computed for other_revenue How to reproduce the problem: - Install sale_timesheet. - Create 2 service products: one with "Create a task in sales order's project" (e.g. Product X), and the other with "Don't create task" (e.g. Product Y), in the Service Tracking field. Both with "Milestones" as Service Invoicing Policy. - Create a Sale Order with these 2 products (with e.g. quantity of 10 for both). Confirm the SO. - Edit the SO. Put 5 in the "Delivered" column of the Product Y. Create Invoice and confirm it. - Go to the Project app -> Overview (of the newly created project). - The "Other Revenues" is missing/not correctly filled Cause of the problem : the query to fetch the value would not take the invoiced Product Y into account, it should now work correctly. opw-2540624 closes odoo/odoo#74191 X-original-commit: 59b5667665124e8db51caa94039e33b5f718718d Signed-off-by: LTU-Odoo --- .../project_profitability_report_analysis.py | 22 ++++++++++--------- .../tests/test_project_overview.py | 16 ++++++++++++-- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/addons/sale_timesheet/report/project_profitability_report_analysis.py b/addons/sale_timesheet/report/project_profitability_report_analysis.py index 8e9c1ab4703..8455d1217db 100644 --- a/addons/sale_timesheet/report/project_profitability_report_analysis.py +++ b/addons/sale_timesheet/report/project_profitability_report_analysis.py @@ -178,16 +178,18 @@ class ProfitabilityAnalysis(models.Model): 0.0 AS amount_untaxed_invoiced, AAL.date AS line_date FROM project_project P - LEFT JOIN account_analytic_account AA ON P.analytic_account_id = AA.id - LEFT JOIN account_analytic_line AAL ON AAL.account_id = AA.id - WHERE AAL.amount > 0.0 AND AAL.project_id IS NULL AND P.active = 't' AND P.allow_timesheets = 't' - AND NOT EXISTS ( - SELECT SOL.id - FROM sale_order_line SOL - JOIN sale_order_line_invoice_rel SOINV ON SOINV.order_line_id = SOL.id AND SOINV.invoice_line_id = AAL.move_id -- AAL.move_id is an account.move.line id - WHERE SOL.qty_delivered_method IN ('timesheet', 'manual') - OR (SOL.qty_delivered_method = 'analytic' AND SOL.invoice_status != 'no') - ) + JOIN account_analytic_account AA ON P.analytic_account_id = AA.id + JOIN account_analytic_line AAL ON AAL.account_id = AA.id + JOIN product_product PP ON PP.id = AAL.product_id + JOIN product_template PT ON PT.id = PP.product_tmpl_id + LEFT JOIN sale_order_line_invoice_rel SOINV ON SOINV.invoice_line_id = AAL.move_id + LEFT JOIN sale_order_line SOL ON SOINV.order_line_id = SOL.id + WHERE AAL.amount > 0.0 AND AAL.project_id IS NULL AND P.active = 't' + AND P.allow_timesheets = 't' + AND PT.service_type = 'manual' -- default value or Milestone service for services products + AND PT.service_tracking = 'no' -- default value or not a tracking service for services products + AND (SOL.id IS NULL + OR (SOL.is_expense IS NOT TRUE AND SOL.is_downpayment IS NOT TRUE)) UNION ALL diff --git a/addons/sale_timesheet/tests/test_project_overview.py b/addons/sale_timesheet/tests/test_project_overview.py index 0623f515dba..90f51e1d0e8 100644 --- a/addons/sale_timesheet/tests/test_project_overview.py +++ b/addons/sale_timesheet/tests/test_project_overview.py @@ -20,6 +20,16 @@ class TestSaleProject(TestReporting): 'price_unit': self.product_delivery_timesheet2.list_price, 'order_id': self.sale_order_2.id, }) + so_line_deliver_no_task = self.env['sale.order.line'].create({ + 'name': self.product_delivery_manual1.name, + 'product_id': self.product_delivery_manual1.id, + 'product_uom_qty': 50, + 'product_uom': self.product_delivery_manual1.uom_id.id, + 'price_unit': self.product_delivery_manual1.list_price, + 'order_id': self.sale_order_2.id, + }) + so_line_deliver_no_task.write({'qty_delivered': 1.0}) + self.sale_order_2.action_confirm() project_so = self.so_line_order_project.project_id # log timesheet for billable time @@ -87,6 +97,7 @@ class TestSaleProject(TestReporting): 'product_id': self.product_expense.id, 'product_uom_id': self.product_expense.uom_id.id, }) + view_id = self.env.ref('sale_timesheet.project_timesheet_action_client_timesheet_plan').id vals = self.env['project.project']._qweb_prepare_qcontext(view_id, [['id', '=', project_so.id]]) @@ -99,6 +110,7 @@ class TestSaleProject(TestReporting): project_rate_total = project_rate_non_billable + project_rate_non_billable_project + project_rate_billable_time + project_rate_billable_fixed project_invoiced = self.so_line_order_project.price_unit * self.so_line_order_project.product_uom_qty * timesheet1.unit_amount project_timesheet_cost = timesheet2.amount + timesheet3.amount + timesheet4.amount + timesheet5.amount + timesheet1.amount + project_other_revenues = invoice.invoice_line_ids.search([('product_id', '=', self.product_delivery_manual1.id)]) self.assertEqual(float_compare(vals['dashboard']['time']['non_billable'], timesheet5.unit_amount, precision_rounding=rounding), 0, "The hours non-billable should be the one from the SO2 line, as we are in ordered quantity") self.assertEqual(float_compare(vals['dashboard']['time']['non_billable_project'], timesheet2.unit_amount, precision_rounding=rounding), 0, "The hours non-billable-project should be the one from the SO2 line, as we are in ordered quantity") @@ -113,6 +125,6 @@ class TestSaleProject(TestReporting): self.assertEqual(float_compare(vals['dashboard']['profit']['invoiced'], project_invoiced, precision_rounding=rounding), 0, "The amount invoiced should be the one from the SO2 line, as we are in ordered quantity") self.assertEqual(float_compare(vals['dashboard']['profit']['cost'], project_timesheet_cost, precision_rounding=rounding), 0, "The amount cost should be the one from the SO2 line, as we are in ordered quantity") self.assertEqual(float_compare(vals['dashboard']['profit']['expense_cost'], expense.amount, precision_rounding=rounding), 0, "The amount expense-cost should be the one from the SO2 line, as we are in ordered quantity") - self.assertEqual(float_compare(vals['dashboard']['profit']['other_revenues'], other_revenues.amount, precision_rounding=rounding), 0, "The amount of the other revenues should be equal to the created other_revenues account analytic line") - self.assertEqual(float_compare(vals['dashboard']['profit']['total'], project_invoiced + project_timesheet_cost + expense.amount + other_revenues.amount, precision_rounding=rounding), 0, "The total amount should be the sum of the SO2 line and the created other_revenues account analytic line") + self.assertEqual(float_compare(vals['dashboard']['profit']['other_revenues'], other_revenues.amount + project_other_revenues.price_total, precision_rounding=rounding), 0, "The amount of the other revenues should be equal to the corresponding account move line and the one from the SO line") + self.assertEqual(float_compare(vals['dashboard']['profit']['total'], project_invoiced + project_timesheet_cost + expense.amount + other_revenues.amount + project_other_revenues.price_total, precision_rounding=rounding), 0, "The total amount should be the sum of the SO2 line and the created other_revenues account analytic line") self.assertEqual(float_compare(vals['repartition_employee_max'], 11.0, precision_rounding=rounding), 0, "The amount of repartition-employee-max should be the one from SO2 line")