From f53b70207170a29fc6b16a469d44e1bd2aee476a Mon Sep 17 00:00:00 2001 From: Adrien Widart Date: Wed, 17 Nov 2021 15:16:09 +0000 Subject: [PATCH] [FIX] stock: transfer the package level to backorder The packages reservations are not correctly done in case of a backorder To reproduce the issue: (Use demo data) 1. In Settings, enable: - Delivery Packages - Multi-Step Routes 2. Edit the warehouse: - Outgoing Shipments: 2 steps 3. In Operations Types > Delivery Order, enable: - Show Detailed Operations - Move Entire Packages 4. Create a Pick P: - 1 x [DESK0004] Desk - 1 x Large Cabinet 5. Put each product in a separate pack 6. Validate P 7. Create a Delivery Order (Planned Transfer): - 1 x [DESK0004] Desk - 1 x Large Cabinet 8. Mark as TODO, Check Availability 9. In Detailed Operations, mark one of the packs as Done 10. Validate the DO, Create a backorder Error: The not-yet-done pack is still on the delivery order and its status is "Reserved". This line shouldn't be present anymore. Moreover, the backorder has a line for this pack, its state is "Draft" (instead of "Reserved") and the state of the BO is Ready. When creating the backorder, the packages levels of the not-yet-done moves are transferred to the new picking (i.e., the backorder) However, these moves does not have a package level defined (due to 9d758fa2e180b96d4b0f7046e7a75a202c4da7ff). Therefore, when checking the packs: https://github.com/odoo/odoo/blob/e7450bee8f018a5334d9628235824f2fc6f32cec/addons/stock/models/stock_picking.py#L822-L832 `package_level_ids` is empty, so a new `stock.package_level` is created (instead of using the one of the initial delivery order). And `move_lines_to_pack` is empty too, so the new `stock.package_level` won't have any move lines and its state will be "Draft" We should rather transfer the package levels of the moves' lines. OPW-2659176 closes #77509 closes odoo/odoo#80072 X-original-commit: 4fd5cd6f940575090021dedd2159d050b594dd69 Signed-off-by: William Henrotin (whe) Signed-off-by: Adrien Widart Co-authored-by: Adrien Widart Co-authored-by: Florent de Labarre --- addons/stock/models/stock_picking.py | 2 +- addons/stock/tests/test_packing.py | 58 ++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index b34508eda6f..1081d1fb67d 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -1133,7 +1133,7 @@ class Picking(models.Model): body=_('The backorder %s has been created.') % ( backorder_picking.id, backorder_picking.name)) moves_to_backorder.write({'picking_id': backorder_picking.id}) - moves_to_backorder.mapped('package_level_id').write({'picking_id':backorder_picking.id}) + moves_to_backorder.move_line_ids.package_level_id.write({'picking_id':backorder_picking.id}) moves_to_backorder.mapped('move_line_ids').write({'picking_id': backorder_picking.id}) backorders |= backorder_picking if backorder_picking.picking_type_id.reservation_method == 'at_confirm': diff --git a/addons/stock/tests/test_packing.py b/addons/stock/tests/test_packing.py index fee21dd3944..9944761e4b7 100644 --- a/addons/stock/tests/test_packing.py +++ b/addons/stock/tests/test_packing.py @@ -831,3 +831,61 @@ class TestPacking(TestPackingCommon): self.assertEqual(receipt.state, 'assigned') receipt.move_ids_without_package[1].product_uom_qty = 0 self.assertEqual(receipt.state, 'assigned') + + def test_2_steps_and_backorder(self): + """ When creating a backorder with a package, the latter should be reserved in the new picking. Moreover, + the initial picking shouldn't have any line about this package """ + def create_picking(pick_type, from_loc, to_loc): + picking = self.env['stock.picking'].create({ + 'picking_type_id': pick_type.id, + 'location_id': from_loc.id, + 'location_dest_id': to_loc.id, + }) + move_A, move_B = self.env['stock.move'].create([{ + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 1, + 'product_uom': self.productA.uom_id.id, + 'picking_id': picking.id, + 'location_id': from_loc.id, + 'location_dest_id': to_loc.id, + }, { + 'name': self.productB.name, + 'product_id': self.productB.id, + 'product_uom_qty': 1, + 'product_uom': self.productB.uom_id.id, + 'picking_id': picking.id, + 'location_id': from_loc.id, + 'location_dest_id': to_loc.id, + }]) + picking.action_confirm() + picking.action_assign() + return picking, move_A, move_B + + self.warehouse.delivery_steps = 'pick_ship' + pick_type = self.warehouse.pick_type_id + delivery_type = self.warehouse.out_type_id + + self.env['stock.quant']._update_available_quantity(self.productA, self.stock_location, 1) + self.env['stock.quant']._update_available_quantity(self.productB, self.stock_location, 1) + + picking, moveA, moveB = create_picking(pick_type, pick_type.default_location_src_id, pick_type.default_location_dest_id) + moveA.move_line_ids.qty_done = 1 + picking.action_put_in_pack() + moveB.move_line_ids.qty_done = 1 + picking.action_put_in_pack() + picking.button_validate() + + picking, _, _ = create_picking(delivery_type, delivery_type.default_location_src_id, self.customer_location) + packB = picking.package_level_ids[1] + with Form(picking) as picking_form: + with picking_form.package_level_ids_details.edit(0) as package_level: + package_level.is_done = True + action_data = picking.button_validate() + backorder_wizard = Form(self.env['stock.backorder.confirmation'].with_context(action_data['context'])).save() + backorder_wizard.process() + bo = self.env['stock.picking'].search([('backorder_id', '=', picking.id)]) + + self.assertNotIn(packB, picking.package_level_ids) + self.assertEqual(packB, bo.package_level_ids) + self.assertEqual(bo.package_level_ids.state, 'assigned')