[FIX] stock: fix reservation on multiple moves when validating a picking

Steps to reproduce:
- Activate developer mode
- Install Inventory and Sales
- Go to "Inventory / Configuration / Settings"
- Activate "Storage Locations" and "Multi-Steps Routes"
- Go to "Inventory / Configuration / Warehouse Management / Warehouses"
- Configure main warehouse: (e.g. San Francisco warehouse)
  * Outgoing Shipments: Send goods in output and then deliver (2 steps)
- Go to "Inventory / Configuration / Warehouse Management / Rules"
- Open the following rule:
  * Action: Pull From
  * Source Location: WH/Stock
  * Destination Location: WH/Output
  * Route: San Francisco: Deliver in 2 steps (pick + ship)
- Configure the rule:
  * Propagation of Procurement Group: Fixed
  * Fixed Procurement Group: [create a new one]
- Create a storable product (e.g. Product X)
- Update its quantity (e.g. 3) and apply
- Create a SO with 2 Product X and confirm
- Go to "Inventory / Operations / Transfers"
- Open the pick move linked to the SO (e.g. WH/PICK/00001)
- Set done quantity to 1 and validate
- Create a backorder for the remaining quantity (e.g. WH/PICK/00002)
- Create another SO with 1 Product X and confirm
=> Its pick move is merged with WH/PICK/00002, which contains now 2 Product X
- Open WH/PICK/00002, set done quantity to 2 and validate

Issue:
When validating WH/PICK/00002, the products should be reserved in the delivery moves
of both SO, but it is only done for the first one, leaving the second one in the
"Waiting Another Operation" state.

Cause:
When validating a move (i.e. WH/PICK/00002) linked to several destination moves,
the destination moves are reserved by checking the availability of the product.
For the first destination move, its origin moves are WH/PICK/00001 and WH/PICK/00002,
having an IN value of 3 and an OUT value of 2, which is correct.
When checking the availability of the second destination move, its origin move is
WH/PICK/00002, having an IN value of 2, but for the OUT value, the first destination move
is taken into account, generating an OUT value of 3.

Solution:
When computing the availability, if the origin move is linked to several destination
moves, it should take all the origin moves of all the destination moves into account.

opw-3548123

closes odoo/odoo#149867

X-original-commit: 0c8f0d14d29117e689d8e4c3331bc90b29ab1b98
Signed-off-by: Anh Thao Pham (pta) <pta@odoo.com>
This commit is contained in:
Anh Thao Pham (pta)
2024-01-18 10:28:46 +00:00
parent e6760d3dcc
commit 0a4ac677d9
2 changed files with 45 additions and 1 deletions
@@ -1653,3 +1653,47 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
return_picking_2 = self.env['stock.picking'].browse(res['res_id'])
return_picking_2.button_validate()
self.assertEqual(return_wizard.product_return_moves.quantity, 1)
def test_2_steps_fixed_procurement_propagation_with_backorder(self):
"""
When validating a picking (partially coming from a backorder) linked to 2 destinations moves in a 2-steps delivery,
stock.move.line should be created for the 2 OUT moves.
Steps:
- Warehouse with Outgoing Shipments in 2 steps and propagation of rule set to Fixed
- Create a SO with 3 Product X
- on PICK_1 picking: set 1 unit in done, validate and create a backorder
- Create a SO with 1 Product X
- on PICK_2 picking: set 3 units in done and validate
"""
warehouse = self.company_data.get('default_warehouse')
warehouse.delivery_steps = 'pick_ship'
rule = warehouse.delivery_route_id.rule_ids.filtered(lambda r: r.procure_method == 'make_to_stock')[0]
rule.group_propagation_option = 'fixed'
fixedGroup = self.env['procurement.group'].create({})
rule.group_id = fixedGroup
self.env['stock.quant']._update_available_quantity(self.test_product_delivery, warehouse.lot_stock_id, 4)
# create a SO with 3 products
so1 = self._get_new_sale_order(product=self.test_product_delivery, amount=3)
so1.action_confirm()
pick1 = fixedGroup.stock_move_ids.filtered(lambda m: m.origin == so1.name)[0].picking_id
out1 = so1.picking_ids.filtered(lambda p: p.picking_type_id == warehouse.out_type_id)
# set 1 done on the PICK move
pick1.move_ids.write({'quantity': 1, 'picked': True})
res_dict = pick1.button_validate()
# create a backorder for the 2 remaining products
backorder_wizard = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])).save()
backorder_wizard.process()
pick2 = pick1.backorder_ids[0]
self.assertEqual(out1.move_line_ids.quantity, 1)
# create another SO with 1 product
so2 = self._get_new_sale_order(product=self.test_product_delivery, amount=1)
so2.action_confirm()
# PICK move of this SO will increment the product quantity of the PICK backorder by 1
# PICK backorder is linked to out1 and out2
out2 = so2.picking_ids.filtered(lambda p: p.picking_type_id == warehouse.out_type_id)
pick2.move_ids.write({'quantity': 3, 'picked': True})
pick2.button_validate()
self.assertEqual(out1.state, 'assigned')
self.assertEqual(out1.move_line_ids.quantity, 3)
self.assertEqual(out2.state, 'assigned')
self.assertEqual(out2.move_line_ids.quantity, 1)
+1 -1
View File
@@ -1528,7 +1528,7 @@ Please change the quantity done or the rounding precision of your unit of measur
return self.env['stock.quant']._get_available_quantity(self.product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=strict, allow_negative=allow_negative)
def _get_available_move_lines_in(self):
move_lines_in = self.move_orig_ids.filtered(lambda m: m.state == 'done').mapped('move_line_ids')
move_lines_in = self.move_orig_ids.move_dest_ids.move_orig_ids.filtered(lambda m: m.state == 'done').mapped('move_line_ids')
def _keys_in_groupby(ml):
return (ml.location_dest_id, ml.lot_id, ml.result_package_id, ml.owner_id)