From f06da8b3c1273f27c5581fc79b65ccbc97dcb4a2 Mon Sep 17 00:00:00 2001 From: William Henrotin Date: Fri, 29 Mar 2024 10:18:29 +0000 Subject: [PATCH] [FIX] stock: update quant with quantity In case a quant for a product tracked by lot/sn exists but without any lot/sn set and have some quantity, `_action_done()` should update it instead of a quant with the correct lot but without any quantity closes odoo/odoo#162683 X-original-commit: 534220ee90da3e213ea99ec5da7ce6cc9eff4203 Signed-off-by: Arnold Moyaux (arm) Signed-off-by: William Henrotin (whe) --- addons/stock/models/stock_quant.py | 4 +- addons/stock/tests/test_inventory.py | 2 +- addons/stock/tests/test_move.py | 2 +- addons/stock/tests/test_move2.py | 67 ++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 3 deletions(-) diff --git a/addons/stock/models/stock_quant.py b/addons/stock/models/stock_quant.py index 77498542307..82483eedd83 100644 --- a/addons/stock/models/stock_quant.py +++ b/addons/stock/models/stock_quant.py @@ -815,6 +815,8 @@ class StockQuant(models.Model): else: availaible_quantities = {lot_id: 0.0 for lot_id in list(set(quants.mapped('lot_id'))) + ['untracked']} for quant in quants: + if not quant.lot_id and strict and lot_id: + continue if not quant.lot_id: availaible_quantities['untracked'] += quant.quantity - quant.reserved_quantity else: @@ -1073,7 +1075,7 @@ class StockQuant(models.Model): if reserved_quantity: vals['reserved_quantity'] = reserved_quantity self.create(vals) - return self._get_available_quantity(product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=False, allow_negative=True), in_date + return self._get_available_quantity(product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=True, allow_negative=True), in_date @api.model def _update_reserved_quantity(self, product_id, location_id, quantity, lot_id=None, package_id=None, owner_id=None, strict=True): diff --git a/addons/stock/tests/test_inventory.py b/addons/stock/tests/test_inventory.py index 6b139607f44..7f7df69ca4e 100644 --- a/addons/stock/tests/test_inventory.py +++ b/addons/stock/tests/test_inventory.py @@ -156,7 +156,7 @@ class TestInventory(TransactionCase): stock_confirmation_wizard.action_confirm() # check - self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location, lot_id=lot1, strict=True), 11.0) + self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location, lot_id=lot1, strict=False), 11.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location, strict=True), 10.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location), 11.0) self.assertEqual(len(self.env['stock.quant']._gather(self.product2, self.stock_location, lot_id=lot1, strict=True).filtered(lambda q: q.lot_id)), 1.0) diff --git a/addons/stock/tests/test_move.py b/addons/stock/tests/test_move.py index 0017e336cdd..aba2ac51af8 100644 --- a/addons/stock/tests/test_move.py +++ b/addons/stock/tests/test_move.py @@ -721,7 +721,7 @@ class StockMove(TransactionCase): self.assertEqual(move1.quantity, 0.0) self.assertEqual(len(move1.move_line_ids), 0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product_serial, self.stock_location, strict=True), 1.0) - self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product_serial, self.stock_location, lot_id=lot1, strict=True), 2.0) + self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product_serial, self.stock_location, lot_id=lot1, strict=False), 2.0) def test_putaway_1(self): """ Receive products from a supplier. Check that putaway rules are rightly applied on diff --git a/addons/stock/tests/test_move2.py b/addons/stock/tests/test_move2.py index 96e86ca7248..ccdb3f81d89 100644 --- a/addons/stock/tests/test_move2.py +++ b/addons/stock/tests/test_move2.py @@ -1781,6 +1781,73 @@ class TestSinglePicking(TestStockCommon): move_line.lot_id = lot1 delivery_order._action_done() + def test_use_create_lot_use_existing_lot_5(self): + """Check if a quant without lot exist, it will be decrease even if a + quant with the right lot exists but is empty""" + self.env['stock.picking.type']\ + .browse(self.picking_type_in)\ + .write({ + 'use_create_lots': False, + 'use_existing_lots': False, + }) + self.productA.tracking = 'lot' + + receipt = self.env['stock.picking'].create({ + 'location_id': self.supplier_location, + 'location_dest_id': self.stock_location, + 'picking_type_id': self.picking_type_in, + }) + self.MoveObj.create({ + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 2, + 'product_uom': self.productA.uom_id.id, + 'picking_id': receipt.id, + 'picking_type_id': self.picking_type_in, + 'location_id': self.supplier_location, + 'location_dest_id': self.stock_location, + }) + + receipt.action_confirm() + receipt.move_ids.quantity = 2 + receipt.move_ids.picked = True + + receipt._action_done() + quant = self.env['stock.quant'].search([ + ('product_id', '=', self.productA.id), + ('location_id', '=', self.stock_location), + ('lot_id', '=', False), + ]) + self.assertTrue(quant, 'A quant without lot should exist') + self.assertEqual(quant.quantity, 2, 'The quantity of the quant without lot should be 2') + lot = self.env['stock.lot'].create({ + 'name': 'lot1', + 'product_id': self.productA.id, + 'company_id': self.env.company.id, + }) + new_quant = self.env['stock.quant'].create({ + 'product_id': self.productA.id, + 'location_id': self.stock_location, + 'lot_id': lot.id, + }) + out_move = self.MoveObj.create({ + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 1, + 'product_uom': self.productA.uom_id.id, + 'picking_type_id': self.picking_type_out, + 'location_id': self.stock_location, + 'location_dest_id': self.customer_location, + }) + out_move._action_confirm() + out_move._action_assign() + out_move.move_line_ids.lot_id = lot + out_move.move_line_ids.quantity = 1 + out_move.picked = True + out_move._action_done() + self.assertEqual(new_quant.quantity, 0, 'The quant with lot should remain untouched 1') + self.assertEqual(quant.quantity, 1, 'The quantity of the quant without lot should be 1') + def test_merge_moves_1(self): receipt = self.env['stock.picking'].create({ 'location_id': self.supplier_location,