diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py index cdfb68920de..8f0eeb113ef 100644 --- a/addons/stock/models/stock_move_line.py +++ b/addons/stock/models/stock_move_line.py @@ -132,10 +132,10 @@ class StockMoveLine(models.Model): if ml.location_id.should_impact_quants() and ml.product_id.type == 'product': qty_to_decrease = ml.product_qty - ml.product_uom_id._compute_quantity(vals['product_uom_qty'], ml.product_id.uom_id, rounding_method='HALF-UP') try: - Quant._update_reserved_quantity(ml.product_id, ml.location_id, -qty_to_decrease, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_reserved_quantity(ml.product_id, ml.location_id, -qty_to_decrease, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, strict=True) except UserError: if ml.lot_id: - Quant._update_reserved_quantity(ml.product_id, ml.location_id, -qty_to_decrease, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_reserved_quantity(ml.product_id, ml.location_id, -qty_to_decrease, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id, strict=True) else: raise @@ -156,10 +156,10 @@ class StockMoveLine(models.Model): for ml in self.filtered(lambda ml: ml.state in ['partially_available', 'assigned']): if ml.location_id.should_impact_quants() and ml.product_id.type == 'product': try: - Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, strict=True) except UserError: if ml.lot_id: - Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id, strict=True) else: raise @@ -233,7 +233,7 @@ class StockMoveLine(models.Model): # Unlinking a pack operation should unreserve. if ml.location_id.should_impact_quants() and ml.product_id.type == 'product' and not float_is_zero(ml.product_qty, precision_digits=precision): self.env['stock.quant']._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=ml.lot_id, - package_id=ml.package_id, owner_id=ml.owner_id) + package_id=ml.package_id, owner_id=ml.owner_id, strict=True) return super(StockMoveLine, self).unlink() def action_done(self): @@ -298,9 +298,9 @@ class StockMoveLine(models.Model): # unreserve what's been reserved if ml.location_id.should_impact_quants() and ml.product_id.type == 'product' and ml.product_qty: try: - Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, strict=True) except UserError: - Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id, strict=True) # move what's been actually done quantity = ml.product_uom_id._compute_quantity(ml.qty_done, ml.move_id.product_id.uom_id, rounding_method='HALF-UP') diff --git a/addons/stock/tests/test_move.py b/addons/stock/tests/test_move.py index a29e2f00e65..597945466f4 100644 --- a/addons/stock/tests/test_move.py +++ b/addons/stock/tests/test_move.py @@ -544,6 +544,53 @@ class StockMove(TransactionCase): self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location), 0.0) self.assertEqual(len(self.env['stock.quant']._gather(self.product2, self.stock_location)), 0.0) + def test_mixed_tracking_reservation_7(self): + """ Similar test_mixed_tracking_reservation_2 but creates first the tracked quant, then the + untracked ones. When adding a lot to the untracked move line, it should not decrease the + untracked quant then increase a non-existing tracked one that will fallback on the + untracked quant. + """ + lot1 = self.env['stock.production.lot'].create({ + 'name': 'lot1', + 'product_id': self.product2.id, + }) + lot2 = self.env['stock.production.lot'].create({ + 'name': 'lot2', + 'product_id': self.product2.id, + }) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 1, lot_id=lot1) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 1) + + self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location), 2.0) + # creation + move1 = self.env['stock.move'].create({ + 'name': 'test_in_1', + 'location_id': self.stock_location.id, + 'location_dest_id': self.customer_location.id, + 'product_id': self.product2.id, + 'product_uom': self.uom_unit.id, + 'product_uom_qty': 2.0, + }) + move1.action_confirm() + move1.action_assign() + self.assertEqual(len(move1.move_line_ids), 2) + for ml in move1.move_line_ids: + self.assertEqual(ml.product_qty, 1.0) + + untracked_move_line = move1.move_line_ids.filtered(lambda ml: not ml.lot_id).lot_id = lot2 + for ml in move1.move_line_ids: + self.assertEqual(ml.product_qty, 1.0) + + move1.move_line_ids.write({'qty_done': 1.0}) + + move1.action_done() + + self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location), 0.0) + self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location, lot_id=lot1, strict=True), 0.0) + self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location, lot_id=lot2, strict=True), 0.0) + quants = self.env['stock.quant']._gather(self.product2, self.stock_location) + self.assertEqual(len(quants), 0) + def test_putaway_1(self): """ Receive products from a supplier. Check that putaway rules are rightly applied on the receipt move line. diff --git a/addons/stock/tests/test_quant.py b/addons/stock/tests/test_quant.py index d8c377dcc70..2e046600d69 100644 --- a/addons/stock/tests/test_quant.py +++ b/addons/stock/tests/test_quant.py @@ -475,7 +475,7 @@ class StockQuant(TransactionCase): }) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 1) - self.env['stock.quant']._update_reserved_quantity(product1, stock_location, -10.0) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, -10.0, strict=True) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 10.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 1) @@ -491,7 +491,7 @@ class StockQuant(TransactionCase): self.env['stock.quant']._update_reserved_quantity(product1, stock_location, 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) with self.assertRaises(UserError): - self.env['stock.quant']._update_reserved_quantity(product1, stock_location, -1.0) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, -1.0, strict=True) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) def test_action_done_1(self): @@ -505,7 +505,7 @@ class StockQuant(TransactionCase): self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0) self.env['stock.quant']._update_reserved_quantity(product1, stock_location, 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) - self.env['stock.quant']._update_reserved_quantity(product1, stock_location, -2.0) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, -2.0, strict=True) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0) self.env['stock.quant']._update_available_quantity(product1, stock_location, -2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) @@ -545,7 +545,7 @@ class StockQuant(TransactionCase): self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, lot_id=lot1), 1.0) with self.assertRaises(UserError): - self.env['stock.quant']._update_reserved_quantity(product1, stock_location, -1.0) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, -1.0, strict=True) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, strict=True), 1.0)