odoo-addon-shopfloor 16.0.1.0.0.24__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 +160 -0
- odoo/addons/shopfloor/__init__.py +4 -0
- odoo/addons/shopfloor/__manifest__.py +65 -0
- odoo/addons/shopfloor/actions/__init__.py +15 -0
- odoo/addons/shopfloor/actions/change_package_lot.py +164 -0
- odoo/addons/shopfloor/actions/completion_info.py +42 -0
- odoo/addons/shopfloor/actions/data.py +329 -0
- odoo/addons/shopfloor/actions/data_detail.py +154 -0
- odoo/addons/shopfloor/actions/inventory.py +150 -0
- odoo/addons/shopfloor/actions/location_content_transfer_sorter.py +89 -0
- odoo/addons/shopfloor/actions/message.py +846 -0
- odoo/addons/shopfloor/actions/move_line_search.py +119 -0
- odoo/addons/shopfloor/actions/packaging.py +59 -0
- odoo/addons/shopfloor/actions/savepoint.py +44 -0
- odoo/addons/shopfloor/actions/schema.py +182 -0
- odoo/addons/shopfloor/actions/schema_detail.py +98 -0
- odoo/addons/shopfloor/actions/search.py +187 -0
- odoo/addons/shopfloor/actions/stock.py +239 -0
- odoo/addons/shopfloor/actions/stock_unreserve.py +66 -0
- odoo/addons/shopfloor/components/__init__.py +5 -0
- odoo/addons/shopfloor/components/scan_handler_location.py +26 -0
- odoo/addons/shopfloor/components/scan_handler_lot.py +26 -0
- odoo/addons/shopfloor/components/scan_handler_package.py +26 -0
- odoo/addons/shopfloor/components/scan_handler_product.py +26 -0
- odoo/addons/shopfloor/components/scan_handler_transfer.py +26 -0
- odoo/addons/shopfloor/data/shopfloor_scenario_data.xml +73 -0
- odoo/addons/shopfloor/demo/shopfloor_app_demo.xml +12 -0
- odoo/addons/shopfloor/demo/shopfloor_menu_demo.xml +64 -0
- odoo/addons/shopfloor/demo/shopfloor_profile_demo.xml +8 -0
- odoo/addons/shopfloor/demo/stock_picking_type_demo.xml +93 -0
- odoo/addons/shopfloor/docs/checkout_diag_seq.plantuml +61 -0
- odoo/addons/shopfloor/docs/checkout_diag_seq.png +0 -0
- odoo/addons/shopfloor/docs/cluster_picking_diag_seq.plantuml +112 -0
- odoo/addons/shopfloor/docs/cluster_picking_diag_seq.png +0 -0
- odoo/addons/shopfloor/docs/delivery_diag_seq.plantuml +56 -0
- odoo/addons/shopfloor/docs/delivery_diag_seq.png +0 -0
- odoo/addons/shopfloor/docs/location_content_transfer_diag_seq.plantuml +66 -0
- odoo/addons/shopfloor/docs/location_content_transfer_diag_seq.png +0 -0
- odoo/addons/shopfloor/docs/oca_logo.png +0 -0
- odoo/addons/shopfloor/docs/single_pack_transfer_diag_seq.plantuml +36 -0
- odoo/addons/shopfloor/docs/single_pack_transfer_diag_seq.png +0 -0
- odoo/addons/shopfloor/docs/zone_picking_diag_seq.plantuml +85 -0
- odoo/addons/shopfloor/docs/zone_picking_diag_seq.png +0 -0
- odoo/addons/shopfloor/exceptions.py +6 -0
- odoo/addons/shopfloor/i18n/ca.po +1802 -0
- odoo/addons/shopfloor/i18n/de.po +1791 -0
- odoo/addons/shopfloor/i18n/es_AR.po +2147 -0
- odoo/addons/shopfloor/i18n/pt_BR.po +1791 -0
- odoo/addons/shopfloor/i18n/shopfloor.pot +1877 -0
- odoo/addons/shopfloor/models/__init__.py +12 -0
- odoo/addons/shopfloor/models/priority_postpone_mixin.py +41 -0
- odoo/addons/shopfloor/models/shopfloor_app.py +9 -0
- odoo/addons/shopfloor/models/shopfloor_menu.py +436 -0
- odoo/addons/shopfloor/models/stock_location.py +76 -0
- odoo/addons/shopfloor/models/stock_move.py +119 -0
- odoo/addons/shopfloor/models/stock_move_line.py +307 -0
- odoo/addons/shopfloor/models/stock_package_level.py +50 -0
- odoo/addons/shopfloor/models/stock_picking.py +118 -0
- odoo/addons/shopfloor/models/stock_picking_batch.py +41 -0
- odoo/addons/shopfloor/models/stock_picking_type.py +26 -0
- odoo/addons/shopfloor/models/stock_quant.py +31 -0
- odoo/addons/shopfloor/models/stock_quant_package.py +101 -0
- odoo/addons/shopfloor/readme/CONTRIBUTORS.rst +18 -0
- odoo/addons/shopfloor/readme/CREDITS.rst +5 -0
- odoo/addons/shopfloor/readme/DESCRIPTION.rst +17 -0
- odoo/addons/shopfloor/readme/HISTORY.rst +4 -0
- odoo/addons/shopfloor/readme/ROADMAP.rst +4 -0
- odoo/addons/shopfloor/readme/USAGE.rst +6 -0
- odoo/addons/shopfloor/security/groups.xml +17 -0
- odoo/addons/shopfloor/services/__init__.py +16 -0
- odoo/addons/shopfloor/services/checkout.py +1763 -0
- odoo/addons/shopfloor/services/cluster_picking.py +1628 -0
- odoo/addons/shopfloor/services/delivery.py +828 -0
- odoo/addons/shopfloor/services/forms/__init__.py +1 -0
- odoo/addons/shopfloor/services/forms/picking_form.py +78 -0
- odoo/addons/shopfloor/services/location_content_transfer.py +1194 -0
- odoo/addons/shopfloor/services/menu.py +60 -0
- odoo/addons/shopfloor/services/picking_batch.py +126 -0
- odoo/addons/shopfloor/services/service.py +101 -0
- odoo/addons/shopfloor/services/single_pack_transfer.py +366 -0
- odoo/addons/shopfloor/services/zone_picking.py +1938 -0
- odoo/addons/shopfloor/static/description/icon.png +0 -0
- odoo/addons/shopfloor/static/description/index.html +500 -0
- odoo/addons/shopfloor/tests/__init__.py +83 -0
- odoo/addons/shopfloor/tests/common.py +324 -0
- odoo/addons/shopfloor/tests/models.py +29 -0
- odoo/addons/shopfloor/tests/test_actions_change_package_lot.py +1175 -0
- odoo/addons/shopfloor/tests/test_actions_data.py +376 -0
- odoo/addons/shopfloor/tests/test_actions_data_base.py +244 -0
- odoo/addons/shopfloor/tests/test_actions_data_detail.py +322 -0
- odoo/addons/shopfloor/tests/test_actions_search.py +248 -0
- odoo/addons/shopfloor/tests/test_actions_stock.py +48 -0
- odoo/addons/shopfloor/tests/test_checkout_auto_post.py +67 -0
- odoo/addons/shopfloor/tests/test_checkout_base.py +81 -0
- odoo/addons/shopfloor/tests/test_checkout_cancel_line.py +154 -0
- odoo/addons/shopfloor/tests/test_checkout_change_packaging.py +184 -0
- odoo/addons/shopfloor/tests/test_checkout_done.py +133 -0
- odoo/addons/shopfloor/tests/test_checkout_list_delivery_packaging.py +131 -0
- odoo/addons/shopfloor/tests/test_checkout_list_package.py +327 -0
- odoo/addons/shopfloor/tests/test_checkout_new_package.py +88 -0
- odoo/addons/shopfloor/tests/test_checkout_no_package.py +95 -0
- odoo/addons/shopfloor/tests/test_checkout_scan.py +174 -0
- odoo/addons/shopfloor/tests/test_checkout_scan_line.py +377 -0
- odoo/addons/shopfloor/tests/test_checkout_scan_line_base.py +25 -0
- odoo/addons/shopfloor/tests/test_checkout_scan_line_no_prefill_qty.py +91 -0
- odoo/addons/shopfloor/tests/test_checkout_scan_package_action.py +451 -0
- odoo/addons/shopfloor/tests/test_checkout_scan_package_action_no_prefill_qty.py +107 -0
- odoo/addons/shopfloor/tests/test_checkout_select.py +74 -0
- odoo/addons/shopfloor/tests/test_checkout_select_line.py +130 -0
- odoo/addons/shopfloor/tests/test_checkout_select_package_base.py +64 -0
- odoo/addons/shopfloor/tests/test_checkout_set_qty.py +257 -0
- odoo/addons/shopfloor/tests/test_checkout_summary.py +69 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_base.py +83 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_batch.py +109 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_change_pack_lot.py +111 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_is_zero.py +98 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_scan_destination.py +376 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_scan_destination_no_prefill_qty.py +115 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_scan_line.py +402 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_scan_line_location_or_pack_first.py +114 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_scan_line_no_prefill_qty.py +70 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_select.py +387 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_skip.py +90 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_stock_issue.py +364 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_unload.py +911 -0
- odoo/addons/shopfloor/tests/test_delivery_base.py +155 -0
- odoo/addons/shopfloor/tests/test_delivery_done.py +108 -0
- odoo/addons/shopfloor/tests/test_delivery_list_stock_picking.py +49 -0
- odoo/addons/shopfloor/tests/test_delivery_reset_qty_done_line.py +119 -0
- odoo/addons/shopfloor/tests/test_delivery_reset_qty_done_pack.py +107 -0
- odoo/addons/shopfloor/tests/test_delivery_scan_deliver.py +557 -0
- odoo/addons/shopfloor/tests/test_delivery_select.py +38 -0
- odoo/addons/shopfloor/tests/test_delivery_set_qty_done_line.py +91 -0
- odoo/addons/shopfloor/tests/test_delivery_set_qty_done_pack.py +135 -0
- odoo/addons/shopfloor/tests/test_delivery_sublocation.py +180 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_base.py +136 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_get_work.py +125 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_mix.py +509 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_putaway.py +143 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_scan_location.py +34 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_set_destination_all.py +343 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_set_destination_package_or_line.py +1074 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_single.py +748 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_start.py +359 -0
- odoo/addons/shopfloor/tests/test_menu_base.py +261 -0
- odoo/addons/shopfloor/tests/test_menu_counters.py +61 -0
- odoo/addons/shopfloor/tests/test_misc.py +25 -0
- odoo/addons/shopfloor/tests/test_move_action_assign.py +87 -0
- odoo/addons/shopfloor/tests/test_openapi.py +21 -0
- odoo/addons/shopfloor/tests/test_picking_form.py +62 -0
- odoo/addons/shopfloor/tests/test_scan_anything.py +49 -0
- odoo/addons/shopfloor/tests/test_single_pack_transfer.py +1121 -0
- odoo/addons/shopfloor/tests/test_single_pack_transfer_base.py +32 -0
- odoo/addons/shopfloor/tests/test_single_pack_transfer_putaway.py +104 -0
- odoo/addons/shopfloor/tests/test_stock_split.py +204 -0
- odoo/addons/shopfloor/tests/test_user.py +42 -0
- odoo/addons/shopfloor/tests/test_zone_picking_base.py +608 -0
- odoo/addons/shopfloor/tests/test_zone_picking_change_pack_lot.py +140 -0
- odoo/addons/shopfloor/tests/test_zone_picking_select_line.py +723 -0
- odoo/addons/shopfloor/tests/test_zone_picking_select_line_first_scan_location.py +207 -0
- odoo/addons/shopfloor/tests/test_zone_picking_select_line_first_scan_location.py.bak +202 -0
- odoo/addons/shopfloor/tests/test_zone_picking_select_line_no_prefill_qty.py +107 -0
- odoo/addons/shopfloor/tests/test_zone_picking_select_picking_type.py +26 -0
- odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination.py +643 -0
- odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination_no_prefill_qty.py +146 -0
- odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination_pick_pack.py +241 -0
- odoo/addons/shopfloor/tests/test_zone_picking_start.py +206 -0
- odoo/addons/shopfloor/tests/test_zone_picking_stock_issue.py +121 -0
- odoo/addons/shopfloor/tests/test_zone_picking_unload_all.py +353 -0
- odoo/addons/shopfloor/tests/test_zone_picking_unload_buffer_lines.py +113 -0
- odoo/addons/shopfloor/tests/test_zone_picking_unload_set_destination.py +374 -0
- odoo/addons/shopfloor/tests/test_zone_picking_unload_single.py +123 -0
- odoo/addons/shopfloor/tests/test_zone_picking_zero_check.py +43 -0
- odoo/addons/shopfloor/utils.py +13 -0
- odoo/addons/shopfloor/views/shopfloor_menu.xml +167 -0
- odoo/addons/shopfloor/views/stock_location.xml +20 -0
- odoo/addons/shopfloor/views/stock_move_line.xml +52 -0
- odoo/addons/shopfloor/views/stock_picking_type.xml +19 -0
- odoo_addon_shopfloor-16.0.1.0.0.24.dist-info/METADATA +192 -0
- odoo_addon_shopfloor-16.0.1.0.0.24.dist-info/RECORD +182 -0
- odoo_addon_shopfloor-16.0.1.0.0.24.dist-info/WHEEL +5 -0
- odoo_addon_shopfloor-16.0.1.0.0.24.dist-info/top_level.txt +1 -0
@@ -0,0 +1,327 @@
|
|
1
|
+
# Copyright 2020 Camptocamp SA (http://www.camptocamp.com)
|
2
|
+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
3
|
+
from odoo import fields
|
4
|
+
|
5
|
+
from .test_checkout_base import CheckoutCommonCase
|
6
|
+
from .test_checkout_select_package_base import CheckoutSelectPackageMixin
|
7
|
+
|
8
|
+
# pylint: disable=missing-return
|
9
|
+
|
10
|
+
|
11
|
+
class SelectDestPackageMixin:
|
12
|
+
def _assert_response_select_dest_package(
|
13
|
+
self, response, picking, selected_lines, packages, message=None
|
14
|
+
):
|
15
|
+
picking_data = self.data.picking(picking)
|
16
|
+
picking_data.update(
|
17
|
+
{
|
18
|
+
"note": None,
|
19
|
+
"origin": None,
|
20
|
+
"weight": 110.0,
|
21
|
+
"move_line_count": len(picking.move_line_ids),
|
22
|
+
}
|
23
|
+
)
|
24
|
+
self.assert_response(
|
25
|
+
response,
|
26
|
+
next_state="select_dest_package",
|
27
|
+
data={
|
28
|
+
"picking": picking_data,
|
29
|
+
"packages": [
|
30
|
+
self._package_data(
|
31
|
+
package.with_context(picking_id=picking.id), picking
|
32
|
+
)
|
33
|
+
for package in packages
|
34
|
+
],
|
35
|
+
"selected_move_lines": [
|
36
|
+
self._move_line_data(ml) for ml in selected_lines.sorted()
|
37
|
+
],
|
38
|
+
},
|
39
|
+
message=message,
|
40
|
+
)
|
41
|
+
|
42
|
+
|
43
|
+
class CheckoutListDestPackageCase(
|
44
|
+
CheckoutCommonCase, CheckoutSelectPackageMixin, SelectDestPackageMixin
|
45
|
+
):
|
46
|
+
def test_list_dest_package_ok(self):
|
47
|
+
picking = self._create_picking(
|
48
|
+
lines=[
|
49
|
+
(self.product_a, 10),
|
50
|
+
(self.product_b, 10),
|
51
|
+
(self.product_c, 10),
|
52
|
+
(self.product_d, 10),
|
53
|
+
]
|
54
|
+
)
|
55
|
+
self._fill_stock_for_moves(picking.move_ids[:2], in_package=True)
|
56
|
+
self._fill_stock_for_moves(picking.move_ids[2], in_package=True)
|
57
|
+
self._fill_stock_for_moves(picking.move_ids[3], in_package=True)
|
58
|
+
picking.action_assign()
|
59
|
+
delivery_packaging = self.env.ref(
|
60
|
+
"stock_storage_type.product_product_9_packaging_single_bag"
|
61
|
+
)
|
62
|
+
delivery_package = self.env["stock.quant.package"].create(
|
63
|
+
{"package_type_id": delivery_packaging.id}
|
64
|
+
)
|
65
|
+
picking.move_ids[1].move_line_ids.result_package_id = delivery_package
|
66
|
+
response = self.service.dispatch(
|
67
|
+
"list_dest_package",
|
68
|
+
params={
|
69
|
+
"picking_id": picking.id,
|
70
|
+
"selected_line_ids": picking.move_line_ids.ids,
|
71
|
+
},
|
72
|
+
)
|
73
|
+
self._assert_response_select_dest_package(
|
74
|
+
response, picking, picking.move_line_ids, delivery_package
|
75
|
+
)
|
76
|
+
|
77
|
+
def test_list_dest_package_error_no_package(self):
|
78
|
+
picking = self._create_picking(
|
79
|
+
lines=[
|
80
|
+
(self.product_a, 10),
|
81
|
+
(self.product_b, 10),
|
82
|
+
(self.product_c, 10),
|
83
|
+
(self.product_d, 10),
|
84
|
+
]
|
85
|
+
)
|
86
|
+
self._fill_stock_for_moves(picking.move_ids)
|
87
|
+
picking.action_assign()
|
88
|
+
self.assertEqual(picking.state, "assigned")
|
89
|
+
response = self.service.dispatch(
|
90
|
+
"list_dest_package",
|
91
|
+
params={
|
92
|
+
"picking_id": picking.id,
|
93
|
+
"selected_line_ids": picking.move_line_ids.ids,
|
94
|
+
},
|
95
|
+
)
|
96
|
+
self._assert_selected_response(
|
97
|
+
response,
|
98
|
+
picking.move_line_ids,
|
99
|
+
message={"message_type": "warning", "body": "No valid package to select."},
|
100
|
+
)
|
101
|
+
|
102
|
+
|
103
|
+
class CheckoutScanSetDestPackageCase(CheckoutCommonCase, SelectDestPackageMixin):
|
104
|
+
@classmethod
|
105
|
+
def setUpClassBaseData(cls):
|
106
|
+
super().setUpClassBaseData()
|
107
|
+
picking = cls._create_picking(
|
108
|
+
lines=[
|
109
|
+
(cls.product_a, 10),
|
110
|
+
(cls.product_b, 10),
|
111
|
+
(cls.product_c, 10),
|
112
|
+
(cls.product_d, 10),
|
113
|
+
]
|
114
|
+
)
|
115
|
+
pack1_moves = picking.move_ids[:3]
|
116
|
+
pack2_moves = picking.move_ids[3:]
|
117
|
+
# put in 2 packs, for this test, we'll work on pack1
|
118
|
+
cls._fill_stock_for_moves(pack1_moves, in_package=True)
|
119
|
+
cls._fill_stock_for_moves(pack2_moves, in_package=True)
|
120
|
+
picking.action_assign()
|
121
|
+
|
122
|
+
cls.selected_lines = pack1_moves.move_line_ids
|
123
|
+
cls.pack1 = pack1_moves.move_line_ids.package_id
|
124
|
+
cls.delivery_packaging = cls.env.ref(
|
125
|
+
"stock_storage_type.product_product_9_packaging_single_bag"
|
126
|
+
)
|
127
|
+
cls.delivery_package = cls.env["stock.quant.package"].create(
|
128
|
+
{"package_type_id": cls.delivery_packaging.id}
|
129
|
+
)
|
130
|
+
cls.move_line1, cls.move_line2, cls.move_line3 = cls.selected_lines
|
131
|
+
# The 'scan_dest_package' and 'set_dest_package' methods can not be
|
132
|
+
# used at all if there is no valid delivery package on the picking
|
133
|
+
# (the user is redirected to the 'select_package' step in that case),
|
134
|
+
# so we need at least to set one to pass this check in order to test
|
135
|
+
# them
|
136
|
+
cls.move_line1.result_package_id = cls.delivery_package
|
137
|
+
# We'll put only product A and B in the destination package
|
138
|
+
cls.move_line1.qty_done = cls.move_line1.reserved_uom_qty
|
139
|
+
cls.move_line2.qty_done = cls.move_line2.reserved_uom_qty
|
140
|
+
cls.move_line3.qty_done = 0
|
141
|
+
|
142
|
+
cls.picking = picking
|
143
|
+
|
144
|
+
def _get_allowed_packages(self, picking):
|
145
|
+
return (
|
146
|
+
picking.mapped("move_line_ids.package_id")
|
147
|
+
| picking.mapped("move_line_ids.result_package_id")
|
148
|
+
).filtered("package_type_id")
|
149
|
+
|
150
|
+
def _assert_package_set(self, response):
|
151
|
+
self.assertRecordValues(
|
152
|
+
self.move_line1 + self.move_line2 + self.move_line3,
|
153
|
+
[
|
154
|
+
{
|
155
|
+
"result_package_id": self.delivery_package.id,
|
156
|
+
"shopfloor_checkout_done": True,
|
157
|
+
},
|
158
|
+
{
|
159
|
+
"result_package_id": self.delivery_package.id,
|
160
|
+
"shopfloor_checkout_done": True,
|
161
|
+
},
|
162
|
+
# qty_done was zero so we don't set it as packed
|
163
|
+
{"result_package_id": self.pack1.id, "shopfloor_checkout_done": False},
|
164
|
+
],
|
165
|
+
)
|
166
|
+
self.assert_response(
|
167
|
+
response,
|
168
|
+
# go pack to the screen to select lines to put in packages
|
169
|
+
next_state="select_line",
|
170
|
+
data=self._data_for_select_line(self.picking),
|
171
|
+
message=self.msg_store.goods_packed_in(self.delivery_package),
|
172
|
+
)
|
173
|
+
|
174
|
+
def test_scan_dest_package_ok(self):
|
175
|
+
response = self.service.dispatch(
|
176
|
+
"scan_dest_package",
|
177
|
+
params={
|
178
|
+
"picking_id": self.picking.id,
|
179
|
+
"selected_line_ids": self.selected_lines.ids,
|
180
|
+
# we keep the goods in the same package, so we scan the source package
|
181
|
+
"barcode": self.delivery_package.name,
|
182
|
+
},
|
183
|
+
)
|
184
|
+
self._assert_package_set(response)
|
185
|
+
|
186
|
+
def test_scan_dest_package_error_not_found(self):
|
187
|
+
barcode = "NO BARCODE"
|
188
|
+
response = self.service.dispatch(
|
189
|
+
"scan_dest_package",
|
190
|
+
params={
|
191
|
+
"picking_id": self.picking.id,
|
192
|
+
"selected_line_ids": self.selected_lines.ids,
|
193
|
+
"barcode": barcode,
|
194
|
+
},
|
195
|
+
)
|
196
|
+
self._assert_response_select_dest_package(
|
197
|
+
response,
|
198
|
+
self.picking,
|
199
|
+
self.selected_lines,
|
200
|
+
self._get_allowed_packages(self.picking),
|
201
|
+
message=self.service.msg_store.package_not_found_for_barcode(barcode),
|
202
|
+
)
|
203
|
+
|
204
|
+
def test_scan_dest_package_error_not_allowed(self):
|
205
|
+
package = self.env["stock.quant.package"].create({})
|
206
|
+
response = self.service.dispatch(
|
207
|
+
"scan_dest_package",
|
208
|
+
params={
|
209
|
+
"picking_id": self.picking.id,
|
210
|
+
"selected_line_ids": self.selected_lines.ids,
|
211
|
+
"barcode": package.name,
|
212
|
+
},
|
213
|
+
)
|
214
|
+
self._assert_response_select_dest_package(
|
215
|
+
response,
|
216
|
+
self.picking,
|
217
|
+
self.selected_lines,
|
218
|
+
self._get_allowed_packages(self.picking),
|
219
|
+
message=self.service.msg_store.dest_package_not_valid(package),
|
220
|
+
)
|
221
|
+
|
222
|
+
def test_set_dest_package_ok(self):
|
223
|
+
response = self.service.dispatch(
|
224
|
+
"set_dest_package",
|
225
|
+
params={
|
226
|
+
"picking_id": self.picking.id,
|
227
|
+
"selected_line_ids": self.selected_lines.ids,
|
228
|
+
"package_id": self.delivery_package.id,
|
229
|
+
},
|
230
|
+
)
|
231
|
+
self._assert_package_set(response)
|
232
|
+
|
233
|
+
def test_set_dest_package_ok_on_partial_qty_done(self):
|
234
|
+
# Partially process line three 3 quantiy out of 10
|
235
|
+
self.move_line3.qty_done = 3
|
236
|
+
response = self.service.dispatch(
|
237
|
+
"set_dest_package",
|
238
|
+
params={
|
239
|
+
"picking_id": self.picking.id,
|
240
|
+
"selected_line_ids": self.selected_lines.ids,
|
241
|
+
"package_id": self.delivery_package.id,
|
242
|
+
},
|
243
|
+
)
|
244
|
+
# self._assert_package_set(response)
|
245
|
+
self.assertRecordValues(
|
246
|
+
self.move_line1 + self.move_line2 + self.move_line3,
|
247
|
+
[
|
248
|
+
{
|
249
|
+
"result_package_id": self.delivery_package.id,
|
250
|
+
"shopfloor_checkout_done": True,
|
251
|
+
},
|
252
|
+
{
|
253
|
+
"result_package_id": self.delivery_package.id,
|
254
|
+
"shopfloor_checkout_done": True,
|
255
|
+
},
|
256
|
+
# Line 3 has been split
|
257
|
+
{
|
258
|
+
"result_package_id": self.delivery_package.id,
|
259
|
+
"shopfloor_checkout_done": True,
|
260
|
+
"product_uom_qty": 3,
|
261
|
+
"qty_done": 3,
|
262
|
+
},
|
263
|
+
],
|
264
|
+
)
|
265
|
+
# Left quantity to do from line 3
|
266
|
+
new_move_line = self.picking.move_line_ids.filtered(
|
267
|
+
lambda line: line.qty_done == 0 and line.reserved_uom_qty == 7
|
268
|
+
)
|
269
|
+
self.assertTrue(new_move_line)
|
270
|
+
self.assertFalse(new_move_line.shopfloor_checkout_done)
|
271
|
+
self.assert_response(
|
272
|
+
response,
|
273
|
+
# go pack to the screen to select lines to put in packages
|
274
|
+
next_state="select_line",
|
275
|
+
data=self._data_for_select_line(self.picking),
|
276
|
+
message=self.msg_store.goods_packed_in(self.delivery_package),
|
277
|
+
)
|
278
|
+
|
279
|
+
def test_set_dest_package_error_not_found(self):
|
280
|
+
response = self.service.dispatch(
|
281
|
+
"set_dest_package",
|
282
|
+
params={
|
283
|
+
"picking_id": self.picking.id,
|
284
|
+
"selected_line_ids": self.selected_lines.ids,
|
285
|
+
"package_id": 0,
|
286
|
+
},
|
287
|
+
)
|
288
|
+
self._assert_response_select_dest_package(
|
289
|
+
response,
|
290
|
+
self.picking,
|
291
|
+
self.selected_lines,
|
292
|
+
self._get_allowed_packages(self.picking),
|
293
|
+
message=self.service.msg_store.record_not_found(),
|
294
|
+
)
|
295
|
+
|
296
|
+
def test_set_dest_package_error_not_allowed(self):
|
297
|
+
package = self.env["stock.quant.package"].create({})
|
298
|
+
response = self.service.dispatch(
|
299
|
+
"set_dest_package",
|
300
|
+
params={
|
301
|
+
"picking_id": self.picking.id,
|
302
|
+
"selected_line_ids": self.selected_lines.ids,
|
303
|
+
"package_id": package.id,
|
304
|
+
},
|
305
|
+
)
|
306
|
+
self._assert_response_select_dest_package(
|
307
|
+
response,
|
308
|
+
self.picking,
|
309
|
+
self.selected_lines,
|
310
|
+
self._get_allowed_packages(self.picking),
|
311
|
+
message=self.service.msg_store.dest_package_not_valid(package),
|
312
|
+
)
|
313
|
+
|
314
|
+
def test_set_dest_package_error_qty_done_above(self):
|
315
|
+
# If the qty_done of a selected line goes beyond
|
316
|
+
# the maximum allowed, a message should be displayed
|
317
|
+
# and the user shouldn't be allowed to select a package.
|
318
|
+
line = fields.first(self.picking.move_line_ids)
|
319
|
+
line.qty_done = line.reserved_uom_qty + 1
|
320
|
+
response = self.service.dispatch(
|
321
|
+
"list_dest_package",
|
322
|
+
params={
|
323
|
+
"picking_id": self.picking.id,
|
324
|
+
"selected_line_ids": self.picking.move_line_ids.ids,
|
325
|
+
},
|
326
|
+
)
|
327
|
+
self._assert_select_package_qty_above(response, self.picking)
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# Copyright 2020 Camptocamp SA (http://www.camptocamp.com)
|
2
|
+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
3
|
+
from odoo import fields
|
4
|
+
|
5
|
+
from .test_checkout_base import CheckoutCommonCase
|
6
|
+
from .test_checkout_select_package_base import CheckoutSelectPackageMixin
|
7
|
+
|
8
|
+
|
9
|
+
class CheckoutNewPackageCase(CheckoutCommonCase, CheckoutSelectPackageMixin):
|
10
|
+
def test_new_package_ok(self):
|
11
|
+
picking = self._create_picking(
|
12
|
+
lines=[
|
13
|
+
(self.product_a, 10),
|
14
|
+
(self.product_b, 10),
|
15
|
+
(self.product_c, 10),
|
16
|
+
(self.product_d, 10),
|
17
|
+
]
|
18
|
+
)
|
19
|
+
pack1_moves = picking.move_ids[:3]
|
20
|
+
pack2_moves = picking.move_ids[3:]
|
21
|
+
# put in 2 packs, for this test, we'll work on pack1
|
22
|
+
self._fill_stock_for_moves(pack1_moves, in_package=True)
|
23
|
+
self._fill_stock_for_moves(pack2_moves, in_package=True)
|
24
|
+
picking.action_assign()
|
25
|
+
|
26
|
+
selected_lines = pack1_moves.move_line_ids
|
27
|
+
pack1 = pack1_moves.move_line_ids.package_id
|
28
|
+
|
29
|
+
move_line1, move_line2, move_line3 = selected_lines
|
30
|
+
# we'll put only the first 2 lines (product A and B) in the new package
|
31
|
+
move_line1.qty_done = move_line1.reserved_uom_qty
|
32
|
+
move_line2.qty_done = move_line2.reserved_uom_qty
|
33
|
+
move_line3.qty_done = 0
|
34
|
+
|
35
|
+
response = self.service.dispatch(
|
36
|
+
"new_package",
|
37
|
+
params={"picking_id": picking.id, "selected_line_ids": selected_lines.ids},
|
38
|
+
)
|
39
|
+
|
40
|
+
new_package = move_line1.result_package_id
|
41
|
+
self.assertNotEqual(pack1, new_package)
|
42
|
+
|
43
|
+
self.assertRecordValues(
|
44
|
+
move_line1,
|
45
|
+
[{"result_package_id": new_package.id, "shopfloor_checkout_done": True}],
|
46
|
+
)
|
47
|
+
self.assertRecordValues(
|
48
|
+
move_line2,
|
49
|
+
[{"result_package_id": new_package.id, "shopfloor_checkout_done": True}],
|
50
|
+
)
|
51
|
+
self.assertRecordValues(
|
52
|
+
move_line3,
|
53
|
+
# qty_done was zero so we don't set it as packed and it remains in
|
54
|
+
# the same package
|
55
|
+
[{"result_package_id": pack1.id, "shopfloor_checkout_done": False}],
|
56
|
+
)
|
57
|
+
self.assert_response(
|
58
|
+
response,
|
59
|
+
# go pack to the screen to select lines to put in packages
|
60
|
+
next_state="select_line",
|
61
|
+
data=self._data_for_select_line(picking),
|
62
|
+
message=self.msg_store.goods_packed_in(new_package),
|
63
|
+
)
|
64
|
+
|
65
|
+
def test_set_dest_package_error_qty_done_above(self):
|
66
|
+
picking = self._create_picking(
|
67
|
+
lines=[
|
68
|
+
(self.product_a, 10),
|
69
|
+
(self.product_b, 10),
|
70
|
+
]
|
71
|
+
)
|
72
|
+
moves = picking.move_ids
|
73
|
+
self._fill_stock_for_moves(moves, in_package=True)
|
74
|
+
picking.action_assign()
|
75
|
+
# If the qty_done of a selected line goes beyond
|
76
|
+
# the maximum allowed, a message should be displayed
|
77
|
+
# and the user shouldn't be allowed to select a package.
|
78
|
+
selected_lines = moves.move_line_ids
|
79
|
+
line = fields.first(selected_lines)
|
80
|
+
line.qty_done = line.reserved_uom_qty + 1
|
81
|
+
response = self.service.dispatch(
|
82
|
+
"list_dest_package",
|
83
|
+
params={
|
84
|
+
"picking_id": picking.id,
|
85
|
+
"selected_line_ids": picking.move_line_ids.ids,
|
86
|
+
},
|
87
|
+
)
|
88
|
+
self._assert_select_package_qty_above(response, picking)
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# Copyright 2020 Camptocamp SA (http://www.camptocamp.com)
|
2
|
+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
3
|
+
import werkzeug
|
4
|
+
|
5
|
+
from odoo import fields
|
6
|
+
|
7
|
+
from .test_checkout_base import CheckoutCommonCase
|
8
|
+
from .test_checkout_select_package_base import CheckoutSelectPackageMixin
|
9
|
+
|
10
|
+
|
11
|
+
# pylint: disable=missing-return
|
12
|
+
class CheckoutNoPackageCase(CheckoutCommonCase, CheckoutSelectPackageMixin):
|
13
|
+
@classmethod
|
14
|
+
def setUpClassBaseData(cls):
|
15
|
+
super().setUpClassBaseData()
|
16
|
+
cls.picking = picking = cls._create_picking(
|
17
|
+
lines=[
|
18
|
+
(cls.product_a, 10),
|
19
|
+
(cls.product_b, 10),
|
20
|
+
(cls.product_c, 10),
|
21
|
+
(cls.product_d, 10),
|
22
|
+
]
|
23
|
+
)
|
24
|
+
cls.pack1_moves = pack1_moves = picking.move_ids[:3]
|
25
|
+
cls.pack2_moves = pack2_moves = picking.move_ids[3:]
|
26
|
+
# put in 2 packs, for this test, we'll work on pack1
|
27
|
+
cls._fill_stock_for_moves(pack1_moves)
|
28
|
+
cls._fill_stock_for_moves(pack2_moves)
|
29
|
+
picking.action_assign()
|
30
|
+
|
31
|
+
def test_no_package_ok(self):
|
32
|
+
move_line1, move_line2, move_line3 = self.pack1_moves.move_line_ids
|
33
|
+
selected_lines = move_line1 + move_line2
|
34
|
+
|
35
|
+
# we'll put only the first 2 lines (product A and B) w/ no package
|
36
|
+
move_line1.qty_done = move_line1.reserved_uom_qty
|
37
|
+
move_line2.qty_done = move_line2.reserved_uom_qty
|
38
|
+
move_line3.qty_done = 0
|
39
|
+
response = self.service.dispatch(
|
40
|
+
"no_package",
|
41
|
+
params={
|
42
|
+
"picking_id": self.picking.id,
|
43
|
+
"selected_line_ids": selected_lines.ids,
|
44
|
+
},
|
45
|
+
)
|
46
|
+
|
47
|
+
self.assertRecordValues(
|
48
|
+
move_line1,
|
49
|
+
[{"result_package_id": False, "shopfloor_checkout_done": True}],
|
50
|
+
)
|
51
|
+
self.assertRecordValues(
|
52
|
+
move_line2,
|
53
|
+
[{"result_package_id": False, "shopfloor_checkout_done": True}],
|
54
|
+
)
|
55
|
+
self.assertRecordValues(
|
56
|
+
move_line3,
|
57
|
+
[{"result_package_id": False, "shopfloor_checkout_done": False}],
|
58
|
+
)
|
59
|
+
self.assert_response(
|
60
|
+
response,
|
61
|
+
# go pack to the screen to select lines to put in packages
|
62
|
+
next_state="select_line",
|
63
|
+
data=self._data_for_select_line(self.picking),
|
64
|
+
message={
|
65
|
+
"message_type": "success",
|
66
|
+
"body": "Product(s) processed as raw product(s)",
|
67
|
+
},
|
68
|
+
)
|
69
|
+
|
70
|
+
def test_no_package_disabled(self):
|
71
|
+
self.service.work.options = {"checkout__disable_no_package": True}
|
72
|
+
with self.assertRaises(werkzeug.exceptions.BadRequest) as err:
|
73
|
+
self.service.dispatch(
|
74
|
+
"no_package",
|
75
|
+
params={
|
76
|
+
"picking_id": self.picking.id,
|
77
|
+
"selected_line_ids": self.pack1_moves.move_line_ids.ids,
|
78
|
+
},
|
79
|
+
)
|
80
|
+
self.assertEqual(repr(err), "`checkout.no_package` endpoint is not enabled")
|
81
|
+
|
82
|
+
def test_set_dest_package_error_qty_done_above(self):
|
83
|
+
# If the qty_done of a selected line goes beyond
|
84
|
+
# the maximum allowed, a message should be displayed
|
85
|
+
# and the user shouldn't be allowed to select a package.
|
86
|
+
line = fields.first(self.picking.move_line_ids)
|
87
|
+
line.qty_done = line.reserved_uom_qty + 1
|
88
|
+
response = self.service.dispatch(
|
89
|
+
"list_dest_package",
|
90
|
+
params={
|
91
|
+
"picking_id": self.picking.id,
|
92
|
+
"selected_line_ids": self.picking.move_line_ids.ids,
|
93
|
+
},
|
94
|
+
)
|
95
|
+
self._assert_select_package_qty_above(response, self.picking)
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# Copyright 2020 Camptocamp SA (http://www.camptocamp.com)
|
2
|
+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
3
|
+
from .test_checkout_base import CheckoutCommonCase
|
4
|
+
|
5
|
+
|
6
|
+
class CheckoutScanCase(CheckoutCommonCase):
|
7
|
+
def _test_scan_ok(self, barcode_func, in_package=True):
|
8
|
+
picking = self._create_picking()
|
9
|
+
self._fill_stock_for_moves(picking.move_ids, in_package=in_package)
|
10
|
+
picking.action_assign()
|
11
|
+
barcode = barcode_func(picking)
|
12
|
+
response = self.service.dispatch("scan_document", params={"barcode": barcode})
|
13
|
+
self.assert_response(
|
14
|
+
response,
|
15
|
+
next_state="select_line",
|
16
|
+
data=self._data_for_select_line(picking),
|
17
|
+
)
|
18
|
+
|
19
|
+
def test_scan_document_stock_picking_ok(self):
|
20
|
+
self._test_scan_ok(lambda picking: picking.name)
|
21
|
+
|
22
|
+
def test_scan_document_location_ok(self):
|
23
|
+
self._test_scan_ok(lambda picking: picking.move_line_ids.location_id.barcode)
|
24
|
+
|
25
|
+
def test_scan_document_package_ok(self):
|
26
|
+
self._test_scan_ok(lambda picking: picking.move_line_ids.package_id.name)
|
27
|
+
|
28
|
+
def test_scan_document_product_ok(self):
|
29
|
+
self._test_scan_ok(
|
30
|
+
lambda picking: picking.move_line_ids.product_id[0].barcode,
|
31
|
+
in_package=False,
|
32
|
+
)
|
33
|
+
|
34
|
+
def test_scan_document_packaging_ok(self):
|
35
|
+
self._test_scan_ok(
|
36
|
+
lambda picking: picking.move_line_ids.product_id[0].packaging_ids.barcode,
|
37
|
+
in_package=False,
|
38
|
+
)
|
39
|
+
|
40
|
+
def test_scan_document_error_not_found(self):
|
41
|
+
response = self.service.dispatch("scan_document", params={"barcode": "NOPE"})
|
42
|
+
self.assert_response(
|
43
|
+
response,
|
44
|
+
next_state="select_document",
|
45
|
+
message={"message_type": "error", "body": "Barcode not found"},
|
46
|
+
)
|
47
|
+
|
48
|
+
def _test_scan_document_error_not_available(self, barcode_func):
|
49
|
+
picking = self._create_picking()
|
50
|
+
# in this test, we want the picking not to be available, but
|
51
|
+
# if we leave the shipping policy to direct, a single move assigned
|
52
|
+
# would make the picking available
|
53
|
+
picking.move_type = "one"
|
54
|
+
# the picking will have one line available, so the endpoint can find
|
55
|
+
# something from a location or package but should reject the picking as
|
56
|
+
# it is not entirely available
|
57
|
+
self._fill_stock_for_moves(picking.move_ids[0], in_package=True)
|
58
|
+
picking.action_assign()
|
59
|
+
barcode = barcode_func(picking)
|
60
|
+
response = self.service.dispatch("scan_document", params={"barcode": barcode})
|
61
|
+
self.assert_response(
|
62
|
+
response,
|
63
|
+
next_state="select_document",
|
64
|
+
message={
|
65
|
+
"message_type": "error",
|
66
|
+
"body": "Transfer {} is not available.".format(picking.name),
|
67
|
+
},
|
68
|
+
)
|
69
|
+
|
70
|
+
def test_scan_document_error_not_available_picking(self):
|
71
|
+
self._test_scan_document_error_not_available(lambda picking: picking.name)
|
72
|
+
|
73
|
+
def test_scan_document_error_not_available_location(self):
|
74
|
+
self._test_scan_document_error_not_available(
|
75
|
+
lambda picking: picking.move_line_ids.location_id.barcode
|
76
|
+
)
|
77
|
+
|
78
|
+
def test_scan_document_error_not_available_package(self):
|
79
|
+
self._test_scan_document_error_not_available(
|
80
|
+
lambda picking: picking.move_line_ids.package_id.name
|
81
|
+
)
|
82
|
+
|
83
|
+
def test_scan_document_error_location_not_child_of_type(self):
|
84
|
+
picking = self._create_picking()
|
85
|
+
picking.location_id = self.dispatch_location
|
86
|
+
self._fill_stock_for_moves(picking.move_ids, in_package=True)
|
87
|
+
picking.action_assign()
|
88
|
+
response = self.service.dispatch(
|
89
|
+
"scan_document", params={"barcode": picking.location_id.barcode}
|
90
|
+
)
|
91
|
+
self.assert_response(
|
92
|
+
response,
|
93
|
+
next_state="select_document",
|
94
|
+
message={"message_type": "error", "body": "Location not allowed here."},
|
95
|
+
)
|
96
|
+
|
97
|
+
def _test_scan_document_error_different_picking_type(self, barcode_func):
|
98
|
+
picking = self._create_picking(picking_type=self.wh.pick_type_id)
|
99
|
+
self._fill_stock_for_moves(picking.move_ids, in_package=True)
|
100
|
+
picking.action_assign()
|
101
|
+
barcode = barcode_func(picking)
|
102
|
+
response = self.service.dispatch("scan_document", params={"barcode": barcode})
|
103
|
+
self.assert_response(
|
104
|
+
response,
|
105
|
+
next_state="select_document",
|
106
|
+
message={
|
107
|
+
"message_type": "error",
|
108
|
+
"body": "You cannot move this using this menu.",
|
109
|
+
},
|
110
|
+
)
|
111
|
+
|
112
|
+
def test_scan_document_error_different_picking_type_picking(self):
|
113
|
+
self._test_scan_document_error_different_picking_type(
|
114
|
+
lambda picking: picking.name
|
115
|
+
)
|
116
|
+
|
117
|
+
def test_scan_document_error_different_picking_type_package(self):
|
118
|
+
self._test_scan_document_error_different_picking_type(
|
119
|
+
lambda picking: picking.move_line_ids.package_id.name
|
120
|
+
)
|
121
|
+
|
122
|
+
def test_scan_document_error_location_several_pickings(self):
|
123
|
+
picking = self._create_picking()
|
124
|
+
# create a second picking at the same place so we don't
|
125
|
+
# know which picking to use
|
126
|
+
picking2 = self._create_picking()
|
127
|
+
pickings = picking | picking2
|
128
|
+
self._fill_stock_for_moves(pickings.move_ids, in_package=True)
|
129
|
+
pickings.action_assign()
|
130
|
+
response = self.service.dispatch(
|
131
|
+
"scan_document",
|
132
|
+
params={"barcode": picking.move_line_ids.location_id.barcode},
|
133
|
+
)
|
134
|
+
self.assert_response(
|
135
|
+
response,
|
136
|
+
next_state="select_document",
|
137
|
+
message={
|
138
|
+
"message_type": "error",
|
139
|
+
"body": "Several transfers found, please scan a package"
|
140
|
+
" or select a transfer manually.",
|
141
|
+
},
|
142
|
+
)
|
143
|
+
|
144
|
+
def test_scan_document_recover(self):
|
145
|
+
"""If the user starts to process a line, and for whatever reason he
|
146
|
+
stops there and restarts the scenario from the beginning, he should
|
147
|
+
still be able to find the previous line.
|
148
|
+
"""
|
149
|
+
picking = self._create_picking()
|
150
|
+
self._fill_stock_for_moves(picking.move_ids, in_package=True)
|
151
|
+
picking.action_assign()
|
152
|
+
package = picking.move_line_ids.package_id
|
153
|
+
# The user selects a line, then stops working in the middle of the process
|
154
|
+
response = self.service.dispatch(
|
155
|
+
"scan_document", params={"barcode": package.name}
|
156
|
+
)
|
157
|
+
data = response["data"]["select_line"]
|
158
|
+
self.assertEqual(data["picking"]["move_line_count"], 2)
|
159
|
+
self.assertEqual(len(data["picking"]["move_lines"]), 2)
|
160
|
+
self.assertFalse(picking.move_line_ids.shopfloor_user_id)
|
161
|
+
response = self.service.dispatch(
|
162
|
+
"select_line",
|
163
|
+
params={"picking_id": picking.id, "package_id": package.id},
|
164
|
+
)
|
165
|
+
self.assertTrue(all(m.qty_done for m in picking.move_line_ids))
|
166
|
+
self.assertEqual(picking.move_line_ids.shopfloor_user_id, self.env.user)
|
167
|
+
# He restarts the scenario and try to select again the previous line
|
168
|
+
# to continue its job
|
169
|
+
response = self.service.dispatch(
|
170
|
+
"scan_document", params={"barcode": package.name}
|
171
|
+
)
|
172
|
+
data = response["data"]["select_line"]
|
173
|
+
self.assertEqual(data["picking"]["move_line_count"], 2)
|
174
|
+
self.assertEqual(len(data["picking"]["move_lines"]), 2) # Lines found
|