[FIX] stock_account: invalid layer on bill due to rounding
What are the steps to reproduce your issue? Price Decimal Precision set at 5, currency at 2. Anglosaxon enabled. Have a product with a unit / purchase cost of 3.30125 Create Purchase for 1500.00 and receipt in. This creates an SVL and AML for 4951.88 Create Bill with unit cost of 3.30125 and total amount of 4951.88 Confirm Invoice What is the current behavior that you observe? The layer unit price value is calculated unrounded (line 304, purchase_stock/models/account_move_line.py) - so 4951.88 / 1500 = 3.30125333333. This is then subtracted from the Invoice unit price leaving a difference of 0.00000333333 Despite the price_unit difference being less than the precision this then multiplies out to be 0.005 that gets rounded to 0.01. A new SVL layer is created, and a new move valued at 0.01 and remaining value on existing correct layer is reduced by 1c. When anglosaxon attempts to reconcile the various moves, it is unable to because there is now a 1c difference in the sum of the relevant AML's. What would be your expected behavior in this case? Not to create useless SVL that is wrong Reconcile anglosaxon records normally. It happens due to the comparaison between the layer price unit that is not rounded and the price unit of the account.move.line that is rounded to the decimal accuracy. We want to keep the most accurate value so we modify _get_gross_price unit to recompute the unit price this way we ignore the rounding close #140410 closes odoo/odoo#143768 X-original-commit: 73aaaa9550b15225e25fcd750ebfd5fb58436064 Signed-off-by: Arnold Moyaux (arm) <arm@odoo.com>
This commit is contained in:
@@ -764,6 +764,76 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
|
||||
self.assertAlmostEqual(picking_aml.amount_currency, -20, msg="credit value for stock should be equal to the standard price of the product.")
|
||||
self.assertAlmostEqual(diff_aml.amount_currency, -80, msg="credit value for price difference")
|
||||
|
||||
def test_valuation_rounding(self):
|
||||
company = self.env.user.company_id
|
||||
company.anglo_saxon_accounting = True
|
||||
company.currency_id = self.usd_currency
|
||||
|
||||
self.product1.product_tmpl_id.categ_id.property_cost_method = 'fifo'
|
||||
self.product1.product_tmpl_id.categ_id.property_valuation = 'real_time'
|
||||
|
||||
self.env.ref('product.decimal_price').digits = 5
|
||||
|
||||
po = self.env['purchase.order'].create({
|
||||
'partner_id': self.partner_id.id,
|
||||
'order_line': [
|
||||
(0, 0, {
|
||||
'name': self.product1.name,
|
||||
'product_id': self.product1.id,
|
||||
'product_qty': 1500.0,
|
||||
'product_uom': self.product1.uom_po_id.id,
|
||||
'price_unit': 3.30125,
|
||||
}),
|
||||
],
|
||||
})
|
||||
po.button_confirm()
|
||||
|
||||
# Receive the goods
|
||||
receipt = po.picking_ids
|
||||
receipt.button_validate()
|
||||
|
||||
self._bill(po)
|
||||
layers = self.env['stock.valuation.layer'].search([('product_id', '=', self.product1.id)])
|
||||
self.assertEqual(len(layers), 1)
|
||||
self.assertEqual(layers.quantity, 1500)
|
||||
self.assertEqual(layers.value, 4951.88)
|
||||
|
||||
def test_valuation_rounding_price_diff(self):
|
||||
company = self.env.user.company_id
|
||||
company.anglo_saxon_accounting = True
|
||||
company.currency_id = self.usd_currency
|
||||
|
||||
self.product1.product_tmpl_id.categ_id.property_cost_method = 'fifo'
|
||||
self.product1.product_tmpl_id.categ_id.property_valuation = 'real_time'
|
||||
|
||||
self.env.ref('product.decimal_price').digits = 5
|
||||
|
||||
po = self.env['purchase.order'].create({
|
||||
'partner_id': self.partner_id.id,
|
||||
'order_line': [
|
||||
(0, 0, {
|
||||
'name': self.product1.name,
|
||||
'product_id': self.product1.id,
|
||||
'product_qty': 1500.0,
|
||||
'product_uom': self.product1.uom_po_id.id,
|
||||
'price_unit': 3.30125,
|
||||
}),
|
||||
],
|
||||
})
|
||||
po.button_confirm()
|
||||
|
||||
# Receive the goods
|
||||
receipt = po.picking_ids
|
||||
receipt.button_validate()
|
||||
|
||||
self._bill(po, price=3.31125)
|
||||
layers = self.env['stock.valuation.layer'].search([('product_id', '=', self.product1.id)])
|
||||
self.assertEqual(len(layers), 2)
|
||||
self.assertEqual(layers[0].quantity, 1500)
|
||||
self.assertEqual(layers[1].quantity, 0)
|
||||
self.assertEqual(layers[0].value, 4951.88)
|
||||
self.assertEqual(round(layers[1].value, company.currency_id.decimal_places), 15)
|
||||
|
||||
def test_valuation_multicurrency_with_tax(self):
|
||||
""" Check that the amount_currency does not include the tax.
|
||||
"""
|
||||
|
||||
@@ -258,8 +258,8 @@ class AccountMoveLine(models.Model):
|
||||
return self.product_id.type == 'product' and self.product_id.valuation == 'real_time'
|
||||
|
||||
def _get_gross_unit_price(self):
|
||||
price_unit = -self.price_unit if self.move_id.move_type == 'in_refund' else self.price_unit
|
||||
price_unit = price_unit * (1 - (self.discount or 0.0) / 100.0)
|
||||
price_unit = self.price_subtotal / self.quantity
|
||||
price_unit = -price_unit if self.move_id.move_type == 'in_refund' else price_unit
|
||||
if not self.tax_ids:
|
||||
return price_unit
|
||||
prec = 1e+6
|
||||
|
||||
Reference in New Issue
Block a user