odoo-addon-shopfloor 16.0.2.5.0.2__py3-none-any.whl → 16.0.2.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. odoo/addons/shopfloor/README.rst +1 -1
  2. odoo/addons/shopfloor/__manifest__.py +1 -1
  3. odoo/addons/shopfloor/actions/message.py +50 -5
  4. odoo/addons/shopfloor/actions/stock_unreserve.py +11 -4
  5. odoo/addons/shopfloor/i18n/shopfloor.pot +35 -13
  6. odoo/addons/shopfloor/services/checkout.py +129 -105
  7. odoo/addons/shopfloor/services/cluster_picking.py +24 -8
  8. odoo/addons/shopfloor/services/delivery.py +89 -64
  9. odoo/addons/shopfloor/services/location_content_transfer.py +34 -18
  10. odoo/addons/shopfloor/services/service.py +52 -15
  11. odoo/addons/shopfloor/services/zone_picking.py +13 -9
  12. odoo/addons/shopfloor/static/description/index.html +1 -1
  13. odoo/addons/shopfloor/tests/test_checkout_scan.py +11 -3
  14. odoo/addons/shopfloor/tests/test_checkout_scan_line.py +35 -4
  15. odoo/addons/shopfloor/tests/test_checkout_select.py +3 -1
  16. odoo/addons/shopfloor/tests/test_cluster_picking_scan_destination_no_prefill_qty.py +6 -4
  17. odoo/addons/shopfloor/tests/test_delivery_scan_deliver.py +143 -1
  18. odoo/addons/shopfloor/tests/test_delivery_set_qty_done_line.py +1 -1
  19. odoo/addons/shopfloor/tests/test_delivery_set_qty_done_pack.py +1 -1
  20. odoo/addons/shopfloor/tests/test_location_content_transfer_start.py +24 -1
  21. {odoo_addon_shopfloor-16.0.2.5.0.2.dist-info → odoo_addon_shopfloor-16.0.2.7.0.dist-info}/METADATA +2 -2
  22. {odoo_addon_shopfloor-16.0.2.5.0.2.dist-info → odoo_addon_shopfloor-16.0.2.7.0.dist-info}/RECORD +24 -24
  23. {odoo_addon_shopfloor-16.0.2.5.0.2.dist-info → odoo_addon_shopfloor-16.0.2.7.0.dist-info}/WHEEL +0 -0
  24. {odoo_addon_shopfloor-16.0.2.5.0.2.dist-info → odoo_addon_shopfloor-16.0.2.7.0.dist-info}/top_level.txt +0 -0
@@ -7,7 +7,7 @@ Shopfloor
7
7
  !! This file is generated by oca-gen-addon-readme !!
8
8
  !! changes will be overwritten. !!
9
9
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10
- !! source digest: sha256:86239aacdfa7d7810aca5b0625ebd9112b12385d98899ac696d596b455b0c57d
10
+ !! source digest: sha256:986a6c228f6ee438330907a4be64b74f7291bb1acfc6498a2617ed5e69777d9e
11
11
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12
12
 
13
13
  .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
@@ -6,7 +6,7 @@
6
6
  {
7
7
  "name": "Shopfloor",
8
8
  "summary": "manage warehouse operations with barcode scanners",
9
- "version": "16.0.2.5.0",
9
+ "version": "16.0.2.7.0",
10
10
  "development_status": "Beta",
11
11
  "category": "Inventory",
12
12
  "website": "https://github.com/OCA/wms",
@@ -214,6 +214,15 @@ class MessageAction(Component):
214
214
  def already_done(self):
215
215
  return {"message_type": "info", "body": _("Operation already processed.")}
216
216
 
217
+ def transfer_canceled(self):
218
+ return {
219
+ "message_type": "info",
220
+ "body": _(
221
+ "Transfer has been canceled. "
222
+ "This cannot be processed using this scenario"
223
+ ),
224
+ }
225
+
217
226
  def move_already_done(self):
218
227
  return {"message_type": "warning", "body": _("Move already processed.")}
219
228
 
@@ -458,6 +467,34 @@ class MessageAction(Component):
458
467
  "body": _("No transfer found for this product."),
459
468
  }
