odoo-addon-shopfloor 16.0.1.0.0.25__py3-none-any.whl → 16.0.2.1.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/data.py +69 -34
- odoo/addons/shopfloor/actions/data_detail.py +20 -0
- odoo/addons/shopfloor/actions/message.py +94 -2
- odoo/addons/shopfloor/actions/move_line_search.py +2 -2
- odoo/addons/shopfloor/actions/packaging.py +10 -0
- odoo/addons/shopfloor/actions/schema.py +11 -0
- odoo/addons/shopfloor/actions/schema_detail.py +14 -8
- odoo/addons/shopfloor/actions/search.py +9 -6
- odoo/addons/shopfloor/components/scan_handler_product.py +2 -0
- odoo/addons/shopfloor/data/shopfloor_scenario_data.xml +4 -2
- odoo/addons/shopfloor/docs/checkout_diag_seq.plantuml +19 -5
- odoo/addons/shopfloor/docs/checkout_diag_seq.png +0 -0
- odoo/addons/shopfloor/docs/single_pack_transfer_diag_seq.plantuml +4 -4
- odoo/addons/shopfloor/docs/single_pack_transfer_diag_seq.png +0 -0
- odoo/addons/shopfloor/i18n/ca.po +373 -143
- odoo/addons/shopfloor/i18n/de.po +357 -145
- odoo/addons/shopfloor/i18n/es_AR.po +489 -174
- odoo/addons/shopfloor/i18n/it.po +642 -252
- odoo/addons/shopfloor/i18n/pt_BR.po +357 -145
- odoo/addons/shopfloor/i18n/shopfloor.pot +133 -8
- odoo/addons/shopfloor/migrations/16.0.2.0.0/post-migration.py +43 -0
- odoo/addons/shopfloor/models/shopfloor_menu.py +29 -5
- odoo/addons/shopfloor/models/stock_move_line.py +3 -0
- odoo/addons/shopfloor/models/stock_picking.py +11 -0
- odoo/addons/shopfloor/services/checkout.py +216 -61
- odoo/addons/shopfloor/services/cluster_picking.py +33 -18
- odoo/addons/shopfloor/services/delivery.py +25 -7
- odoo/addons/shopfloor/services/location_content_transfer.py +42 -28
- odoo/addons/shopfloor/services/single_pack_transfer.py +36 -13
- odoo/addons/shopfloor/services/zone_picking.py +187 -67
- odoo/addons/shopfloor/static/description/index.html +1 -1
- odoo/addons/shopfloor/tests/__init__.py +2 -0
- odoo/addons/shopfloor/tests/common.py +3 -1
- odoo/addons/shopfloor/tests/test_actions_data.py +46 -7
- odoo/addons/shopfloor/tests/test_actions_data_base.py +15 -0
- odoo/addons/shopfloor/tests/test_actions_data_detail.py +30 -8
- odoo/addons/shopfloor/tests/test_actions_packaging.py +43 -0
- odoo/addons/shopfloor/tests/test_checkout_base.py +15 -5
- odoo/addons/shopfloor/tests/test_checkout_done.py +40 -5
- odoo/addons/shopfloor/tests/test_checkout_list_delivery_packaging.py +1 -0
- odoo/addons/shopfloor/tests/test_checkout_list_package.py +3 -1
- odoo/addons/shopfloor/tests/test_checkout_scan.py +19 -0
- odoo/addons/shopfloor/tests/test_checkout_scan_dest_location.py +99 -0
- odoo/addons/shopfloor/tests/test_checkout_scan_line.py +3 -2
- odoo/addons/shopfloor/tests/test_checkout_scan_line_no_prefill_qty.py +48 -0
- odoo/addons/shopfloor/tests/test_checkout_scan_package_action.py +26 -0
- odoo/addons/shopfloor/tests/test_checkout_scan_package_action_no_prefill_qty.py +16 -0
- odoo/addons/shopfloor/tests/test_checkout_select_package_base.py +4 -1
- odoo/addons/shopfloor/tests/test_checkout_summary.py +1 -1
- odoo/addons/shopfloor/tests/test_cluster_picking_unload.py +37 -8
- odoo/addons/shopfloor/tests/test_delivery_list_stock_picking.py +5 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_base.py +4 -4
- odoo/addons/shopfloor/tests/test_location_content_transfer_set_destination_all.py +24 -2
- odoo/addons/shopfloor/tests/test_location_content_transfer_set_destination_package_or_line.py +6 -4
- odoo/addons/shopfloor/tests/test_location_content_transfer_single.py +45 -0
- odoo/addons/shopfloor/tests/test_scan_anything.py +7 -0
- odoo/addons/shopfloor/tests/test_single_pack_transfer.py +59 -8
- odoo/addons/shopfloor/tests/test_zone_picking_base.py +36 -10
- odoo/addons/shopfloor/tests/test_zone_picking_change_pack_lot.py +2 -0
- odoo/addons/shopfloor/tests/test_zone_picking_complete_mix_pack_flux.py +59 -0
- odoo/addons/shopfloor/tests/test_zone_picking_select_line.py +33 -2
- odoo/addons/shopfloor/tests/test_zone_picking_select_line_first_scan_location.py +8 -3
- odoo/addons/shopfloor/tests/test_zone_picking_select_line_no_prefill_qty.py +19 -2
- odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination.py +88 -19
- odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination_package_not_allowed.py +94 -0
- odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination_pick_pack.py +1 -5
- odoo/addons/shopfloor/tests/test_zone_picking_start.py +4 -4
- odoo/addons/shopfloor/tests/test_zone_picking_unload_all.py +1 -1
- odoo/addons/shopfloor/tests/test_zone_picking_unload_set_destination.py +4 -4
- odoo/addons/shopfloor/views/shopfloor_menu.xml +30 -0
- {odoo_addon_shopfloor-16.0.1.0.0.25.dist-info → odoo_addon_shopfloor-16.0.2.1.0.1.dist-info}/METADATA +2 -2
- {odoo_addon_shopfloor-16.0.1.0.0.25.dist-info → odoo_addon_shopfloor-16.0.2.1.0.1.dist-info}/RECORD +76 -71
- {odoo_addon_shopfloor-16.0.1.0.0.25.dist-info → odoo_addon_shopfloor-16.0.2.1.0.1.dist-info}/WHEEL +0 -0
- {odoo_addon_shopfloor-16.0.1.0.0.25.dist-info → odoo_addon_shopfloor-16.0.2.1.0.1.dist-info}/top_level.txt +0 -0
@@ -20,6 +20,16 @@ class CheckoutScanLineNoPrefillQtyCase(CheckoutScanLineCaseBase):
|
|
20
20
|
cls._fill_stock_for_moves(move, in_lot=True)
|
21
21
|
cls.picking.action_assign()
|
22
22
|
cls.move_lines = cls.picking.move_line_ids
|
23
|
+
cls.delivery_packaging = (
|
24
|
+
cls.env["stock.package.type"]
|
25
|
+
.sudo()
|
26
|
+
.create(
|
27
|
+
{
|
28
|
+
"name": "DelivBox",
|
29
|
+
"barcode": "DelivBox",
|
30
|
+
}
|
31
|
+
)
|
32
|
+
)
|
23
33
|
|
24
34
|
def _assert_quantity_done(self, barcode, selected_lines, qties):
|
25
35
|
picking = selected_lines.mapped("picking_id")
|
@@ -89,3 +99,41 @@ class CheckoutScanLineNoPrefillQtyCase(CheckoutScanLineCaseBase):
|
|
89
99
|
# should be the packaging qty, if a packaging is scanned
|
90
100
|
qties = [1.0] * len(first_line)
|
91
101
|
self._assert_quantity_done(lot.name, first_line, qties)
|
102
|
+
|
103
|
+
def test_scan_line_delivery_package_with_no_prefill_qty(self):
|
104
|
+
# Scan a delivery package
|
105
|
+
response = self.service.dispatch(
|
106
|
+
"scan_line",
|
107
|
+
params={
|
108
|
+
"picking_id": self.picking.id,
|
109
|
+
"barcode": self.delivery_packaging.barcode,
|
110
|
+
},
|
111
|
+
)
|
112
|
+
# Back to select_line asking to set some quantities
|
113
|
+
self.assertEqual(response["next_state"], "select_line")
|
114
|
+
self.assertEqual(
|
115
|
+
response["message"],
|
116
|
+
self.msg_store.no_lines_to_process_set_quantities(),
|
117
|
+
)
|
118
|
+
# Scan a product B to set some quantities
|
119
|
+
self.service.dispatch(
|
120
|
+
"scan_line",
|
121
|
+
params={
|
122
|
+
"picking_id": self.picking.id,
|
123
|
+
"barcode": self.product_b.barcode,
|
124
|
+
},
|
125
|
+
)
|
126
|
+
line_product_b = self.move_lines.filtered(
|
127
|
+
lambda line: line.product_id == self.product_b
|
128
|
+
)
|
129
|
+
self.assertFalse(line_product_b.result_package_id)
|
130
|
+
# Scan the delivery package again
|
131
|
+
response = self.service.dispatch(
|
132
|
+
"scan_line",
|
133
|
+
params={
|
134
|
+
"picking_id": self.picking.id,
|
135
|
+
"barcode": self.delivery_packaging.barcode,
|
136
|
+
},
|
137
|
+
)
|
138
|
+
# Check the line has been packed
|
139
|
+
self.assertTrue(line_product_b.result_package_id)
|
@@ -175,6 +175,7 @@ class CheckoutScanPackageActionCase(CheckoutCommonCase, CheckoutSelectPackageMix
|
|
175
175
|
"no_package_enabled": not self.service.options.get(
|
176
176
|
"checkout__disable_no_package"
|
177
177
|
),
|
178
|
+
"package_allowed": True,
|
178
179
|
},
|
179
180
|
message=self.service.msg_store.dest_package_not_valid(pack1),
|
180
181
|
)
|
@@ -449,3 +450,28 @@ class CheckoutScanPackageActionCase(CheckoutCommonCase, CheckoutSelectPackageMix
|
|
449
450
|
selected_line,
|
450
451
|
message={"message_type": "error", "body": "Barcode not found"},
|
451
452
|
)
|
453
|
+
|
454
|
+
def test_put_in_pack(self):
|
455
|
+
picking = self._create_picking(
|
456
|
+
lines=[(self.product_a, 10), (self.product_b, 20)]
|
457
|
+
)
|
458
|
+
self._fill_stock_for_moves(picking.move_ids)
|
459
|
+
picking.action_assign()
|
460
|
+
|
461
|
+
# Test that the move lines are marked as 'shopfloor_checkout_done'
|
462
|
+
# when putting them in a pack in the backend.
|
463
|
+
picking._put_in_pack(picking.move_line_ids)
|
464
|
+
self.assertTrue(
|
465
|
+
all(line.shopfloor_checkout_done for line in picking.move_line_ids)
|
466
|
+
)
|
467
|
+
|
468
|
+
# Check that we return those lines to the frontend.
|
469
|
+
res = self.service.dispatch(
|
470
|
+
"summary",
|
471
|
+
params={
|
472
|
+
"picking_id": picking.id,
|
473
|
+
},
|
474
|
+
)
|
475
|
+
returned_lines = res["data"]["summary"]["picking"]["move_lines"]
|
476
|
+
expected_line_ids = [line["id"] for line in returned_lines]
|
477
|
+
self.assertEqual(expected_line_ids, picking.move_line_ids.ids)
|
@@ -40,6 +40,8 @@ class CheckoutScanPackageActionCaseNoPrefillQty(
|
|
40
40
|
"""Scan a product which is present in two lines.
|
41
41
|
|
42
42
|
Only one line should have its quantity incremented.
|
43
|
+
If one line has been fully processed,
|
44
|
+
then the second line will have its quantity incremented.
|
43
45
|
|
44
46
|
"""
|
45
47
|
picking = self._create_picking(
|
@@ -64,6 +66,20 @@ class CheckoutScanPackageActionCaseNoPrefillQty(
|
|
64
66
|
{move_lines[0]: 1, move_lines[1]: 0},
|
65
67
|
)
|
66
68
|
|
69
|
+
# First line is fully processed,
|
70
|
+
# so we expect the second line to be incremented.
|
71
|
+
move_lines[0].qty_done = 3.0
|
72
|
+
self.service.dispatch(
|
73
|
+
"scan_package_action",
|
74
|
+
params={
|
75
|
+
"picking_id": picking.id,
|
76
|
+
"selected_line_ids": move_lines.ids,
|
77
|
+
"barcode": self.product_a.barcode,
|
78
|
+
},
|
79
|
+
)
|
80
|
+
self.assertEqual(move_lines[0].qty_done, 3.0)
|
81
|
+
self.assertEqual(move_lines[1].qty_done, 1.0)
|
82
|
+
|
67
83
|
def test_scan_package_action_scan_lot_to_increment_qty(self):
|
68
84
|
""" """
|
69
85
|
picking = self._create_picking(lines=[(self.product_a, 3)])
|
@@ -10,6 +10,7 @@ class CheckoutSelectPackageMixin:
|
|
10
10
|
message=None,
|
11
11
|
packing_info="",
|
12
12
|
no_package_enabled=True,
|
13
|
+
package_allowed=True,
|
13
14
|
):
|
14
15
|
picking = selected_lines.mapped("picking_id")
|
15
16
|
self.assert_response(
|
@@ -22,6 +23,7 @@ class CheckoutSelectPackageMixin:
|
|
22
23
|
"picking": self._picking_summary_data(picking),
|
23
24
|
"packing_info": packing_info,
|
24
25
|
"no_package_enabled": no_package_enabled,
|
26
|
+
"package_allowed": package_allowed,
|
25
27
|
},
|
26
28
|
message=message,
|
27
29
|
)
|
@@ -61,4 +63,5 @@ class CheckoutSelectPackageMixin:
|
|
61
63
|
)
|
62
64
|
for line in unselected_lines + related_lines:
|
63
65
|
self.assertEqual(line.qty_done, 0)
|
64
|
-
|
66
|
+
package_lines = selected_lines + related_lines
|
67
|
+
self._assert_selected_response(response, package_lines, message=message, **kw)
|
@@ -383,15 +383,17 @@ class ClusterPickingSetDestinationAllCase(ClusterPickingUnloadingCommonCase):
|
|
383
383
|
self._set_dest_package_and_done(move_lines, self.bin1)
|
384
384
|
move_lines.write({"location_dest_id": self.packing_a_location.id})
|
385
385
|
|
386
|
+
barcode = self.packing_b_location.barcode
|
386
387
|
response = self.service.dispatch(
|
387
388
|
"set_destination_all",
|
388
389
|
params={
|
389
390
|
"picking_batch_id": self.batch.id,
|
390
|
-
"barcode":
|
391
|
+
"barcode": barcode,
|
391
392
|
},
|
392
393
|
)
|
393
394
|
location = move_lines[0].location_dest_id
|
394
395
|
data = self._data_for_batch(self.batch, location)
|
396
|
+
data["confirmation"] = barcode
|
395
397
|
self.assert_response(
|
396
398
|
response,
|
397
399
|
next_state="confirm_unload_all",
|
@@ -404,12 +406,13 @@ class ClusterPickingSetDestinationAllCase(ClusterPickingUnloadingCommonCase):
|
|
404
406
|
self._set_dest_package_and_done(move_lines, self.bin1)
|
405
407
|
move_lines.write({"location_dest_id": self.packing_a_location.id})
|
406
408
|
|
409
|
+
barcode = self.packing_b_location.barcode
|
407
410
|
response = self.service.dispatch(
|
408
411
|
"set_destination_all",
|
409
412
|
params={
|
410
413
|
"picking_batch_id": self.batch.id,
|
411
|
-
"barcode":
|
412
|
-
"confirmation":
|
414
|
+
"barcode": barcode,
|
415
|
+
"confirmation": barcode,
|
413
416
|
},
|
414
417
|
)
|
415
418
|
self.assertRecordValues(
|
@@ -426,6 +429,29 @@ class ClusterPickingSetDestinationAllCase(ClusterPickingUnloadingCommonCase):
|
|
426
429
|
message={"message_type": "success", "body": "Batch Transfer complete"},
|
427
430
|
)
|
428
431
|
|
432
|
+
def test_set_destination_all_check_confirmation(self):
|
433
|
+
"""Endpoint called confirming with a different location, ask confirmation again"""
|
434
|
+
move_lines = self.move_lines
|
435
|
+
self._set_dest_package_and_done(move_lines, self.bin1)
|
436
|
+
move_lines.write({"location_dest_id": self.packing_a_location.id})
|
437
|
+
|
438
|
+
barcode = self.packing_b_location.barcode
|
439
|
+
response = self.service.dispatch(
|
440
|
+
"set_destination_all",
|
441
|
+
params={
|
442
|
+
"picking_batch_id": self.batch.id,
|
443
|
+
"barcode": barcode,
|
444
|
+
"confirmation": "other_barcode",
|
445
|
+
},
|
446
|
+
)
|
447
|
+
data = self._data_for_batch(self.batch, self.packing_a_location)
|
448
|
+
data["confirmation"] = barcode
|
449
|
+
self.assert_response(
|
450
|
+
response,
|
451
|
+
next_state="confirm_unload_all",
|
452
|
+
data=data,
|
453
|
+
)
|
454
|
+
|
429
455
|
|
430
456
|
class ClusterPickingUnloadSplitCase(ClusterPickingUnloadingCommonCase):
|
431
457
|
"""Tests covering the /unload_split endpoint
|
@@ -610,7 +636,7 @@ class ClusterPickingUnloadScanDestinationCase(ClusterPickingUnloadingCommonCase)
|
|
610
636
|
"picking_batch_id": self.batch.id,
|
611
637
|
"package_id": self.bin1.id,
|
612
638
|
"barcode": dest_location.barcode,
|
613
|
-
"confirmation":
|
639
|
+
"confirmation": dest_location.barcode,
|
614
640
|
},
|
615
641
|
)
|
616
642
|
self.assertRecordValues(
|
@@ -630,7 +656,7 @@ class ClusterPickingUnloadScanDestinationCase(ClusterPickingUnloadingCommonCase)
|
|
630
656
|
"picking_batch_id": self.batch.id,
|
631
657
|
"package_id": self.bin2.id,
|
632
658
|
"barcode": dest_location.barcode,
|
633
|
-
"confirmation":
|
659
|
+
"confirmation": dest_location.barcode,
|
634
660
|
},
|
635
661
|
)
|
636
662
|
self.assertRecordValues(
|
@@ -825,16 +851,18 @@ class ClusterPickingUnloadScanDestinationCase(ClusterPickingUnloadingCommonCase)
|
|
825
851
|
|
826
852
|
def test_unload_scan_destination_need_confirmation(self):
|
827
853
|
"""Endpoint called with a barcode for another (valid) location"""
|
854
|
+
barcode = self.packing_b_location.barcode
|
828
855
|
response = self.service.dispatch(
|
829
856
|
"unload_scan_destination",
|
830
857
|
params={
|
831
858
|
"picking_batch_id": self.batch.id,
|
832
859
|
"package_id": self.bin1.id,
|
833
|
-
"barcode":
|
860
|
+
"barcode": barcode,
|
834
861
|
},
|
835
862
|
)
|
836
863
|
location = self.bin1_lines[0].location_dest_id
|
837
864
|
data = self._data_for_batch(self.batch, location, pack=self.bin1)
|
865
|
+
data["confirmation"] = barcode
|
838
866
|
self.assert_response(
|
839
867
|
response,
|
840
868
|
next_state="confirm_unload_set_destination",
|
@@ -843,13 +871,14 @@ class ClusterPickingUnloadScanDestinationCase(ClusterPickingUnloadingCommonCase)
|
|
843
871
|
|
844
872
|
def test_unload_scan_destination_with_confirmation(self):
|
845
873
|
"""Endpoint called with a barcode for another (valid) location, confirm"""
|
874
|
+
barcode = self.packing_a_location.barcode
|
846
875
|
response = self.service.dispatch(
|
847
876
|
"unload_scan_destination",
|
848
877
|
params={
|
849
878
|
"picking_batch_id": self.batch.id,
|
850
879
|
"package_id": self.bin2.id,
|
851
|
-
"barcode":
|
852
|
-
"confirmation":
|
880
|
+
"barcode": barcode,
|
881
|
+
"confirmation": barcode,
|
853
882
|
},
|
854
883
|
)
|
855
884
|
self.assertRecordValues(
|
@@ -47,3 +47,8 @@ class DeliveryListStockPickingCase(DeliveryCommonCase):
|
|
47
47
|
response,
|
48
48
|
pickings=self.picking1 + self.picking2,
|
49
49
|
)
|
50
|
+
# Cancel picking2
|
51
|
+
self.picking2.action_cancel()
|
52
|
+
response = self.service.dispatch("list_stock_picking", params={})
|
53
|
+
# Only picking1 is available
|
54
|
+
self.assert_response_manual_selection(response, pickings=self.picking1)
|
@@ -65,7 +65,7 @@ class LocationContentTransferCommonCase(CommonCase):
|
|
65
65
|
)
|
66
66
|
|
67
67
|
def _assert_response_scan_destination_all(
|
68
|
-
self, state, response, pickings, message=None, confirmation_required=
|
68
|
+
self, state, response, pickings, message=None, confirmation_required=None
|
69
69
|
):
|
70
70
|
# this code is repeated from the implementation, not great, but we
|
71
71
|
# mostly want to ensure the selection of pickings is right, and the
|
@@ -87,7 +87,7 @@ class LocationContentTransferCommonCase(CommonCase):
|
|
87
87
|
)
|
88
88
|
|
89
89
|
def assert_response_scan_destination_all(
|
90
|
-
self, response, pickings, message=None, confirmation_required=
|
90
|
+
self, response, pickings, message=None, confirmation_required=None
|
91
91
|
):
|
92
92
|
self._assert_response_scan_destination_all(
|
93
93
|
"scan_destination_all",
|
@@ -112,7 +112,7 @@ class LocationContentTransferCommonCase(CommonCase):
|
|
112
112
|
)
|
113
113
|
|
114
114
|
def _assert_response_scan_destination(
|
115
|
-
self, state, response, next_content, message=None, confirmation_required=
|
115
|
+
self, state, response, next_content, message=None, confirmation_required=None
|
116
116
|
):
|
117
117
|
location = next_content.location_id
|
118
118
|
data = self.service._data_content_line_for_location(location, next_content)
|
@@ -125,7 +125,7 @@ class LocationContentTransferCommonCase(CommonCase):
|
|
125
125
|
)
|
126
126
|
|
127
127
|
def assert_response_scan_destination(
|
128
|
-
self, response, next_content, message=None, confirmation_required=
|
128
|
+
self, response, next_content, message=None, confirmation_required=None
|
129
129
|
):
|
130
130
|
self._assert_response_scan_destination(
|
131
131
|
"scan_destination",
|
@@ -249,7 +249,7 @@ class LocationContentTransferSetDestinationAllCase(LocationContentTransferCommon
|
|
249
249
|
response,
|
250
250
|
self.pickings,
|
251
251
|
message=self.service.msg_store.need_confirmation(),
|
252
|
-
confirmation_required=
|
252
|
+
confirmation_required=self.shelf2.barcode,
|
253
253
|
)
|
254
254
|
|
255
255
|
def test_set_destination_all_dest_location_confirmation(self):
|
@@ -265,7 +265,7 @@ class LocationContentTransferSetDestinationAllCase(LocationContentTransferCommon
|
|
265
265
|
# picking type's default dest location, ask confirmation (second scan)
|
266
266
|
# from the user
|
267
267
|
"barcode": self.shelf2.barcode,
|
268
|
-
"confirmation":
|
268
|
+
"confirmation": self.shelf2.barcode,
|
269
269
|
},
|
270
270
|
)
|
271
271
|
self.assert_response_start(
|
@@ -276,6 +276,28 @@ class LocationContentTransferSetDestinationAllCase(LocationContentTransferCommon
|
|
276
276
|
)
|
277
277
|
self.assert_all_done(self.shelf2)
|
278
278
|
|
279
|
+
def test_set_destination_all_dest_location_confirm_different(self):
|
280
|
+
"""Scanned different location on location confirmation.
|
281
|
+
|
282
|
+
New confirmation is requested
|
283
|
+
"""
|
284
|
+
response = self.service.dispatch(
|
285
|
+
"set_destination_all",
|
286
|
+
params={
|
287
|
+
"location_id": self.content_loc.id,
|
288
|
+
# expected shelf2 confirmation, but scanned shelf3
|
289
|
+
# another confirmation is required
|
290
|
+
"barcode": self.shelf3.barcode,
|
291
|
+
"confirmation": self.shelf2.barcode,
|
292
|
+
},
|
293
|
+
)
|
294
|
+
self.assert_response_scan_destination_all(
|
295
|
+
response,
|
296
|
+
self.pickings,
|
297
|
+
message=self.service.msg_store.need_confirmation(),
|
298
|
+
confirmation_required=self.shelf3.barcode,
|
299
|
+
)
|
300
|
+
|
279
301
|
def test_set_destination_all_dest_location_invalid(self):
|
280
302
|
"""The scanned destination location is not in the menu's picking types"""
|
281
303
|
response = self.service.dispatch(
|
odoo/addons/shopfloor/tests/test_location_content_transfer_set_destination_package_or_line.py
CHANGED
@@ -146,6 +146,7 @@ class LocationContentTransferSetDestinationXCase(LocationContentTransferCommonCa
|
|
146
146
|
|
147
147
|
def test_set_destination_package_dest_location_to_confirm(self):
|
148
148
|
"""Scanned destination location valid, but need a confirmation."""
|
149
|
+
barcode = self.env.ref("stock.stock_location_14").barcode
|
149
150
|
package_level = self.picking1.package_level_ids[0]
|
150
151
|
self._simulate_selected_move_line(package_level.move_line_ids)
|
151
152
|
response = self.service.dispatch(
|
@@ -153,14 +154,14 @@ class LocationContentTransferSetDestinationXCase(LocationContentTransferCommonCa
|
|
153
154
|
params={
|
154
155
|
"location_id": self.content_loc.id,
|
155
156
|
"package_level_id": package_level.id,
|
156
|
-
"barcode":
|
157
|
+
"barcode": barcode,
|
157
158
|
},
|
158
159
|
)
|
159
160
|
self.assert_response_scan_destination(
|
160
161
|
response,
|
161
162
|
package_level,
|
162
163
|
message=self.service.msg_store.need_confirmation(),
|
163
|
-
confirmation_required=
|
164
|
+
confirmation_required=barcode,
|
164
165
|
)
|
165
166
|
|
166
167
|
def test_set_destination_package_dest_location_ok(self):
|
@@ -337,6 +338,7 @@ class LocationContentTransferSetDestinationXCase(LocationContentTransferCommonCa
|
|
337
338
|
|
338
339
|
def test_set_destination_line_dest_location_to_confirm(self):
|
339
340
|
"""Scanned destination location valid, but need a confirmation."""
|
341
|
+
barcode = self.env.ref("stock.stock_location_14").barcode
|
340
342
|
move_line = self.picking2.move_line_ids[0]
|
341
343
|
self._simulate_selected_move_line(move_line)
|
342
344
|
response = self.service.dispatch(
|
@@ -345,14 +347,14 @@ class LocationContentTransferSetDestinationXCase(LocationContentTransferCommonCa
|
|
345
347
|
"location_id": self.content_loc.id,
|
346
348
|
"move_line_id": move_line.id,
|
347
349
|
"quantity": move_line.reserved_uom_qty,
|
348
|
-
"barcode":
|
350
|
+
"barcode": barcode,
|
349
351
|
},
|
350
352
|
)
|
351
353
|
self.assert_response_scan_destination(
|
352
354
|
response,
|
353
355
|
move_line,
|
354
356
|
message=self.service.msg_store.need_confirmation(),
|
355
|
-
confirmation_required=
|
357
|
+
confirmation_required=barcode,
|
356
358
|
)
|
357
359
|
|
358
360
|
def test_set_destination_line_dest_location_ok(self):
|
@@ -552,6 +552,32 @@ class LocationContentTransferSingleCase(LocationContentTransferCommonCase):
|
|
552
552
|
move_lines.mapped("picking_id"),
|
553
553
|
)
|
554
554
|
|
555
|
+
def test_stock_out_package_ok_lines_not_owned_by_user(self):
|
556
|
+
"""Declare a stock out on a package_level with lines not owned by user.
|
557
|
+
|
558
|
+
Same than the previous test, but lines will not be canceled, but
|
559
|
+
the assigned user will be removed.
|
560
|
+
|
561
|
+
"""
|
562
|
+
self.env.user = self.shopfloor_manager
|
563
|
+
self.assertTrue(self.env.user != self.picking1.create_uid)
|
564
|
+
package_level = self.picking1.move_line_ids.package_level_id
|
565
|
+
move_lines_before = self.picking1.move_line_ids
|
566
|
+
move_lines_before.shopfloor_user_id = self.env.user
|
567
|
+
response = self.service.dispatch(
|
568
|
+
"stock_out_package",
|
569
|
+
params={
|
570
|
+
"location_id": self.content_loc.id,
|
571
|
+
"package_level_id": package_level.id,
|
572
|
+
},
|
573
|
+
)
|
574
|
+
move_lines = self.service._find_transfer_move_lines(self.content_loc)
|
575
|
+
self.assert_response_start_single(
|
576
|
+
response,
|
577
|
+
move_lines.mapped("picking_id"),
|
578
|
+
)
|
579
|
+
self.assertFalse(move_lines_before.exists())
|
580
|
+
|
555
581
|
def test_stock_out_line_wrong_parameters(self):
|
556
582
|
"""Wrong 'location_id' and 'move_line_id' parameters, redirect the
|
557
583
|
user to the 'start' screen.
|
@@ -746,3 +772,22 @@ class LocationContentTransferSingleSpecialCase(LocationContentTransferCommonCase
|
|
746
772
|
response,
|
747
773
|
move_lines.mapped("picking_id"),
|
748
774
|
)
|
775
|
+
|
776
|
+
def test_stock_out_line_not_created_by_user(self):
|
777
|
+
"""Declare a stock out on move line not owned by the user.
|
778
|
+
|
779
|
+
This will remove the assigned user but not cancel the move,
|
780
|
+
compare to the previous test.
|
781
|
+
|
782
|
+
"""
|
783
|
+
self.env.user = self.shopfloor_manager
|
784
|
+
self.assertTrue(self.env.user != self.picking.create_uid)
|
785
|
+
move_line = self.move_product_b.move_line_ids.filtered(
|
786
|
+
lambda ml: ml.reserved_uom_qty == 4 # 4/10 to stock out
|
787
|
+
)
|
788
|
+
move_line.shopfloor_user_id = self.env.user
|
789
|
+
self.service.dispatch(
|
790
|
+
"stock_out_line",
|
791
|
+
params={"location_id": self.content_loc.id, "move_line_id": move_line.id},
|
792
|
+
)
|
793
|
+
self.assertFalse(move_line.exists())
|
@@ -47,3 +47,10 @@ class ScanAnythingCase(ActionsDataDetailCaseBase, ScanAnythingTestMixin):
|
|
47
47
|
identifier = record.name
|
48
48
|
data = self.data_detail.picking_detail(record)
|
49
49
|
self._test_response_ok(rec_type, data, identifier)
|
50
|
+
|
51
|
+
def test_scan_packaging(self):
|
52
|
+
record = self.product_a_packaging
|
53
|
+
rec_type = "product"
|
54
|
+
identifier = record.barcode
|
55
|
+
data = self.data_detail.product_detail(record.product_id)
|
56
|
+
self._test_response_ok(rec_type, data, identifier)
|
@@ -79,6 +79,9 @@ class TestSinglePackTransfer(SinglePackTransferCommonBase):
|
|
79
79
|
return {
|
80
80
|
"id": package_level.id,
|
81
81
|
"name": package_level.package_id.name,
|
82
|
+
"weight_uom": package_level.package_id.weight_uom_id.name,
|
83
|
+
"weight": package_level.package_id.pack_weight,
|
84
|
+
"estimated_weight_kg": package_level.package_id.estimated_pack_weight_kg,
|
82
85
|
"location_src": self.data.location(package_level.location_id),
|
83
86
|
"location_dest": self.data.location(package_level.location_dest_id),
|
84
87
|
"picking": self.data.picking(self.picking),
|
@@ -121,7 +124,7 @@ class TestSinglePackTransfer(SinglePackTransferCommonBase):
|
|
121
124
|
next_state="scan_location",
|
122
125
|
data=dict(
|
123
126
|
self._response_package_level_data(package_level),
|
124
|
-
confirmation_required=
|
127
|
+
confirmation_required=None,
|
125
128
|
),
|
126
129
|
)
|
127
130
|
|
@@ -189,13 +192,16 @@ class TestSinglePackTransfer(SinglePackTransferCommonBase):
|
|
189
192
|
expected_data = {
|
190
193
|
"id": package_level.id,
|
191
194
|
"name": package_level.package_id.name,
|
195
|
+
"weight_uom": package_level.package_id.weight_uom_id.name,
|
196
|
+
"weight": package_level.package_id.pack_weight,
|
197
|
+
"estimated_weight_kg": package_level.package_id.estimated_pack_weight_kg,
|
192
198
|
"location_src": self.data.location(self.shelf1),
|
193
199
|
"location_dest": self.data.location(
|
194
200
|
self.picking_type.default_location_dest_id
|
195
201
|
),
|
196
202
|
"picking": self.data.picking(package_level.picking_id),
|
197
203
|
"products": self.data.products(self.product_a),
|
198
|
-
"confirmation_required":
|
204
|
+
"confirmation_required": None,
|
199
205
|
}
|
200
206
|
|
201
207
|
self.assert_response(response, next_state="scan_location", data=expected_data)
|
@@ -404,7 +410,7 @@ class TestSinglePackTransfer(SinglePackTransferCommonBase):
|
|
404
410
|
},
|
405
411
|
data=dict(
|
406
412
|
self._response_package_level_data(package_level),
|
407
|
-
confirmation_required=
|
413
|
+
confirmation_required=barcode,
|
408
414
|
),
|
409
415
|
)
|
410
416
|
|
@@ -726,7 +732,7 @@ class TestSinglePackTransfer(SinglePackTransferCommonBase):
|
|
726
732
|
message=message,
|
727
733
|
data=dict(
|
728
734
|
self._response_package_level_data(package_level),
|
729
|
-
confirmation_required=
|
735
|
+
confirmation_required=sub_shelf2.barcode,
|
730
736
|
),
|
731
737
|
)
|
732
738
|
|
@@ -761,7 +767,7 @@ class TestSinglePackTransfer(SinglePackTransferCommonBase):
|
|
761
767
|
"package_level_id": package_level.id,
|
762
768
|
"location_barcode": self.shelf2.barcode,
|
763
769
|
# acknowledge the change of destination
|
764
|
-
"confirmation":
|
770
|
+
"confirmation": self.shelf2.barcode,
|
765
771
|
},
|
766
772
|
)
|
767
773
|
|
@@ -783,9 +789,11 @@ class TestSinglePackTransfer(SinglePackTransferCommonBase):
|
|
783
789
|
[{"location_dest_id": self.shelf2.id, "state": "done"}],
|
784
790
|
)
|
785
791
|
|
786
|
-
def
|
792
|
+
def test_cancel_transfer_not_created_by_user(self):
|
787
793
|
"""Test the happy path for single pack transfer /cancel endpoint
|
788
794
|
|
795
|
+
The transfer was not created by the shopfloor user.
|
796
|
+
|
789
797
|
The pre-conditions:
|
790
798
|
|
791
799
|
* /start has been called
|
@@ -797,6 +805,8 @@ class TestSinglePackTransfer(SinglePackTransferCommonBase):
|
|
797
805
|
# setup the picking as we need, like if the move line
|
798
806
|
# was already started by the first step (start operation)
|
799
807
|
package_level = self._simulate_started(self.pack_a)
|
808
|
+
self.menu.sudo().allow_move_create = True
|
809
|
+
self.env.user = self.shopfloor_manager
|
800
810
|
self.assertTrue(package_level.is_done)
|
801
811
|
|
802
812
|
# keep references for later checks
|
@@ -809,7 +819,48 @@ class TestSinglePackTransfer(SinglePackTransferCommonBase):
|
|
809
819
|
)
|
810
820
|
self.assertRecordValues(move, [{"state": "assigned"}])
|
811
821
|
self.assertRecordValues(picking, [{"state": "assigned"}])
|
812
|
-
self.
|
822
|
+
self.assertTrue(move.move_line_ids.exists())
|
823
|
+
self.assertFalse(move.move_line_ids.shopfloor_user_id)
|
824
|
+
self.assert_response(
|
825
|
+
response,
|
826
|
+
next_state="start",
|
827
|
+
message={
|
828
|
+
"message_type": "success",
|
829
|
+
"body": "Canceled, you can scan a new pack.",
|
830
|
+
},
|
831
|
+
)
|
832
|
+
|
833
|
+
def test_cancel_transfer_created_by_user(self):
|
834
|
+
"""Test the happy path for single pack transfer /cancel endpoint
|
835
|
+
|
836
|
+
The transfer was created by the shopfloor user.
|
837
|
+
|
838
|
+
The pre-conditions:
|
839
|
+
|
840
|
+
* /start has been called
|
841
|
+
|
842
|
+
Expected result:
|
843
|
+
|
844
|
+
* The package level has is_done to False
|
845
|
+
* The move and picking are canceled.
|
846
|
+
"""
|
847
|
+
self.menu.sudo().allow_move_create = True
|
848
|
+
# setup the picking as we need, like if the move line
|
849
|
+
# was already started by the first step (start operation)
|
850
|
+
package_level = self._simulate_started(self.pack_a)
|
851
|
+
self.assertTrue(package_level.is_done)
|
852
|
+
|
853
|
+
# keep references for later checks
|
854
|
+
move = package_level.move_line_ids.move_id
|
855
|
+
picking = move.picking_id
|
856
|
+
|
857
|
+
# now, call the service to cancel
|
858
|
+
response = self.service.dispatch(
|
859
|
+
"cancel", params={"package_level_id": package_level.id}
|
860
|
+
)
|
861
|
+
self.assertRecordValues(move, [{"state": "cancel"}])
|
862
|
+
self.assertRecordValues(picking, [{"state": "cancel"}])
|
863
|
+
self.assertFalse(package_level.exists())
|
813
864
|
|
814
865
|
self.assert_response(
|
815
866
|
response,
|
@@ -994,7 +1045,7 @@ class SinglePackTransferSpecialCase(SinglePackTransferCommonBase):
|
|
994
1045
|
next_state="scan_location",
|
995
1046
|
data=dict(
|
996
1047
|
self.service._data_after_package_scanned(new_package_level),
|
997
|
-
confirmation_required=
|
1048
|
+
confirmation_required=None,
|
998
1049
|
),
|
999
1050
|
)
|
1000
1051
|
self.assertRecordValues(
|