diff --git a/addons/pos_sale/report/sale_report.py b/addons/pos_sale/report/sale_report.py index ad1c91da8f5..46d6de5ad11 100644 --- a/addons/pos_sale/report/sale_report.py +++ b/addons/pos_sale/report/sale_report.py @@ -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""" diff --git a/addons/sale/report/sale_report.py b/addons/sale/report/sale_report.py index a7a179ffb52..0ad5b4df3a9 100644 --- a/addons/sale/report/sale_report.py +++ b/addons/sale/report/sale_report.py @@ -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""" diff --git a/addons/sale/tests/__init__.py b/addons/sale/tests/__init__.py index 9348f7d6e16..2a21d3536a3 100644 --- a/addons/sale/tests/__init__.py +++ b/addons/sale/tests/__init__.py @@ -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 diff --git a/addons/sale/tests/test_sale_report.py b/addons/sale/tests/test_sale_report.py new file mode 100644 index 00000000000..74c4a5553e7 --- /dev/null +++ b/addons/sale/tests/test_sale_report.py @@ -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) diff --git a/addons/sale_margin/report/sale_report.py b/addons/sale_margin/report/sale_report.py index 7a9d7b7b59e..75d5b41aac1 100644 --- a/addons/sale_margin/report/sale_report.py +++ b/addons/sale_margin/report/sale_report.py @@ -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