460
469
 
470
+ def transfer_not_found_for_barcode(self, barcode):
471
+ body = _("No transfer found for barcode %s", barcode)
472
+ return {
473
+ "message_type": "error",
474
+ "body": body,
475
+ }
476
+
477
+ def transfer_not_found_for_record(self, record):
478
+ model_mapping = {
479
+ "product.product": "product",
480
+ "stock.picking": "transfer",
481
+ "stock.quant.package": "package",
482
+ "product.packaging": "packaging",
483
+ "stock.location": "location",
484
+ "stock.lot": "lot",
485
+ "stock.move": "move",
486
+ }
487
+ model_name = model_mapping.get(record._name)
488
+ body = _(
489
+ "No transfer found for %(model_name)s %(record_name)s",
490
+ model_name=model_name,
491
+ record_name=record.name,
492
+ )
493
+ return {
494
+ "message_type": "error",
495
+ "body": body,
496
+ }
497
+
461
498
  def product_not_found_in_location_or_transfer(self, product, location, picking):
462
499
  return {
463
500
  "message_type": "error",
@@ -526,11 +563,9 @@ class MessageAction(Component):
526
563
  "body": _("Place it in {}?").format(location_name),
527
564
  }
528
565
 
529
- def product_not_found_in_current_picking(self):
530
- return {
531
- "message_type": "error",
532
- "body": _("Product is not in the current transfer."),
533
- }
566
+ def product_not_found_in_current_picking(self, product):
567
+ body = _("Product %s is not in the current transfer.", product.name)
568
+ return {"message_type": "error", "body": body}
534
569
 
535
570
  def lot_mixed_package_scan_package(self):
536
571
  return {
@@ -982,3 +1017,13 @@ class MessageAction(Component):
982
1017
  "message_type": "error",
983
1018
  "body": _("Unable to find a line with the same product but different lot."),
984
1019
  }
1020
+
1021
+ def reserved_for_other_picking_type(self, picking):
1022
+ body = _("Reserved for %(picking_type)s %(picking_name)s") % {
1023
+ "picking_type": picking.picking_type_id.name,
1024
+ "picking_name": picking.name,
1025
+ }
1026
+ return {
1027
+ "message_type": "error",
1028
+ "body": body,
1029
+ }
@@ -10,7 +10,9 @@ class StockUnreserve(Component):
10
10
  _inherit = "shopfloor.process.action"
11
11
  _usage = "stock.unreserve"
12
12
 
13
- def check_unreserve(self, location, move_lines, product=None, lot=None):
13
+ def check_unreserve(
14
+ self, location, move_lines, product=None, lot=None, allowed_types=None
15
+ ):
14
16
  """Return a message if there is an ongoing operation in the location.
15
17
 
16
18
  It could be a move line with some qty already processed or another
@@ -20,12 +22,17 @@ class StockUnreserve(Component):
20
22
  :param move_lines: move lines to unreserve
21
23
  :param product: optional product to limit the scope in the location
22
24
  """
25
+ if not allowed_types:
26
+ allowed_types = self.env["stock.picking.type"]
23
27
  location_move_lines = self._find_location_all_move_lines(location, product, lot)
24
28
  extra_move_lines = location_move_lines - move_lines
25
29
  if extra_move_lines:
26
- return self.msg_store.picking_already_started_in_location(
27
- extra_move_lines.picking_id
28
- )
30
+ extra_pickings = extra_move_lines.picking_id
31
+ if allowed_types:
32
+ for picking in extra_pickings:
33
+ if picking.picking_type_id not in allowed_types:
34
+ return self.msg_store.reserved_for_other_picking_type(picking)
35
+ return self.msg_store.picking_already_started_in_location(extra_pickings)
29
36
 
30
37
  def unreserve_moves(self, move_lines, picking_types):
