Skip to content
Snippets Groups Projects
Commit 2d6f4213 authored by Yolann Sabaux's avatar Yolann Sabaux
Browse files

[FIX] stock_account: compute new price with correct rounding


Steps to reproduce:

Decimal Accuracy - Product Price = 2
- create a product `alc 50%` with BOM (10 unites = 1 unit Water [cost=0.14]; 1 unit Alc [cost=0.08])
- Set `quantity on hands` = 10,000
- Trigger `Compute Price from BoM`

-> In Reporting > Inventory Valuation; click on the layer; in Other Info: You will see "Product value manually modified (from 0.0 to 0.022000000000000002)"
=> It can cause computing mistakes as we changed the costs

Cause:

The value is calculated as the difference between the New Price (cost) and and the current Product Standard Price (cost).
But, on one hand the Product Standard Price is rounded to the number of digits defined in the Decimal Accuracy for the Product Price.
On the other hand, the New Price is used as is with no rounding.

If we add an extra step and modify the cost of the Water to 0.45 and trigger again the `Compute Price from BoM` we will have:
"Product value manually modified (from 0.02 to 0.053000000000000005)"

Solution:

Use for the New Price the same rounding precision as we use for the Standard Price.

Example:

Product		Price/unit
--------------------------
Water		0.14
Alc. 100%	0.08

BoM: Alc. 50%
Product		Quantity Needed
--------------------------
Water		0.1
Alc. 100%	0.1

Cost/unit of Alc. 50%: 0.022 => 0.02 (standard_price is rounded)
Set Quantity on Hand: 10,000

Stock Valuation: 200 = 10,000 * 0.02
=> The standard_price is rounded to the second digit when intialized

Product         Price/unit
--------------------------
Water           0.45
Alc. 100%       0.08

BoM: Alc. 50%
Product         Quantity Needed
--------------------------
Water           0.1
Alc. 100%       0.1

Cost/unit of Alc. 50%: 0.053
Set Quantity on Hand: 10,000

Stock Valuation WITHOUT FIX: 530 = 200 (first layer) + 330 (second layer) = 0.02 * 10,000 + (0.053-0.02) * 10,000
Stock Valuation WITH FIX: 500 = 200 (first layer) + 300 (second layer) = 0.02 * 10,000 + (0.05-0.02) * 10,000

=> Without fix, the value is computed with the rounded standard_price and the not rounded new_price.
=> With fix, the new_price is rounded the same way as the standard_price

opw-2724975

closes odoo/odoo#87600

Signed-off-by: default avatarWilliam Henrotin (whe) <whe@odoo.com>
parent 52ab8af5
Branches
Tags
No related merge requests found
......@@ -223,7 +223,8 @@ class ProductProduct(models.Model):
quantity_svl = product.sudo().quantity_svl
if float_compare(quantity_svl, 0.0, precision_rounding=product.uom_id.rounding) <= 0:
continue
diff = new_price - product.standard_price
rounded_new_price = company_id.currency_id.round(new_price)
diff = rounded_new_price - product.standard_price
value = company_id.currency_id.round(quantity_svl * diff)
if company_id.currency_id.is_zero(value):
continue
......@@ -231,7 +232,7 @@ class ProductProduct(models.Model):
svl_vals = {
'company_id': company_id.id,
'product_id': product.id,
'description': _('Product value manually modified (from %s to %s)') % (product.standard_price, new_price),
'description': _('Product value manually modified (from %s to %s)') % (product.standard_price, rounded_new_price),
'value': value,
'quantity': 0,
}
......
......@@ -125,6 +125,39 @@ class TestStockValuationLayerRevaluation(TestStockValuationCommon):
self.assertEqual(len(credit_lines), 1)
self.assertEqual(credit_lines[0].account_id.id, self.stock_valuation_account.id)
def test_stock_valuation_layer_revaluation_avco_rounding_2_digits(self):
"""
Check that the rounding of the new price (cost) is equivalent to the rounding of the standard price (cost)
The check is done indirectly via the layers valuations.
If correct => rounding method is correct too
"""
self.product1.categ_id.property_cost_method = 'average'
self.env['decimal.precision'].search([
('name', '=', 'Product Price'),
]).digits = 2
self.product1.write({'standard_price': 0})
# First Move
self.product1.write({'standard_price': 0.022})
self._make_in_move(self.product1, 10000)
self.assertEqual(self.product1.standard_price, 0.02)
self.assertEqual(self.product1.quantity_svl, 10000)
layer = self.product1.stock_valuation_layer_ids
self.assertEqual(layer.value, 200)
# Second Move
self.product1.write({'standard_price': 0.053})
self.assertEqual(self.product1.standard_price, 0.05)
self.assertEqual(self.product1.quantity_svl, 10000)
layers = self.product1.stock_valuation_layer_ids
self.assertEqual(layers[0].value, 200)
self.assertEqual(layers[1].value, 300)
def test_stock_valuation_layer_revaluation_fifo(self):
self.product1.categ_id.property_cost_method = 'fifo'
context = {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment