Files
stock-logistics-warehouse/stock_vertical_lift/tests/test_pick.py
Carlos Serra-Toro e1e417b5f7 [IMP] stock_vertical_lift: Add skip operation to vertical lift shuttles
In the screen for the vertical lift shuttles, accessible through
Inventory > Operations > Vertical Lift Shuttles, a new button has been
added to allow to skip an operation. This button can also be triggered
by scanning the barcode O-BTN.skip.svg that is inside the folder
'images'.

When a skip is done, the next stock.move.line to pick is chosen and
shown to the operator. A skipped move line is added to the end of the
list of pending move lines to be picked, so they will be shown again
in the future as soon as the other move lines have been successfully
processed.

This option was added because, sometimes, the operator can not process
a move line for whatever reason. Right now, the only way of proceeding
is to wait until he/she can effectively process it, which involves a
delay in the operations. With this new skip operation, the operator
can continue processing the rest of move lines.
2021-09-16 20:17:34 +07:00

237 lines
10 KiB
Python

# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from .common import VerticalLiftCase
class TestPick(VerticalLiftCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.picking_out = cls.env.ref(
"stock_vertical_lift.stock_picking_out_demo_vertical_lift_1"
)
# we have a move line to pick created by demo picking
# stock_picking_out_demo_vertical_lift_1
cls.out_move_line = cls.picking_out.move_line_ids[0]
def test_switch_pick(self):
self.shuttle.switch_pick()
self.assertEqual(self.shuttle.mode, "pick")
self.assertEqual(
self.shuttle._operation_for_mode().current_move_line_id, self.out_move_line
)
def test_pick_action_open_screen(self):
self.shuttle.switch_pick()
action = self.shuttle.action_open_screen()
operation = self.shuttle._operation_for_mode()
self.assertTrue(operation.current_move_line_id)
self.assertEqual(action["type"], "ir.actions.act_window")
self.assertEqual(action["res_model"], "vertical.lift.operation.pick")
self.assertEqual(action["res_id"], operation.id)
def test_pick_select_next_move_line(self):
operation = self._open_screen("pick")
operation.select_next_move_line()
self.assertEqual(operation.current_move_line_id, self.out_move_line)
self.assertEqual(operation.state, "scan_destination")
def test_pick_select_next_move_line_was_skipped(self):
"""Previously skipped moves can be reprocessed"""
self.picking_out.move_line_ids.write({"vertical_lift_skipped": True})
operation = self._open_screen("pick")
operation.select_next_move_line()
self.assertEqual(operation.current_move_line_id, self.out_move_line)
self.assertEqual(operation.state, "scan_destination")
self.assertFalse(operation.current_move_line_id.vertical_lift_skipped)
def test_pick_save(self):
operation = self._open_screen("pick")
# assume we already scanned the destination, current state is save
operation.state = "save"
operation.current_move_line_id = self.out_move_line
operation.button_save()
self.assertEqual(operation.current_move_line_id.state, "done")
self.assertEqual(operation.state, "release")
def test_pick_skip_from_scan_destination(self):
"""Being in state Scan Destination, skip it"""
self._test_pick_skip_from_state("scan_destination")
def test_pick_skip_from_save(self):
"""Being in state Save, skip it"""
self._test_pick_skip_from_state("save")
def test_pick_skip_from_release(self):
"""Being in state Release, skip it"""
self._test_pick_skip_from_state("release")
def _test_pick_skip_from_state(self, state):
operation = self._open_screen("pick")
operation.state = state
operation.current_move_line_id = self.out_move_line
first_move_line = operation.current_move_line_id
self.assertFalse(operation.current_move_line_id.vertical_lift_skipped)
operation.button_skip()
second_move_line = operation.current_move_line_id
self.assertNotEqual(first_move_line, second_move_line)
self.assertFalse(operation.current_move_line_id.vertical_lift_skipped)
self.assertEqual(operation.current_move_line_id.state, "assigned")
self.assertEqual(operation.state, "scan_destination")
def test_pick_related_fields(self):
operation = self._open_screen("pick")
ml = operation.current_move_line_id = self.out_move_line
# Trays related fields
# For pick, this is the source location, which is the cell where the
# product is.
self.assertEqual(operation.tray_location_id, ml.location_id)
self.assertEqual(
operation.tray_name,
# parent = tray
ml.location_id.location_id.name,
)
self.assertEqual(
operation.tray_type_id,
# the tray type is on the parent of the cell (on the tray)
ml.location_id.location_id.tray_type_id,
)
self.assertEqual(
operation.tray_type_code, ml.location_id.location_id.tray_type_id.code
)
self.assertEqual(operation.tray_x, ml.location_id.posx)
self.assertEqual(operation.tray_y, ml.location_id.posy)
# Move line related fields
self.assertEqual(operation.picking_id, ml.picking_id)
self.assertEqual(operation.picking_origin, ml.picking_id.origin)
self.assertEqual(operation.picking_partner_id, ml.picking_id.partner_id)
self.assertEqual(operation.product_id, ml.product_id)
self.assertEqual(operation.product_uom_id, ml.product_uom_id)
self.assertEqual(operation.product_uom_qty, ml.product_uom_qty)
self.assertEqual(operation.qty_done, ml.qty_done)
self.assertEqual(operation.lot_id, ml.lot_id)
def test_pick_count_move_lines(self):
product1 = self.env.ref("stock_vertical_lift.product_running_socks")
product2 = self.env.ref("stock_vertical_lift.product_recovery_socks")
# cancel the picking from demo data to start from a clean state
self.env.ref(
"stock_vertical_lift.stock_picking_out_demo_vertical_lift_1"
).action_cancel()
# ensure that we have stock in some cells, we'll put product1
# in the first Shuttle and product2 in the second
cell1 = self.env.ref(
"stock_vertical_lift." "stock_location_vertical_lift_demo_tray_1a_x3y2"
)
self._update_quantity_in_cell(cell1, product1, 50)
cell2 = self.env.ref(
"stock_vertical_lift." "stock_location_vertical_lift_demo_tray_2a_x1y1"
)
self._update_quantity_in_cell(cell2, product2, 50)
# create pickings (we already have an existing one from demo data)
pickings = self.env["stock.picking"].browse()
pickings |= self._create_simple_picking_out(product1, 1)
pickings |= self._create_simple_picking_out(product1, 1)
pickings |= self._create_simple_picking_out(product1, 1)
pickings |= self._create_simple_picking_out(product1, 1)
pickings |= self._create_simple_picking_out(product2, 20)
pickings |= self._create_simple_picking_out(product2, 30)
# this one should be 'assigned', so should be included in the operation
# count
unassigned = self._create_simple_picking_out(product2, 1)
pickings |= unassigned
pickings.action_confirm()
# product1 will be taken from the shuttle1, product2 from shuttle2
pickings.action_assign()
shuttle1 = self.shuttle
operation1 = shuttle1._operation_for_mode()
shuttle2 = self.env.ref(
"stock_vertical_lift.stock_vertical_lift_demo_shuttle_2"
)
operation2 = shuttle2._operation_for_mode()
self.assertEqual(operation1.number_of_ops, 4)
self.assertEqual(operation2.number_of_ops, 2)
self.assertEqual(operation1.number_of_ops_all, 6)
self.assertEqual(operation2.number_of_ops_all, 6)
# Process a line, should change the numbers.
operation1.select_next_move_line()
operation1.process_current()
self.assertEqual(operation1.number_of_ops, 3)
self.assertEqual(operation2.number_of_ops, 2)
self.assertEqual(operation1.number_of_ops_all, 5)
self.assertEqual(operation2.number_of_ops_all, 5)
# add stock and make the last one assigned to check the number is
# updated
self._update_quantity_in_cell(cell2, product2, 10)
unassigned.action_assign()
self.assertEqual(operation1.number_of_ops, 3)
self.assertEqual(operation2.number_of_ops, 3)
self.assertEqual(operation1.number_of_ops_all, 6)
self.assertEqual(operation2.number_of_ops_all, 6)
def test_on_barcode_scanned(self):
operation = self._open_screen("pick")
self.assertEqual(operation.state, "scan_destination")
move_line = operation.current_move_line_id
current_destination = move_line.location_dest_id
stock_location = self.env.ref("stock.stock_location_stock")
self.assertEqual(
current_destination, self.env.ref("stock.stock_location_customers")
)
operation.on_barcode_scanned(stock_location.barcode)
self.assertEqual(move_line.location_dest_id, stock_location)
self.assertEqual(operation.state, "save")
def test_button_release(self):
self._open_screen("pick")
self._test_button_release(self.picking_out.move_line_ids, "noop")
def test_process_current_pick(self):
operation = self._open_screen("pick")
operation.current_move_line_id = self.out_move_line
qty_to_process = self.out_move_line.product_qty
operation.process_current()
self.assertEqual(self.out_move_line.state, "done")
self.assertEqual(self.out_move_line.qty_done, qty_to_process)
def test_matrix(self):
operation = self._open_screen("pick")
operation.current_move_line_id = self.out_move_line
location = self.out_move_line.location_id
# offset by -1 because the fields are for humans
expected_x = location.posx - 1
expected_y = location.posy - 1
self.assertEqual(
operation.tray_matrix,
{
"selected": [expected_x, expected_y],
# fmt: off
'cells': [
[0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0],
]
# fmt: on
},
)
def test_tray_qty(self):
cell = self.env.ref(
"stock_vertical_lift." "stock_location_vertical_lift_demo_tray_1a_x3y2"
)
self.out_move_line.location_id = cell
operation = self.shuttle._operation_for_mode()
operation.current_move_line_id = self.out_move_line
self._update_quantity_in_cell(cell, self.out_move_line.product_id, 50)
self.assertEqual(operation.tray_qty, 50)
self._update_quantity_in_cell(cell, self.out_move_line.product_id, -20)
self.assertEqual(operation.tray_qty, 30)