31
38
  """Unreserve moves from `move_lines'.
@@ -839,6 +839,20 @@ msgstr ""
839
839
  msgid "No quantity has been processed, unable to complete the transfer."
840
840
  msgstr ""
841
841
 
842
+ #. module: shopfloor
843
+ #. odoo-python
844
+ #: code:addons/shopfloor/actions/message.py:0
845
+ #, python-format
846
+ msgid "No transfer found for %(model_name)s %(record_name)s"
847
+ msgstr ""
848
+
849
+ #. module: shopfloor
850
+ #. odoo-python
851
+ #: code:addons/shopfloor/actions/message.py:0
852
+ #, python-format
853
+ msgid "No transfer found for barcode %s"
854
+ msgstr ""
855
+
842
856
  #. module: shopfloor
843
857
  #. odoo-python
844
858
  #: code:addons/shopfloor/actions/message.py:0
@@ -1047,13 +1061,6 @@ msgstr ""
1047
1061
  msgid "Package {} is not empty."
1048
1062
  msgstr ""
1049
1063
 
1050
- #. module: shopfloor
1051
- #. odoo-python
1052
- #: code:addons/shopfloor/services/checkout.py:0
1053
- #, python-format
1054
- msgid "Package {} is not in the current transfer."
1055
- msgstr ""
1056
-
1057
1064
  #. module: shopfloor
1058
1065
  #: model:ir.model,name:shopfloor.model_stock_quant_package
1059
1066
  msgid "Packages"
@@ -1209,16 +1216,16 @@ msgid ""
1209
1216
  " %(picking_name)s."
1210
1217
  msgstr ""
1211
1218
 
1212
- #. module: shopfloor
1213
- #: model:ir.model,name:shopfloor.model_stock_move_line
1214
- msgid "Product Moves (Stock Move Line)"
1215
- msgstr ""
1216
-
1217
1219
  #. module: shopfloor
1218
1220
  #. odoo-python
1219
1221
  #: code:addons/shopfloor/actions/message.py:0
1220
1222
  #, python-format
1221
- msgid "Product is not in the current transfer."
1223
+ msgid "Product %s is not in the current transfer."
1224
+ msgstr ""
1225
+
1226
+ #. module: shopfloor
1227
+ #: model:ir.model,name:shopfloor.model_stock_move_line
1228
+ msgid "Product Moves (Stock Move Line)"
1222
1229
  msgstr ""
1223
1230
 
1224
1231
  #. module: shopfloor
@@ -1289,6 +1296,13 @@ msgstr ""
1289
1296
  msgid "Reserved Move Line"
1290
1297
  msgstr ""
1291
1298
 
1299
+ #. module: shopfloor
1300
+ #. odoo-python
1301
+ #: code:addons/shopfloor/actions/message.py:0
1302
+ #, python-format
1303
+ msgid "Reserved for %(picking_type)s %(picking_name)s"
1304
+ msgstr ""
1305
+
1292
1306
  #. module: shopfloor
1293
1307
  #. odoo-python
1294
1308
  #: code:addons/shopfloor/actions/message.py:0
@@ -1890,6 +1904,14 @@ msgstr ""
1890
1904
  msgid "Transfer"
1891
1905
  msgstr ""
1892
1906
 
1907
+ #. module: shopfloor
1908
+ #. odoo-python
1909
+ #: code:addons/shopfloor/actions/message.py:0
1910
+ #, python-format
1911
+ msgid ""
1912
+ "Transfer has been canceled. This cannot be processed using this scenario"
1913
+ msgstr ""
1914
+
1893
1915
  #. module: shopfloor
1894
1916
  #. odoo-python
1895
1917
  #: code:addons/shopfloor/actions/message.py:0
@@ -214,25 +214,29 @@ class Checkout(Component):
214
214
  * summary: stock.picking is selected and all its lines have a
215
215
  destination pack set
216
216
  """
