summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Mathy (MAMA) <mama@odoo.com>2025-01-15 12:52:20 +0000
committersvs-odoo <svs@odoo.com>2025-02-06 10:44:08 +0000
commit2ab0b63b7042293f8229b29bcea478d37d4c3df5 (patch)
treee9d70eccc128d4f9554a7f00da95c505d2e110e9
parent36f3f346744ef82bb76bf7593b2cd071f27570c1 (diff)
[FIX] stock: wrong result_package_id
When forcefully unreserving then reserving products coming from a same package for multiple pickings, the source package is wrongly propagated as destination package on the multiple pickings. To reproduce: - `-i sale_stock,sale_management` - Create a storable product (I) with 30 qty on hand - Create and confirm an internal transfer to put the product I in an pack (P) - Create and confirm two SO : - Sell 10 I - Sell 20 I - Check the 2 SO delivery pickings (D): - Each are reserved from pack P - They don't have any 'Destination Package' [Expected] - From the picking list view, by selecting the 2 pickings D : - 'Unreserve' them both - 'Check Availability'them both - Check the pickings D: - Each are reserved from pack P - Each have 'Destination Package' P [Faulty] opw-4272573 closes odoo/odoo#196701 X-original-commit: 2777dfcc1cd9eee973ba59fd032d2081b8fe60a3 Signed-off-by: Steve Van Essche <svs@odoo.com> Signed-off-by: Mathias Mathy (mama) <mama@odoo.com>
-rw-r--r--addons/stock/models/stock_picking.py6
-rw-r--r--addons/stock/tests/test_packing.py48
2 files changed, 51 insertions, 3 deletions
diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py
index f006623f3d9..1a68fa4710a 100644
--- a/addons/stock/models/stock_picking.py
+++ b/addons/stock/models/stock_picking.py
@@ -1299,9 +1299,9 @@ class Picking(models.Model):
'move_line_ids': [(6, 0, move_lines_to_pack.ids)],
'company_id': pickings.company_id.id,
})
- # Propagate the result package in the next move for disposable packages only.
- if package.package_use == 'disposable':
- move_lines_to_pack.write({'result_package_id': package.id})
+ # Propagate the result package in the next move for disposable packages only.
+ if package.package_use == 'disposable':
+ move_lines_to_pack.write({'result_package_id': package.id})
else:
move_lines_in_package_level = move_lines_to_pack.filtered(lambda ml: ml.move_id.package_level_id)
move_lines_without_package_level = move_lines_to_pack - move_lines_in_package_level
diff --git a/addons/stock/tests/test_packing.py b/addons/stock/tests/test_packing.py
index f8e9cbb4d80..4d28ced6c0f 100644
--- a/addons/stock/tests/test_packing.py
+++ b/addons/stock/tests/test_packing.py
@@ -1917,3 +1917,51 @@ class TestPackagePropagation(TestPackingCommon):
self.assertEqual(len(pack_lines), 2, 'Should have only 2 stock move line')
self.assertFalse(pack_lines[0].result_package_id, 'Should not have the reusable package')
self.assertEqual(pack_lines[1].result_package_id, disposable_package, 'Should have only the disposable package')
+
+ def test_conditional_package_propagation(self):
+ """If a picking completely moves the products of a package, you want to pass it as result_package_id.
+ On the other hand, if the quantity of the same pack is split between several pickings, you want to leave the result_package_id empty.
+ """
+ # Storable product : 30 qty in a package.
+ package = self.env['stock.quant.package'].create({'name': 'packtest'})
+ self.env['stock.quant']._update_available_quantity(self.productA, self.stock_location, 30.0, package_id=package)
+
+ # 1 delivery picking, 30 product, action_assign => On move line, package_id == result_package_id
+ full_delivery = self.env['stock.picking'].create({
+ 'picking_type_id': self.warehouse.out_type_id.id,
+ 'location_id': self.stock_location.id,
+ 'location_dest_id': self.customer_location.id,
+ 'move_ids': [Command.create({
+ 'name': 'move full',
+ 'product_id': self.productA.id,
+ 'product_uom_qty': 30.0,
+ 'product_uom': self.productA.uom_id.id,
+ 'location_id': self.stock_location.id,
+ 'location_dest_id': self.customer_location.id,
+ })]
+ })
+ full_delivery.action_confirm()
+ full_delivery.action_assign()
+ self.assertEqual(full_delivery.move_line_ids.package_id, package, "The package should be used as source.")
+ self.assertEqual(full_delivery.move_line_ids.result_package_id, package, "If all the products in a package are to be moved, we must move the entire package.")
+ full_delivery.action_cancel() # Cancel delivery to unreserve the package/quantity.
+
+ # Create 2 delivery picking : 10 & 20 of product each.
+ partial_deliveries = self.env['stock.picking'].create([{
+ 'picking_type_id': self.warehouse.out_type_id.id,
+ 'location_id': self.stock_location.id,
+ 'location_dest_id': self.customer_location.id,
+ 'move_ids': [Command.create({
+ 'name': 'move partial',
+ 'product_id': self.productA.id,
+ 'product_uom_qty': qty,
+ 'product_uom': self.productA.uom_id.id,
+ 'location_id': self.stock_location.id,
+ 'location_dest_id': self.customer_location.id,
+ })]
+ } for qty in [10, 20]])
+ partial_deliveries.action_confirm()
+ partial_deliveries.action_assign()
+ # action_assign => On move lines, result_package_id is not set.
+ self.assertEqual(partial_deliveries.move_line_ids.package_id, package, "The package should be used as source.")
+ self.assertFalse(partial_deliveries.move_line_ids.result_package_id, "If the contents of a single pack are reserved by multiple picks, the entire pack can't reproduce on each pick.")