[FIX] sale: fix currency conversion in sale report

Sale Analysis report shows prices in company currency, converting foreign currency into the company currency according to the currency exchange rate.
Currently, the currency conversion is done incorrectly.

For example let's say 1 EUR = 25 CZK OR 1 CZK = 0.04 EUR.
Sales order: 39 EUR = 975 CZK.
Sales Analysis report shows 1.56.

This is because we are trying to multiply the order amount by 0.04, while it should be divided.
It used to be divided up until 16.0.

This commit changes the operator to convert the currency correctly.

opw-3167522

closes odoo/odoo#113525

X-original-commit: ef57d53866dc1d404138809132176c79d60a3b51
Signed-off-by: Aliya Tastemirova (alta) <alta@odoo.com>
This commit is contained in:
aliya
2023-02-23 18:29:02 +01:00
parent 3121454e9d
commit 141bed9360
5 changed files with 105 additions and 22 deletions
+10 -10
View File
@@ -33,20 +33,20 @@ class SaleReport(models.Model):
CASE WHEN pos.state = 'invoiced' THEN SUM(l.qty) ELSE 0 END AS qty_invoiced,
CASE WHEN pos.state != 'invoiced' THEN SUM(l.qty) ELSE 0 END AS qty_to_invoice,
SUM(l.price_subtotal_incl)
* MIN({self._case_value_or_one('pos.currency_rate')})
* {self._case_value_or_one('currency_table.rate')}
/ MIN({self._case_value_or_one('pos.currency_rate')})
/ {self._case_value_or_one('currency_table.rate')}
AS price_total,
SUM(l.price_subtotal)
* MIN({self._case_value_or_one('pos.currency_rate')})
* {self._case_value_or_one('currency_table.rate')}
/ MIN({self._case_value_or_one('pos.currency_rate')})
/ {self._case_value_or_one('currency_table.rate')}
AS price_subtotal,
(CASE WHEN pos.state != 'invoiced' THEN SUM(l.price_subtotal) ELSE 0 END)
* MIN({self._case_value_or_one('pos.currency_rate')})
* {self._case_value_or_one('currency_table.rate')}
/ MIN({self._case_value_or_one('pos.currency_rate')})
/ {self._case_value_or_one('currency_table.rate')}
AS amount_to_invoice,
(CASE WHEN pos.state = 'invoiced' THEN SUM(l.price_subtotal) ELSE 0 END)
* MIN({self._case_value_or_one('pos.currency_rate')})
* {self._case_value_or_one('currency_table.rate')}
/ MIN({self._case_value_or_one('pos.currency_rate')})
/ {self._case_value_or_one('currency_table.rate')}
AS amount_invoiced,
count(*) AS nbr,
pos.name AS name,
@@ -71,8 +71,8 @@ class SaleReport(models.Model):
(SUM(p.volume) * l.qty / u.factor) AS volume,
l.discount AS discount,
SUM((l.price_unit * l.discount * l.qty / 100.0
* {self._case_value_or_one('pos.currency_rate')}
* {self._case_value_or_one('currency_table.rate')}))
/ {self._case_value_or_one('pos.currency_rate')}
/ {self._case_value_or_one('currency_table.rate')}))
AS discount_amount,
NULL AS order_id"""
+10 -10
View File
@@ -79,23 +79,23 @@ class SaleReport(models.Model):
CASE WHEN l.product_id IS NOT NULL THEN SUM(l.qty_invoiced / u.factor * u2.factor) ELSE 0 END AS qty_invoiced,
CASE WHEN l.product_id IS NOT NULL THEN SUM(l.qty_to_invoice / u.factor * u2.factor) ELSE 0 END AS qty_to_invoice,
CASE WHEN l.product_id IS NOT NULL THEN SUM(l.price_total
* {self._case_value_or_one('s.currency_rate')}
* {self._case_value_or_one('currency_table.rate')}
/ {self._case_value_or_one('s.currency_rate')}
/ {self._case_value_or_one('currency_table.rate')}
) ELSE 0
END AS price_total,
CASE WHEN l.product_id IS NOT NULL THEN SUM(l.price_subtotal
* {self._case_value_or_one('s.currency_rate')}
* {self._case_value_or_one('currency_table.rate')}
/ {self._case_value_or_one('s.currency_rate')}
/ {self._case_value_or_one('currency_table.rate')}
) ELSE 0
END AS price_subtotal,
CASE WHEN l.product_id IS NOT NULL THEN SUM(l.untaxed_amount_to_invoice
* {self._case_value_or_one('s.currency_rate')}
* {self._case_value_or_one('currency_table.rate')}
/ {self._case_value_or_one('s.currency_rate')}
/ {self._case_value_or_one('currency_table.rate')}
) ELSE 0
END AS untaxed_amount_to_invoice,
CASE WHEN l.product_id IS NOT NULL THEN SUM(l.untaxed_amount_invoiced
* {self._case_value_or_one('s.currency_rate')}
* {self._case_value_or_one('currency_table.rate')}
/ {self._case_value_or_one('s.currency_rate')}
/ {self._case_value_or_one('currency_table.rate')}
) ELSE 0
END AS untaxed_amount_invoiced,
COUNT(*) AS nbr,
@@ -121,8 +121,8 @@ class SaleReport(models.Model):
CASE WHEN l.product_id IS NOT NULL THEN SUM(p.volume * l.product_uom_qty / u.factor * u2.factor) ELSE 0 END AS volume,
l.discount AS discount,
CASE WHEN l.product_id IS NOT NULL THEN SUM(l.price_unit * l.product_uom_qty * l.discount / 100.0
* {self._case_value_or_one('s.currency_rate')}
* {self._case_value_or_one('currency_table.rate')}
/ {self._case_value_or_one('s.currency_rate')}
/ {self._case_value_or_one('currency_table.rate')}
) ELSE 0
END AS discount_amount,
s.id AS order_id"""
+1
View File
@@ -17,3 +17,4 @@ from . import test_sale_refund
from . import test_sale_tax_totals
from . import test_sale_to_invoice
from . import test_sale_order_down_payment
from . import test_sale_report
+82
View File
@@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from freezegun import freeze_time
from odoo import fields
from odoo.fields import Command
from odoo.tests import tagged
from odoo.addons.sale.tests.common import SaleCommon
@tagged('-at_install', 'post_install')
class TestSaleReportCurrencyRate(SaleCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.company = cls.env['res.company'].create({
'name': 'Test Company',
'currency_id': cls.env.ref('base.USD').id,
})
def test_sale_report_foreign_currency(self):
# Test the amounts shown in the sales report for orders in foreign currency
currency_eur = self._enable_currency('EUR')
eur_pricelist = self.env['product.pricelist'].create({
'name': 'Pricelist (EUR)',
'currency_id': currency_eur.id,
})
with freeze_time('2022-02-22'):
self.env['res.currency.rate'].create({
'name': fields.Date.today(),
'company_rate': 3.0,
'currency_id': currency_eur.id,
'company_id': self.company.id,
})
eur_order = self.env['sale.order'].with_company(self.company).create({
'partner_id': self.partner.id,
'pricelist_id': eur_pricelist.id,
'date_order': fields.Date.today(),
'order_line': [
Command.create({
'product_id': self.product.id,
'product_uom_qty': 1.0,
}),
]
})
# the sales order's amount is in foreign currency
self.assertEqual(eur_order.amount_total, 60.0)
# the report should show the amount in company currency
report_line = self.env['sale.report'].sudo().search(
[('order_id', '=', eur_order.id)])
self.assertEqual(report_line.price_total, 20.0)
def test_sale_report_company_currency(self):
usd_pricelist = self.env['product.pricelist'].create({
'name': 'Pricelist (USD)',
'currency_id': self.company.currency_id.id,
})
usd_order = self.env['sale.order'].with_company(self.company).create({
'partner_id': self.partner.id,
'pricelist_id': usd_pricelist.id,
'order_line': [
Command.create({
'product_id': self.product.id,
'product_uom_qty': 1.0,
}),
]
})
# the sales order's amount is in company currency
self.assertEqual(usd_order.amount_total, 20.0)
# the report should match the amount on the SO
report_line = self.env['sale.report'].sudo().search(
[('order_id', '=', usd_order.id)])
self.assertEqual(report_line.price_total, 20.0)
+2 -2
View File
@@ -12,7 +12,7 @@ class SaleReport(models.Model):
def _select_additional_fields(self):
res = super()._select_additional_fields()
res['margin'] = f"""SUM(l.margin
* {self._case_value_or_one('s.currency_rate')}
* {self._case_value_or_one('currency_table.rate')})
/ {self._case_value_or_one('s.currency_rate')}
/ {self._case_value_or_one('currency_table.rate')})
"""
return res