217
- search_result = self._scan_document_find(barcode)
218
- result_handler = getattr(self, "_select_document_from_" + search_result.type)
219
- return result_handler(search_result.record)
217
+ handlers = {
218
+ "picking": self._select_document_from_picking,
219
+ "location": self._select_document_from_location,
220
+ "package": self._select_document_from_package,
221
+ "packaging": self._select_document_from_packaging,
222
+ "product": self._select_document_from_product,
223
+ "none": self._select_document_from_none,
224
+ }
225
+ if self.work.menu.scan_location_or_pack_first:
226
+ handlers.pop("product")
227
+ search_result = self._scan_document_find(barcode, handlers.keys())
228
+ # Keep track of what has been initially scan, and forward it through kwargs
229
+ kwargs = {
230
+ "barcode": barcode,
231
+ "current_state": "select_document",
232
+ "scanned_record": search_result.record,
233
+ }
234
+ handler = handlers.get(search_result.type, self._select_document_from_none)
235
+ return handler(search_result.record, **kwargs)
220
236
 
221
- def _scan_document_find(self, barcode, search_types=None):
237
+ def _scan_document_find(self, barcode, search_types):
222
238
  search = self._actions_for("search")
223
- search_types = (
224
- "picking",
225
- "location",
226
- "package",
227
- "packaging",
228
- ) + (("product",) if not self.work.menu.scan_location_or_pack_first else ())
229
- return search.find(
230
- barcode,
231
- types=search_types,
232
- )
233
-
234
- def _select_document_from_picking(self, picking, **kw):
235
- return self._select_picking(picking, "select_document")
239
+ return search.find(barcode, types=search_types)
236
240
 
237
241
  def _select_document_from_location(self, location, **kw):
238
242
  if not self.is_src_location_valid(location):
@@ -251,7 +255,9 @@ class Checkout(Component):
251
255
  ),
252
256
  }
253
257
  )
254
- return self._select_picking(pickings, "select_document")
258
+ # Keep track of what has been initially scan, and forward it through kwargs
259
+ kwargs = {**kw, "current_state": "select_document"}
260
+ return self._select_document_from_picking(pickings, **kwargs)
255
261
 
256
262
  def _select_document_from_package(self, package, **kw):
257
263
  pickings = package.move_line_ids.filtered(
@@ -260,14 +266,15 @@ class Checkout(Component):
260
266
  if len(pickings) > 1:
261
267
  # Filter only if we find several pickings to narrow the
262
268
  # selection to one of the good type. If we have one picking
263
- # of the wrong type, it will be caught in _select_picking
269
+ # of the wrong type, it will be caught in _select_document_from_picking
264
270
  # with the proper error message.
265
271
  # Side note: rather unlikely to have several transfers ready
266
272
  # and moving the same things
267
273
  pickings = pickings.filtered(
268
274
  lambda p: p.picking_type_id in self.picking_types
269
275
  )
270
- return self._select_picking(fields.first(pickings), "select_document")
276
+ kwargs = {**kw, "current_state": "select_document"}
277
+ return self._select_document_from_picking(fields.first(pickings), **kwargs)
271
278
 
272
279
  def _select_document_from_product(self, product, line_domain=None, **kw):
273
280
  line_domain = line_domain or []
@@ -287,7 +294,8 @@ class Checkout(Component):
287
294
  order="priority desc, scheduled_date asc, id desc",
288
295
  limit=1,
289
296
  )
290
- return self._select_picking(picking, "select_document")
297
+ kwargs = {**kw, "current_state": "select_document"}
298
+ return self._select_document_from_picking(picking, **kwargs)
291
299
 
292
300
  def _select_document_from_packaging(self, packaging, **kw):
293
301
  # And retrieve its product
@@ -298,35 +306,33 @@ class Checkout(Component):
298
306
  line_domain = [("reserved_uom_qty", ">=", packaging.qty)]
299
307
  return self._select_document_from_product(product, line_domain=line_domain)
300
308
 
301
- def _select_document_from_none(self, picking, **kw):
309
+ def _select_document_from_none(self, *args, barcode=None, **kwargs):
302
310
  """Handle result when no record is found."""
303
- return self._select_picking(picking, "select_document")
311
+ return self._response_for_select_document(
312
+ message=self.msg_store.transfer_not_found_for_barcode(barcode)
313
+ )
304
314
 
