Skip to content

Commit 704ada6

Browse files
committed
shopfloor checkout: scan document better messages
1 parent db4ce04 commit 704ada6

File tree

3 files changed

+94
-49
lines changed

3 files changed

+94
-49
lines changed

shopfloor/actions/message.py

+24
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,30 @@ def product_not_found_in_pickings(self):
468468
"body": _("No transfer found for this product."),
469469
}
470470

471+
def transfer_not_found_for_barcode(self, barcode):
472+
body = _("No transfer found for barcode {}").format(barcode)
473+
return {
474+
"message_type": "error",
475+
"body": body,
476+
}
477+
478+
def transfer_not_found_for_record(self, record):
479+
model_mapping = {
480+
"product.product": "product",
481+
"stock.picking": "transfer",
482+
"stock.quant.package": "package",
483+
"product.packaging": "packaging",
484+
"stock.location": "location",
485+
"stock.production.lot": "lot",
486+
"stock.move": "move",
487+
}
488+
model_name = model_mapping.get(record._name)
489+
body = _("No transfer found for {} {}").format(model_name, record.name)
490+
return {
491+
"message_type": "error",
492+
"body": body,
493+
}
494+
471495
def product_not_found_in_location_or_transfer(self, product, location, picking):
472496
return {
473497
"message_type": "error",

shopfloor/services/checkout.py

+59-46
Original file line numberDiff line numberDiff line change
@@ -212,25 +212,29 @@ def scan_document(self, barcode):
212212
* summary: stock.picking is selected and all its lines have a
213213
destination pack set
214214
"""
215-
search_result = self._scan_document_find(barcode)
216-
result_handler = getattr(self, "_select_document_from_" + search_result.type)
217-
return result_handler(search_result.record)
215+
handlers = {
216+
"picking": self._select_document_from_picking,
217+
"location": self._select_document_from_location,
218+
"package": self._select_document_from_package,
219+
"packaging": self._select_document_from_packaging,
220+
"product": self._select_document_from_product,
221+
"none": self._select_document_from_none,
222+
}
223+
if self.work.menu.scan_location_or_pack_first:
224+
handlers.pop("product")
225+
search_result = self._scan_document_find(barcode, handlers.keys())
226+
# Keep track of what has been initially scan, and forward it through kwargs
227+
kwargs = {
228+
"barcode": barcode,
229+
"current_state": "select_document",
230+
"scanned_record": search_result.record,
231+
}
232+
handler = handlers.get(search_result.type, self._select_document_from_none)
233+
return handler(search_result.record, **kwargs)
218234

219-
def _scan_document_find(self, barcode, search_types=None):
235+
def _scan_document_find(self, barcode, search_types):
220236
search = self._actions_for("search")
221-
search_types = (
222-
"picking",
223-
"location",
224-
"package",
225-
"packaging",
226-
) + (("product",) if not self.work.menu.scan_location_or_pack_first else ())
227-
return search.find(
228-
barcode,
229-
types=search_types,
230-
)
231-
232-
def _select_document_from_picking(self, picking, **kw):
233-
return self._select_picking(picking, "select_document")
237+
return search.find(barcode, types=search_types)
234238

235239
def _select_document_from_location(self, location, **kw):
236240
if not self.is_src_location_valid(location):
@@ -249,7 +253,9 @@ def _select_document_from_location(self, location, **kw):
249253
),
250254
}
251255
)
252-
return self._select_picking(pickings, "select_document")
256+
# Keep track of what has been initially scan, and forward it through kwargs
257+
kwargs = {**kw, "current_state": "select_document"}
258+
return self._select_document_from_picking(pickings, **kwargs)
253259

254260
def _select_document_from_package(self, package, **kw):
255261
pickings = package.move_line_ids.filtered(
@@ -258,14 +264,15 @@ def _select_document_from_package(self, package, **kw):
258264
if len(pickings) > 1:
259265
# Filter only if we find several pickings to narrow the
260266
# selection to one of the good type. If we have one picking
261-
# of the wrong type, it will be caught in _select_picking
267+
# of the wrong type, it will be caught in _select_document_from_picking
262268
# with the proper error message.
263269
# Side note: rather unlikely to have several transfers ready
264270
# and moving the same things
265271
pickings = pickings.filtered(
266272
lambda p: p.picking_type_id in self.picking_types
267273
)
268-
return self._select_picking(fields.first(pickings), "select_document")
274+
kwargs = {**kw, "current_state": "select_document"}
275+
return self._select_document_from_picking(fields.first(pickings), **kwargs)
269276

270277
def _select_document_from_product(self, product, line_domain=None, **kw):
271278
line_domain = line_domain or []
@@ -285,7 +292,8 @@ def _select_document_from_product(self, product, line_domain=None, **kw):
285292
order="priority desc, scheduled_date asc, id desc",
286293
limit=1,
287294
)
288-
return self._select_picking(picking, "select_document")
295+
kwargs = {**kw, "current_state": "select_document"}
296+
return self._select_document_from_picking(picking, **kwargs)
289297

290298
def _select_document_from_packaging(self, packaging, **kw):
291299
# And retrieve its product
@@ -296,35 +304,33 @@ def _select_document_from_packaging(self, packaging, **kw):
296304
line_domain = [("product_uom_qty", ">=", packaging.qty)]
297305
return self._select_document_from_product(product, line_domain=line_domain)
298306

299-
def _select_document_from_none(self, picking, **kw):
307+
def _select_document_from_none(self, *args, barcode=None, **kwargs):
300308
"""Handle result when no record is found."""
301-
return self._select_picking(picking, "select_document")
309+
return self._response_for_select_document(
310+
message=self.msg_store.transfer_not_found_for_barcode(barcode)
311+
)
302312

303-
def _select_picking(self, picking, state_for_error):
313+
def _select_document_from_picking(
314+
self, picking, current_state=None, barcode=None, **kwargs
315+
):
316+
# Get origin record to give more context to the user when raising an error
317+
# as we got picking from product/package/packaging/...
318+
scanned_record = kwargs.get("scanned_record")
304319
if not picking:
305-
if state_for_error == "manual_selection":
306-
return self._response_for_manual_selection(
307-
message=self.msg_store.stock_picking_not_found()
308-
)
309-
return self._response_for_select_document(
310-
message=self.msg_store.barcode_not_found()
311-
)
320+
message = self.msg_store.transfer_not_found_for_record(scanned_record)
321+
if current_state == "manual_selection":
322+
return self._response_for_manual_selection(message=message)
323+
return self._response_for_select_document(message=message)
312324
if picking.picking_type_id not in self.picking_types:
313-
if state_for_error == "manual_selection":
314-
return self._response_for_manual_selection(
315-
message=self.msg_store.cannot_move_something_in_picking_type()
316-
)
317-
return self._response_for_select_document(
318-
message=self.msg_store.cannot_move_something_in_picking_type()
319-
)
325+
message = self.msg_store.reserved_for_other_picking_type(picking)
326+
if current_state == "manual_selection":
327+
return self._response_for_manual_selection(message=message)
328+
return self._response_for_select_document(message=message)
320329
if picking.state != "assigned":
321-
if state_for_error == "manual_selection":
322-
return self._response_for_manual_selection(
323-
message=self.msg_store.stock_picking_not_available(picking)
324-
)
325-
return self._response_for_select_document(
326-
message=self.msg_store.stock_picking_not_available(picking)
327-
)
330+
message = self.msg_store.stock_picking_not_available(picking)
331+
if current_state == "manual_selection":
332+
return self._response_for_manual_selection(message=message)
333+
return self._response_for_select_document(message=message)
328334
return self._response_for_select_line(picking)
329335

330336
def _data_for_move_lines(self, lines, **kw):
@@ -403,7 +409,14 @@ def select(self, picking_id):
403409
message = self._check_picking_processible(picking)
404410
if message:
405411
return self._response_for_manual_selection(message=message)
406-
return self._select_picking(picking, "manual_selection")
412+
# Because _select_document_from_picking expects some context
413+
# to give meaningful infos to the user, add some here.
414+
kwargs = {
415+
"current_state": "manual_selection",
416+
"barcode": picking.name,
417+
"scanned_record": picking,
418+
}
419+
return self._select_document_from_picking(picking, **kwargs)
407420

408421
def _select_lines(self, lines, prefill_qty=0, related_lines=None):
409422
for i, line in enumerate(lines):

shopfloor/tests/test_checkout_scan.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ def test_scan_document_with_option_product_not_ok(self):
4141
self.assert_response(
4242
response,
4343
next_state="select_document",
44-
message={"message_type": "error", "body": "Barcode not found"},
44+
message={
45+
"message_type": "error",
46+
"body": "No transfer found for barcode A",
47+
},
4548
data={"restrict_scan_first": True},
4649
)
4750

@@ -56,7 +59,10 @@ def test_scan_document_error_not_found(self):
5659
self.assert_response(
5760
response,
5861
next_state="select_document",
59-
message={"message_type": "error", "body": "Barcode not found"},
62+
message={
63+
"message_type": "error",
64+
"body": "No transfer found for barcode NOPE",
65+
},
6066
data={"restrict_scan_first": False},
6167
)
6268

@@ -117,12 +123,14 @@ def _test_scan_document_error_different_picking_type(self, barcode_func):
117123
picking.action_assign()
118124
barcode = barcode_func(picking)
119125
response = self.service.dispatch("scan_document", params={"barcode": barcode})
126+
picking_name = picking.name
127+
type_name = picking.picking_type_id.name
120128
self.assert_response(
121129
response,
122130
next_state="select_document",
123131
message={
124132
"message_type": "error",
125-
"body": "You cannot move this using this menu.",
133+
"body": f"Reserved for {type_name} {picking_name}",
126134
},
127135
data={"restrict_scan_first": False},
128136
)

0 commit comments

Comments
 (0)