From 40745b1de9038bd1c1bbfcd295a02e9fdea957e3 Mon Sep 17 00:00:00 2001 From: "Dylan Kiss (dyki)" Date: Tue, 30 Jan 2024 14:08:09 +0100 Subject: [PATCH] [IMP] {stock_}account: margin and inventory measures in invoice analysis In order to better analyze profitability, we added an extra measure to the Invoice Analysis report to show the "Margin" on every invoice line based on the product cost price. In order to have a simplified inventory valuation without fully using the Inventory app, we also added an "Inventory Value" measure that also uses the product cost price to show the change in inventory value based on incoming and outgoing accounting documents. An extra filter "Inventory Valuation" was added as well to show the "Inventory Value" values per storable product and per month. task-3708415 closes odoo/odoo#151805 Signed-off-by: Cedric Snauwaert --- .../account/report/account_invoice_report.py | 14 +++++++++++++- .../report/account_invoice_report_view.xml | 2 ++ .../tests/test_account_invoice_report.py | 19 +++++++++++-------- addons/stock_account/__manifest__.py | 1 + .../report/account_invoice_report_view.xml | 10 ++++++++++ 5 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 addons/stock_account/report/account_invoice_report_view.xml diff --git a/addons/account/report/account_invoice_report.py b/addons/account/report/account_invoice_report.py index c76b60856fc..342d88901f5 100644 --- a/addons/account/report/account_invoice_report.py +++ b/addons/account/report/account_invoice_report.py @@ -47,6 +47,8 @@ class AccountInvoiceReport(models.Model): price_subtotal = fields.Float(string='Untaxed Total', readonly=True) price_total = fields.Float(string='Total in Currency', readonly=True) price_average = fields.Float(string='Average Price', readonly=True, group_operator="avg") + price_margin = fields.Float(string='Margin', readonly=True) + inventory_value = fields.Float(string='Inventory Value', readonly=True) currency_id = fields.Many2one('res.currency', string='Currency', readonly=True) _depends = { @@ -59,7 +61,7 @@ class AccountInvoiceReport(models.Model): 'move_id', 'product_id', 'product_uom_id', 'account_id', 'journal_id', 'company_id', 'currency_id', 'partner_id', ], - 'product.product': ['product_tmpl_id'], + 'product.product': ['product_tmpl_id', 'standard_price'], 'product.template': ['categ_id'], 'uom.uom': ['category_id', 'factor', 'name', 'uom_type'], 'res.currency.rate': ['currency_id', 'name'], @@ -104,6 +106,13 @@ class AccountInvoiceReport(models.Model): -- convert to template uom * (NULLIF(COALESCE(uom_line.factor, 1), 0.0) / NULLIF(COALESCE(uom_template.factor, 1), 0.0)), 0.0) * currency_table.rate AS price_average, + CASE + WHEN move.move_type NOT IN ('out_invoice', 'out_receipt') THEN 0.0 + ELSE -line.balance * currency_table.rate - (line.quantity / NULLIF(COALESCE(uom_line.factor, 1) / COALESCE(uom_template.factor, 1), 0.0)) * product_standard_price.value_float + END + AS price_margin, + line.quantity / NULLIF(COALESCE(uom_line.factor, 1) / COALESCE(uom_template.factor, 1), 0.0) * (CASE WHEN move.move_type IN ('out_invoice','in_refund','out_receipt') THEN -1 ELSE 1 END) + * product_standard_price.value_float AS inventory_value, COALESCE(partner.country_id, commercial_partner.country_id) AS country_id, line.currency_id AS currency_id ''' @@ -120,6 +129,9 @@ class AccountInvoiceReport(models.Model): LEFT JOIN uom_uom uom_template ON uom_template.id = template.uom_id INNER JOIN account_move move ON move.id = line.move_id LEFT JOIN res_partner commercial_partner ON commercial_partner.id = move.commercial_partner_id + LEFT JOIN ir_property product_standard_price + ON product_standard_price.res_id = CONCAT('product.product,', product.id) + AND product_standard_price.name = 'standard_price' JOIN {currency_table} ON currency_table.company_id = line.company_id '''.format( currency_table=self.env['res.currency']._get_query_currency_table(self.env.companies.ids, fields.Date.today()) diff --git a/addons/account/report/account_invoice_report_view.xml b/addons/account/report/account_invoice_report_view.xml index 6c6decdb27e..4d388914e4d 100644 --- a/addons/account/report/account_invoice_report_view.xml +++ b/addons/account/report/account_invoice_report_view.xml @@ -43,6 +43,8 @@ + + diff --git a/addons/account/tests/test_account_invoice_report.py b/addons/account/tests/test_account_invoice_report.py index d1458036c9d..f15e1b8f814 100644 --- a/addons/account/tests/test_account_invoice_report.py +++ b/addons/account/tests/test_account_invoice_report.py @@ -102,18 +102,21 @@ class TestAccountInvoiceReport(AccountTestInvoicingCommon): 'price_average': vals[0], 'price_subtotal': vals[1], 'quantity': vals[2], + 'price_margin': vals[3], + 'inventory_value': vals[4], } for vals in expected_values_list] self.assertRecordValues(reports, expected_values_dict) def test_invoice_report_multiple_types(self): self.assertInvoiceReportValues([ - #price_average price_subtotal quantity - [2000, 2000, 1], - [1000, 1000, 1], - [250, 750, 3], - [6, 6, 1], - [20, -20, -1], - [20, -20, -1], - [600, -600, -1], + # pylint: disable=bad-whitespace + # price_average, price_subtotal, quantity, price_margin, inventory_value + [ 2000, 2000, 1, 1200, -800], # price_unit = 6000, currency.rate = 3.0 + [ 1000, 1000, 1, 200, -800], # price_unit = 3000, currency.rate = 3.0 + [ 250, 750, 3, -1650, -2400], # price_unit = 750, currency.rate = 2.0 + [ 6, 6, 1, 0, -800], # price_unit = 12, currency.rate = 2.0 + [ 20, -20, -1, 0, 800], # price_unit = 60, currency.rate = 3.0 + [ 20, -20, -1, 0, 800], # price_unit = 60, currency.rate = 3.0 + [ 600, -600, -1, 0, 800], # price_unit = 1200, currency.rate = 2.0 ]) diff --git a/addons/stock_account/__manifest__.py b/addons/stock_account/__manifest__.py index 77cd09eb3e2..b91c868554b 100644 --- a/addons/stock_account/__manifest__.py +++ b/addons/stock_account/__manifest__.py @@ -36,6 +36,7 @@ Dashboard / Reports for Warehouse Management includes: 'wizard/stock_request_count.xml', 'wizard/stock_valuation_layer_revaluation_views.xml', 'wizard/stock_quantity_history.xml', + 'report/account_invoice_report_view.xml', ], 'installable': True, 'auto_install': True, diff --git a/addons/stock_account/report/account_invoice_report_view.xml b/addons/stock_account/report/account_invoice_report_view.xml new file mode 100644 index 00000000000..d07c6461bcb --- /dev/null +++ b/addons/stock_account/report/account_invoice_report_view.xml @@ -0,0 +1,10 @@ + + + + Inventory Valuation + account.invoice.report + [('product_id.type', '=', 'product')] + + {'group_by': ['product_id'], 'pivot_column_groupby': ['invoice_date:month'], 'pivot_measures': ['inventory_value'], 'graph_measure': 'inventory_value'} + +