305
- def _select_picking(self, picking, state_for_error):
315
+ def _select_document_from_picking(
316
+ self, picking, current_state=None, barcode=None, **kwargs
317
+ ):
318
+ # Get origin record to give more context to the user when raising an error
319
+ # as we got picking from product/package/packaging/...
320
+ scanned_record = kwargs.get("scanned_record")
306
321
  if not picking:
307
- if state_for_error == "manual_selection":
308
- return self._response_for_manual_selection(
309
- message=self.msg_store.stock_picking_not_found()
310
- )
311
- return self._response_for_select_document(
312
- message=self.msg_store.barcode_not_found()
313
- )
322
+ message = self.msg_store.transfer_not_found_for_record(scanned_record)
323
+ if current_state == "manual_selection":
324
+ return self._response_for_manual_selection(message=message)
325
+ return self._response_for_select_document(message=message)
314
326
  if picking.picking_type_id not in self.picking_types:
315
- if state_for_error == "manual_selection":
316
- return self._response_for_manual_selection(
317
- message=self.msg_store.cannot_move_something_in_picking_type()
318
- )
319
- return self._response_for_select_document(
320
- message=self.msg_store.cannot_move_something_in_picking_type()
321
- )
327
+ message = self.msg_store.reserved_for_other_picking_type(picking)
328
+ if current_state == "manual_selection":
329
+ return self._response_for_manual_selection(message=message)
330
+ return self._response_for_select_document(message=message)
322
331
  if picking.state != "assigned":
323
- if state_for_error == "manual_selection":
324
- return self._response_for_manual_selection(
325
- message=self.msg_store.stock_picking_not_available(picking)
326
- )
327
- return self._response_for_select_document(
328
- message=self.msg_store.stock_picking_not_available(picking)
329
- )
332
+ message = self.msg_store.stock_picking_not_available(picking)
333
+ if current_state == "manual_selection":
334
+ return self._response_for_manual_selection(message=message)
335
+ return self._response_for_select_document(message=message)
330
336
  return self._response_for_select_line(picking)
331
337
 
332
338
  def _data_for_move_lines(self, lines, **kw):
@@ -402,10 +408,17 @@ class Checkout(Component):
402
408
  lines
403
409
  """
404
410
  picking = self.env["stock.picking"].browse(picking_id)
405
- message = self._check_picking_status(picking)
411
+ message = self._check_picking_processible(picking)
406
412
  if message:
407
413
  return self._response_for_manual_selection(message=message)
408
- return self._select_picking(picking, "manual_selection")
414
+ # Because _select_document_from_picking expects some context
415
+ # to give meaningful infos to the user, add some here.
416
+ kwargs = {
417
+ "current_state": "manual_selection",
418
+ "barcode": picking.name,
419
+ "scanned_record": picking,
420
+ }
421
+ return self._select_document_from_picking(picking, **kwargs)
409
422
 
410
423
  def _select_lines(self, lines, prefill_qty=0, related_lines=None):
411
424
  for i, line in enumerate(lines):
@@ -451,7 +464,7 @@ class Checkout(Component):
451
464
  screen to change the qty done and destination pack if needed
452
465
  """
453
466
  picking = self.env["stock.picking"].browse(picking_id)
454
- message = self._check_picking_status(picking)
467
+ message = self._check_picking_processible(picking)
455
468
  if message:
456
469
  return self._response_for_select_document(message=message)
457
470
 
@@ -460,21 +473,31 @@ class Checkout(Component):
460
473
  return self._response_for_summary(picking)
461
474
 
462
475
  # Search of the destination package
