[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) <arm@odoo.com>
This commit is contained in:
Tom De Caluwé
2023-11-24 23:57:32 +00:00
committed by Arnold Moyaux
parent ee0b81b06d
commit fee810535e
3 changed files with 56 additions and 5 deletions
@@ -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 ""
@@ -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()
@@ -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)