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.
Files changed (182) hide show
  1. odoo/addons/shopfloor/README.rst +160 -0
  2. odoo/addons/shopfloor/__init__.py +4 -0
  3. odoo/addons/shopfloor/__manifest__.py +65 -0
  4. odoo/addons/shopfloor/actions/__init__.py +15 -0
  5. odoo/addons/shopfloor/actions/change_package_lot.py +164 -0
  6. odoo/addons/shopfloor/actions/completion_info.py +42 -0
  7. odoo/addons/shopfloor/actions/data.py +329 -0
  8. odoo/addons/shopfloor/actions/data_detail.py +154 -0
  9. odoo/addons/shopfloor/actions/inventory.py +150 -0
  10. odoo/addons/shopfloor/actions/location_content_transfer_sorter.py +89 -0
  11. odoo/addons/shopfloor/actions/message.py +846 -0
  12. odoo/addons/shopfloor/actions/move_line_search.py +119 -0
  13. odoo/addons/shopfloor/actions/packaging.py +59 -0
  14. odoo/addons/shopfloor/actions/savepoint.py +44 -0
  15. odoo/addons/shopfloor/actions/schema.py +182 -0
  16. odoo/addons/shopfloor/actions/schema_detail.py +98 -0
  17. odoo/addons/shopfloor/actions/search.py +187 -0
  18. odoo/addons/shopfloor/actions/stock.py +239 -0
  19. odoo/addons/shopfloor/actions/stock_unreserve.py +66 -0
  20. odoo/addons/shopfloor/components/__init__.py +5 -0
  21. odoo/addons/shopfloor/components/scan_handler_location.py +26 -0
  22. odoo/addons/shopfloor/components/scan_handler_lot.py +26 -0
  23. odoo/addons/shopfloor/components/scan_handler_package.py +26 -0
  24. odoo/addons/shopfloor/components/scan_handler_product.py +26 -0
  25. odoo/addons/shopfloor/components/scan_handler_transfer.py +26 -0
  26. odoo/addons/shopfloor/data/shopfloor_scenario_data.xml +73 -0
  27. odoo/addons/shopfloor/demo/shopfloor_app_demo.xml +12 -0
  28. odoo/addons/shopfloor/demo/shopfloor_menu_demo.xml +64 -0
  29. odoo/addons/shopfloor/demo/shopfloor_profile_demo.xml +8 -0
  30. odoo/addons/shopfloor/demo/stock_picking_type_demo.xml +93 -0
  31. odoo/addons/shopfloor/docs/checkout_diag_seq.plantuml +61 -0
  32. odoo/addons/shopfloor/docs/checkout_diag_seq.png +0 -0
  33. odoo/addons/shopfloor/docs/cluster_picking_diag_seq.plantuml +112 -0
  34. odoo/addons/shopfloor/docs/cluster_picking_diag_seq.png +0 -0
  35. odoo/addons/shopfloor/docs/delivery_diag_seq.plantuml +56 -0
  36. odoo/addons/shopfloor/docs/delivery_diag_seq.png +0 -0
  37. odoo/addons/shopfloor/docs/location_content_transfer_diag_seq.plantuml +66 -0
  38. odoo/addons/shopfloor/docs/location_content_transfer_diag_seq.png +0 -0
  39. odoo/addons/shopfloor/docs/oca_logo.png +0 -0
  40. odoo/addons/shopfloor/docs/single_pack_transfer_diag_seq.plantuml +36 -0
  41. odoo/addons/shopfloor/docs/single_pack_transfer_diag_seq.png +0 -0
  42. odoo/addons/shopfloor/docs/zone_picking_diag_seq.plantuml +85 -0
  43. odoo/addons/shopfloor/docs/zone_picking_diag_seq.png +0 -0
  44. odoo/addons/shopfloor/exceptions.py +6 -0
  45. odoo/addons/shopfloor/i18n/ca.po +1802 -0
  46. odoo/addons/shopfloor/i18n/de.po +1791 -0
  47. odoo/addons/shopfloor/i18n/es_AR.po +2147 -0
  48. odoo/addons/shopfloor/i18n/pt_BR.po +1791 -0
  49. odoo/addons/shopfloor/i18n/shopfloor.pot +1877 -0
  50. odoo/addons/shopfloor/models/__init__.py +12 -0
  51. odoo/addons/shopfloor/models/priority_postpone_mixin.py +41 -0
  52. odoo/addons/shopfloor/models/shopfloor_app.py +9 -0
  53. odoo/addons/shopfloor/models/shopfloor_menu.py +436 -0
  54. odoo/addons/shopfloor/models/stock_location.py +76 -0
  55. odoo/addons/shopfloor/models/stock_move.py +119 -0
  56. odoo/addons/shopfloor/models/stock_move_line.py +307 -0
  57. odoo/addons/shopfloor/models/stock_package_level.py +50 -0
  58. odoo/addons/shopfloor/models/stock_picking.py +118 -0
  59. odoo/addons/shopfloor/models/stock_picking_batch.py +41 -0
  60. odoo/addons/shopfloor/models/stock_picking_type.py +26 -0
  61. odoo/addons/shopfloor/models/stock_quant.py +31 -0
  62. odoo/addons/shopfloor/models/stock_quant_package.py +101 -0
  63. odoo/addons/shopfloor/readme/CONTRIBUTORS.rst +18 -0
  64. odoo/addons/shopfloor/readme/CREDITS.rst +5 -0
  65. odoo/addons/shopfloor/readme/DESCRIPTION.rst +17 -0
  66. odoo/addons/shopfloor/readme/HISTORY.rst +4 -0
  67. odoo/addons/shopfloor/readme/ROADMAP.rst +4 -0
  68. odoo/addons/shopfloor/readme/USAGE.rst +6 -0
  69. odoo/addons/shopfloor/security/groups.xml +17 -0
  70. odoo/addons/shopfloor/services/__init__.py +16 -0
  71. odoo/addons/shopfloor/services/checkout.py +1763 -0
  72. odoo/addons/shopfloor/services/cluster_picking.py +1628 -0
  73. odoo/addons/shopfloor/services/delivery.py +828 -0
  74. odoo/addons/shopfloor/services/forms/__init__.py +1 -0
  75. odoo/addons/shopfloor/services/forms/picking_form.py +78 -0
  76. odoo/addons/shopfloor/services/location_content_transfer.py +1194 -0
  77. odoo/addons/shopfloor/services/menu.py +60 -0
  78. odoo/addons/shopfloor/services/picking_batch.py +126 -0
  79. odoo/addons/shopfloor/services/service.py +101 -0
  80. odoo/addons/shopfloor/services/single_pack_transfer.py +366 -0
  81. odoo/addons/shopfloor/services/zone_picking.py +1938 -0
  82. odoo/addons/shopfloor/static/description/icon.png +0 -0
  83. odoo/addons/shopfloor/static/description/index.html +500 -0
  84. odoo/addons/shopfloor/tests/__init__.py +83 -0
  85. odoo/addons/shopfloor/tests/common.py +324 -0
  86. odoo/addons/shopfloor/tests/models.py +29 -0
  87. odoo/addons/shopfloor/tests/test_actions_change_package_lot.py +1175 -0
  88. odoo/addons/shopfloor/tests/test_actions_data.py +376 -0
  89. odoo/addons/shopfloor/tests/test_actions_data_base.py +244 -0
  90. odoo/addons/shopfloor/tests/test_actions_data_detail.py +322 -0
  91. odoo/addons/shopfloor/tests/test_actions_search.py +248 -0
  92. odoo/addons/shopfloor/tests/test_actions_stock.py +48 -0
  93. odoo/addons/shopfloor/tests/test_checkout_auto_post.py +67 -0
  94. odoo/addons/shopfloor/tests/test_checkout_base.py +81 -0
  95. odoo/addons/shopfloor/tests/test_checkout_cancel_line.py +154 -0
  96. odoo/addons/shopfloor/tests/test_checkout_change_packaging.py +184 -0
  97. odoo/addons/shopfloor/tests/test_checkout_done.py +133 -0
  98. odoo/addons/shopfloor/tests/test_checkout_list_delivery_packaging.py +131 -0
  99. odoo/addons/shopfloor/tests/test_checkout_list_package.py +327 -0
  100. odoo/addons/shopfloor/tests/test_checkout_new_package.py +88 -0
  101. odoo/addons/shopfloor/tests/test_checkout_no_package.py +95 -0
  102. odoo/addons/shopfloor/tests/test_checkout_scan.py +174 -0
  103. odoo/addons/shopfloor/tests/test_checkout_scan_line.py +377 -0
  104. odoo/addons/shopfloor/tests/test_checkout_scan_line_base.py +25 -0
  105. odoo/addons/shopfloor/tests/test_checkout_scan_line_no_prefill_qty.py +91 -0
  106. odoo/addons/shopfloor/tests/test_checkout_scan_package_action.py +451 -0
  107. odoo/addons/shopfloor/tests/test_checkout_scan_package_action_no_prefill_qty.py +107 -0
  108. odoo/addons/shopfloor/tests/test_checkout_select.py +74 -0
  109. odoo/addons/shopfloor/tests/test_checkout_select_line.py +130 -0
  110. odoo/addons/shopfloor/tests/test_checkout_select_package_base.py +64 -0
  111. odoo/addons/shopfloor/tests/test_checkout_set_qty.py +257 -0
  112. odoo/addons/shopfloor/tests/test_checkout_summary.py +69 -0
  113. odoo/addons/shopfloor/tests/test_cluster_picking_base.py +83 -0
  114. odoo/addons/shopfloor/tests/test_cluster_picking_batch.py +109 -0
  115. odoo/addons/shopfloor/tests/test_cluster_picking_change_pack_lot.py +111 -0
  116. odoo/addons/shopfloor/tests/test_cluster_picking_is_zero.py +98 -0
  117. odoo/addons/shopfloor/tests/test_cluster_picking_scan_destination.py +376 -0
  118. odoo/addons/shopfloor/tests/test_cluster_picking_scan_destination_no_prefill_qty.py +115 -0
  119. odoo/addons/shopfloor/tests/test_cluster_picking_scan_line.py +402 -0
  120. odoo/addons/shopfloor/tests/test_cluster_picking_scan_line_location_or_pack_first.py +114 -0
  121. odoo/addons/shopfloor/tests/test_cluster_picking_scan_line_no_prefill_qty.py +70 -0
  122. odoo/addons/shopfloor/tests/test_cluster_picking_select.py +387 -0
  123. odoo/addons/shopfloor/tests/test_cluster_picking_skip.py +90 -0
  124. odoo/addons/shopfloor/tests/test_cluster_picking_stock_issue.py +364 -0
  125. odoo/addons/shopfloor/tests/test_cluster_picking_unload.py +911 -0
  126. odoo/addons/shopfloor/tests/test_delivery_base.py +155 -0
  127. odoo/addons/shopfloor/tests/test_delivery_done.py +108 -0
  128. odoo/addons/shopfloor/tests/test_delivery_list_stock_picking.py +49 -0
  129. odoo/addons/shopfloor/tests/test_delivery_reset_qty_done_line.py +119 -0
  130. odoo/addons/shopfloor/tests/test_delivery_reset_qty_done_pack.py +107 -0
  131. odoo/addons/shopfloor/tests/test_delivery_scan_deliver.py +557 -0
  132. odoo/addons/shopfloor/tests/test_delivery_select.py +38 -0
  133. odoo/addons/shopfloor/tests/test_delivery_set_qty_done_line.py +91 -0
  134. odoo/addons/shopfloor/tests/test_delivery_set_qty_done_pack.py +135 -0
  135. odoo/addons/shopfloor/tests/test_delivery_sublocation.py +180 -0
  136. odoo/addons/shopfloor/tests/test_location_content_transfer_base.py +136 -0
  137. odoo/addons/shopfloor/tests/test_location_content_transfer_get_work.py +125 -0
  138. odoo/addons/shopfloor/tests/test_location_content_transfer_mix.py +509 -0
  139. odoo/addons/shopfloor/tests/test_location_content_transfer_putaway.py +143 -0
  140. odoo/addons/shopfloor/tests/test_location_content_transfer_scan_location.py +34 -0
  141. odoo/addons/shopfloor/tests/test_location_content_transfer_set_destination_all.py +343 -0
  142. odoo/addons/shopfloor/tests/test_location_content_transfer_set_destination_package_or_line.py +1074 -0
  143. odoo/addons/shopfloor/tests/test_location_content_transfer_single.py +748 -0
  144. odoo/addons/shopfloor/tests/test_location_content_transfer_start.py +359 -0
  145. odoo/addons/shopfloor/tests/test_menu_base.py +261 -0
  146. odoo/addons/shopfloor/tests/test_menu_counters.py +61 -0
  147. odoo/addons/shopfloor/tests/test_misc.py +25 -0
  148. odoo/addons/shopfloor/tests/test_move_action_assign.py +87 -0
  149. odoo/addons/shopfloor/tests/test_openapi.py +21 -0
  150. odoo/addons/shopfloor/tests/test_picking_form.py +62 -0
  151. odoo/addons/shopfloor/tests/test_scan_anything.py +49 -0
  152. odoo/addons/shopfloor/tests/test_single_pack_transfer.py +1121 -0
  153. odoo/addons/shopfloor/tests/test_single_pack_transfer_base.py +32 -0
  154. odoo/addons/shopfloor/tests/test_single_pack_transfer_putaway.py +104 -0
  155. odoo/addons/shopfloor/tests/test_stock_split.py +204 -0
  156. odoo/addons/shopfloor/tests/test_user.py +42 -0
  157. odoo/addons/shopfloor/tests/test_zone_picking_base.py +608 -0
  158. odoo/addons/shopfloor/tests/test_zone_picking_change_pack_lot.py +140 -0
  159. odoo/addons/shopfloor/tests/test_zone_picking_select_line.py +723 -0
  160. odoo/addons/shopfloor/tests/test_zone_picking_select_line_first_scan_location.py +207 -0
  161. odoo/addons/shopfloor/tests/test_zone_picking_select_line_first_scan_location.py.bak +202 -0
  162. odoo/addons/shopfloor/tests/test_zone_picking_select_line_no_prefill_qty.py +107 -0
  163. odoo/addons/shopfloor/tests/test_zone_picking_select_picking_type.py +26 -0
  164. odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination.py +643 -0
  165. odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination_no_prefill_qty.py +146 -0
  166. odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination_pick_pack.py +241 -0
  167. odoo/addons/shopfloor/tests/test_zone_picking_start.py +206 -0
  168. odoo/addons/shopfloor/tests/test_zone_picking_stock_issue.py +121 -0
  169. odoo/addons/shopfloor/tests/test_zone_picking_unload_all.py +353 -0
  170. odoo/addons/shopfloor/tests/test_zone_picking_unload_buffer_lines.py +113 -0
  171. odoo/addons/shopfloor/tests/test_zone_picking_unload_set_destination.py +374 -0
  172. odoo/addons/shopfloor/tests/test_zone_picking_unload_single.py +123 -0
  173. odoo/addons/shopfloor/tests/test_zone_picking_zero_check.py +43 -0
  174. odoo/addons/shopfloor/utils.py +13 -0
  175. odoo/addons/shopfloor/views/shopfloor_menu.xml +167 -0
  176. odoo/addons/shopfloor/views/stock_location.xml +20 -0
  177. odoo/addons/shopfloor/views/stock_move_line.xml +52 -0
  178. odoo/addons/shopfloor/views/stock_picking_type.xml +19 -0
  179. odoo_addon_shopfloor-16.0.1.0.0.24.dist-info/METADATA +192 -0
  180. odoo_addon_shopfloor-16.0.1.0.0.24.dist-info/RECORD +182 -0
  181. odoo_addon_shopfloor-16.0.1.0.0.24.dist-info/WHEEL +5 -0
  182. 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
+ )