463
- search_result = self._scan_line_find(picking, barcode)
464
- result_handler = getattr(self, "_select_lines_from_" + search_result.type)
465
- kw = {"confirm_pack_all": confirm_pack_all, "confirm_lot": confirm_lot}
466
- return result_handler(picking, selection_lines, search_result.record, **kw)
476
+ handlers = {
477
+ "package": self._select_lines_from_package,
478
+ "product": self._select_lines_from_product,
479
+ "packaging": self._select_lines_from_packaging,
480
+ "lot": self._select_lines_from_lot,
481
+ "serial": self._select_lines_from_serial,
482
+ "delivery_packaging": self._select_lines_from_delivery_packaging,
483
+ "none": self._select_lines_from_none,
484
+ }
485
+ search_result = self._scan_line_find(picking, barcode, handlers.keys())
486
+ # setting scanned record as kwarg in order to make better logs.
487
+ # The reason for this is that from a product we might select various records
488
+ # and lose track of what was initially scanned. This forces us to display
489
+ # standard messages that might have no meaning for the user.
490
+ kwargs = {
491
+ "confirm_pack_all": confirm_pack_all,
492
+ "confirm_lot": confirm_lot,
493
+ "scanned_record": search_result.record,
494
+ "barcode": barcode,
495
+ }
496
+ handler = handlers.get(search_result.type, self._select_lines_from_none)
497
+ return handler(picking, selection_lines, search_result.record, **kwargs)
467
498
 
468
- def _scan_line_find(self, picking, barcode, search_types=None):
499
+ def _scan_line_find(self, picking, barcode, search_types):
469
500
  search = self._actions_for("search")
470
- search_types = (
471
- "package",
472
- "product",
473
- "packaging",
474
- "lot",
475
- "serial",
476
- "delivery_packaging",
477
- )
478
501
  return search.find(
479
502
  barcode,
480
503
  types=search_types,
@@ -497,15 +520,14 @@ class Checkout(Component):
497
520
  lambda l: l.package_id == package and not l.shopfloor_checkout_done
498
521
  )
499
522
  if not lines:
500
- return self._response_for_select_line(
501
- picking,
502
- message={
503
- "message_type": "error",
504
- "body": _("Package {} is not in the current transfer.").format(
505
- package.name
506
- ),
507
- },
508
- )
523
+ # No line for scanned package in selected picking
524
+ # Check if there's any picking reserving this product.
525
+ return_picking = self._get_pickings_for_package(package, limit=1)
526
+ if return_picking:
527
+ message = self.msg_store.reserved_for_other_picking_type(return_picking)
528
+ else:
529
+ message = self.msg_store.package_not_found_in_picking(package, picking)
530
+ return self._response_for_select_line(picking, message=message)
509
531
  self._select_lines(lines, prefill_qty=prefill_qty)
510
532
  if self.work.menu.no_prefill_qty:
511
533
  lines = picking.move_line_ids
@@ -522,9 +544,12 @@ class Checkout(Component):
522
544
 
523
545
  lines = selection_lines.filtered(lambda l: l.product_id == product)
524
546
  if not lines:
525
- return self._response_for_select_line(
526
- picking, message=self.msg_store.product_not_found_in_current_picking()
527
- )
547
+ return_picking = self._get_pickings_for_product(product, limit=1)
548
+ if return_picking:
549
+ message = self.msg_store.reserved_for_other_picking_type(return_picking)
550
+ else:
551
+ message = self.msg_store.product_not_found_in_current_picking(product)
552
+ return self._response_for_select_line(picking, message=message)
528
553
 
529
554
  # When products are as units outside of packages, we can select them for
530
555
  # packing, but if they are in a package, we want the user to scan the packages.
@@ -774,7 +799,7 @@ class Checkout(Component):
774
799
  assert package_id or move_line_id
775
800
 
776
801
  picking = self.env["stock.picking"].browse(picking_id)
777
- message = self._check_picking_status(picking)
802
+ message = self._check_picking_processible(picking)
778
803
  if message:
779
804
  return self._response_for_select_document(message=message)
780
805
 
@@ -793,7 +818,7 @@ class Checkout(Component):
793
818
  self, picking_id, selected_line_ids, move_line_ids, quantity_func
794
819
  ):
795
820
  picking = self.env["stock.picking"].browse(picking_id)
796
- message = self._check_picking_status(picking)
821
+ message = self._check_picking_processible(picking)
797
822
  if message:
798
823
  return self._response_for_select_document(message=message)
799
824
 
@@ -1031,25 +1056,28 @@ class Checkout(Component):
1031
1056
  to close the stock picking
