[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 <IT-Ideas@users.noreply.github.com>
This commit is contained in:
prro-odoo
2021-07-23 17:00:10 +00:00
parent 0b911fe04a
commit 173cc43ca2
2 changed files with 26 additions and 12 deletions
@@ -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
@@ -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")