[FIX] stock: filter quants when updating qty

In some cases, when making an inventory adjustment, the `in_date` of the
new quant will be incorrect

To reproduce the issue:
(Let D01 be the current date)
1. Create a storable product P
2. Set its quantity to 1
3. Process a delivery order with 1 x P
4. Set the date in the future
    - Let D02 be this date
5. Make an inventory adjustment with 1 x P

Error: The `in_date` of the quant (for P in the stock location) is D01
instead of D02 (can be observed either directly in PSQL, on the form
view of the quant (via Locations > Current Stock), or by adding the
field on the tree view)

When validating the stock adjustment, at some point, the module calls
`_action_done` on a SML (1 x P from Inventory Adjustment to the Stock
Location). To do so, it decreases the quantity of the origin location
and increases the quantity of the destination location thanks to
`_update_available_quantity`:
https://github.com/odoo/odoo/blob/b4a9e5b8307ab1b730effe2de23f15260326ef6c/addons/stock/models/stock_move_line.py#L485-L493
But here is the issue: when decreasing the quantity in the virtual
location (Inventory Adjustment), it finds an old quant (the one from
step 2 in above use case). It then stores its `in_date` (D01) and since
this date is before the current one (D02), D01 is kept, used to update
the quant quantity and returned in `action_done`. As a result, when
increasing the quantity in the stock location,
`_update_available_quantity` is called with the parameter `in_date`
defined and equal to D01. Again, D01 will be the earliest date, so the
date will be used to create/update the quant in stock location.

OPW-2702198

closes odoo/odoo#83009

X-original-commit: e27ee5cd6b19351a00030310d1db3a0defe5b31a
Signed-off-by: Arnold Moyaux <arm@odoo.com>
Signed-off-by: Adrien Widart <awt@odoo.com>
This commit is contained in:
Adrien Widart
2022-01-19 14:06:45 +00:00
parent 65a89b4d57
commit 716bc63dd2
2 changed files with 46 additions and 1 deletions
+5 -1
View File
@@ -688,7 +688,11 @@ class StockQuant(models.Model):
self = self.sudo()
quants = self._gather(product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=True)
incoming_dates = [d for d in quants.mapped('in_date') if d]
if location_id.should_bypass_reservation():
incoming_dates = []
else:
incoming_dates = [quant.in_date for quant in quants if quant.in_date and
float_compare(quant.quantity, 0, precision_rounding=quant.product_uom_id.rounding) > 0]
if in_date:
incoming_dates += [in_date]
# If multiple incoming dates are available for a given lot_id/package_id/owner_id, we
+41
View File
@@ -3,7 +3,9 @@
from contextlib import closing
from datetime import datetime, timedelta
from unittest.mock import patch
from odoo import fields
from odoo.addons.mail.tests.common import mail_new_test_user
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase
@@ -687,3 +689,42 @@ class StockQuant(TransactionCase):
self.assertEqual(quants[0][0].reserved_quantity, 2)
# The last one should then be taken in stock_location/subloc3 since the first location doesn't have enough products
self.assertEqual(quants[1][0].reserved_quantity, 1)
def test_in_date_6(self):
"""
One P in stock, P is delivered. Later on, a stock adjustement adds one P. This test checks
the date value of the related quant
"""
self.env['stock.quant']._update_available_quantity(self.product, self.stock_location, 1.0)
move = self.env['stock.move'].create({
'name': 'OUT 1 product',
'product_id': self.product.id,
'product_uom_qty': 1,
'product_uom': self.product.uom_id.id,
'location_id': self.stock_location.id,
'location_dest_id': self.ref('stock.stock_location_customers'),
})
move._action_confirm()
move._action_assign()
move.quantity_done = 1
move._action_done()
tomorrow = fields.Datetime.now() + timedelta(days=1)
with patch.object(fields.Datetime, 'now', lambda: tomorrow):
move = self.env['stock.move'].create({
'name': 'IN 1 product',
'product_id': self.product.id,
'product_uom_qty': 1,
'product_uom': self.product.uom_id.id,
'location_id': self.ref('stock.stock_location_suppliers'),
'location_dest_id': self.stock_location.id,
})
move._action_confirm()
move._action_assign()
move.quantity_done = 1
move._action_done()
quant = self.env['stock.quant'].search([('product_id', '=', self.product.id), ('location_id', '=', self.stock_location.id), ('quantity', '>', 0)])
self.assertEqual(quant.in_date, tomorrow)