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,81 @@
|
|
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 .common import CommonCase
|
4
|
+
|
5
|
+
|
6
|
+
# pylint: disable=missing-return
|
7
|
+
class CheckoutCommonCase(CommonCase):
|
8
|
+
@classmethod
|
9
|
+
def setUpClassVars(cls, *args, **kwargs):
|
10
|
+
super().setUpClassVars(*args, **kwargs)
|
11
|
+
cls.menu = cls.env.ref("shopfloor.shopfloor_menu_demo_checkout")
|
12
|
+
cls.profile = cls.env.ref("shopfloor.profile_demo_1")
|
13
|
+
cls.picking_type = cls.menu.picking_type_ids
|
14
|
+
cls.wh = cls.picking_type.warehouse_id
|
15
|
+
|
16
|
+
@classmethod
|
17
|
+
def setUpClassBaseData(cls, *args, **kwargs):
|
18
|
+
super().setUpClassBaseData(*args, **kwargs)
|
19
|
+
cls.wh.sudo().delivery_steps = "pick_pack_ship"
|
20
|
+
cls.delivery_packaging = (
|
21
|
+
cls.env["stock.package.type"]
|
22
|
+
.sudo()
|
23
|
+
.create(
|
24
|
+
{
|
25
|
+
"name": "Pallet",
|
26
|
+
"package_carrier_type": "none",
|
27
|
+
"barcode": "PALCODE",
|
28
|
+
}
|
29
|
+
)
|
30
|
+
)
|
31
|
+
|
32
|
+
def setUp(self):
|
33
|
+
super().setUp()
|
34
|
+
self.service = self.get_service(
|
35
|
+
"checkout", menu=self.menu, profile=self.profile
|
36
|
+
)
|
37
|
+
|
38
|
+
def _stock_picking_data(self, picking, **kw):
|
39
|
+
return self.service._data_for_stock_picking(picking, **kw)
|
40
|
+
|
41
|
+
# we test the methods that structure data in test_actions_data.py
|
42
|
+
def _picking_summary_data(self, picking):
|
43
|
+
return self.data.picking(picking)
|
44
|
+
|
45
|
+
def _move_line_data(self, move_line):
|
46
|
+
return self.data.move_line(move_line)
|
47
|
+
|
48
|
+
def _package_data(self, package, picking):
|
49
|
+
return self.data.package(package, picking=picking, with_packaging=True)
|
50
|
+
|
51
|
+
def _packaging_data(self, packaging):
|
52
|
+
return self.data.delivery_packaging(packaging)
|
53
|
+
|
54
|
+
def _data_for_select_line(self, picking, **kw):
|
55
|
+
data = {
|
56
|
+
"picking": self._stock_picking_data(picking),
|
57
|
+
"group_lines_by_location": True,
|
58
|
+
"show_oneline_package_content": False,
|
59
|
+
"need_confirm_pack_all": False,
|
60
|
+
}
|
61
|
+
data.update(kw)
|
62
|
+
return data
|
63
|
+
|
64
|
+
def _assert_select_package_qty_above(self, response, picking):
|
65
|
+
self.assert_response(
|
66
|
+
response,
|
67
|
+
next_state="select_package",
|
68
|
+
data={
|
69
|
+
"selected_move_lines": [
|
70
|
+
self._move_line_data(ml) for ml in picking.move_line_ids.sorted()
|
71
|
+
],
|
72
|
+
"picking": self._picking_summary_data(picking),
|
73
|
+
"packing_info": "",
|
74
|
+
"no_package_enabled": True,
|
75
|
+
},
|
76
|
+
message={
|
77
|
+
"message_type": "warning",
|
78
|
+
"body": "The quantity scanned for one or more lines cannot be "
|
79
|
+
"higher than the maximum allowed.",
|
80
|
+
},
|
81
|
+
)
|
@@ -0,0 +1,154 @@
|
|
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
|
+
# pylint: disable=missing-return
|
7
|
+
class CheckoutRemovePackageCase(CheckoutCommonCase):
|
8
|
+
@classmethod
|
9
|
+
def setUpClassBaseData(cls):
|
10
|
+
super().setUpClassBaseData()
|
11
|
+
cls.picking = picking = cls._create_picking(
|
12
|
+
lines=[
|
13
|
+
(cls.product_a, 10),
|
14
|
+
(cls.product_b, 10),
|
15
|
+
(cls.product_c, 10),
|
16
|
+
(cls.product_d, 10),
|
17
|
+
]
|
18
|
+
)
|
19
|
+
cls.pack1_moves = picking.move_ids[:2]
|
20
|
+
cls.pack2_moves = picking.move_ids[2]
|
21
|
+
cls.raw_move = picking.move_ids[3]
|
22
|
+
cls._fill_stock_for_moves(cls.pack1_moves, in_package=True)
|
23
|
+
cls._fill_stock_for_moves(cls.pack2_moves, in_package=True)
|
24
|
+
cls._fill_stock_for_moves(cls.raw_move)
|
25
|
+
picking.action_assign()
|
26
|
+
|
27
|
+
def test_cancel_package_ok(self):
|
28
|
+
picking = self.picking
|
29
|
+
|
30
|
+
pack1_lines = self.pack1_moves.move_line_ids
|
31
|
+
pack2_lines = self.pack2_moves.move_line_ids
|
32
|
+
raw_line = self.raw_move.move_line_ids
|
33
|
+
|
34
|
+
# do as we packed the lines in 2 different packages
|
35
|
+
new_package = self.env["stock.quant.package"].create({})
|
36
|
+
(pack1_lines | raw_line).write(
|
37
|
+
{
|
38
|
+
"qty_done": 10,
|
39
|
+
"result_package_id": new_package.id,
|
40
|
+
"shopfloor_checkout_done": True,
|
41
|
+
}
|
42
|
+
)
|
43
|
+
new_package2 = self.env["stock.quant.package"].create({})
|
44
|
+
pack2_lines.write(
|
45
|
+
{
|
46
|
+
"qty_done": 10,
|
47
|
+
"result_package_id": new_package2.id,
|
48
|
+
"shopfloor_checkout_done": True,
|
49
|
+
}
|
50
|
+
)
|
51
|
+
|
52
|
+
# and now, we want to drop the new_package
|
53
|
+
response = self.service.dispatch(
|
54
|
+
"cancel_line",
|
55
|
+
params={"picking_id": picking.id, "package_id": new_package.id},
|
56
|
+
)
|
57
|
+
|
58
|
+
self.assertRecordValues(
|
59
|
+
pack1_lines + raw_line + pack2_lines,
|
60
|
+
[
|
61
|
+
{
|
62
|
+
"qty_done": 0,
|
63
|
+
# reset to origin package
|
64
|
+
"result_package_id": pack1_lines.mapped("package_id").id,
|
65
|
+
"shopfloor_checkout_done": False,
|
66
|
+
},
|
67
|
+
{
|
68
|
+
"qty_done": 0,
|
69
|
+
# reset to origin package
|
70
|
+
"result_package_id": pack1_lines.mapped("package_id").id,
|
71
|
+
"shopfloor_checkout_done": False,
|
72
|
+
},
|
73
|
+
{
|
74
|
+
"qty_done": 0,
|
75
|
+
# result to an empty package (raw product)
|
76
|
+
"result_package_id": False,
|
77
|
+
"shopfloor_checkout_done": False,
|
78
|
+
},
|
79
|
+
# different package, leave untouched
|
80
|
+
{
|
81
|
+
"qty_done": 10,
|
82
|
+
"result_package_id": new_package2.id,
|
83
|
+
"shopfloor_checkout_done": True,
|
84
|
+
},
|
85
|
+
],
|
86
|
+
)
|
87
|
+
|
88
|
+
self.assert_response(
|
89
|
+
response,
|
90
|
+
next_state="select_line",
|
91
|
+
data=self._data_for_select_line(picking),
|
92
|
+
message={"body": "Package cancelled", "message_type": "success"},
|
93
|
+
)
|
94
|
+
|
95
|
+
def test_cancel_line_ok(self):
|
96
|
+
picking = self.picking
|
97
|
+
|
98
|
+
raw_line = self.raw_move.move_line_ids
|
99
|
+
|
100
|
+
raw_line.write({"qty_done": 10, "shopfloor_checkout_done": True})
|
101
|
+
|
102
|
+
# and now, we want to drop the new_package
|
103
|
+
response = self.service.dispatch(
|
104
|
+
"cancel_line",
|
105
|
+
params={"picking_id": picking.id, "line_id": raw_line.id},
|
106
|
+
)
|
107
|
+
|
108
|
+
self.assertRecordValues(
|
109
|
+
raw_line,
|
110
|
+
[{"qty_done": 0, "shopfloor_checkout_done": False}],
|
111
|
+
)
|
112
|
+
|
113
|
+
self.assert_response(
|
114
|
+
response,
|
115
|
+
next_state="select_line",
|
116
|
+
data=self._data_for_select_line(picking),
|
117
|
+
message={"body": "Line cancelled", "message_type": "success"},
|
118
|
+
)
|
119
|
+
|
120
|
+
def test_cancel_line_error_package_not_found(self):
|
121
|
+
# and now, we want to drop the new_package
|
122
|
+
response = self.service.dispatch(
|
123
|
+
"cancel_line", params={"picking_id": self.picking.id, "package_id": 0}
|
124
|
+
)
|
125
|
+
self.assert_response(
|
126
|
+
response,
|
127
|
+
next_state="summary",
|
128
|
+
data={
|
129
|
+
"picking": self._stock_picking_data(self.picking, done=True),
|
130
|
+
"all_processed": False,
|
131
|
+
},
|
132
|
+
message={
|
133
|
+
"message_type": "error",
|
134
|
+
"body": "The record you were working on does not exist anymore.",
|
135
|
+
},
|
136
|
+
)
|
137
|
+
|
138
|
+
def test_cancel_line_error_line_not_found(self):
|
139
|
+
# and now, we want to drop the new_package
|
140
|
+
response = self.service.dispatch(
|
141
|
+
"cancel_line", params={"picking_id": self.picking.id, "line_id": 0}
|
142
|
+
)
|
143
|
+
self.assert_response(
|
144
|
+
response,
|
145
|
+
next_state="summary",
|
146
|
+
data={
|
147
|
+
"picking": self._stock_picking_data(self.picking, done=True),
|
148
|
+
"all_processed": False,
|
149
|
+
},
|
150
|
+
message={
|
151
|
+
"message_type": "error",
|
152
|
+
"body": "The record you were working on does not exist anymore.",
|
153
|
+
},
|
154
|
+
)
|
@@ -0,0 +1,184 @@
|
|
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
|
+
# pylint: disable=missing-return
|
7
|
+
class CheckoutListSetPackagingCase(CheckoutCommonCase):
|
8
|
+
@classmethod
|
9
|
+
def setUpClassBaseData(cls):
|
10
|
+
super().setUpClassBaseData()
|
11
|
+
cls.env["stock.package.type"].sudo().search([]).active = False
|
12
|
+
pallet_type = (
|
13
|
+
cls.env["product.packaging.level"]
|
14
|
+
.sudo()
|
15
|
+
.create({"name": "Pallet", "code": "P", "sequence": 3})
|
16
|
+
)
|
17
|
+
cls.packaging_pallet = (
|
18
|
+
cls.env["stock.package.type"]
|
19
|
+
.sudo()
|
20
|
+
.create(
|
21
|
+
{
|
22
|
+
"packaging_level_id": pallet_type.id,
|
23
|
+
"name": "Pallet",
|
24
|
+
"barcode": "PPP",
|
25
|
+
"height": 100,
|
26
|
+
"width": 100,
|
27
|
+
"packaging_length": 100,
|
28
|
+
"sequence": 2,
|
29
|
+
}
|
30
|
+
)
|
31
|
+
)
|
32
|
+
box_type = (
|
33
|
+
cls.env["product.packaging.level"]
|
34
|
+
.sudo()
|
35
|
+
.create({"name": "Box", "code": "B", "sequence": 2})
|
36
|
+
)
|
37
|
+
cls.packaging_box = (
|
38
|
+
cls.env["stock.package.type"]
|
39
|
+
.sudo()
|
40
|
+
.create(
|
41
|
+
{
|
42
|
+
"packaging_level_id": box_type.id,
|
43
|
+
"name": "Box",
|
44
|
+
"barcode": "BBB",
|
45
|
+
"height": 20,
|
46
|
+
"width": 20,
|
47
|
+
"packaging_length": 20,
|
48
|
+
"sequence": 1,
|
49
|
+
}
|
50
|
+
)
|
51
|
+
)
|
52
|
+
inner_box_type = (
|
53
|
+
cls.env["product.packaging.level"]
|
54
|
+
.sudo()
|
55
|
+
.create({"name": "Inner Box", "code": "I", "sequence": 1})
|
56
|
+
)
|
57
|
+
cls.packaging_inner_box = (
|
58
|
+
cls.env["stock.package.type"]
|
59
|
+
.sudo()
|
60
|
+
.create(
|
61
|
+
{
|
62
|
+
"packaging_level_id": inner_box_type.id,
|
63
|
+
"name": "Inner Box",
|
64
|
+
"barcode": "III",
|
65
|
+
"height": 10,
|
66
|
+
"width": 10,
|
67
|
+
"packaging_length": 10,
|
68
|
+
"sequence": 0,
|
69
|
+
}
|
70
|
+
)
|
71
|
+
)
|
72
|
+
cls.picking = cls._create_picking(lines=[(cls.product_a, 10)])
|
73
|
+
cls._fill_stock_for_moves(cls.picking.move_ids, in_package=True)
|
74
|
+
cls.picking.action_assign()
|
75
|
+
cls.package = cls.picking.move_line_ids.result_package_id
|
76
|
+
cls.package.package_type_id = cls.packaging_pallet
|
77
|
+
cls.packagings = cls.env["stock.package.type"].search([]).sorted()
|
78
|
+
|
79
|
+
def test_list_packaging_ok(self):
|
80
|
+
response = self.service.dispatch(
|
81
|
+
"list_packaging",
|
82
|
+
params={"picking_id": self.picking.id, "package_id": self.package.id},
|
83
|
+
)
|
84
|
+
|
85
|
+
self.assert_response(
|
86
|
+
response,
|
87
|
+
next_state="change_packaging",
|
88
|
+
data={
|
89
|
+
"picking": self._picking_summary_data(self.picking),
|
90
|
+
"package": self._package_data(self.package, self.picking),
|
91
|
+
"packaging": [
|
92
|
+
self._packaging_data(packaging)
|
93
|
+
for packaging in self.packaging_inner_box
|
94
|
+
+ self.packaging_box
|
95
|
+
+ self.packaging_pallet
|
96
|
+
],
|
97
|
+
},
|
98
|
+
)
|
99
|
+
|
100
|
+
def test_list_packaging_error_package_not_found(self):
|
101
|
+
response = self.service.dispatch(
|
102
|
+
"list_packaging", params={"picking_id": self.picking.id, "package_id": 0}
|
103
|
+
)
|
104
|
+
self.assert_response(
|
105
|
+
response,
|
106
|
+
next_state="summary",
|
107
|
+
data={
|
108
|
+
"picking": self._stock_picking_data(self.picking, done=True),
|
109
|
+
"all_processed": False,
|
110
|
+
},
|
111
|
+
message={
|
112
|
+
"message_type": "error",
|
113
|
+
"body": "The record you were working on does not exist anymore.",
|
114
|
+
},
|
115
|
+
)
|
116
|
+
|
117
|
+
def test_set_packaging_ok(self):
|
118
|
+
response = self.service.dispatch(
|
119
|
+
"set_packaging",
|
120
|
+
params={
|
121
|
+
"picking_id": self.picking.id,
|
122
|
+
"package_id": self.package.id,
|
123
|
+
"package_type_id": self.packaging_inner_box.id,
|
124
|
+
},
|
125
|
+
)
|
126
|
+
self.assertRecordValues(
|
127
|
+
self.package, [{"package_type_id": self.packaging_inner_box.id}]
|
128
|
+
)
|
129
|
+
self.assert_response(
|
130
|
+
response,
|
131
|
+
next_state="summary",
|
132
|
+
data={
|
133
|
+
"picking": self._stock_picking_data(self.picking, done=True),
|
134
|
+
"all_processed": False,
|
135
|
+
},
|
136
|
+
message={
|
137
|
+
"message_type": "success",
|
138
|
+
"body": "Packaging changed on package {}".format(self.package.name),
|
139
|
+
},
|
140
|
+
)
|
141
|
+
|
142
|
+
def test_set_packaging_error_package_not_found(self):
|
143
|
+
response = self.service.dispatch(
|
144
|
+
"set_packaging",
|
145
|
+
params={
|
146
|
+
"picking_id": self.picking.id,
|
147
|
+
"package_id": 0,
|
148
|
+
"package_type_id": self.packaging_inner_box.id,
|
149
|
+
},
|
150
|
+
)
|
151
|
+
self.assert_response(
|
152
|
+
response,
|
153
|
+
next_state="summary",
|
154
|
+
data={
|
155
|
+
"picking": self._stock_picking_data(self.picking, done=True),
|
156
|
+
"all_processed": False,
|
157
|
+
},
|
158
|
+
message={
|
159
|
+
"message_type": "error",
|
160
|
+
"body": "The record you were working on does not exist anymore.",
|
161
|
+
},
|
162
|
+
)
|
163
|
+
|
164
|
+
def test_set_packaging_error_packaging_not_found(self):
|
165
|
+
response = self.service.dispatch(
|
166
|
+
"set_packaging",
|
167
|
+
params={
|
168
|
+
"picking_id": self.picking.id,
|
169
|
+
"package_id": self.package.id,
|
170
|
+
"package_type_id": 0,
|
171
|
+
},
|
172
|
+
)
|
173
|
+
self.assert_response(
|
174
|
+
response,
|
175
|
+
next_state="summary",
|
176
|
+
data={
|
177
|
+
"picking": self._stock_picking_data(self.picking, done=True),
|
178
|
+
"all_processed": False,
|
179
|
+
},
|
180
|
+
message={
|
181
|
+
"message_type": "error",
|
182
|
+
"body": "The record you were working on does not exist anymore.",
|
183
|
+
},
|
184
|
+
)
|
@@ -0,0 +1,133 @@
|
|
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
|
+
# pylint: disable=missing-return
|
7
|
+
class CheckoutDoneCase(CheckoutCommonCase):
|
8
|
+
def test_done_ok(self):
|
9
|
+
picking = self._create_picking(lines=[(self.product_a, 10)])
|
10
|
+
self._fill_stock_for_moves(picking.move_ids, in_package=True)
|
11
|
+
picking.action_assign()
|
12
|
+
# line is done
|
13
|
+
picking.move_line_ids.write({"qty_done": 10, "shopfloor_checkout_done": True})
|
14
|
+
response = self.service.dispatch("done", params={"picking_id": picking.id})
|
15
|
+
|
16
|
+
self.assertRecordValues(picking, [{"state": "done"}])
|
17
|
+
|
18
|
+
self.assert_response(
|
19
|
+
response,
|
20
|
+
next_state="select_document",
|
21
|
+
message={
|
22
|
+
"message_type": "success",
|
23
|
+
"body": "Transfer {} done".format(picking.name),
|
24
|
+
},
|
25
|
+
)
|
26
|
+
|
27
|
+
|
28
|
+
class CheckoutDonePartialCase(CheckoutCommonCase):
|
29
|
+
@classmethod
|
30
|
+
def setUpClassBaseData(cls):
|
31
|
+
super().setUpClassBaseData()
|
32
|
+
cls.picking = picking = cls._create_picking(
|
33
|
+
lines=[(cls.product_a, 10), (cls.product_b, 10)]
|
34
|
+
)
|
35
|
+
cls._fill_stock_for_moves(picking.move_ids)
|
36
|
+
picking.action_assign()
|
37
|
+
cls.line1 = picking.move_line_ids[0]
|
38
|
+
cls.line2 = picking.move_line_ids[1]
|
39
|
+
cls.line1.write({"qty_done": 10, "shopfloor_checkout_done": True})
|
40
|
+
cls.line2.write({"qty_done": 2, "shopfloor_checkout_done": True})
|
41
|
+
|
42
|
+
def test_done_partial(self):
|
43
|
+
# line is done
|
44
|
+
response = self.service.dispatch("done", params={"picking_id": self.picking.id})
|
45
|
+
|
46
|
+
self.assertRecordValues(self.picking, [{"state": "assigned"}])
|
47
|
+
|
48
|
+
self.assert_response(
|
49
|
+
response,
|
50
|
+
next_state="confirm_done",
|
51
|
+
data={"picking": self._stock_picking_data(self.picking, done=True)},
|
52
|
+
message=self.service.msg_store.transfer_confirm_done(),
|
53
|
+
)
|
54
|
+
|
55
|
+
def test_done_partial_confirm(self):
|
56
|
+
# lines are done
|
57
|
+
response = self.service.dispatch(
|
58
|
+
"done", params={"picking_id": self.picking.id, "confirmation": True}
|
59
|
+
)
|
60
|
+
# as they are all the lines that relate to the picking, they didn't have
|
61
|
+
# been extracted in a separate transfer. An usual backorder has been
|
62
|
+
# created for the unprocessed qty.
|
63
|
+
self.assertRecordValues(self.picking, [{"state": "done"}])
|
64
|
+
self.assertTrue(self.picking.backorder_ids)
|
65
|
+
self.assertEqual(self.picking.backorder_ids.move_line_ids.reserved_uom_qty, 8)
|
66
|
+
|
67
|
+
self.assert_response(
|
68
|
+
response,
|
69
|
+
next_state="select_document",
|
70
|
+
message=self.service.msg_store.transfer_done_success(self.picking),
|
71
|
+
)
|
72
|
+
|
73
|
+
|
74
|
+
class CheckoutDoneRawUnpackedCase(CheckoutCommonCase):
|
75
|
+
@classmethod
|
76
|
+
def setUpClassBaseData(cls):
|
77
|
+
super().setUpClassBaseData()
|
78
|
+
cls.picking = picking = cls._create_picking(
|
79
|
+
lines=[(cls.product_a, 10), (cls.product_b, 10)]
|
80
|
+
)
|
81
|
+
cls._fill_stock_for_moves(picking.move_ids)
|
82
|
+
picking.action_assign()
|
83
|
+
cls.line1 = picking.move_line_ids[0]
|
84
|
+
cls.line2 = picking.move_line_ids[1]
|
85
|
+
cls.package = cls.env["stock.quant.package"].create({})
|
86
|
+
cls.line1.write(
|
87
|
+
{
|
88
|
+
"qty_done": 10,
|
89
|
+
"shopfloor_checkout_done": True,
|
90
|
+
"result_package_id": cls.package.id,
|
91
|
+
}
|
92
|
+
)
|
93
|
+
cls.line2.write({"qty_done": 10, "shopfloor_checkout_done": False})
|
94
|
+
|
95
|
+
def test_done_partial(self):
|
96
|
+
# line is done
|
97
|
+
response = self.service.dispatch("done", params={"picking_id": self.picking.id})
|
98
|
+
|
99
|
+
self.assertRecordValues(self.picking, [{"state": "assigned"}])
|
100
|
+
|
101
|
+
self.assert_response(
|
102
|
+
response,
|
103
|
+
next_state="confirm_done",
|
104
|
+
data={"picking": self._stock_picking_data(self.picking, done=True)},
|
105
|
+
message={
|
106
|
+
"message_type": "warning",
|
107
|
+
"body": "Remaining raw product not packed, proceed anyway?",
|
108
|
+
},
|
109
|
+
)
|
110
|
+
|
111
|
+
def test_done_partial_confirm(self):
|
112
|
+
# line is done
|
113
|
+
response = self.service.dispatch(
|
114
|
+
"done", params={"picking_id": self.picking.id, "confirmation": True}
|
115
|
+
)
|
116
|
+
|
117
|
+
# it has been extracted in its own picking, the current one staying open
|
118
|
+
picking_done = self.line1.picking_id
|
119
|
+
self.assertRecordValues(picking_done, [{"state": "done", "backorder_ids": []}])
|
120
|
+
self.assertRecordValues(
|
121
|
+
self.picking, [{"state": "assigned", "backorder_ids": [picking_done.id]}]
|
122
|
+
)
|
123
|
+
self.assertRecordValues(
|
124
|
+
self.line1 + self.line2,
|
125
|
+
[{"result_package_id": self.package.id}, {"result_package_id": False}],
|
126
|
+
)
|
127
|
+
self.assertIn(self.line2, self.picking.move_line_ids)
|
128
|
+
|
129
|
+
self.assert_response(
|
130
|
+
response,
|
131
|
+
next_state="select_document",
|
132
|
+
message=self.service.msg_store.transfer_done_success(picking_done),
|
133
|
+
)
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# Copyright 2021 Camptocamp SA (http://www.camptocamp.com)
|
2
|
+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
3
|
+
from odoo_test_helper import FakeModelLoader
|
4
|
+
|
5
|
+
from .test_checkout_base import CheckoutCommonCase
|
6
|
+
from .test_checkout_select_package_base import CheckoutSelectPackageMixin
|
7
|
+
|
8
|
+
|
9
|
+
# pylint: disable=missing-return
|
10
|
+
class CheckoutListDeliveryPackagingCase(CheckoutCommonCase, CheckoutSelectPackageMixin):
|
11
|
+
@classmethod
|
12
|
+
def setUpClass(cls):
|
13
|
+
try:
|
14
|
+
super().setUpClass()
|
15
|
+
except BaseException:
|
16
|
+
# ensure that the registry is restored in case of error in setUpClass
|
17
|
+
# since tearDownClass is not called in this case and our _load_test_models
|
18
|
+
# loads fake models
|
19
|
+
if hasattr(cls, "loader"):
|
20
|
+
cls.loader.restore_registry()
|
21
|
+
raise
|
22
|
+
|
23
|
+
@classmethod
|
24
|
+
def _load_test_models(cls):
|
25
|
+
cls.loader = FakeModelLoader(cls.env, cls.__module__)
|
26
|
+
cls.loader.backup_registry()
|
27
|
+
from .models import DeliveryCarrierTest, StockPackageType
|
28
|
+
|
29
|
+
cls.loader.update_registry((DeliveryCarrierTest, StockPackageType))
|
30
|
+
|
31
|
+
@classmethod
|
32
|
+
def tearDownClass(cls):
|
33
|
+
cls.loader.restore_registry()
|
34
|
+
super(CheckoutListDeliveryPackagingCase, cls).tearDownClass()
|
35
|
+
|
36
|
+
@classmethod
|
37
|
+
def setUpClassBaseData(cls, *args, **kwargs):
|
38
|
+
super().setUpClassBaseData(*args, **kwargs)
|
39
|
+
cls._load_test_models()
|
40
|
+
cls.carrier = cls.env["delivery.carrier"].search([], limit=1)
|
41
|
+
cls.carrier.sudo().delivery_type = "test"
|
42
|
+
cls.picking = cls._create_picking(
|
43
|
+
lines=[
|
44
|
+
(cls.product_a, 10),
|
45
|
+
(cls.product_b, 10),
|
46
|
+
(cls.product_c, 10),
|
47
|
+
(cls.product_d, 10),
|
48
|
+
]
|
49
|
+
)
|
50
|
+
cls.picking.carrier_id = cls.carrier
|
51
|
+
cls.packaging_type = (
|
52
|
+
cls.env["product.packaging.level"]
|
53
|
+
.sudo()
|
54
|
+
.create({"name": "Transport Box", "code": "TB", "sequence": 0})
|
55
|
+
)
|
56
|
+
cls.delivery_packaging1 = (
|
57
|
+
cls.env["stock.package.type"]
|
58
|
+
.sudo()
|
59
|
+
.create(
|
60
|
+
{
|
61
|
+
"name": "Box 1",
|
62
|
+
"package_carrier_type": "test",
|
63
|
+
"barcode": "BOX1",
|
64
|
+
}
|
65
|
+
)
|
66
|
+
)
|
67
|
+
cls.delivery_packaging2 = (
|
68
|
+
cls.env["stock.package.type"]
|
69
|
+
.sudo()
|
70
|
+
.create(
|
71
|
+
{
|
72
|
+
"name": "Box 2",
|
73
|
+
"package_carrier_type": "test",
|
74
|
+
"barcode": "BOX2",
|
75
|
+
}
|
76
|
+
)
|
77
|
+
)
|
78
|
+
cls.delivery_packaging = (
|
79
|
+
cls.delivery_packaging1 | cls.delivery_packaging2
|
80
|
+
).sorted("name")
|
81
|
+
|
82
|
+
def test_list_delivery_packaging_available(self):
|
83
|
+
self._fill_stock_for_moves(self.picking.move_ids, in_package=True)
|
84
|
+
self.picking.action_assign()
|
85
|
+
selected_lines = self.picking.move_line_ids
|
86
|
+
response = self.service.dispatch(
|
87
|
+
"list_delivery_packaging",
|
88
|
+
params={
|
89
|
+
"picking_id": self.picking.id,
|
90
|
+
"selected_line_ids": selected_lines.ids,
|
91
|
+
},
|
92
|
+
)
|
93
|
+
self.assert_response(
|
94
|
+
response,
|
95
|
+
next_state="select_delivery_packaging",
|
96
|
+
data={
|
97
|
+
"packaging": self.service.data.delivery_packaging_list(
|
98
|
+
self.delivery_packaging
|
99
|
+
),
|
100
|
+
},
|
101
|
+
)
|
102
|
+
|
103
|
+
def test_list_delivery_packaging_not_available(self):
|
104
|
+
self.delivery_packaging.package_carrier_type = False
|
105
|
+
self._fill_stock_for_moves(self.picking.move_ids, in_package=True)
|
106
|
+
self.picking.action_assign()
|
107
|
+
selected_lines = self.picking.move_line_ids
|
108
|
+
# for line in selected_lines:
|
109
|
+
# line.qty_done = line.reserved_uom_qty
|
110
|
+
response = self.service.dispatch(
|
111
|
+
"list_delivery_packaging",
|
112
|
+
params={
|
113
|
+
"picking_id": self.picking.id,
|
114
|
+
"selected_line_ids": selected_lines.ids,
|
115
|
+
},
|
116
|
+
)
|
117
|
+
self.assert_response(
|
118
|
+
response,
|
119
|
+
next_state="select_package",
|
120
|
+
data={
|
121
|
+
"picking": self._picking_summary_data(self.picking),
|
122
|
+
"selected_move_lines": [
|
123
|
+
self._move_line_data(ml) for ml in selected_lines.sorted()
|
124
|
+
],
|
125
|
+
"packing_info": self.service._data_for_packing_info(self.picking),
|
126
|
+
"no_package_enabled": not self.service.options.get(
|
127
|
+
"checkout__disable_no_package"
|
128
|
+
),
|
129
|
+
},
|
130
|
+
message=self.service.msg_store.no_delivery_packaging_available(),
|
131
|
+
)
|