From 716bc63dd287f406bc7db5d4e1f1708461eb29aa Mon Sep 17 00:00:00 2001 From: Adrien Widart Date: Tue, 11 Jan 2022 12:49:08 +0000 Subject: [PATCH] [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 Signed-off-by: Adrien Widart --- addons/stock/models/stock_quant.py | 6 ++++- addons/stock/tests/test_quant.py | 41 ++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/addons/stock/models/stock_quant.py b/addons/stock/models/stock_quant.py index b893f86b14f..3178e38ea62 100644 --- a/addons/stock/models/stock_quant.py +++ b/addons/stock/models/stock_quant.py @@ -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 diff --git a/addons/stock/tests/test_quant.py b/addons/stock/tests/test_quant.py index 7840ef95186..5617259ab87 100644 --- a/addons/stock/tests/test_quant.py +++ b/addons/stock/tests/test_quant.py @@ -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)