From fee810535ebae47d4a2c658d43e1461e77c95ad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20De=20Caluw=C3=A9?= Date: Mon, 12 Jun 2023 12:14:54 +0000 Subject: [PATCH] [FIX] stock_account: avoid negative values after revaluation When performing a manual stock revaluation, the value difference is distributed equally among the available stock. This method breaks down however in case of a devaluation where some items in stock are already valued less than the unit cost difference: this results in a negative value. This commit will prevent such devaluations by raising a UserError whenever the remaining value of a stock.valuation.layer becomes negative. Additionally, after a revaluation, the standard_price field will now also be updated for fifo valued products. opw-3340298 closes odoo/odoo#143437 X-original-commit: a6db4b48f1d32f1020ee3ad242c77211aa10b3b2 Signed-off-by: Arnold Moyaux (arm) --- addons/stock_account/i18n/stock_account.pot | 5 +++ .../tests/test_stockvaluation.py | 43 +++++++++++++++++++ .../stock_valuation_layer_revaluation.py | 13 +++--- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/addons/stock_account/i18n/stock_account.pot b/addons/stock_account/i18n/stock_account.pot index 92e731d1c06..ec8a85b5756 100644 --- a/addons/stock_account/i18n/stock_account.pot +++ b/addons/stock_account/i18n/stock_account.pot @@ -1061,3 +1061,8 @@ msgstr "" #: model_terms:ir.ui.view,arch_db:stock_account.stock_account_report_invoice_document msgid "units" msgstr "" + +#. module: stock_account +#: code:addons/stock_account/wizard/stock_valuation_layer_revaluation.py:0 +msgid "'The value of a stock valuation layer cannot be negative. Landed cost could be use to correct a specific transfer." +msgstr "" diff --git a/addons/stock_account/tests/test_stockvaluation.py b/addons/stock_account/tests/test_stockvaluation.py index ad053c5f854..14ae486d7b9 100644 --- a/addons/stock_account/tests/test_stockvaluation.py +++ b/addons/stock_account/tests/test_stockvaluation.py @@ -4004,3 +4004,46 @@ class TestStockValuation(TransactionCase): self.product1.write({'standard_price': 7}) self.assertEqual(self.product1.value_svl, 49) + + def test_average_manual_revaluation(self): + self.product1.categ_id.property_cost_method = 'average' + + self._make_in_move(self.product1, 1, unit_cost=20) + self._make_in_move(self.product1, 1, unit_cost=30) + self.assertEqual(self.product1.standard_price, 25) + + Form(self.env['stock.valuation.layer.revaluation'].with_context({ + 'default_product_id': self.product1.id, + 'default_company_id': self.env.company.id, + 'default_account_id': self.stock_valuation_account, + 'default_added_value': -10.0, + })).save().action_validate_revaluation() + + self.assertEqual(self.product1.standard_price, 20) + + def test_fifo_manual_revaluation(self): + revaluation_vals = { + 'default_product_id': self.product1.id, + 'default_company_id': self.env.company.id, + 'default_account_id': self.stock_valuation_account, + } + self.product1.categ_id.property_cost_method = 'fifo' + + self._make_in_move(self.product1, 1, unit_cost=15) + self._make_in_move(self.product1, 1, unit_cost=30) + self.assertEqual(self.product1.stock_valuation_layer_ids[0].remaining_value, 15) + + Form(self.env['stock.valuation.layer.revaluation'].with_context({ + **revaluation_vals, + 'default_added_value': -10.0, + })).save().action_validate_revaluation() + + self.assertEqual(self.product1.stock_valuation_layer_ids[0].remaining_value, 10) + + revaluation = Form(self.env['stock.valuation.layer.revaluation'].with_context({ + **revaluation_vals, + 'default_added_value': -25.0, + })).save() + + with self.assertRaises(UserError): + revaluation.action_validate_revaluation() diff --git a/addons/stock_account/wizard/stock_valuation_layer_revaluation.py b/addons/stock_account/wizard/stock_valuation_layer_revaluation.py index a53ced022de..e46927e1efc 100644 --- a/addons/stock_account/wizard/stock_valuation_layer_revaluation.py +++ b/addons/stock_account/wizard/stock_valuation_layer_revaluation.py @@ -3,7 +3,7 @@ from odoo import _, api, fields, models from odoo.exceptions import UserError -from odoo.tools import float_is_zero +from odoo.tools import float_compare, float_is_zero class StockValuationLayerRevaluation(models.TransientModel): @@ -97,12 +97,15 @@ class StockValuationLayerRevaluation(models.TransientModel): remaining_value_unit_cost = self.currency_id.round(remaining_value / remaining_qty) for svl in remaining_svls: if float_is_zero(svl.remaining_qty - remaining_qty, precision_rounding=self.product_id.uom_id.rounding): - svl.remaining_value += remaining_value + taken_remaining_value = remaining_value else: taken_remaining_value = remaining_value_unit_cost * svl.remaining_qty - svl.remaining_value += taken_remaining_value - remaining_value -= taken_remaining_value - remaining_qty -= svl.remaining_qty + if float_compare(svl.remaining_value + taken_remaining_value, 0, precision_rounding=self.product_id.uom_id.rounding) < 0: + raise UserError(_('The value of a stock valuation layer cannot be negative. Landed cost could be use to correct a specific transfer.')) + + svl.remaining_value += taken_remaining_value + remaining_value -= taken_remaining_value + remaining_qty -= svl.remaining_qty revaluation_svl = self.env['stock.valuation.layer'].create(revaluation_svl_vals)