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,376 @@
1
+ # Copyright 2020 Camptocamp SA (http://www.camptocamp.com)
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
3
+ # pylint: disable=missing-return
4
+ from markupsafe import Markup
5
+
6
+ from .common import PickingBatchMixin
7
+ from .test_actions_data_base import ActionsDataCaseBase
8
+
9
+
10
+ class ActionsDataCase(ActionsDataCaseBase):
11
+ def test_data_packaging(self):
12
+ data = self.data.packaging(self.packaging)
13
+ self.assert_schema(self.schema.packaging(), data)
14
+ self.assertDictEqual(data, self._expected_packaging(self.packaging))
15
+
16
+ def test_data_delivery_packaging(self):
17
+ data = self.data.delivery_packaging(self.delivery_packaging)
18
+ self.assert_schema(self.schema.delivery_packaging(), data)
19
+ self.assertDictEqual(
20
+ data, self._expected_delivery_packaging(self.delivery_packaging)
21
+ )
22
+
23
+ def test_data_location(self):
24
+ location = self.stock_location
25
+ data = self.data.location(location)
26
+ self.assert_schema(self.schema.location(), data)
27
+ expected = {
28
+ "id": location.id,
29
+ "name": location.name,
30
+ "barcode": location.barcode,
31
+ }
32
+ self.assertDictEqual(data, expected)
33
+
34
+ def test_data_location_no_barcode(self):
35
+ location = self.stock_location
36
+ location.sudo().barcode = None
37
+ data = self.data.location(location)
38
+ self.assert_schema(self.schema.location(), data)
39
+ expected = {
40
+ "id": location.id,
41
+ "name": location.name,
42
+ "barcode": location.name,
43
+ }
44
+ self.assertDictEqual(data, expected)
45
+
46
+ def test_data_location_with_operation_progress(self):
47
+ location = self.stock_location
48
+ location.sudo().barcode = None
49
+ data = self.data.location(location, with_operation_progress=True)
50
+ self.assert_schema(self.schema.location(), data)
51
+ expected = {
52
+ "id": location.id,
53
+ "name": location.name,
54
+ "barcode": location.name,
55
+ "operation_progress": {
56
+ "done": 2.0,
57
+ "to_do": 210.0,
58
+ },
59
+ }
60
+ self.assertDictEqual(data, expected)
61
+
62
+ def test_data_lot(self):
63
+ lot = self.env["stock.lot"].create(
64
+ {
65
+ "product_id": self.product_b.id,
66
+ "company_id": self.env.company.id,
67
+ "ref": "#FOO",
68
+ }
69
+ )
70
+ data = self.data.lot(lot)
71
+ self.assert_schema(self.schema.lot(), data)
72
+ expected = {
73
+ "id": lot.id,
74
+ "name": lot.name,
75
+ "ref": "#FOO",
76
+ "expiration_date": None,
77
+ }
78
+ self.assertDictEqual(data, expected)
79
+
80
+ def test_data_package(self):
81
+ package = self.move_a.move_line_ids.package_id
82
+ package.product_packaging_id = self.packaging.id
83
+ package.package_type_id = self.storage_type_pallet
84
+ data = self.data.package(package, picking=self.picking, with_packaging=True)
85
+ self.assert_schema(self.schema.package(with_packaging=True), data)
86
+ expected = {
87
+ "id": package.id,
88
+ "name": package.name,
89
+ "move_line_count": 1,
90
+ "packaging": self._expected_packaging(package.product_packaging_id),
91
+ "storage_type": self._expected_storage_type(package.package_type_id),
92
+ "weight": 20.0,
93
+ }
94
+ self.assertDictEqual(data, expected)
95
+
96
+ def test_data_package_level(self):
97
+ package_level = self.picking.package_level_ids[0]
98
+ data = self.data.package_level(package_level)
99
+ self.assert_schema(self.schema.package_level(), data)
100
+ expected = {
101
+ "id": package_level.id,
102
+ "is_done": False,
103
+ "picking": self.picking.jsonify(["id", "name"])[0],
104
+ "package_src": self._expected_package(package_level.package_id),
105
+ "location_dest": self._expected_location(package_level.location_dest_id),
106
+ "location_src": self._expected_location(
107
+ package_level.picking_id.location_id
108
+ ),
109
+ "product": self._expected_product(
110
+ package_level.package_id.single_product_id
111
+ ),
112
+ "quantity": package_level.package_id.single_product_qty,
113
+ }
114
+ self.assertDictEqual(data, expected)
115
+
116
+ def test_data_picking(self):
117
+ carrier = self.picking.carrier_id.search([], limit=1)
118
+ self.picking.write(
119
+ {"origin": "created by test", "note": "read me", "carrier_id": carrier.id}
120
+ )
121
+ data = self.data.picking(self.picking)
122
+ self.assert_schema(self.schema.picking(), data)
123
+ expected = {
124
+ "id": self.picking.id,
125
+ "move_line_count": 4,
126
+ "package_level_count": 2,
127
+ "bulk_line_count": 2,
128
+ "name": self.picking.name,
129
+ "note": Markup("<p>read me</p>"),
130
+ "origin": "created by test",
131
+ "weight": 110.0,
132
+ "partner": {"id": self.customer.id, "name": self.customer.name},
133
+ "carrier": {"id": carrier.id, "name": carrier.name},
134
+ "ship_carrier": None,
135
+ }
136
+ self.assertEqual(data.pop("scheduled_date").split("T")[0], "2020-08-03")
137
+ self.assertDictEqual(data, expected)
138
+
139
+ def test_data_picking_with_progress(self):
140
+ carrier = self.picking.carrier_id.search([], limit=1)
141
+ self.picking.write(
142
+ {"origin": "created by test", "note": "read me", "carrier_id": carrier.id}
143
+ )
144
+ data = self.data.picking(self.picking, with_progress=True)
145
+ self.assert_schema(self.schema.picking(), data)
146
+ expected = {
147
+ "id": self.picking.id,
148
+ "move_line_count": 4,
149
+ "package_level_count": 2,
150
+ "bulk_line_count": 2,
151
+ "name": self.picking.name,
152
+ "note": Markup("<p>read me</p>"),
153
+ "origin": "created by test",
154
+ "weight": 110.0,
155
+ "partner": {"id": self.customer.id, "name": self.customer.name},
156
+ "carrier": {"id": carrier.id, "name": carrier.name},
157
+ "ship_carrier": None,
158
+ "progress": 0.0,
159
+ }
160
+ self.assertEqual(data.pop("scheduled_date").split("T")[0], "2020-08-03")
161
+ self.assertDictEqual(data, expected)
162
+
163
+ def test_data_product(self):
164
+ (
165
+ self.env["product.packaging"]
166
+ .sudo()
167
+ .create(
168
+ {
169
+ "name": "Box 2",
170
+ "product_id": self.product_a.id,
171
+ "barcode": "ProductABox2",
172
+ }
173
+ )
174
+ )
175
+ self.product_a.packaging_ids.write({"qty": 0})
176
+ data = self.data.product(self.product_a)
177
+ self.assert_schema(self.schema.product(), data)
178
+ # No packaging expected as all qties are zero
179
+ expected = self._expected_product(self.product_a)
180
+ self.assertDictEqual(data, expected)
181
+ # packaging w/ no zero qty are included
182
+ self.product_a.packaging_ids[0].write({"qty": 100})
183
+ self.product_a.packaging_ids[1].write({"qty": 20})
184
+ data = self.data.product(self.product_a)
185
+ expected = self._expected_product(self.product_a)
186
+ self.assertDictEqual(data, expected)
187
+
188
+ def test_data_move_line_package(self):
189
+ move_line = self.move_a.move_line_ids
190
+ result_package = self.env["stock.quant.package"].create(
191
+ {"product_packaging_id": self.packaging.id}
192
+ )
193
+ move_line.write({"qty_done": 3.0, "result_package_id": result_package.id})
194
+ data = self.data.move_line(move_line)
195
+ self.assert_schema(self.schema.move_line(), data)
196
+ self.assertIn(self.move_a.state, ["partially_available", "assigned", "done"])
197
+ expected = {
198
+ "id": move_line.id,
199
+ "qty_done": 3.0,
200
+ "quantity": move_line.reserved_uom_qty,
201
+ "product": self._expected_product(self.product_a),
202
+ "lot": None,
203
+ "package_src": {
204
+ "id": move_line.package_id.id,
205
+ "name": move_line.package_id.name,
206
+ "move_line_count": 0,
207
+ "weight": 20.0,
208
+ "storage_type": None,
209
+ },
210
+ "package_dest": {
211
+ "id": result_package.id,
212
+ "name": result_package.name,
213
+ "move_line_count": 1,
214
+ "weight": 6.0,
215
+ "storage_type": None,
216
+ },
217
+ "location_src": self._expected_location(move_line.location_id),
218
+ "location_dest": self._expected_location(move_line.location_dest_id),
219
+ "priority": "1",
220
+ "progress": 30.0,
221
+ }
222
+ self.assertDictEqual(data, expected)
223
+
224
+ def test_data_move_line_lot(self):
225
+ move_line = self.move_b.move_line_ids
226
+ data = self.data.move_line(move_line)
227
+ self.assert_schema(self.schema.move_line(), data)
228
+ expected = {
229
+ "id": move_line.id,
230
+ "qty_done": 0.0,
231
+ "quantity": move_line.reserved_uom_qty,
232
+ "product": self._expected_product(self.product_b),
233
+ "lot": {
234
+ "id": move_line.lot_id.id,
235
+ "name": move_line.lot_id.name,
236
+ "ref": None,
237
+ "expiration_date": None,
238
+ },
239
+ "package_src": None,
240
+ "package_dest": None,
241
+ "location_src": self._expected_location(move_line.location_id),
242
+ "location_dest": self._expected_location(move_line.location_dest_id),
243
+ "priority": "1",
244
+ "progress": 0.0,
245
+ }
246
+ self.assertDictEqual(data, expected)
247
+
248
+ def test_data_move_line_package_lot(self):
249
+ move_line = self.move_c.move_line_ids
250
+ data = self.data.move_line(move_line)
251
+ self.assert_schema(self.schema.move_line(), data)
252
+ self.assertIn(self.move_a.state, ["partially_available", "assigned", "done"])
253
+ expected = {
254
+ "id": move_line.id,
255
+ "qty_done": 0.0,
256
+ "quantity": move_line.reserved_uom_qty,
257
+ "product": self._expected_product(self.product_c),
258
+ "lot": {
259
+ "id": move_line.lot_id.id,
260
+ "name": move_line.lot_id.name,
261
+ "ref": None,
262
+ "expiration_date": None,
263
+ },
264
+ "package_src": {
265
+ "id": move_line.package_id.id,
266
+ "name": move_line.package_id.name,
267
+ "move_line_count": 1,
268
+ "weight": 30,
269
+ "storage_type": None,
270
+ },
271
+ "package_dest": {
272
+ "id": move_line.result_package_id.id,
273
+ "name": move_line.result_package_id.name,
274
+ "move_line_count": 1,
275
+ "weight": 0,
276
+ "storage_type": None,
277
+ },
278
+ "location_src": self._expected_location(move_line.location_id),
279
+ "location_dest": self._expected_location(move_line.location_dest_id),
280
+ "priority": "1",
281
+ "progress": 0.0,
282
+ }
283
+ self.assertDictEqual(data, expected)
284
+
285
+ def test_data_move_line_raw(self):
286
+ move_line = self.move_d.move_line_ids
287
+ data = self.data.move_line(move_line)
288
+ self.assert_schema(self.schema.move_line(), data)
289
+ expected = {
290
+ "id": move_line.id,
291
+ "qty_done": 0.0,
292
+ "quantity": move_line.reserved_uom_qty,
293
+ "product": self._expected_product(self.product_d),
294
+ "lot": None,
295
+ "package_src": None,
296
+ "package_dest": None,
297
+ "location_src": self._expected_location(move_line.location_id),
298
+ "location_dest": self._expected_location(move_line.location_dest_id),
299
+ "priority": "1",
300
+ "progress": 0.0,
301
+ }
302
+ self.assertDictEqual(data, expected)
303
+
304
+ def test_data_move_line_with_picking(self):
305
+ move_line = self.move_d.move_line_ids
306
+ data = self.data.move_line(move_line, with_picking=True)
307
+ self.assert_schema(self.schema.move_line(with_picking=True), data)
308
+ expected = {
309
+ "id": move_line.id,
310
+ "qty_done": 0.0,
311
+ "quantity": move_line.reserved_uom_qty,
312
+ "product": self._expected_product(self.product_d),
313
+ "lot": None,
314
+ "package_src": None,
315
+ "package_dest": None,
316
+ "location_src": self._expected_location(move_line.location_id),
317
+ "location_dest": self._expected_location(move_line.location_dest_id),
318
+ "picking": self.data.picking(move_line.picking_id),
319
+ "priority": "1",
320
+ "progress": 0.0,
321
+ }
322
+ self.assertDictEqual(data, expected)
323
+
324
+
325
+ class ActionsDataCaseBatchPicking(ActionsDataCaseBase, PickingBatchMixin):
326
+ @classmethod
327
+ def setUpClassBaseData(cls):
328
+ super().setUpClassBaseData()
329
+ cls.batch = cls._create_picking_batch(
330
+ [
331
+ [
332
+ cls.BatchProduct(product=cls.product_a, quantity=10),
333
+ cls.BatchProduct(product=cls.product_b, quantity=20),
334
+ ],
335
+ [cls.BatchProduct(product=cls.product_a, quantity=30)],
336
+ ]
337
+ )
338
+
339
+ def test_data_picking_batch(self):
340
+ data = self.data.picking_batch(self.batch)
341
+ self.assert_schema(self.schema.picking_batch(), data)
342
+ # no assigned pickings
343
+ expected = {
344
+ "id": self.batch.id,
345
+ "name": self.batch.name,
346
+ "picking_count": 0,
347
+ "move_line_count": 0,
348
+ "weight": 0.0,
349
+ }
350
+ self.assertDictEqual(data, expected)
351
+
352
+ self._simulate_batch_selected(self.batch, fill_stock=True)
353
+ expected.update(
354
+ {
355
+ "picking_count": 2,
356
+ "move_line_count": 3,
357
+ "weight": sum(self.batch.picking_ids.mapped("total_weight")),
358
+ }
359
+ )
360
+ data = self.data.picking_batch(self.batch)
361
+ self.assertDictEqual(data, expected)
362
+
363
+ def test_data_picking_batch_with_pickings(self):
364
+ self._simulate_batch_selected(self.batch, fill_stock=True)
365
+ data = self.data.picking_batch(self.batch, with_pickings=True)
366
+ self.assert_schema(self.schema.picking_batch(with_pickings=True), data)
367
+ # no assigned pickings
368
+ expected = {
369
+ "id": self.batch.id,
370
+ "name": self.batch.name,
371
+ "picking_count": 2,
372
+ "move_line_count": 3,
373
+ "weight": sum(self.batch.picking_ids.mapped("total_weight")),
374
+ "pickings": self.data.pickings(self.batch.picking_ids),
375
+ }
376
+ self.assertDictEqual(data, expected)
@@ -0,0 +1,244 @@
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.tools.float_utils import float_round
4
+
5
+ from odoo.addons.shopfloor_base.tests.common_misc import ActionsDataTestMixin
6
+
7
+ from .common import CommonCase
8
+
9
+
10
+ # pylint: disable=missing-return
11
+ class ActionsDataCaseBase(CommonCase, ActionsDataTestMixin):
12
+ @classmethod
13
+ def setUpClassVars(cls):
14
+ super().setUpClassVars()
15
+ cls.wh = cls.env.ref("stock.warehouse0")
16
+ cls.picking_type = cls.wh.out_type_id
17
+ cls.storage_type_pallet = cls.env.ref(
18
+ "stock_storage_type.package_storage_type_pallets"
19
+ )
20
+
21
+ @classmethod
22
+ def setUpClassBaseData(cls):
23
+ super().setUpClassBaseData()
24
+ cls.packaging_type = (
25
+ cls.env["product.packaging.level"]
26
+ .sudo()
27
+ .create({"name": "Transport Box", "code": "TB", "sequence": 0})
28
+ )
29
+ cls.packaging = (
30
+ cls.env["product.packaging"]
31
+ .sudo()
32
+ .create({"name": "Pallet", "packaging_level_id": cls.packaging_type.id})
33
+ )
34
+ cls.delivery_packaging = (
35
+ cls.env["stock.package.type"]
36
+ .sudo()
37
+ .create(
38
+ {
39
+ "name": "Pallet",
40
+ "package_carrier_type": "none",
41
+ "barcode": "PALCODE",
42
+ }
43
+ )
44
+ )
45
+ cls.product_b.tracking = "lot"
46
+ cls.product_c.tracking = "lot"
47
+ cls.picking = cls._create_picking(
48
+ lines=[
49
+ (cls.product_a, 10),
50
+ (cls.product_b, 10),
51
+ (cls.product_c, 10),
52
+ (cls.product_d, 10),
53
+ ]
54
+ )
55
+ cls.picking.scheduled_date = "2020-08-03"
56
+ # put product A in a package
57
+ cls.move_a = cls.picking.move_ids[0]
58
+ cls._fill_stock_for_moves(cls.move_a, in_package=True)
59
+ # product B has a lot
60
+ cls.move_b = cls.picking.move_ids[1]
61
+ cls._fill_stock_for_moves(cls.move_b, in_lot=True)
62
+ # product C has a lot and package
63
+ cls.move_c = cls.picking.move_ids[2]
64
+ cls._fill_stock_for_moves(cls.move_c, in_package=True, in_lot=True)
65
+ # product D is raw
66
+ cls.move_d = cls.picking.move_ids[3]
67
+ cls._fill_stock_for_moves(cls.move_d)
68
+ (cls.move_a + cls.move_b + cls.move_c + cls.move_d).write({"priority": "1"})
69
+ cls.picking.action_assign()
70
+
71
+ cls.supplier = cls.env["res.partner"].sudo().create({"name": "Supplier"})
72
+ cls.product_a_vendor = (
73
+ cls.env["product.supplierinfo"]
74
+ .sudo()
75
+ .create(
76
+ {
77
+ "partner_id": cls.supplier.id,
78
+ "price": 8.0,
79
+ "product_code": "VENDOR_CODE_A",
80
+ "product_id": cls.product_a.id,
81
+ "product_tmpl_id": cls.product_a.product_tmpl_id.id,
82
+ }
83
+ )
84
+ )
85
+ cls.product_a_variant = cls.product_a.copy(
86
+ {
87
+ "name": "Product A variant 1",
88
+ "type": "product",
89
+ "default_code": "A-VARIANT",
90
+ "barcode": "A-VARIANT",
91
+ }
92
+ )
93
+ # create another supplier info w/ lower sequence
94
+ cls.product_a_vendor = (
95
+ cls.env["product.supplierinfo"]
96
+ .sudo()
97
+ .create(
98
+ {
99
+ "partner_id": cls.supplier.id,
100
+ "price": 12.0,
101
+ "product_code": "VENDOR_CODE_VARIANT",
102
+ "product_id": cls.product_a_variant.id,
103
+ "product_tmpl_id": cls.product_a.product_tmpl_id.id,
104
+ "sequence": 0,
105
+ }
106
+ )
107
+ )
108
+ cls.product_a_variant.flush_recordset()
109
+ cls.product_a_vendor.flush_recordset()
110
+
111
+ def _expected_location(self, record, **kw):
112
+ data = {
113
+ "id": record.id,
114
+ "name": record.name,
115
+ "barcode": record.barcode,
116
+ }
117
+ data.update(kw)
118
+ return data
119
+
120
+ def _expected_product(self, record, **kw):
121
+ data = {
122
+ "id": record.id,
123
+ "name": record.name,
124
+ "display_name": record.display_name,
125
+ "default_code": record.default_code,
126
+ "barcode": record.barcode,
127
+ "packaging": [
128
+ self._expected_packaging(x) for x in record.packaging_ids if x.qty
129
+ ],
130
+ "uom": {
131
+ "factor": record.uom_id.factor,
132
+ "id": record.uom_id.id,
133
+ "name": record.uom_id.name,
134
+ "rounding": record.uom_id.rounding,
135
+ },
136
+ "supplier_code": self._expected_supplier_code(record),
137
+ }
138
+ data.update(kw)
139
+ return data
140
+
141
+ def _expected_supplier_code(self, product):
142
+ supplier_info = product.seller_ids.filtered(lambda x: x.product_id == product)
143
+ return supplier_info[0].product_code if supplier_info else ""
144
+
145
+ def _expected_packaging(self, record, **kw):
146
+ data = {
147
+ "id": record.id,
148
+ "name": record.packaging_level_id.name,
149
+ "code": record.packaging_level_id.code,
150
+ "qty": record.qty,
151
+ }
152
+ data.update(kw)
153
+ return data
154
+
155
+ def _expected_delivery_packaging(self, record, **kw):
156
+ data = {
157
+ "id": record.id,
158
+ "name": record.name,
159
+ "packaging_type": record.package_carrier_type,
160
+ "barcode": record.barcode,
161
+ }
162
+ data.update(kw)
163
+ return data
164
+
165
+ def _expected_storage_type(self, record, **kw):
166
+ data = {
167
+ "id": record.id,
168
+ "name": record.name,
169
+ }
170
+ data.update(kw)
171
+ return data
172
+
173
+ def _expected_package(self, record, **kw):
174
+ data = {
175
+ "id": record.id,
176
+ "name": record.name,
177
+ "weight": record.pack_weight or record.estimated_pack_weight_kg,
178
+ "storage_type": None,
179
+ }
180
+ data.update(kw)
181
+ return data
182
+
183
+
184
+ class ActionsDataDetailCaseBase(ActionsDataCaseBase):
185
+ @classmethod
186
+ def setUpClassBaseData(cls):
187
+ super().setUpClassBaseData()
188
+ cls.lot = cls.env["stock.lot"].create(
189
+ {"product_id": cls.product_b.id, "company_id": cls.env.company.id}
190
+ )
191
+ cls.package = cls.move_a.move_line_ids.package_id
192
+
193
+ @classmethod
194
+ def setUpClassVars(cls):
195
+ super().setUpClassVars()
196
+ cls.storage_type_pallet = cls.env.ref(
197
+ "stock_storage_type.package_storage_type_pallets"
198
+ )
199
+
200
+ def _expected_location_detail(self, record, **kw):
201
+ return dict(
202
+ **self._expected_location(record),
203
+ **{
204
+ "complete_name": record.complete_name,
205
+ "reserved_move_lines": self.data_detail.move_lines(
206
+ kw.get("move_lines", [])
207
+ ),
208
+ }
209
+ )
210
+
211
+ def _expected_product_detail(self, record, **kw):
212
+ qty_available = record.qty_available
213
+ qty_reserved = float_round(
214
+ record.qty_available - record.free_qty,
215
+ precision_rounding=record.uom_id.rounding,
216
+ )
217
+ detail = {
218
+ "qty_available": qty_available,
219
+ "qty_reserved": qty_reserved,
220
+ }
221
+ if kw.get("full"):
222
+ detail.update(
223
+ {
224
+ "image": "/web/image/product.product/{}/image_128".format(record.id)
225
+ if record.image_128
226
+ else None,
227
+ "manufacturer": {
228
+ "id": record.manufacturer_id.id,
229
+ "name": record.manufacturer_id.name,
230
+ }
231
+ if record.manufacturer_id
232
+ else None,
233
+ "suppliers": [
234
+ {
235
+ "id": v.partner_id.id,
236
+ "partner": v.partner_id.name,
237
+ "product_name": None,
238
+ "product_code": v.product_code,
239
+ }
240
+ for v in record.seller_ids
241
+ ],
242
+ }
243
+ )
244
+ return dict(**self._expected_product(record), **detail)