diff --git a/addons/stock/models/stock_quant.py b/addons/stock/models/stock_quant.py index 15084292a5e..641e3e3f5b4 100644 --- a/addons/stock/models/stock_quant.py +++ b/addons/stock/models/stock_quant.py @@ -183,15 +183,17 @@ class StockQuant(models.Model): max_quantity_on_quant = quant.quantity - quant.reserved_quantity if max_quantity_on_quant <= 0: continue + max_quantity_on_quant = min(max_quantity_on_quant, quantity) + quant.reserved_quantity += max_quantity_on_quant + reserved_quants.append((quant, max_quantity_on_quant)) + quantity -= max_quantity_on_quant + available_quantity -= max_quantity_on_quant else: - max_quantity_on_quant = quant.reserved_quantity - max_quantity_on_quant = min(max_quantity_on_quant, quantity) - - quant.reserved_quantity += max_quantity_on_quant - reserved_quants.append((quant, max_quantity_on_quant)) - - quantity -= max_quantity_on_quant - available_quantity -= max_quantity_on_quant + max_quantity_on_quant = min(quant.reserved_quantity, abs(quantity)) + quant.reserved_quantity -= max_quantity_on_quant + reserved_quants.append((quant, -max_quantity_on_quant)) + quantity += max_quantity_on_quant + available_quantity += max_quantity_on_quant if quantity == 0 or available_quantity == 0: break diff --git a/addons/stock/tests/test_move.py b/addons/stock/tests/test_move.py index 597945466f4..c08a63a2f8c 100644 --- a/addons/stock/tests/test_move.py +++ b/addons/stock/tests/test_move.py @@ -831,6 +831,45 @@ class StockMove(TransactionCase): self.assertEqual(quants.reserved_quantity, 0.0) self.assertEqual(len(move1.move_line_ids), 0.0) + def test_unreserve_5(self): + """ Check the unreservation of a stock move reserved on multiple quants. + """ + # make some stock + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 3) + self.env['stock.quant'].create({ + 'product_id': self.product1.id, + 'location_id': self.stock_location.id, + 'quantity': 2, + }) + self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location)), 2) + self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 5) + + # creation + move1 = self.env['stock.move'].create({ + 'name': 'test_unreserve_5', + 'location_id': self.stock_location.id, + 'location_dest_id': self.customer_location.id, + 'product_id': self.product1.id, + 'product_uom': self.uom_unit.id, + 'product_uom_qty': 5.0, + }) + self.assertEqual(move1.state, 'draft') + + # confirmation + move1.action_confirm() + self.assertEqual(move1.state, 'confirmed') + + # assignment + move1.action_assign() + self.assertEqual(move1.state, 'assigned') + self.assertEqual(len(move1.move_line_ids), 1) + move1.do_unreserve() + + quants = self.env['stock.quant']._gather(self.product1, self.stock_location) + self.assertEqual(len(quants), 2.0) + for quant in quants: + self.assertEqual(quant.reserved_quantity, 0) + def test_link_assign_1(self): """ Test the assignment mechanism when two chained stock moves try to move one unit of an untracked product.