From 20fbc19a2d552011690287d90f4405681582becd Mon Sep 17 00:00:00 2001 From: Horacio Tellez Date: Wed, 2 Feb 2022 08:45:11 +0000 Subject: [PATCH] [FIX] sale: Report on converted currency Before when reporting in the sale module in a multi-company environment currencies where not converted to a unique currency before mathematical operations (sum, avg, ...). Now before mathematical operations currencies are converted to the currency of the company currently selected. Task - 2696759 closes odoo/odoo#83550 Signed-off-by: Victor Feyens (vfe) --- addons/pos_sale/report/sale_report.py | 40 +++++++++++++---- addons/sale/report/sale_report.py | 56 +++++++++++++++++++----- addons/sale_margin/report/sale_report.py | 5 ++- 3 files changed, 80 insertions(+), 21 deletions(-) diff --git a/addons/pos_sale/report/sale_report.py b/addons/pos_sale/report/sale_report.py index d8399ee4b78..31ea63057fc 100644 --- a/addons/pos_sale/report/sale_report.py +++ b/addons/pos_sale/report/sale_report.py @@ -23,7 +23,7 @@ class SaleReport(models.Model): ) def _select_pos(self): - select_ = """ + select_ = f""" -MIN(l.id) AS id, l.product_id AS product_id, t.uom_id AS product_uom, @@ -32,10 +32,22 @@ class SaleReport(models.Model): 0 AS qty_to_deliver, 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(CASE COALESCE(pos.currency_rate, 0) WHEN 0 THEN 1.0 ELSE pos.currency_rate END) AS price_total, - SUM(l.price_subtotal) / MIN(CASE COALESCE(pos.currency_rate, 0) WHEN 0 THEN 1.0 ELSE pos.currency_rate END) AS price_subtotal, - (CASE WHEN pos.state != 'invoiced' THEN SUM(l.price_subtotal_incl) ELSE 0 END) / MIN(CASE COALESCE(pos.currency_rate, 0) WHEN 0 THEN 1.0 ELSE pos.currency_rate END) AS amount_to_invoice, - (CASE WHEN pos.state = 'invoiced' THEN SUM(l.price_subtotal_incl) ELSE 0 END) / MIN(CASE COALESCE(pos.currency_rate, 0) WHEN 0 THEN 1.0 ELSE pos.currency_rate END) AS amount_invoiced, + SUM(l.price_subtotal_incl) + * 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')} + AS price_subtotal, + (CASE WHEN pos.state != 'invoiced' THEN SUM(l.price_subtotal_incl) ELSE 0 END) + * 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_incl) ELSE 0 END) + * 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, pos.date_order AS date, @@ -57,7 +69,10 @@ class SaleReport(models.Model): (SUM(t.weight) * l.qty / u.factor) AS weight, (SUM(t.volume) * l.qty / u.factor) AS volume, l.discount AS discount, - SUM((l.price_unit * l.discount * l.qty / 100.0 / CASE COALESCE(pos.currency_rate, 0) WHEN 0 THEN 1.0 ELSE pos.currency_rate END)) AS discount_amount, + 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')})) + AS discount_amount, NULL AS order_id""" additional_fields_info = self._select_additional_fields() @@ -76,7 +91,15 @@ class SaleReport(models.Model): LEFT JOIN product_template t ON p.product_tmpl_id=t.id LEFT JOIN uom_uom u ON u.id=t.uom_id LEFT JOIN pos_session session ON session.id = pos.session_id - LEFT JOIN pos_config config ON config.id = session.config_id""" + LEFT JOIN pos_config config ON config.id = session.config_id + JOIN {currency_table} ON currency_table.company_id = pos.company_id + """.format( + currency_table=self.env['res.currency']._get_query_currency_table( + { + 'multi_company': True, + 'date': {'date_to': fields.Date.today()} + }), + ) def _where_pos(self): return """ @@ -103,7 +126,8 @@ class SaleReport(models.Model): partner.industry_id, partner.commercial_partner_id, u.factor, - pos.crm_team_id""" + pos.crm_team_id, + currency_table.rate""" def _query(self): res = super()._query() diff --git a/addons/sale/report/sale_report.py b/addons/sale/report/sale_report.py index 217384f534a..01f77e8e87f 100644 --- a/addons/sale/report/sale_report.py +++ b/addons/sale/report/sale_report.py @@ -62,8 +62,8 @@ class SaleReport(models.Model): return "" def _select_sale(self): - select_ = """ - coalesce(min(l.id), -s.id) AS id, + select_ = f""" + COALESCE(min(l.id), -s.id) AS id, l.product_id AS product_id, t.uom_id AS product_uom, CASE WHEN l.product_id IS NOT NULL THEN SUM(l.product_uom_qty / u.factor * u2.factor) ELSE 0 END AS product_uom_qty, @@ -71,10 +71,26 @@ class SaleReport(models.Model): CASE WHEN l.product_id IS NOT NULL THEN SUM((l.product_uom_qty - l.qty_delivered) / u.factor * u2.factor) ELSE 0 END AS qty_to_deliver, 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 / CASE COALESCE(s.currency_rate, 0) WHEN 0 THEN 1.0 ELSE s.currency_rate END) ELSE 0 END AS price_total, - CASE WHEN l.product_id IS NOT NULL THEN SUM(l.price_subtotal / CASE COALESCE(s.currency_rate, 0) WHEN 0 THEN 1.0 ELSE s.currency_rate END) ELSE 0 END AS price_subtotal, - CASE WHEN l.product_id IS NOT NULL THEN SUM(l.untaxed_amount_to_invoice / CASE COALESCE(s.currency_rate, 0) WHEN 0 THEN 1.0 ELSE s.currency_rate END) ELSE 0 END AS untaxed_amount_to_invoice, - CASE WHEN l.product_id IS NOT NULL THEN SUM(l.untaxed_amount_invoiced / CASE COALESCE(s.currency_rate, 0) WHEN 0 THEN 1.0 ELSE s.currency_rate END) ELSE 0 END AS untaxed_amount_invoiced, + 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')} + ) 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')} + ) 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')} + ) 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')} + ) ELSE 0 + END AS untaxed_amount_invoiced, COUNT(*) AS nbr, s.name AS name, s.date_order AS date, @@ -96,7 +112,11 @@ class SaleReport(models.Model): CASE WHEN l.product_id IS NOT NULL THEN SUM(p.weight * l.product_uom_qty / u.factor * u2.factor) ELSE 0 END AS weight, 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 / CASE COALESCE(s.currency_rate, 0) WHEN 0 THEN 1.0 ELSE s.currency_rate END))ELSE 0 END AS discount_amount, + 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')} + ) ELSE 0 + END AS discount_amount, s.id AS order_id""" additional_fields_info = self._select_additional_fields() @@ -107,6 +127,9 @@ class SaleReport(models.Model): return select_ + def _case_value_or_one(self, value): + return f"""CASE COALESCE({value}, 0) WHEN 0 THEN 1.0 ELSE {value} END""" + def _select_additional_fields(self): """Hook to return additional fields SQL specification for select part of the table query. @@ -123,7 +146,15 @@ class SaleReport(models.Model): LEFT JOIN product_product p ON l.product_id=p.id LEFT JOIN product_template t ON p.product_tmpl_id=t.id LEFT JOIN uom_uom u ON u.id=l.product_uom - LEFT JOIN uom_uom u2 ON u2.id=t.uom_id""" + LEFT JOIN uom_uom u2 ON u2.id=t.uom_id + JOIN {currency_table} ON currency_table.company_id = s.company_id + """.format( + currency_table=self.env['res.currency']._get_query_currency_table( + { + 'multi_company': True, + 'date': {'date_to': fields.Date.today()} + }), + ) def _where_sale(self): return """ @@ -152,7 +183,8 @@ class SaleReport(models.Model): partner.industry_id, partner.commercial_partner_id, l.discount, - s.id""" + s.id, + currency_table.rate""" def _query(self): with_ = self._with_sale() @@ -165,6 +197,6 @@ class SaleReport(models.Model): {")" if with_ else ""} """ - def init(self): - tools.drop_view_if_exists(self.env.cr, self._table) - self.env.cr.execute(f"CREATE OR REPLACE VIEW {self._table} AS {self._query()}") + @property + def _table_query(self): + return self._query() diff --git a/addons/sale_margin/report/sale_report.py b/addons/sale_margin/report/sale_report.py index e43a053a351..7a9d7b7b59e 100644 --- a/addons/sale_margin/report/sale_report.py +++ b/addons/sale_margin/report/sale_report.py @@ -11,5 +11,8 @@ class SaleReport(models.Model): def _select_additional_fields(self): res = super()._select_additional_fields() - res['margin'] = "SUM(l.margin / CASE COALESCE(s.currency_rate, 0) WHEN 0 THEN 1.0 ELSE s.currency_rate END)" + res['margin'] = f"""SUM(l.margin + * {self._case_value_or_one('s.currency_rate')} + * {self._case_value_or_one('currency_table.rate')}) + """ return res