odoo-addon-shopfloor 16.0.2.6.0__py3-none-any.whl → 16.0.2.7.0.1__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.
- odoo/addons/shopfloor/README.rst +1 -1
- odoo/addons/shopfloor/__manifest__.py +1 -1
- odoo/addons/shopfloor/actions/message.py +50 -5
- odoo/addons/shopfloor/actions/stock_unreserve.py +11 -4
- odoo/addons/shopfloor/i18n/ca.po +35 -13
- odoo/addons/shopfloor/i18n/de.po +35 -13
- odoo/addons/shopfloor/i18n/es_AR.po +44 -14
- odoo/addons/shopfloor/i18n/it.po +44 -14
- odoo/addons/shopfloor/i18n/pt_BR.po +35 -13
- odoo/addons/shopfloor/i18n/shopfloor.pot +35 -13
- odoo/addons/shopfloor/services/checkout.py +129 -105
- odoo/addons/shopfloor/services/delivery.py +89 -64
- odoo/addons/shopfloor/services/location_content_transfer.py +34 -18
- odoo/addons/shopfloor/services/service.py +52 -15
- odoo/addons/shopfloor/static/description/index.html +1 -1
- odoo/addons/shopfloor/tests/test_checkout_scan.py +11 -3
- odoo/addons/shopfloor/tests/test_checkout_scan_line.py +35 -4
- odoo/addons/shopfloor/tests/test_checkout_select.py +3 -1
- odoo/addons/shopfloor/tests/test_delivery_scan_deliver.py +143 -1
- odoo/addons/shopfloor/tests/test_delivery_set_qty_done_line.py +1 -1
- odoo/addons/shopfloor/tests/test_delivery_set_qty_done_pack.py +1 -1
- odoo/addons/shopfloor/tests/test_location_content_transfer_start.py +24 -1
- {odoo_addon_shopfloor-16.0.2.6.0.dist-info → odoo_addon_shopfloor-16.0.2.7.0.1.dist-info}/METADATA +2 -2
- {odoo_addon_shopfloor-16.0.2.6.0.dist-info → odoo_addon_shopfloor-16.0.2.7.0.1.dist-info}/RECORD +26 -26
- {odoo_addon_shopfloor-16.0.2.6.0.dist-info → odoo_addon_shopfloor-16.0.2.7.0.1.dist-info}/WHEEL +0 -0
- {odoo_addon_shopfloor-16.0.2.6.0.dist-info → odoo_addon_shopfloor-16.0.2.7.0.1.dist-info}/top_level.txt +0 -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
|
-
|
218
|
-
|
219
|
-
|
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
|
237
|
+
def _scan_document_find(self, barcode, search_types):
|
222
238
|
search = self._actions_for("search")
|
223
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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,
|
309
|
+
def _select_document_from_none(self, *args, barcode=None, **kwargs):
|
302
310
|
"""Handle result when no record is found."""
|
303
|
-
return self.
|
311
|
+
return self._response_for_select_document(
|
312
|
+
message=self.msg_store.transfer_not_found_for_barcode(barcode)
|
313
|
+
)
|
304
314
|
|
305
|
-
def
|
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
|
-
|
308
|
-
|
309
|
-
|
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
|
-
|
316
|
-
|
317
|
-
|
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
|
-
|
324
|
-
|
325
|
-
|
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.
|
411
|
+
message = self._check_picking_processible(picking)
|
406
412
|
if message:
|
407
413
|
return self._response_for_manual_selection(message=message)
|
408
|
-
|
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.
|
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
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
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
|
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
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
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
|
-
|
526
|
-
|
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.
|
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.
|
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.
|
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
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
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
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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")
|