1032
1057
  """
1033
1058
  picking = self.env["stock.picking"].browse(picking_id)
1034
- message = self._check_picking_status(picking)
1059
+ message = self._check_picking_processible(picking)
1035
1060
  if message:
1036
1061
  return self._response_for_select_document(message=message)
1037
1062
 
1038
1063
  selected_lines = self.env["stock.move.line"].browse(selected_line_ids).exists()
1039
- search_result = self._scan_package_find(picking, barcode)
1040
- message = self._check_scan_package_find(picking, search_result)
1041
- if message:
1042
- return self._response_for_select_package(
1043
- picking,
1044
- selected_lines,
1045
- message=message,
1046
- )
1047
- result_handler = getattr(
1048
- self, "_scan_package_action_from_" + search_result.type
1049
- )
1050
- return result_handler(picking, selected_lines, search_result.record)
1064
+ handlers = {
1065
+ "package": self._scan_package_action_from_package,
1066
+ "product": self._scan_package_action_from_product,
1067
+ "packaging": self._scan_package_action_from_packaging,
1068
+ "lot": self._scan_package_action_from_lot,
1069
+ "serial": self._scan_package_action_from_serial,
1070
+ "delivery_packaging": self._scan_package_action_from_delivery_packaging,
1071
+ }
1072
+ search_result = self._scan_package_find(picking, barcode, handlers.keys())
1073
+ handler = handlers.get(search_result.type, self._scan_package_action_from_none)
1074
+ kwargs = {
1075
+ "barcode": barcode,
1076
+ "scanned_record": search_result.record,
1077
+ }
1078
+ return handler(picking, selected_lines, search_result.record, **kwargs)
1051
1079
 
1052
- def _scan_package_find(self, picking, barcode, search_types=None):
1080
+ def _scan_package_find(self, picking, barcode, search_types):
1053
1081
  search = self._actions_for("search")
1054
1082
  search_types = (
1055
1083
  "package",
@@ -1068,10 +1096,6 @@ class Checkout(Component):
1068
1096
  ),
1069
1097
  )
1070
1098
 
1071
- def _check_scan_package_find(self, picking, search_result):
1072
- # Used by inheriting modules
1073
- return False
1074
-
1075
1099
  def _find_line_to_increment(self, product_lines):
1076
1100
  """Find which line should have its qty incremented.
1077
1101
 
@@ -1186,7 +1210,7 @@ class Checkout(Component):
1186
1210
  * select_package: when no delivery packaging is available
1187
1211
  """
1188
1212
  picking = self.env["stock.picking"].browse(picking_id)
1189
- message = self._check_picking_status(picking)
1213
+ message = self._check_picking_processible(picking)
1190
1214
  if message:
1191
1215
  return self._response_for_select_document(message=message)
1192
1216
  selected_lines = self.env["stock.move.line"].browse(selected_line_ids).exists()
@@ -1216,7 +1240,7 @@ class Checkout(Component):
1216
1240
  * select_line: goes back to selection of lines to work on next lines
1217
1241
  """
1218
1242
  picking = self.env["stock.picking"].browse(picking_id)
1219
- message = self._check_picking_status(picking)
1243
+ message = self._check_picking_processible(picking)
1220
1244
  if message:
1221
1245
  return self._response_for_select_document(message=message)
1222
1246
  packaging = None
@@ -1238,7 +1262,7 @@ class Checkout(Component):
1238
1262
  if self.options.get("checkout__disable_no_package"):
1239
1263
  raise BadRequest("`checkout.no_package` endpoint is not enabled")
1240
1264
  picking = self.env["stock.picking"].browse(picking_id)
1241
- message = self._check_picking_status(picking)
1265
+ message = self._check_picking_processible(picking)
1242
1266
  if message:
1243
1267
  return self._response_for_select_document(message=message)
1244
1268
  selected_lines = self.env["stock.move.line"].browse(selected_line_ids).exists()
@@ -1270,7 +1294,7 @@ class Checkout(Component):
1270
1294
  * select_package: when no package is available
