summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/stock_account/models/product.py24
-rw-r--r--addons/stock_account/models/stock_move.py1
-rw-r--r--addons/stock_account/tests/test_stockvaluationlayer.py21
3 files changed, 37 insertions, 9 deletions
diff --git a/addons/stock_account/models/product.py b/addons/stock_account/models/product.py
index 07aadea626e..901d393984c 100644
--- a/addons/stock_account/models/product.py
+++ b/addons/stock_account/models/product.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_is_zero, float_repr
from odoo.exceptions import ValidationError
@@ -185,12 +185,22 @@ class ProductProduct(models.Model):
if self.cost_method in ('average', 'fifo'):
fifo_vals = self._run_fifo(abs(quantity), company)
vals['remaining_qty'] = fifo_vals.get('remaining_qty')
- # in case of AVCO, fix rounding issue of standard price when needed.
+ # In case of AVCO, fix rounding issue of standard price when needed.
if self.cost_method == 'average':
- rounding_error = self.standard_price * self.quantity_svl - self.value_svl
- vals['value'] += self.env.company.currency_id.round(rounding_error)
- if self.quantity_svl:
- vals['unit_cost'] = self.value_svl / self.quantity_svl
+ currency = self.env.company.currency_id
+ rounding_error = currency.round(self.standard_price * self.quantity_svl - self.value_svl)
+ if rounding_error:
+ # If it is bigger than the (smallest number of the currency * quantity) / 2,
+ # then it isn't a rounding error but a stock valuation error, we shouldn't fix it under the hood ...
+ if abs(rounding_error) <= (abs(quantity) * currency.rounding) / 2:
+ vals['value'] += rounding_error
+ vals['rounding_adjustment'] = '\nRounding Adjustment: %s%s %s' % (
+ '+' if rounding_error > 0 else '',
+ float_repr(rounding_error, precision_digits=currency.decimal_places),
+ currency.symbol
+ )
+ if self.quantity_svl:
+ vals['unit_cost'] = self.value_svl / self.quantity_svl
if self.cost_method == 'fifo':
vals.update(fifo_vals)
return vals
@@ -528,7 +538,7 @@ class ProductProduct(models.Model):
# FIXME: create an empty layer to track the change?
continue
svsl_vals = product._prepare_out_svl_vals(product.quantity_svl, self.env.company)
- svsl_vals['description'] = description
+ svsl_vals['description'] = description + svsl_vals.pop('rounding_adjustment', '')
svsl_vals['company_id'] = self.env.company.id
empty_stock_svl_list.append(svsl_vals)
return empty_stock_svl_list, products_orig_quantity_svl, impacted_products
diff --git a/addons/stock_account/models/stock_move.py b/addons/stock_account/models/stock_move.py
index 46cfc895e4a..5b30e804a0e 100644
--- a/addons/stock_account/models/stock_move.py
+++ b/addons/stock_account/models/stock_move.py
@@ -179,6 +179,7 @@ class StockMove(models.Model):
svl_vals.update(move._prepare_common_svl_vals())
if forced_quantity:
svl_vals['description'] = 'Correction of %s (modification of past move)' % move.picking_id.name or move.name
+ svl_vals['description'] += svl_vals.pop('rounding_adjustment', '')
svl_vals_list.append(svl_vals)
return self.env['stock.valuation.layer'].sudo().create(svl_vals_list)
diff --git a/addons/stock_account/tests/test_stockvaluationlayer.py b/addons/stock_account/tests/test_stockvaluationlayer.py
index df804b3c57f..136bc967737 100644
--- a/addons/stock_account/tests/test_stockvaluationlayer.py
+++ b/addons/stock_account/tests/test_stockvaluationlayer.py
@@ -485,19 +485,36 @@ class TestStockValuationAVCO(TestStockValuationCommon):
self.assertEqual(self.product1.quantity_svl, 2)
self.assertEqual(self.product1.standard_price, 15)
- def test_rounding_1(self):
+ def test_rounding_slv_1(self):
move1 = self._make_in_move(self.product1, 1, unit_cost=1.00)
move2 = self._make_in_move(self.product1, 1, unit_cost=1.00)
move3 = self._make_in_move(self.product1, 1, unit_cost=1.01)
self.assertAlmostEqual(self.product1.value_svl, 3.01)
- move4 = self._make_out_move(self.product1, 3, create_picking=True)
+ move_out = self._make_out_move(self.product1, 3, create_picking=True)
+
+ self.assertIn('Rounding Adjustment: -0.01', move_out.stock_valuation_layer_ids.description)
self.assertEqual(self.product1.value_svl, 0)
self.assertEqual(self.product1.quantity_svl, 0)
self.assertEqual(self.product1.standard_price, 1.00)
+ def test_rounding_slv_2(self):
+ self._make_in_move(self.product1, 1, unit_cost=1.02)
+ self._make_in_move(self.product1, 1, unit_cost=1.00)
+ self._make_in_move(self.product1, 1, unit_cost=1.00)
+
+ self.assertAlmostEqual(self.product1.value_svl, 3.02)
+
+ move_out = self._make_out_move(self.product1, 3, create_picking=True)
+
+ self.assertIn('Rounding Adjustment: +0.01', move_out.stock_valuation_layer_ids.description)
+
+ self.assertEqual(self.product1.value_svl, 0)
+ self.assertEqual(self.product1.quantity_svl, 0)
+ self.assertEqual(self.product1.standard_price, 1.01)
+
class TestStockValuationFIFO(TestStockValuationCommon):
def setUp(self):