[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:
@@ -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"""
|
||||
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user