# Part of Odoo. See LICENSE file for full copyright and licensing details.

from datetime import timedelta

from odoo.tests import Form
from odoo.addons.stock.tests.common import TestStockCommon

class TestOldRules(TestStockCommon):

    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.partner = cls.env['res.partner'].create({'name': 'Partner'})

        # Since the old rules are still a valid setup for multi-step routes, we need to make sure they still work.
        # Create a warehouse with 3 steps using old rules setup so we need to restore it only once.
        cls.warehouse_3_steps = cls.env['stock.warehouse'].create({
            'name': 'Warehouse 3 steps',
            'code': '3S',
            'reception_steps': 'three_steps',
            'delivery_steps': 'pick_pack_ship',
        })
        delivery_route_3 = cls.warehouse_3_steps.delivery_route_id
        delivery_route_3.rule_ids[0].write({
            'location_dest_id': delivery_route_3.rule_ids[1].location_src_id.id,
        })
        delivery_route_3.rule_ids[1].write({'action': 'pull'})
        delivery_route_3.rule_ids[2].write({'action': 'pull'})
        reception_route_3 = cls.warehouse_3_steps.reception_route_id
        reception_route_3.rule_ids[0].write({
            'location_src_id': reception_route_3.rule_ids[1].location_dest_id.id,
        })
        reception_route_3.rule_ids[1].write({'action': 'pull_push'})
        reception_route_3.rule_ids[2].write({'action': 'pull_push'})


        # Create a warehouse with 2 steps using old rules setup.
        cls.warehouse_2_steps = cls.env['stock.warehouse'].create({
            'name': 'Warehouse 2 steps',
            'code': '2S',
            'reception_steps': 'two_steps',
            'delivery_steps': 'pick_ship',
        })
        delivery_route_2 = cls.warehouse_2_steps.delivery_route_id
        delivery_route_2.rule_ids[0].write({
            'location_dest_id': delivery_route_2.rule_ids[1].location_src_id.id,
            'name': '2S: Stock → Output',
        })
        delivery_route_2.rule_ids[1].write({'action': 'pull'})

    def test_delay_alert_3_old(self):
        partner_demo_customer = self.partner
        final_location = partner_demo_customer.property_stock_customer
        pg = self.env['procurement.group'].create({'name': 'Test-delay_alert_3'})
        self.env['procurement.group'].run([
            pg.Procurement(
                self.productA,
                4.0,
                self.productA.uom_id,
                final_location,
                'delay',
                'delay',
                self.warehouse_3_steps.company_id,
                {
                    'warehouse_id': self.warehouse_3_steps,
                    'group_id': pg
                }
            ),
        ])
        ship, pack, pick = self.env['stock.move'].search([('product_id', '=', self.productA.id)])
        # by default they all the same `date`
        self.assertEqual(set((ship + pack + pick).mapped('date')), {pick.date})

        # pick - pack - ship
        ship.date += timedelta(days=2)
        pack.date += timedelta(days=1)
        self.assertFalse(pick.delay_alert_date)
        self.assertFalse(pack.delay_alert_date)
        self.assertFalse(ship.delay_alert_date)

        # move the pack after the ship
        # pick - ship - pack
        pack.date += timedelta(days=2)
        self.assertFalse(pick.delay_alert_date)
        self.assertFalse(pack.delay_alert_date)
        self.assertTrue(ship.delay_alert_date)
        self.assertAlmostEqual(ship.delay_alert_date, pack.date)

        # restore the pack before the ship
        # pick - pack - ship
        pack.date -= timedelta(days=2)
        self.assertFalse(pick.delay_alert_date)
        self.assertFalse(pack.delay_alert_date)
        self.assertFalse(ship.delay_alert_date)

        # move the pick after the pack
        # pack - ship - pick
        pick.date += timedelta(days=3)
        self.assertFalse(pick.delay_alert_date)
        self.assertTrue(pack.delay_alert_date)
        self.assertFalse(ship.delay_alert_date)
        self.assertAlmostEqual(pack.delay_alert_date, pick.date)

        # move the ship before the pack
        # ship - pack - pick
        ship.date -= timedelta(days=2)
        self.assertFalse(pick.delay_alert_date)
        self.assertTrue(pack.delay_alert_date)
        self.assertTrue(ship.delay_alert_date)
        self.assertAlmostEqual(pack.delay_alert_date, pick.date)
        self.assertAlmostEqual(ship.delay_alert_date, pack.date)

        # move the pack at the end
        # ship - pick - pack
        pack.date = pick.date + timedelta(days=2)
        self.assertFalse(pick.delay_alert_date)
        self.assertFalse(pack.delay_alert_date)
        self.assertTrue(ship.delay_alert_date)
        self.assertAlmostEqual(ship.delay_alert_date, pack.date)

        # fix the ship
        ship.date = pack.date + timedelta(days=2)
        self.assertFalse(pick.delay_alert_date)
        self.assertFalse(pack.delay_alert_date)
        self.assertFalse(ship.delay_alert_date)

    def test_mtso(self):
        """ Run a procurement for 5 products when there are only 4 in stock then
        check that MTS is applied on the moves when the rule is set to 'mts_else_mto'
        Also ensure the whole stock is emptied and only the needed quantity is propagated.
        """
        partner_demo_customer = self.partner
        final_location = partner_demo_customer.property_stock_customer

        self.env['stock.quant']._update_available_quantity(self.productA, self.warehouse_3_steps.wh_output_stock_loc_id, 4.0)

        # We set quantities in the stock location to avoid warnings
        # triggered by '_onchange_product_id_check_availability'
        self.env['stock.quant']._update_available_quantity(self.productA, self.warehouse_3_steps.lot_stock_id, 4.0)

        # We alter one rule and we set it to 'mts_else_mto'
        self.warehouse_3_steps.delivery_route_id.rule_ids.filtered(lambda r: r.procure_method == "make_to_order").write({
            'procure_method': 'mts_else_mto',
        })

        pg = self.env['procurement.group'].create({'name': 'Test-pg-mtso-mto'})

        self.env['procurement.group'].run([
            pg.Procurement(
                self.productA,
                5.0,
                self.productA.uom_id,
                final_location,
                'test_mtso_mto',
                'test_mtso_mto',
                self.warehouse_3_steps.company_id,
                {
                    'warehouse_id': self.warehouse_3_steps,
                    'group_id': pg
                }
            )
        ])

        qty_available = self.env['stock.quant']._get_available_quantity(self.productA, self.warehouse_3_steps.wh_output_stock_loc_id)

        # 3 pickings should be created.
        picking_ids = self.env['stock.picking'].search([('group_id', '=', pg.id)])
        self.assertEqual(len(picking_ids), 3)
        for picking in picking_ids:
            self.assertEqual(picking.move_ids.procure_method, 'make_to_stock')
            self.assertEqual(len(picking.move_ids), 1)
        self.assertRecordValues(picking_ids.move_ids, [
            {'product_qty': 5, 'procure_method': 'make_to_stock'},
            {'product_qty': 1, 'procure_method': 'make_to_stock'},
            {'product_qty': 1, 'procure_method': 'make_to_stock'},
        ])
        self.assertEqual(qty_available, 0, 'The 4 products should still be available')

    def test_mtso_multi_pg(self):
        """ Run 3 procurements for 2 products at the same times when there are 4 in stock then
        check that MTS is applied on the moves when the rule is set to 'mts_else_mto'
        """
        warehouse = self.warehouse_3_steps
        partner_demo_customer = self.partner
        final_location = partner_demo_customer.property_stock_customer
        product_a = self.env['product.product'].create({
            'name': 'ProductA',
            'is_storable': True,
        })

        self.env['stock.quant']._update_available_quantity(product_a, warehouse.wh_output_stock_loc_id, 4.0)

        # We alter one rule and we set it to 'mts_else_mto'
        self.warehouse_3_steps.delivery_route_id.rule_ids.filtered(
            lambda r: r.procure_method == "make_to_order"
        ).write({
            'procure_method': 'mts_else_mto',
        })

        pg1 = self.env['procurement.group'].create({'name': 'Test-pg-mtso-mts-1'})
        pg2 = self.env['procurement.group'].create({'name': 'Test-pg-mtso-mts-2'})
        pg3 = self.env['procurement.group'].create({'name': 'Test-pg-mtso-mts-3'})

        self.env['procurement.group'].run([
            pg1.Procurement(
                product_a,
                2.0,
                product_a.uom_id,
                final_location,
                'test_mtso_mts_1',
                'test_mtso_mts_1',
                warehouse.company_id,
                {
                    'warehouse_id': warehouse,
                    'group_id': pg1
                }
            ),
            pg2.Procurement(
                product_a,
                2.0,
                product_a.uom_id,
                final_location,
                'test_mtso_mts_2',
                'test_mtso_mts_2',
                warehouse.company_id,
                {
                    'warehouse_id': warehouse,
                    'group_id': pg2
                }
            ),
            pg3.Procurement(
                product_a,
                2.0,
                product_a.uom_id,
                final_location,
                'test_mtso_mts_3',
                'test_mtso_mts_3',
                warehouse.company_id,
                {
                    'warehouse_id': warehouse,
                    'group_id': pg3
                }
            )
        ])

        pickings_pg1 = self.env['stock.picking'].search([('group_id', '=', pg1.id)])
        pickings_pg2 = self.env['stock.picking'].search([('group_id', '=', pg2.id)])
        pickings_pg3 = self.env['stock.picking'].search([('group_id', '=', pg3.id)])

        # The 2 first procurements should have create only 1 picking since enough quantities
        # are left in the delivery location
        self.assertEqual(len(pickings_pg1), 1)
        self.assertEqual(len(pickings_pg2), 1)
        self.assertEqual(pickings_pg1.move_ids.procure_method, 'make_to_stock')
        self.assertEqual(pickings_pg2.move_ids.procure_method, 'make_to_stock')

        # The last one should have 3 pickings as there's nothing left in the delivery location
        self.assertEqual(len(pickings_pg3), 3)
        for picking in pickings_pg3:
            # Only the picking from Stock to Pack should be MTS
            self.assertEqual(picking.move_ids.procure_method, 'make_to_stock')

            # All the moves should be should have the same quantity as it is on each procurements
            self.assertEqual(len(picking.move_ids), 1)
            self.assertEqual(picking.move_ids.product_uom_qty, 2)

    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,
                'state': 'draft',
            })
            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

        pick_type = self.warehouse_2_steps.pick_type_id
        delivery_type = self.warehouse_2_steps.out_type_id
        customer_location = delivery_type.default_location_dest_id

        self.env['stock.quant']._update_available_quantity(self.productA, self.warehouse_2_steps.lot_stock_id, 1)
        self.env['stock.quant']._update_available_quantity(self.productB, self.warehouse_2_steps.lot_stock_id, 1)

        picking, moveA, moveB = create_picking(pick_type, pick_type.default_location_src_id, pick_type.default_location_dest_id)
        moveA.picked = True
        picking.action_put_in_pack()
        moveB.picked = True
        picking.action_put_in_pack()
        picking.button_validate()
        delivery_type.show_entire_packs = True
        picking, _, _ = create_picking(delivery_type, delivery_type.default_location_src_id, customer_location)
        packB = picking.package_level_ids[1]
        picking.package_level_ids_details[0].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')

    def test_pack_delivery_three_step_propagate_package_consumable_old(self):
        """ Checks all works right in the following case:
          * For a three-step delivery
          * Put products in a package then validate the receipt.
          * The automatically generated internal transfer should have package set by default.
        """
        prod = self.env['product.product'].create({'name': 'bad dragon', 'type': 'consu'})
        ship_move = self.env['stock.move'].create({
            'name': 'The ship move',
            'product_id': prod.id,
            'product_uom_qty': 5.0,
            'product_uom': prod.uom_id.id,
            'location_id': self.warehouse_3_steps.wh_output_stock_loc_id.id,
            'location_dest_id': self.env.ref('stock.stock_location_customers').id,
            'warehouse_id':  self.warehouse_3_steps.id,
            'picking_type_id':  self.warehouse_3_steps.out_type_id.id,
            'procure_method': 'make_to_order',
            'state': 'draft',
        })

        # create chained pick/pack moves to test with
        ship_move._assign_picking()
        ship_move._action_confirm()
        pack_move = ship_move.move_orig_ids[0]
        pick_move = pack_move.move_orig_ids[0]

        picking = pick_move.picking_id
        picking.action_confirm()
        picking.action_put_in_pack()
        self.assertTrue(picking.move_line_ids.result_package_id)
        picking.button_validate()
        self.assertEqual(pack_move.move_line_ids.result_package_id, picking.move_line_ids.result_package_id)

    def test_procurement_group_merge(self):
        """ Enable the pick ship route, force a procurement group on the
        pick. When a second move is added, make sure the `partner_id` and
        `origin` fields are erased.
        """
        # create a procurement group and set in on the pick stock rule
        procurement_group0 = self.env['procurement.group'].create({})
        product1 = self.env['product.product'].create({
            'name': 'test_procurement_group_merge',
            'is_storable': True,
        })
        pick_ship_route = self.warehouse_2_steps.delivery_route_id
        ship_rule = pick_ship_route.rule_ids.filtered(lambda rule: '2S: Output → Customers' in rule.name)
        pick_rule = pick_ship_route.rule_ids - ship_rule
        pick_rule.write({
            'group_propagation_option': 'fixed',
            'group_id': procurement_group0.id,
        })

        pick_location = ship_rule.picking_type_id.default_location_src_id
        customer_location = ship_rule.location_dest_id
        partners = self.env['res.partner'].search([], limit=2)
        partner0 = partners[0]
        partner1 = partners[1]
        procurement_group1 = self.env['procurement.group'].create({'partner_id': partner0.id})
        procurement_group2 = self.env['procurement.group'].create({'partner_id': partner1.id})

        move1 = self.env['stock.move'].create({
            'name': 'first out move',
            'procure_method': 'make_to_order',
            'location_id': pick_location.id,
            'location_dest_id': customer_location.id,
            'product_id': product1.id,
            'product_uom': self.uom_unit.id,
            'product_uom_qty': 1.0,
            'warehouse_id': self.warehouse_2_steps.id,
            'group_id': procurement_group1.id,
            'origin': 'origin1',
        })

        move2 = self.env['stock.move'].create({
            'name': 'second out move',
            'procure_method': 'make_to_order',
            'location_id': pick_location.id,
            'location_dest_id': customer_location.id,
            'product_id': product1.id,
            'product_uom': self.uom_unit.id,
            'product_uom_qty': 1.0,
            'warehouse_id': self.warehouse_2_steps.id,
            'group_id': procurement_group2.id,
            'origin': 'origin2',
        })

        # first out move, the "pick" picking should have a partner and an origin
        move1._action_confirm()
        picking_pick = move1.move_orig_ids.picking_id
        self.assertEqual(picking_pick.partner_id.id, procurement_group1.partner_id.id)
        self.assertEqual(picking_pick.origin, move1.group_id.name)

        # second out move, the "pick" picking should have lost its partner and origin
        move2._action_confirm()
        self.assertEqual(picking_pick.partner_id.id, False)
        self.assertEqual(picking_pick.origin, False)

    def test_fixed_procurement_01(self):
        """ Run a procurement for 5 products when there are only 4 in stock then
        check that MTO is applied on the moves when the rule is set to 'mts_else_mto'
        """
        self.partner = self.env['res.partner'].create({'name': 'Partner'})
        final_location = self.partner.property_stock_customer

        # Create a product and add 10 units in stock
        product_a = self.env['product.product'].create({
            'name': 'ProductA',
            'is_storable': True,
        })
        self.env['stock.quant']._update_available_quantity(product_a, self.warehouse_2_steps.lot_stock_id, 10.0)
        warehouse = self.warehouse_2_steps
        # Create a route which will allows 'wave picking'
        wave_pg = self.env['procurement.group'].create({'name': 'Wave PG'})
        wave_route = self.env['stock.route'].create({
            'name': 'Wave for ProductA',
            'product_selectable': True,
            'sequence': 1,
            'rule_ids': [(0, 0, {
                'name': 'Stock -> output rule',
                'action': 'pull',
                'picking_type_id': warehouse.pick_type_id.id,
                'location_src_id': warehouse.lot_stock_id.id,
                'location_dest_id': warehouse.wh_output_stock_loc_id.id,
                'group_propagation_option': 'fixed',
                'group_id': wave_pg.id,
            })],
        })

        # Set this route on `product_a`
        product_a.write({
            'route_ids': [(4, wave_route.id)]
        })

        # Create a procurement for 2 units
        pg = self.env['procurement.group'].create({'name': 'Wave 1'})
        self.env['procurement.group'].run([
            pg.Procurement(
                product_a,
                2.0,
                product_a.uom_id,
                final_location,
                'wave_part_1',
                'wave_part_1',
                warehouse.company_id,
                {
                    'warehouse_id': warehouse,
                    'group_id': pg
                }
            )
        ])

        # 2 pickings should be created: 1 for pick, 1 for ship
        picking_pick = self.env['stock.picking'].search([('group_id', '=', wave_pg.id)])
        picking_ship = self.env['stock.picking'].search([('group_id', '=', pg.id)])
        self.assertAlmostEqual(picking_pick.move_ids.product_uom_qty, 2.0)
        self.assertAlmostEqual(picking_ship.move_ids.product_uom_qty, 2.0)

        # Create a procurement for 3 units
        pg = self.env['procurement.group'].create({'name': 'Wave 2'})
        self.env['procurement.group'].run([
            pg.Procurement(
                product_a,
                3.0,
                product_a.uom_id,
                final_location,
                'wave_part_2',
                'wave_part_2',
                warehouse.company_id,
                {
                    'warehouse_id': warehouse,
                    'group_id': pg
                }
            )
        ])

        # The picking for the pick operation should be reused and the lines merged.
        picking_ship = self.env['stock.picking'].search([('group_id', '=', pg.id)])
        self.assertAlmostEqual(picking_pick.move_ids.product_uom_qty, 5.0)
        self.assertAlmostEqual(picking_ship.move_ids.product_uom_qty, 3.0)

    def test_report_reception_4_pick_pack(self):
        """ Check that reception report ignores outgoing moves that are not beginning of chain
        """

        warehouse = self.warehouse_3_steps
        self.product = self.env['product.product'].create({
            'name': 'Test product',
            'is_storable': True,
        })

        ship_move = self.env['stock.move'].create({
            'name': 'The ship move',
            'product_id': self.product.id,
            'product_uom_qty': 5.0,
            'product_uom': self.product.uom_id.id,
            'location_id': warehouse.wh_output_stock_loc_id.id,
            'location_dest_id': self.env.ref('stock.stock_location_customers').id,
            'warehouse_id': warehouse.id,
            'picking_type_id': warehouse.out_type_id.id,
            'procure_method': 'make_to_order',
            'state': 'draft',
        })

        # create chained pick/pack moves to test with
        ship_move._assign_picking()
        ship_move._action_confirm()
        pack_move = ship_move.move_orig_ids[0]
        pick_move = pack_move.move_orig_ids[0]

        self.assertEqual(pack_move.state, 'waiting', "Pack move wasn't created...")
        self.assertEqual(pick_move.state, 'confirmed', "Pick move wasn't created...")

        receipt_form = Form(self.env['stock.picking'], view='stock.view_picking_form')
        receipt_form.partner_id = self.partner
        receipt_form.picking_type_id = warehouse.in_type_id
        with receipt_form.move_ids_without_package.new() as move_line:
            move_line.product_id = self.product
            move_line.product_uom_qty = 15
        receipt = receipt_form.save()

        report = self.env['report.stock.report_reception']
        report_values = report._get_report_values(docids=[receipt.id])
        self.assertEqual(len(report_values['sources_to_lines']), 1, "There should only be 1 line (pick move)")

    def test_pick_ship_1(self):
        """ Enable the pick ship route, force a procurement group on the
        pick. When a second move is added, make sure the `partner_id` and
        `origin` fields are erased.
        """
        pick_ship_route = self.warehouse_2_steps.delivery_route_id
        # create a procurement group and set in on the pick stock rule
        procurement_group0 = self.env['procurement.group'].create({})
        pick_rule = pick_ship_route.rule_ids.filtered(lambda rule: 'Stock → Output' in rule.name)
        push_rule = pick_ship_route.rule_ids - pick_rule
        pick_rule.write({
            'group_propagation_option': 'fixed',
            'group_id': procurement_group0.id,
        })

        ship_location = pick_rule.location_dest_id
        customer_location = push_rule.location_dest_id
        partners = self.env['res.partner'].search([], limit=2)
        partner0 = partners[0]
        partner1 = partners[1]
        procurement_group1 = self.env['procurement.group'].create({'partner_id': partner0.id})
        procurement_group2 = self.env['procurement.group'].create({'partner_id': partner1.id})

        move1 = self.env['stock.move'].create({
            'name': 'first out move',
            'procure_method': 'make_to_order',
            'location_id': ship_location.id,
            'location_dest_id': customer_location.id,
            'product_id': self.productA.id,
            'product_uom': self.uom_unit.id,
            'product_uom_qty': 1.0,
            'warehouse_id': self.warehouse_2_steps.id,
            'group_id': procurement_group1.id,
            'origin': 'origin1',
        })

        move2 = self.env['stock.move'].create({
            'name': 'second out move',
            'procure_method': 'make_to_order',
            'location_id': ship_location.id,
            'location_dest_id': customer_location.id,
            'product_id': self.productA.id,
            'product_uom': self.uom_unit.id,
            'product_uom_qty': 1.0,
            'warehouse_id': self.warehouse_2_steps.id,
            'group_id': procurement_group2.id,
            'origin': 'origin2',
        })

        # first out move, the "pick" picking should have a partner and an origin
        move1._action_confirm()
        picking_pick = move1.move_orig_ids.picking_id
        self.assertEqual(picking_pick.partner_id.id, procurement_group1.partner_id.id)
        self.assertEqual(picking_pick.origin, move1.group_id.name)

        # second out move, the "pick" picking should have lost its partner and origin
        move2._action_confirm()
        self.assertEqual(picking_pick.partner_id.id, False)
        self.assertEqual(picking_pick.origin, False)

    def test_propagate_cancel_in_pull_setup(self):
        """
        Check the cancellation propagation in pull set ups.
        """
        # create a procurement group
        procurement_group0 = self.env['procurement.group'].create({})
        product1 = self.env['product.product'].create({
            'name': 'test_procurement_cancel_propagation',
            'is_storable': True,
        })
        pick_pack_ship_route = self.warehouse_3_steps.delivery_route_id
        pick_rule = pick_pack_ship_route.rule_ids.filtered(lambda rule: rule.picking_type_id == self.warehouse_3_steps.pick_type_id)
        pack_rule = pick_pack_ship_route.rule_ids.filtered(lambda rule:  rule.picking_type_id == self.warehouse_3_steps.pack_type_id)
        (pick_rule | pack_rule).propagate_cancel = True
        ship_rule = pick_pack_ship_route.rule_ids - (pick_rule | pack_rule)
        self.env['procurement.group'].run([
            procurement_group0.Procurement(
                product1,
                1.0,
                product1.uom_id,
                ship_rule.location_dest_id,
                'test_mtso_mts_1',
                'test_mtso_mts_1',
                self.warehouse_3_steps.company_id,
                {
                    'warehouse_id': self.warehouse_3_steps,
                    'group_id': procurement_group0,
                }
            ),
        ])
        move_chain = self.env['stock.move'].search([('product_id', '=', product1.id)])
        self.assertEqual(len(move_chain), 3)
        pick_move = move_chain.filtered(lambda m: m.picking_type_id == self.warehouse_3_steps.pick_type_id)
        pick_move.picking_id.action_cancel()
        self.assertEqual(move_chain.mapped('state'), ['cancel', 'cancel', 'cancel'])