1271
1295
  """
1272
1296
  picking = self.env["stock.picking"].browse(picking_id)
1273
- message = self._check_picking_status(picking)
1297
+ message = self._check_picking_processible(picking)
1274
1298
  if message:
1275
1299
  return self._response_for_select_document(message=message)
1276
1300
  lines = self.env["stock.move.line"].browse(selected_line_ids).exists()
@@ -1320,7 +1344,7 @@ class Checkout(Component):
1320
1344
  * summary: all lines are put in packages
1321
1345
  """
1322
1346
  picking = self.env["stock.picking"].browse(picking_id)
1323
- message = self._check_picking_status(picking)
1347
+ message = self._check_picking_processible(picking)
1324
1348
  if message:
1325
1349
  return self._response_for_select_document(message=message)
1326
1350
  lines = self.env["stock.move.line"].browse(selected_line_ids).exists()
@@ -1347,7 +1371,7 @@ class Checkout(Component):
1347
1371
  * summary: all lines are put in packages
1348
1372
  """
1349
1373
  picking = self.env["stock.picking"].browse(picking_id)
1350
- message = self._check_picking_status(picking)
1374
+ message = self._check_picking_processible(picking)
1351
1375
  if message:
1352
1376
  return self._response_for_select_document(message=message)
1353
1377
  lines = self.env["stock.move.line"].browse(selected_line_ids).exists()
@@ -1374,7 +1398,7 @@ class Checkout(Component):
1374
1398
  * summary
1375
1399
  """
1376
1400
  picking = self.env["stock.picking"].browse(picking_id)
1377
- message = self._check_picking_status(picking)
1401
+ message = self._check_picking_processible(picking)
1378
1402
  if message:
1379
1403
  return self._response_for_select_document(message=message)
1380
1404
  return self._response_for_summary(picking)
@@ -1393,7 +1417,7 @@ class Checkout(Component):
1393
1417
  * summary: if the package_id no longer exists
1394
1418
  """
1395
1419
  picking = self.env["stock.picking"].browse(picking_id)
1396
- message = self._check_picking_status(picking)
1420
+ message = self._check_picking_processible(picking)
1397
1421
  if message:
1398
1422
  return self._response_for_select_document(message=message)
1399
1423
  package = self.env["stock.quant.package"].browse(package_id).exists()
@@ -1408,7 +1432,7 @@ class Checkout(Component):
1408
1432
  * summary
1409
1433
  """
1410
1434
  picking = self.env["stock.picking"].browse(picking_id)
1411
- message = self._check_picking_status(picking)
1435
+ message = self._check_picking_processible(picking)
1412
1436
  if message:
1413
1437
  return self._response_for_select_document(message=message)
1414
1438
 
@@ -1445,7 +1469,7 @@ class Checkout(Component):
1445
1469
  * select_line: when package or line has been canceled
1446
1470
  """
1447
1471
  picking = self.env["stock.picking"].browse(picking_id)
1448
- message = self._check_picking_status(picking)
1472
+ message = self._check_picking_processible(picking)
1449
1473
  if message:
1450
1474
  return self._response_for_select_document(message=message)
1451
1475
 
@@ -1490,7 +1514,7 @@ class Checkout(Component):
1490
1514
  * select_child_location: there are child destination locations
1491
1515
  """
1492
1516
  picking = self.env["stock.picking"].browse(picking_id)
1493
- message = self._check_picking_status(picking)
1517
+ message = self._check_picking_processible(picking)
1494
1518
  if message:
1495
1519
  return self._response_for_select_document(message=message)
1496
1520
  lines = picking.move_line_ids
@@ -1533,7 +1557,7 @@ class Checkout(Component):
1533
1557
  * select_child_location: in case of error
1534
1558
  """
1535
1559
  picking = self.env["stock.picking"].browse(picking_id)
1536
- message = self._check_picking_status(picking)
1560
+ message = self._check_picking_processible(picking)
1537
1561
  if message:
1538
1562
  return self._response_for_select_document(message=message)
1539
1563
  search = self._actions_for("search")