diff --git a/shopfloor/actions/data.py b/shopfloor/actions/data.py
index 0b364c2254..8506191362 100644
--- a/shopfloor/actions/data.py
+++ b/shopfloor/actions/data.py
@@ -13,7 +13,7 @@ class DataAction(Component):
def location(self, record, **kw):
parser = self._location_parser
data = self._jsonify(record.with_context(location=record.id), parser, **kw)
- if "with_operation_progress" in kw:
+ if kw.get("with_operation_progress"):
lines_blacklist = (
kw.get("progress_lines_blacklist")
or self.env["stock.move.line"].browse()
@@ -46,7 +46,7 @@ def _get_picking_parser(self, record, **kw):
# and it may reduce performance significatively
# when dealing with a large number of pickings.
# Thus, we make it optional.
- if "with_progress" in kw:
+ if kw.get("with_progress"):
parser.append("progress")
return parser
@@ -72,6 +72,7 @@ def _picking_parser(self, **kw):
"bulk_line_count",
"total_weight:weight",
"scheduled_date",
+ "priority",
]
@ensure_model("stock.quant.package")
diff --git a/shopfloor/actions/schema.py b/shopfloor/actions/schema.py
index 34314960e4..5c8491e004 100644
--- a/shopfloor/actions/schema.py
+++ b/shopfloor/actions/schema.py
@@ -27,6 +27,7 @@ def picking(self):
"scheduled_date": {"type": "string", "nullable": False, "required": True},
"progress": {"type": "float", "nullable": True},
"location_dest": self._schema_dict_of(self.location(), required=False),
+ "priority": {"type": "string", "nullable": True, "required": False},
}
def move_line(self, with_packaging=False, with_picking=False):
diff --git a/shopfloor/models/stock_move_line.py b/shopfloor/models/stock_move_line.py
index e70ae50307..b70d90f4c7 100644
--- a/shopfloor/models/stock_move_line.py
+++ b/shopfloor/models/stock_move_line.py
@@ -24,6 +24,7 @@ class StockMoveLine(models.Model):
# we search lines based on their location in some workflows
location_id = fields.Many2one(index=True)
package_id = fields.Many2one(index=True)
+ result_package_id = fields.Many2one(index=True)
# allow domain on picking_id.xxx without too much perf penalty
picking_id = fields.Many2one(auto_join=True)
diff --git a/shopfloor/models/stock_picking.py b/shopfloor/models/stock_picking.py
index bb11e54c2b..3bff487489 100644
--- a/shopfloor/models/stock_picking.py
+++ b/shopfloor/models/stock_picking.py
@@ -116,3 +116,14 @@ def split_assigned_move_lines(self, move_lines=None):
)
assigned_moves._action_assign()
return new_picking.id
+
+ def _put_in_pack(self, move_line_ids, create_package_level=True):
+ """
+ Marks the corresponding move lines as 'shopfloor_checkout_done'
+ when the package is created in the backend.
+
+ """
+ new_package = super()._put_in_pack(move_line_ids, create_package_level)
+ lines = move_line_ids.filtered(lambda p: p.result_package_id == new_package)
+ lines.write({"shopfloor_checkout_done": True})
+ return new_package
diff --git a/shopfloor/services/checkout.py b/shopfloor/services/checkout.py
index 0bc23b384a..52d815fdb1 100644
--- a/shopfloor/services/checkout.py
+++ b/shopfloor/services/checkout.py
@@ -103,7 +103,6 @@ def _response_for_select_package(self, picking, lines, message=None):
data={
"selected_move_lines": self._data_for_move_lines(lines.sorted()),
"picking": self.data.picking(picking),
- "packing_info": self._data_for_packing_info(picking),
"no_package_enabled": not self.options.get(
"checkout__disable_no_package"
),
@@ -111,14 +110,6 @@ def _response_for_select_package(self, picking, lines, message=None):
message=message,
)
- def _data_for_packing_info(self, picking):
- """Return the packing information
-
- Intended to be extended.
- """
- # TODO: This could be avoided if included in the picking parser.
- return ""
-
def _response_for_select_dest_package(self, picking, move_lines, message=None):
packages = picking.mapped("move_line_ids.result_package_id").filtered(
"packaging_id"
@@ -363,7 +354,7 @@ def _domain_for_list_stock_picking(self):
]
def _order_for_list_stock_picking(self):
- return "scheduled_date asc, id asc"
+ return "priority desc, scheduled_date asc, id asc"
def list_stock_picking(self):
"""List stock.picking records available
@@ -1478,11 +1469,8 @@ def done(self, picking_id, confirmation=False):
},
)
lines_done = self._lines_checkout_done(picking)
- dest_location = picking.location_dest_id
- child_locations = self.env["stock.location"].search(
- [("id", "child_of", dest_location.id), ("usage", "!=", "view")]
- )
- if len(child_locations) > 0 and child_locations != dest_location:
+ dest_location = lines_done.move_id.location_dest_id
+ if len(dest_location) != 1 or dest_location.usage == "view":
return self._response_for_select_child_location(
picking,
)
diff --git a/shopfloor/services/cluster_picking.py b/shopfloor/services/cluster_picking.py
index 721f835c72..f5fec4b87d 100644
--- a/shopfloor/services/cluster_picking.py
+++ b/shopfloor/services/cluster_picking.py
@@ -776,8 +776,11 @@ def scan_destination_pack(self, picking_batch_id, move_line_id, barcode, quantit
qty_done=quantity,
)
move_line.write({"qty_done": quantity, "result_package_id": bin_package.id})
-
- zero_check = move_line.picking_id.picking_type_id.shopfloor_zero_check
+ # Only apply zero check if the product is of type "product".
+ zero_check = (
+ move_line.product_id.type == "product"
+ and move_line.picking_id.picking_type_id.shopfloor_zero_check
+ )
if zero_check and move_line.location_id.planned_qty_in_location_is_empty():
return self._response_for_zero_check(batch, move_line)
diff --git a/shopfloor/services/zone_picking.py b/shopfloor/services/zone_picking.py
index d73283f13b..fad89f3671 100644
--- a/shopfloor/services/zone_picking.py
+++ b/shopfloor/services/zone_picking.py
@@ -667,12 +667,15 @@ def _scan_source_package(
)
else:
change_package_lot = self._actions_for("change.package.lot")
+ move_line = first(move_lines)
response = change_package_lot.change_package(
- first(move_lines),
+ move_line,
package,
- # FIXME we may need to pass the quantity being done
- self._response_for_set_line_destination,
- self._response_for_change_pack_lot,
+ response_ok_func=functools.partial(
+ self._response_for_set_line_destination,
+ qty_done=self._get_prefill_qty(move_line, qty=0),
+ ),
+ response_error_func=self._response_for_change_pack_lot,
)
else:
response = self._list_move_lines(sublocation or self.zone_location)
@@ -959,7 +962,11 @@ def _set_destination_location(
location_changed = True
# Zero check
- zero_check = self.picking_type.shopfloor_zero_check
+ # Only apply zero check if the product is of type "product".
+ zero_check = (
+ move_line.product_id.type == "product"
+ and self.picking_type.shopfloor_zero_check
+ )
if zero_check and move_line.location_id.planned_qty_in_location_is_empty():
response = self._response_for_zero_check(move_line)
return (location_changed, response)
@@ -1042,7 +1049,11 @@ def _set_destination_package(self, move_line, quantity, package):
return (package_changed, response)
package_changed = True
# Zero check
- zero_check = self.picking_type.shopfloor_zero_check
+ # Only apply zero check if the product is of type "product".
+ zero_check = (
+ move_line.product_id.type == "product"
+ and self.picking_type.shopfloor_zero_check
+ )
if zero_check and move_line.location_id.planned_qty_in_location_is_empty():
response = self._response_for_zero_check(move_line)
return (package_changed, response)
@@ -1434,7 +1445,10 @@ def change_pack_lot(self, move_line_id, barcode):
# pre-configured callable used to generate the response as the
# change.package.lot component is not aware of the needed response type
# and related parameters for zone picking scenario
- response_ok_func = functools.partial(self._response_for_set_line_destination)
+ response_ok_func = functools.partial(
+ self._response_for_set_line_destination,
+ qty_done=self._get_prefill_qty(move_line),
+ )
response_error_func = functools.partial(self._response_for_change_pack_lot)
response = None
change_package_lot = self._actions_for("change.package.lot")
diff --git a/shopfloor/tests/test_actions_data.py b/shopfloor/tests/test_actions_data.py
index 0fbe90233e..de502b4f76 100644
--- a/shopfloor/tests/test_actions_data.py
+++ b/shopfloor/tests/test_actions_data.py
@@ -155,6 +155,7 @@ def test_data_picking(self):
"partner": {"id": self.customer.id, "name": self.customer.name},
"carrier": {"id": carrier.id, "name": carrier.name},
"ship_carrier": None,
+ "priority": "0",
}
self.assertEqual(data.pop("scheduled_date").split("T")[0], "2020-08-03")
self.assertDictEqual(data, expected)
@@ -179,6 +180,7 @@ def test_data_picking_with_progress(self):
"carrier": {"id": carrier.id, "name": carrier.name},
"ship_carrier": None,
"progress": 0.0,
+ "priority": "0",
}
self.assertEqual(data.pop("scheduled_date").split("T")[0], "2020-08-03")
self.assertDictEqual(data, expected)
diff --git a/shopfloor/tests/test_checkout_base.py b/shopfloor/tests/test_checkout_base.py
index c5134ed85b..738c3172a6 100644
--- a/shopfloor/tests/test_checkout_base.py
+++ b/shopfloor/tests/test_checkout_base.py
@@ -68,7 +68,6 @@ def _assert_select_package_qty_above(self, response, picking):
self._move_line_data(ml) for ml in picking.move_line_ids.sorted()
],
"picking": self._picking_summary_data(picking),
- "packing_info": "",
"no_package_enabled": True,
},
message={
diff --git a/shopfloor/tests/test_checkout_done.py b/shopfloor/tests/test_checkout_done.py
index a9acce2032..1e6c93c3aa 100644
--- a/shopfloor/tests/test_checkout_done.py
+++ b/shopfloor/tests/test_checkout_done.py
@@ -65,8 +65,34 @@ def test_done_partial_confirm(self):
"done", params={"picking_id": self.picking.id, "confirmation": True}
)
- self.assertRecordValues(self.picking, [{"state": "assigned"}])
+ self.assertRecordValues(self.picking, [{"state": "done"}])
+
+ self.assert_response(
+ response,
+ next_state="select_document",
+ message=self.service.msg_store.transfer_done_success(self.picking),
+ data={"restrict_scan_first": False},
+ )
+ def test_done_ask_destination_location(self):
+ """Check asking for destination location for view type location."""
+ view_location = (
+ self.env["stock.location"]
+ .sudo()
+ .create(
+ {
+ "name": "Test Location Usage View",
+ "location_id": self.picking.move_lines.location_dest_id.id,
+ "usage": "view",
+ }
+ )
+ )
+ self.picking.move_lines.location_dest_id = view_location
+ response = self.service.dispatch(
+ "done", params={"picking_id": self.picking.id, "confirmation": True}
+ )
+
+ self.assertRecordValues(self.picking, [{"state": "assigned"}])
self.assert_response(
response,
next_state="select_child_location",
diff --git a/shopfloor/tests/test_checkout_list_delivery_packaging.py b/shopfloor/tests/test_checkout_list_delivery_packaging.py
index 48fc87c446..2e702a83a5 100644
--- a/shopfloor/tests/test_checkout_list_delivery_packaging.py
+++ b/shopfloor/tests/test_checkout_list_delivery_packaging.py
@@ -111,7 +111,6 @@ def test_list_delivery_packaging_not_available(self):
"selected_move_lines": [
self._move_line_data(ml) for ml in selected_lines.sorted()
],
- "packing_info": self.service._data_for_packing_info(self.picking),
"no_package_enabled": not self.service.options.get(
"checkout__disable_no_package"
),
diff --git a/shopfloor/tests/test_checkout_scan_package_action.py b/shopfloor/tests/test_checkout_scan_package_action.py
index 446f50debd..a2609d3f8e 100644
--- a/shopfloor/tests/test_checkout_scan_package_action.py
+++ b/shopfloor/tests/test_checkout_scan_package_action.py
@@ -172,7 +172,6 @@ def test_scan_package_action_scan_package_keep_source_package_error(self):
data={
"picking": self.data.picking(picking),
"selected_move_lines": self.data.move_lines(selected_lines),
- "packing_info": self.service._data_for_packing_info(picking),
"no_package_enabled": not self.service.options.get(
"checkout__disable_no_package"
),
@@ -455,3 +454,28 @@ def test_scan_package_action_scan_not_found(self):
selected_line,
message={"message_type": "error", "body": "Barcode not found"},
)
+
+ def test_put_in_pack(self):
+ picking = self._create_picking(
+ lines=[(self.product_a, 10), (self.product_b, 20)]
+ )
+ self._fill_stock_for_moves(picking.move_lines)
+ picking.action_assign()
+
+ # Test that the move lines are marked as 'shopfloor_checkout_done'
+ # when putting them in a pack in the backend.
+ picking._put_in_pack(picking.move_line_ids)
+ self.assertTrue(
+ all(line.shopfloor_checkout_done for line in picking.move_line_ids)
+ )
+
+ # Check that we return those lines to the frontend.
+ res = self.service.dispatch(
+ "summary",
+ params={
+ "picking_id": picking.id,
+ },
+ )
+ returned_lines = res["data"]["summary"]["picking"]["move_lines"]
+ expected_line_ids = [line["id"] for line in returned_lines]
+ self.assertEqual(expected_line_ids, picking.move_line_ids.ids)
diff --git a/shopfloor/tests/test_checkout_select_package_base.py b/shopfloor/tests/test_checkout_select_package_base.py
index 5f4ffe42ce..b3be128eab 100644
--- a/shopfloor/tests/test_checkout_select_package_base.py
+++ b/shopfloor/tests/test_checkout_select_package_base.py
@@ -20,7 +20,6 @@ def _assert_selected_response(
self._move_line_data(ml) for ml in selected_lines.sorted()
],
"picking": self._picking_summary_data(picking),
- "packing_info": packing_info,
"no_package_enabled": no_package_enabled,
},
message=message,
diff --git a/shopfloor/tests/test_zone_picking_change_pack_lot.py b/shopfloor/tests/test_zone_picking_change_pack_lot.py
index 7e080c90e2..282f0398fa 100644
--- a/shopfloor/tests/test_zone_picking_change_pack_lot.py
+++ b/shopfloor/tests/test_zone_picking_change_pack_lot.py
@@ -87,6 +87,7 @@ def test_change_pack_lot_change_pack_ok(self):
message=self.service.msg_store.package_replaced_by_package(
previous_package, self.free_package
),
+ qty_done=self.service._get_prefill_qty(move_line),
)
def test_change_pack_lot_change_lot_ok(self):
@@ -137,4 +138,5 @@ def test_change_pack_lot_change_lot_ok(self):
message=self.service.msg_store.lot_replaced_by_lot(
previous_lot, self.free_lot
),
+ qty_done=self.service._get_prefill_qty(move_line),
)
diff --git a/shopfloor/tests/test_zone_picking_select_line.py b/shopfloor/tests/test_zone_picking_select_line.py
index b673d59510..d6b486c134 100644
--- a/shopfloor/tests/test_zone_picking_select_line.py
+++ b/shopfloor/tests/test_zone_picking_select_line.py
@@ -348,6 +348,7 @@ def test_scan_source_barcode_package_can_replace_in_line(self):
message=self.service.msg_store.package_replaced_by_package(
package1, package1b
),
+ qty_done=self.service._get_prefill_qty(move_lines[0]),
)
# Check the package has been changed on the move line
self.assertEqual(self.picking1.package_level_ids[0].package_id, package1b)
diff --git a/shopfloor/views/shopfloor_menu.xml b/shopfloor/views/shopfloor_menu.xml
index 868dc85c6c..5617de5f9e 100644
--- a/shopfloor/views/shopfloor_menu.xml
+++ b/shopfloor/views/shopfloor_menu.xml
@@ -112,6 +112,7 @@
name="scan_location_or_pack_first"
attrs="{'invisible': [('scan_location_or_pack_first_is_possible', '=', False)]}"
>
+