odoo-addon-shopfloor-mobile 16.0.1.0.0.6__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 (57) hide show
  1. odoo/addons/shopfloor_mobile/README.rst +215 -0
  2. odoo/addons/shopfloor_mobile/__init__.py +0 -0
  3. odoo/addons/shopfloor_mobile/__manifest__.py +17 -0
  4. odoo/addons/shopfloor_mobile/i18n/es_AR.po +39 -0
  5. odoo/addons/shopfloor_mobile/i18n/pt_BR.po +14 -0
  6. odoo/addons/shopfloor_mobile/i18n/shopfloor_mobile.pot +13 -0
  7. odoo/addons/shopfloor_mobile/readme/CONTRIBUTORS.rst +12 -0
  8. odoo/addons/shopfloor_mobile/readme/CREDITS.rst +5 -0
  9. odoo/addons/shopfloor_mobile/readme/DESCRIPTION.rst +31 -0
  10. odoo/addons/shopfloor_mobile/readme/HISTORY.rst +4 -0
  11. odoo/addons/shopfloor_mobile/readme/ROADMAP.rst +29 -0
  12. odoo/addons/shopfloor_mobile/readme/USAGE.rst +34 -0
  13. odoo/addons/shopfloor_mobile/static/description/icon.png +0 -0
  14. odoo/addons/shopfloor_mobile/static/description/index.html +555 -0
  15. odoo/addons/shopfloor_mobile/static/wms/.gitignore +21 -0
  16. odoo/addons/shopfloor_mobile/static/wms/src/components/batch_picking_detail.js +69 -0
  17. odoo/addons/shopfloor_mobile/static/wms/src/components/batch_picking_line_detail.js +141 -0
  18. odoo/addons/shopfloor_mobile/static/wms/src/components/detail/detail_location.js +66 -0
  19. odoo/addons/shopfloor_mobile/static/wms/src/components/detail/detail_lot.js +91 -0
  20. odoo/addons/shopfloor_mobile/static/wms/src/components/detail/detail_operation.js +50 -0
  21. odoo/addons/shopfloor_mobile/static/wms/src/components/detail/detail_package.js +73 -0
  22. odoo/addons/shopfloor_mobile/static/wms/src/components/detail/detail_picking.js +40 -0
  23. odoo/addons/shopfloor_mobile/static/wms/src/components/detail/detail_product.js +70 -0
  24. odoo/addons/shopfloor_mobile/static/wms/src/components/detail/detail_transfer.js +128 -0
  25. odoo/addons/shopfloor_mobile/static/wms/src/components/forms/form_edit_stock_picking.js +39 -0
  26. odoo/addons/shopfloor_mobile/static/wms/src/components/manual_select_color.js +24 -0
  27. odoo/addons/shopfloor_mobile/static/wms/src/components/misc.js +201 -0
  28. odoo/addons/shopfloor_mobile/static/wms/src/components/packaging-qty-picker.js +329 -0
  29. odoo/addons/shopfloor_mobile/static/wms/src/components/scenario_picking_detail/mixins.js +130 -0
  30. odoo/addons/shopfloor_mobile/static/wms/src/components/scenario_picking_detail/picking_select.js +135 -0
  31. odoo/addons/shopfloor_mobile/static/wms/src/components/scenario_picking_detail/picking_summary.js +212 -0
  32. odoo/addons/shopfloor_mobile/static/wms/src/css/main.css +73 -0
  33. odoo/addons/shopfloor_mobile/static/wms/src/css/normalize.css +351 -0
  34. odoo/addons/shopfloor_mobile/static/wms/src/demo/demo.checkout.js +257 -0
  35. odoo/addons/shopfloor_mobile/static/wms/src/demo/demo.cluster_picking.js +188 -0
  36. odoo/addons/shopfloor_mobile/static/wms/src/demo/demo.delivery.js +79 -0
  37. odoo/addons/shopfloor_mobile/static/wms/src/demo/demo.location_content_transfer.js +179 -0
  38. odoo/addons/shopfloor_mobile/static/wms/src/demo/demo.scan_anything.js +124 -0
  39. odoo/addons/shopfloor_mobile/static/wms/src/demo/demo.single_pack_transfer.js +83 -0
  40. odoo/addons/shopfloor_mobile/static/wms/src/demo/demo.zone_picking.js +277 -0
  41. odoo/addons/shopfloor_mobile/static/wms/src/i18n/add_translations_to_registry.js +4 -0
  42. odoo/addons/shopfloor_mobile/static/wms/src/i18n/en.json +31 -0
  43. odoo/addons/shopfloor_mobile/static/wms/src/i18n/fr.json +27 -0
  44. odoo/addons/shopfloor_mobile/static/wms/src/scenario/checkout.js +390 -0
  45. odoo/addons/shopfloor_mobile/static/wms/src/scenario/checkout_states.js +380 -0
  46. odoo/addons/shopfloor_mobile/static/wms/src/scenario/cluster_picking.js +481 -0
  47. odoo/addons/shopfloor_mobile/static/wms/src/scenario/delivery.js +353 -0
  48. odoo/addons/shopfloor_mobile/static/wms/src/scenario/location_content_transfer.js +388 -0
  49. odoo/addons/shopfloor_mobile/static/wms/src/scenario/single_pack_transfer.js +132 -0
  50. odoo/addons/shopfloor_mobile/static/wms/src/scenario/zone_picking.js +838 -0
  51. odoo/addons/shopfloor_mobile/static/wms/src/screen.js +36 -0
  52. odoo/addons/shopfloor_mobile/static/wms/src/wms_utils.js +318 -0
  53. odoo/addons/shopfloor_mobile/templates/assets.xml +180 -0
  54. odoo_addon_shopfloor_mobile-16.0.1.0.0.6.dist-info/METADATA +235 -0
  55. odoo_addon_shopfloor_mobile-16.0.1.0.0.6.dist-info/RECORD +57 -0
  56. odoo_addon_shopfloor_mobile-16.0.1.0.0.6.dist-info/WHEEL +5 -0
  57. odoo_addon_shopfloor_mobile-16.0.1.0.0.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,838 @@
1
+ /**
2
+ * Copyright 2020 Camptocamp SA (http://www.camptocamp.com)
3
+ * @author Simone Orsi <simahawk@gmail.com>
4
+ * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
5
+ */
6
+
7
+ import {ScenarioBaseMixin} from "/shopfloor_mobile_base/static/wms/src/scenario/mixins.js";
8
+ import {process_registry} from "/shopfloor_mobile_base/static/wms/src/services/process_registry.js";
9
+
10
+ const template_mobile = `
11
+ <Screen :screen_info="screen_info">
12
+ <template v-slot:header>
13
+ <state-display-info :info="state.display_info" v-if="state.display_info"/>
14
+ </template>
15
+ <searchbar
16
+ v-if="state.on_scan"
17
+ v-on:found="on_scan"
18
+ :input_placeholder="search_input_placeholder"
19
+ />
20
+
21
+ <div v-if="state_is('scan_location')">
22
+ <manual-select
23
+ v-on:select="state.on_select"
24
+ :records="state.data.zones"
25
+ :options="scan_location_manual_select_options()"
26
+ :key="make_state_component_key(['manual-select'])"
27
+ />
28
+ <div class="button-list button-vertical-list full">
29
+ <v-row align="center">
30
+ <v-col class="text-center" cols="12">
31
+ <btn-back :router_back="false"/>
32
+ </v-col>
33
+ </v-row>
34
+ <v-row align="center" v-if="! _.isEmpty(state.data.buffer)">
35
+ <v-col class="text-center" cols="12">
36
+ <btn-action @click="state.on_unload_at_destination()">Unload at destination</btn-action>
37
+ </v-col>
38
+ </v-row>
39
+
40
+ </div>
41
+ </div>
42
+ <div v-if="state_is('select_picking_type')">
43
+ <manual-select
44
+ v-on:select="state.on_select"
45
+ :records="state.data.picking_types"
46
+ :options="select_picking_type_manual_select_options()"
47
+ :key="make_state_component_key(['manual-select'])"
48
+ />
49
+ <div class="button-list button-vertical-list full">
50
+ <v-row align="center">
51
+ <v-col class="text-center" cols="12">
52
+ <btn-back :router_back="false"/>
53
+ </v-col>
54
+ </v-row>
55
+ </div>
56
+ </div>
57
+
58
+ <div v-if="state_is('select_line')">
59
+ <item-detail-card
60
+ v-if="device_mode == 'mobile'"
61
+ v-for="line in state.data.move_lines"
62
+ :key="make_state_component_key(['line', line.id])"
63
+ :record="line"
64
+ :options="select_line_move_line_detail_options()"
65
+ :card_color="utils.colors.color_for('screen_step_todo')"
66
+ />
67
+
68
+ <v-data-table
69
+ v-if="device_mode == 'desktop'"
70
+ :headers="select_line_table_headers()"
71
+ :items="select_line_table_items()"
72
+ :key="make_state_component_key(['data-table'])"
73
+ class="elevation-1">
74
+
75
+ <template v-slot:item.quantity="{ item }">
76
+ <packaging-qty-picker-display
77
+ :key="make_state_component_key(['qty-picker-widget', item['_origin'].id])"
78
+ v-bind="utils.wms.move_line_qty_picker_props(item['_origin'], {'qtyInit': item.quantity})"
79
+ />
80
+ </template>
81
+ <template v-slot:item.priority="{ item }">
82
+ <priority-widget
83
+ :key="make_state_component_key(['priority-widget', item['_origin'].id])"
84
+ :options="{priority: parseInt(item.priority || '0', 10)}" />
85
+ </template>
86
+ <template v-slot:item.location_will_be_empty="{ item }">
87
+ <empty-location-icon :record="item"
88
+ :key="make_state_component_key(['empty-location-icon', item['_origin'].id])"
89
+ />
90
+ </template>
91
+ </v-data-table>
92
+
93
+ <div class="button-list button-vertical-list full">
94
+ <v-row align="center">
95
+ <v-col class="text-center" cols="12">
96
+ <btn-action @click="toggle_sort_lines_by()">{{ sort_lines_by_btn_label }}</btn-action>
97
+ </v-col>
98
+ </v-row>
99
+ <!-- TODO: this btn should be available only if there are lines already processed -->
100
+ <v-row align="center">
101
+ <v-col class="text-center" cols="12">
102
+ <btn-action @click="state.on_unload_at_destination()">Unload at destination</btn-action>
103
+ </v-col>
104
+ </v-row>
105
+ <v-row align="center">
106
+ <v-col class="text-center" cols="12">
107
+ <btn-back :router_back="false"/>
108
+ </v-col>
109
+ </v-row>
110
+ </div>
111
+ </div>
112
+
113
+ <item-detail-card
114
+ v-if="state_in(['set_line_destination', 'change_pack_lot'])"
115
+ :key="make_state_component_key(['detail-move-line-loc', state.data.move_line.id])"
116
+ :record="state.data.move_line"
117
+ :options="{main: true, key_title: 'location_src.name', title_action_field: {action_val_path: 'location_src.barcode'}}"
118
+ :card_color="utils.colors.color_for('screen_step_done')"
119
+ />
120
+ <item-detail-card
121
+ v-if="state_in(['set_line_destination', 'stock_issue', 'change_pack_lot'])"
122
+ :key="make_state_component_key(['detail-move-line-product', state.data.move_line.id])"
123
+ :record="state.data.move_line"
124
+ :options="utils.wms.move_line_product_detail_options(state.data.move_line, {fields_blacklist: ['quantity']})"
125
+ :card_color="utils.colors.color_for(state_in(['set_line_destination']) ? 'screen_step_done': 'screen_step_todo')"
126
+ />
127
+ <item-detail-card
128
+ v-if="state_in(['set_line_destination'])"
129
+ :key="make_state_component_key(['detail-move-line-loc-dest', state.data.move_line.id])"
130
+ :record="state.data.move_line"
131
+ :options="{main: true, key_title: 'location_dest.name', title_action_field: {action_val_path: 'location_dest.barcode'}}"
132
+ :card_color="utils.colors.color_for('screen_step_todo')"
133
+ />
134
+ <v-card v-if="state_in(['set_line_destination', 'change_pack_lot'])"
135
+ class="pa-2" :color="utils.colors.color_for('screen_step_todo')">
136
+ <packaging-qty-picker
137
+ :key="make_state_component_key(['packaging-qty-picker', state.data.move_line.id])"
138
+ v-bind="utils.wms.move_line_qty_picker_props(state.data.move_line)"
139
+ />
140
+ </v-card>
141
+ <item-detail-card
142
+ v-if="state_in(['change_pack_lot'])"
143
+ :key="make_state_component_key(['detail-move-line-dest-pack', state.data.move_line.id])"
144
+ :record="state.data.move_line"
145
+ :options="{main: true, key_title: 'package_dest.name'}"
146
+ :card_color="utils.colors.color_for('screen_step_todo')"
147
+ />
148
+ <div v-if="state_is('set_line_destination')">
149
+ <line-actions-popup
150
+ :line="state.data.move_line"
151
+ :actions="[
152
+ {name: 'Declare stock out', event_name: 'action_stock_out'},
153
+ {name: 'Change pack or lot', event_name: 'action_change_pack_lot'},
154
+ ]"
155
+ :key="make_state_component_key(['line-actions', state.data.move_line.id])"
156
+ v-on:action="state.on_action"
157
+ />
158
+ </div>
159
+
160
+ <div v-if="state_in(['unload_all'])">
161
+ <picking-summary
162
+ :record="state.data.move_lines[0].picking"
163
+ :records="state.data.move_lines"
164
+ :records_grouped="picking_summary_records_grouped(state.data.move_lines)"
165
+ :list_options="picking_summary_move_line_list_options(state.data.move_lines)"
166
+ :key="make_state_component_key(['picking-summary'])"
167
+ />
168
+ <div class="button-list button-vertical-list full">
169
+ <v-row align="center">
170
+ <v-col class="text-center" cols="12">
171
+ <btn-action @click="state.on_action_split()">Split</btn-action>
172
+ </v-col>
173
+ </v-row>
174
+ </div>
175
+ </div>
176
+
177
+ <div v-if="state_in(['unload_single', 'unload_set_destination'])">
178
+ <user-information
179
+ v-if="state.data.full_order_picking"
180
+ :message="{body: 'Full order picking, no more operation.'}"
181
+ />
182
+ <picking-summary
183
+ v-if="state.data.move_line"
184
+ :record="state.data.move_line.picking"
185
+ :records="[state.data.move_line]"
186
+ :records_grouped="picking_summary_records_grouped([state.data.move_line])"
187
+ :list_options="picking_summary_move_line_list_options([state.data.move_line])"
188
+ :key="make_state_component_key(['picking-summary'])"
189
+ />
190
+ <div class="no-line-found" v-if="_.isEmpty(state.data.move_line)">
191
+ <!-- In theory this should not happen.
192
+ Handled only because something seems wrong backend side
193
+ and we might get here w/ no line info. -->
194
+ No line to process.
195
+ </div>
196
+ </div>
197
+
198
+ <stock-zero-check
199
+ v-if="state_is('zero_check')"
200
+ v-on:action="state.on_action"
201
+ />
202
+
203
+ <line-stock-out
204
+ v-if="state_is('stock_issue')"
205
+ v-on:confirm_stock_issue="state.on_confirm_stock_issue"
206
+ />
207
+ <div class="button-list button-vertical-list full">
208
+ <v-row align="center" v-if="state_in(['change_pack_lot'])">
209
+ <v-col class="text-center" cols="12">
210
+ <btn-back />
211
+ </v-col>
212
+ </v-row>
213
+ </div>
214
+ </Screen>
215
+ `;
216
+
217
+ const TEMPLATES = {
218
+ mobile: Vue.compile(template_mobile),
219
+ desktop: Vue.compile(template_mobile),
220
+ };
221
+
222
+ const ZonePicking = {
223
+ mixins: [ScenarioBaseMixin],
224
+ methods: {
225
+ /**
226
+ * Override to inject headers for zone location and picking type when needed.
227
+ */
228
+ _get_odoo_params: function () {
229
+ const params = this.$super(ScenarioBaseMixin)._get_odoo_params();
230
+ const zone = this.current_zone_location();
231
+ const picking_type = this.current_picking_type();
232
+ if (_.isUndefined(params.headers)) {
233
+ params.headers = {};
234
+ }
235
+ _.defaults(
236
+ params.headers,
237
+ this._get_zone_picking_headers(zone.id, picking_type.id)
238
+ );
239
+ return params;
240
+ },
241
+ /**
242
+ * Retrieve zone_picking scenario specific headers.
243
+ *
244
+ * The zone picking scenario requires some special headers
245
+ * to share some key parameters accross all methods.
246
+ *
247
+ * @param {*} zone_id: ID of current zone
248
+ * @param {*} picking_type_id: ID of selected picking type
249
+ */
250
+ _get_zone_picking_headers: function (zone_id, picking_type_id) {
251
+ const res = {};
252
+ if (_.isInteger(zone_id)) {
253
+ res["SERVICE-CTX-ZONE-LOCATION-ID"] = zone_id;
254
+ }
255
+ if (_.isInteger(picking_type_id)) {
256
+ res["SERVICE-CTX-PICKING-TYPE-ID"] = picking_type_id;
257
+ }
258
+ res["SERVICE-CTX-LINES-ORDER"] = this.order_lines_by;
259
+ return res;
260
+ },
261
+ screen_klass: function () {
262
+ return (
263
+ this.$super(ScenarioBaseMixin).screen_klass() +
264
+ " device-mode-" +
265
+ this.device_mode
266
+ );
267
+ },
268
+ screen_title: function () {
269
+ const picking = this.current_picking();
270
+ if (picking) {
271
+ return picking.name;
272
+ }
273
+ const picking_type = this.current_picking_type();
274
+ if (!_.isEmpty(picking_type)) {
275
+ return picking_type.name;
276
+ }
277
+ return this.menu_item().name;
278
+ },
279
+ current_picking: function () {
280
+ const states = ["set_line_destination", "stock_issue", "change_pack_lot"];
281
+ if (states.includes(this.current_state_key)) {
282
+ return this.state.data.move_line.picking;
283
+ }
284
+ return null;
285
+ },
286
+ current_doc: function () {
287
+ const picking = this.current_picking();
288
+ if (!picking) {
289
+ return {};
290
+ }
291
+ return {
292
+ record: picking,
293
+ identifier: picking.name,
294
+ };
295
+ },
296
+ current_picking_type: function () {
297
+ if (
298
+ ["start", "scan_location", "select_picking_type"].includes(
299
+ this.current_state_key
300
+ )
301
+ ) {
302
+ return {};
303
+ }
304
+ const data = this.state_get_data("select_line");
305
+ if (_.isEmpty(data) || _.isEmpty(data.picking_type)) {
306
+ const buffer = this.state_get_data("scan_location").buffer;
307
+ if (_.isEmpty(buffer)) {
308
+ return {};
309
+ }
310
+ return buffer.picking_type;
311
+ }
312
+ return data.picking_type;
313
+ },
314
+ current_zone_location: function () {
315
+ if (["start", "scan_location"].includes(this.current_state_key)) {
316
+ return {};
317
+ }
318
+ const data = this.state_get_data("select_picking_type");
319
+ if (_.isEmpty(data) || _.isEmpty(data.zone_location)) {
320
+ const buffer = this.state_get_data("scan_location").buffer;
321
+ if (_.isEmpty(buffer)) {
322
+ return {};
323
+ }
324
+ return buffer.zone_location;
325
+ }
326
+ return data.zone_location;
327
+ },
328
+ scan_location_manual_select_options: function () {
329
+ return {
330
+ group_title_default: "Available zones",
331
+ group_color: this.utils.colors.color_for("screen_step_todo"),
332
+ showActions: false,
333
+ list_item_options: {
334
+ show_title: false,
335
+ fields: this.manual_select_zone_fields(),
336
+ },
337
+ };
338
+ },
339
+ manual_select_zone_fields: function () {
340
+ return [
341
+ {
342
+ path: "name",
343
+ render_component: "select-zone-item",
344
+ },
345
+ ];
346
+ },
347
+ select_picking_type_manual_select_options: function () {
348
+ return {
349
+ group_title_default: "Available operation types",
350
+ group_color: this.utils.colors.color_for("screen_step_todo"),
351
+ showActions: false,
352
+ list_item_options: {
353
+ show_title: false,
354
+ fields: this.manual_select_picking_type_fields(),
355
+ },
356
+ };
357
+ },
358
+ manual_select_picking_type_fields: function () {
359
+ return [
360
+ {
361
+ path: "name",
362
+ renderer: this.picking_type_render_lines_count,
363
+ display_no_value: true,
364
+ },
365
+ ];
366
+ },
367
+ picking_type_render_lines_count(record, field) {
368
+ return _.template("(${counters}) ${name}")({
369
+ counters: this.$t("misc.lines_count", record),
370
+ name: record.name,
371
+ });
372
+ },
373
+ select_line_table_headers: function () {
374
+ // Convert to v-data-table keys
375
+ const headers = _.map(this.move_line_list_fields(true), function (field) {
376
+ return {
377
+ text: field.label,
378
+ value: field.path,
379
+ // Sorting delegated to button
380
+ sortable: false,
381
+ };
382
+ });
383
+ return headers;
384
+ },
385
+ select_line_table_items: function () {
386
+ const self = this;
387
+ // Convert to v-data-table keys
388
+ const items = _.map(this.state.data.move_lines, function (record) {
389
+ const item_data = {};
390
+ _.forEach(self.move_line_list_fields(true), function (field) {
391
+ item_data[field.path] = _.result(record, field.path);
392
+ if (field.renderer) {
393
+ item_data[field.path] = field.renderer(record, field);
394
+ }
395
+ });
396
+ item_data._origin = record;
397
+ return item_data;
398
+ });
399
+ return items;
400
+ },
401
+ select_line_move_line_detail_options: function () {
402
+ const options = {
403
+ key_title: "location_src.name",
404
+ loud_labels: true,
405
+ title_action_field: {action_val_path: "product.barcode"},
406
+ fields: this.move_line_list_fields(),
407
+ };
408
+ return options;
409
+ },
410
+ move_line_list_fields: function (table_mode = false) {
411
+ const self = this;
412
+ const fields = [
413
+ {path: "product.display_name", label: table_mode ? "Product" : null},
414
+ {
415
+ path: "package_src.name",
416
+ label: "Pack / Lot",
417
+ renderer: function (rec, field) {
418
+ const pkg = _.result(rec, "package_src.name", "");
419
+ const lot = _.result(rec, "lot.name", "");
420
+ return lot ? pkg + "\n" + lot : pkg;
421
+ },
422
+ },
423
+ {
424
+ path: "quantity",
425
+ label: "Qty",
426
+ render_component: "packaging-qty-picker-display",
427
+ render_props: function (record) {
428
+ return self.utils.wms.move_line_qty_picker_props(record, {
429
+ qtyInit: record.quantity,
430
+ });
431
+ },
432
+ },
433
+ {path: "package_src.weight", label: "Weight"},
434
+ {
435
+ path: "picking.scheduled_date",
436
+ label: "Date",
437
+ renderer: function (rec, field) {
438
+ return self.utils.display.render_field_date(rec, field);
439
+ },
440
+ },
441
+ {
442
+ path: "priority",
443
+ label: table_mode ? "Priority" : null,
444
+ render_component: "priority-widget",
445
+ render_options: function (record) {
446
+ return {priority: parseInt(record.priority || "0", 10)};
447
+ },
448
+ },
449
+ {
450
+ path: "location_will_be_empty",
451
+ render_component: "empty-location-icon",
452
+ display_no_value: true,
453
+ },
454
+ ];
455
+ if (table_mode) {
456
+ fields.unshift({path: "location_src.name", label: "Location"});
457
+ }
458
+ return fields;
459
+ },
460
+ select_line_move_line_records_grouped(move_lines) {
461
+ return this.utils.wms.group_lines_by_location(move_lines, {});
462
+ },
463
+ toggle_sort_lines_by() {
464
+ this.order_lines_by =
465
+ this.order_lines_by == "priority" ? "location" : "priority";
466
+ return this.list_move_lines(this.current_picking_type().id);
467
+ },
468
+ list_move_lines(picking_type_id) {
469
+ const zone_id = this.current_zone_location().id;
470
+ this.odoo._update_headers(
471
+ this._get_zone_picking_headers(zone_id, picking_type_id)
472
+ );
473
+ return this.wait_call(this.odoo.call("list_move_lines", {}));
474
+ },
475
+ scan_source(barcode) {
476
+ let data = {
477
+ barcode: barcode,
478
+ confirmation: this.state.data.confirmation_required,
479
+ };
480
+ if (this.state_is("select_line") && this.state.data.product) {
481
+ data.product_id = this.state.data.product.id;
482
+ }
483
+ if (this.state_is("select_line") && this.state.data.sublocation) {
484
+ data.sublocation_id = this.state.data.sublocation.id;
485
+ }
486
+ if (this.state_is("select_line") && this.state.data.package) {
487
+ data.package_id = this.state.data.package.id;
488
+ }
489
+ return this.wait_call(this.odoo.call("scan_source", data));
490
+ },
491
+ picking_summary_records_grouped(move_lines) {
492
+ return this.utils.wms.group_lines_by_location(move_lines, {
493
+ group_key: "location_dest",
494
+ // Group_no_title: true,
495
+ prepare_records: _.partialRight(
496
+ this.utils.wms.group_by_pack,
497
+ "package_dest"
498
+ ),
499
+ group_color_maker: function (lines) {
500
+ return "screen_step_todo";
501
+ },
502
+ });
503
+ },
504
+ picking_summary_move_line_list_options: function (move_lines) {
505
+ return {
506
+ group_color: this.state_in(["unload_set_destination"])
507
+ ? this.utils.colors.color_for("screen_step_done")
508
+ : this.utils.colors.color_for("screen_step_todo"),
509
+ list_item_options: {
510
+ actions: [],
511
+ fields: this.picking_summary_move_line_detail_fields(),
512
+ list_item_klass_maker: this.utils.wms.move_line_color_klass,
513
+ },
514
+ };
515
+ },
516
+ picking_summary_move_line_detail_fields: function () {
517
+ return [{path: "package_src.name", klass: "loud"}];
518
+ },
519
+ },
520
+ computed: {
521
+ sort_lines_by_btn_label() {
522
+ return this.order_lines_by == "priority"
523
+ ? this.$t("order_lines_by.location")
524
+ : this.$t("order_lines_by.priority");
525
+ },
526
+ device_mode() {
527
+ let _mode = "mobile";
528
+ _.forEach(this.media_queries, function (mode, query) {
529
+ if (window.matchMedia(query).matches) {
530
+ _mode = mode;
531
+ }
532
+ });
533
+ return _mode;
534
+ },
535
+ },
536
+ data: function () {
537
+ return {
538
+ usage: "zone_picking",
539
+ initial_state_key: "scan_location",
540
+ order_lines_by: "priority",
541
+ scan_destination_qty: 0,
542
+ states: {
543
+ init: {
544
+ enter: () => {
545
+ this.wait_call(this.odoo.call("select_zone"));
546
+ },
547
+ },
548
+ scan_location: {
549
+ display_info: {
550
+ title: "Start by scanning a location",
551
+ scan_placeholder: "Select a zone",
552
+ },
553
+ events: {
554
+ go_back: "on_back",
555
+ },
556
+ on_back: () => {
557
+ this.state_to("init");
558
+ this.reset_notification();
559
+ },
560
+ on_select: (selected) => {
561
+ this.wait_call(
562
+ this.odoo.call("scan_location", {barcode: selected.barcode})
563
+ );
564
+ },
565
+ on_scan: (scanned) => {
566
+ this.wait_call(
567
+ this.odoo.call("scan_location", {barcode: scanned.text})
568
+ );
569
+ },
570
+ on_unload_at_destination: () => {
571
+ const loaded_data = this.state.data.buffer;
572
+ const odoo_params = this._get_odoo_params();
573
+ // Zone and picking type are needed in the header
574
+ // To call prepare_unload.
575
+ _.defaults(
576
+ odoo_params.headers,
577
+ this._get_zone_picking_headers(
578
+ loaded_data.zone_location.id,
579
+ loaded_data.picking_type.id
580
+ )
581
+ );
582
+ const odoo = this.$root.getOdoo(odoo_params);
583
+ this.wait_call(odoo.call("prepare_unload", {}));
584
+ },
585
+ },
586
+ select_picking_type: {
587
+ display_info: {
588
+ title: "Select operation type",
589
+ },
590
+ events: {
591
+ go_back: "on_back",
592
+ },
593
+ on_back: () => {
594
+ this.state_to("init");
595
+ this.reset_notification();
596
+ },
597
+ on_select: (selected) => {
598
+ this.list_move_lines(selected.id);
599
+ this.force_lines_refresh = true;
600
+ },
601
+ },
602
+ select_line: {
603
+ enter: () => {
604
+ if (!this.force_lines_refresh) {
605
+ // Ensure that the list of lines is always refreshed
606
+ // when landing on this screen.
607
+ // We don't need to call this method on enter
608
+ // if we come from select_picking_type, as it takes care of that already.
609
+ this.list_move_lines(this.state.data.picking_type.id);
610
+ }
611
+ },
612
+ display_info: {
613
+ title: "Select move",
614
+ scan_placeholder: () => {
615
+ const sublocation = this.state.data.sublocation;
616
+ if (
617
+ this.state.data.scan_location_or_pack_first &&
618
+ !sublocation
619
+ ) {
620
+ return "Scan location / pack";
621
+ }
622
+ if (sublocation) {
623
+ return "Scan product / lot / package";
624
+ }
625
+ return "Scan location / pack / product / lot";
626
+ },
627
+ },
628
+ events: {
629
+ select: "on_select",
630
+ go_back: "on_back",
631
+ },
632
+ on_back: () => {
633
+ this.reset_notification();
634
+ this.wait_call(
635
+ this.odoo.call("scan_location", {
636
+ barcode: this.current_zone_location().barcode,
637
+ })
638
+ );
639
+ },
640
+ on_scan: (scanned) => {
641
+ this.scan_source(scanned.text);
642
+ },
643
+ on_select: (selected) => {
644
+ const path = "package_src.name";
645
+ let barcode = _.result(selected, path);
646
+ while (!barcode) {
647
+ _.forEach(
648
+ ["lot.name", "product.barcode", "location_src.barcode"],
649
+ function (path) {
650
+ barcode = _.result(selected, path);
651
+ }
652
+ );
653
+ }
654
+ this.scan_source(barcode);
655
+ },
656
+ on_unload_at_destination: () => {
657
+ this.wait_call(this.odoo.call("prepare_unload", {}));
658
+ },
659
+ },
660
+ set_line_destination: {
661
+ display_info: {
662
+ title: "Set destination",
663
+ scan_placeholder: "Scan location or package",
664
+ scan_placeholder_full: "Scan location or package",
665
+ scan_placeholder_partial: "Scan package",
666
+ },
667
+ events: {
668
+ qty_edit: "on_qty_update",
669
+ },
670
+ on_qty_update: (qty) => {
671
+ this.scan_destination_qty = parseInt(qty, 10);
672
+ if (this.state.data.move_line.quantity != qty) {
673
+ this.state.display_info.scan_placeholder =
674
+ this.state.display_info.scan_placeholder_partial;
675
+ } else {
676
+ this.state.display_info.scan_placeholder =
677
+ this.state.display_info.scan_placeholder_full;
678
+ }
679
+ },
680
+ on_scan: (scanned) => {
681
+ const data = this.state.data;
682
+ this.wait_call(
683
+ this.odoo.call("set_destination", {
684
+ move_line_id: data.move_line.id,
685
+ barcode: scanned.text,
686
+ quantity: this.scan_destination_qty,
687
+ confirmation: data.confirmation_required,
688
+ })
689
+ );
690
+ },
691
+ on_action: (action) => {
692
+ this.state["on_" + action.event_name].call(this);
693
+ },
694
+ on_action_stock_out: () => {
695
+ this.state_set_data(this.state.data, "stock_issue");
696
+ this.state_to("stock_issue");
697
+ },
698
+ on_action_change_pack_lot: () => {
699
+ this.state_set_data(this.state.data, "change_pack_lot");
700
+ this.state_to("change_pack_lot");
701
+ },
702
+ },
703
+
704
+ // ---> TODO: pretty equal to cluster picking: shall we move to mixin?
705
+ unload_all: {
706
+ display_info: {
707
+ title: "Unload all bins",
708
+ scan_placeholder: "Scan location",
709
+ },
710
+ on_scan: (scanned) => {
711
+ this.state_set_data({location_barcode: scanned.text});
712
+ this.wait_call(
713
+ this.odoo.call("set_destination_all", {
714
+ barcode: scanned.text,
715
+ confirmation: this.state.data.confirmation_required,
716
+ })
717
+ );
718
+ },
719
+ on_action_split: () => {
720
+ this.wait_call(this.odoo.call("unload_split", {}));
721
+ },
722
+ },
723
+ unload_single: {
724
+ display_info: {
725
+ title: "Unload single pack",
726
+ scan_placeholder: "Scan pack",
727
+ },
728
+ on_scan: (scanned) => {
729
+ this.wait_call(
730
+ this.odoo.call("unload_scan_pack", {
731
+ package_id: this.state.data.move_line.package_dest.id,
732
+ barcode: scanned.text,
733
+ })
734
+ );
735
+ },
736
+ },
737
+ unload_set_destination: {
738
+ display_info: {
739
+ title: "Set destination",
740
+ scan_placeholder: "Scan location",
741
+ },
742
+ on_scan: (scanned) => {
743
+ this.wait_call(
744
+ this.odoo.call("unload_set_destination", {
745
+ package_id: this.state.data.move_line.package_dest.id,
746
+ barcode: scanned.text,
747
+ confirmation: this.state.data.confirmation_required,
748
+ })
749
+ );
750
+ },
751
+ },
752
+ change_pack_lot: {
753
+ display_info: {
754
+ title: "Change pack or lot",
755
+ scan_placeholder: "Scan pack or lot",
756
+ },
757
+ on_scan: (scanned) => {
758
+ this.wait_call(
759
+ this.odoo.call("change_pack_lot", {
760
+ move_line_id: this.state.data.move_line.id,
761
+ barcode: scanned.text,
762
+ })
763
+ );
764
+ },
765
+ },
766
+ stock_issue: {
767
+ enter: () => {
768
+ this.reset_notification();
769
+ },
770
+ on_action: (action) => {
771
+ this.state["on_" + action].call(this);
772
+ },
773
+ on_confirm_stock_issue: () => {
774
+ this.wait_call(
775
+ this.odoo.call("stock_issue", {
776
+ move_line_id: this.state.data.move_line.id,
777
+ })
778
+ );
779
+ },
780
+ on_back: () => {
781
+ this.state_set_data({});
782
+ this.reset_notification();
783
+ this.state_to("start_line");
784
+ },
785
+ },
786
+ zero_check: {
787
+ on_action: (action) => {
788
+ this.state["on_" + action].call(this);
789
+ },
790
+ is_zero: (zero_flag) => {
791
+ this.wait_call(
792
+ this.odoo.call("is_zero", {
793
+ move_line_id: this.state.data.move_line.id,
794
+ zero: zero_flag,
795
+ })
796
+ );
797
+ },
798
+ on_action_confirm_zero: () => {
799
+ this.state.is_zero(true);
800
+ },
801
+ on_action_confirm_not_zero: () => {
802
+ this.state.is_zero(false);
803
+ },
804
+ },
805
+ },
806
+ force_lines_refresh: false,
807
+ };
808
+ },
809
+ // TODO: move this lovely feature to a mixin or provide it to all components.
810
+ props: {
811
+ default_template: {
812
+ type: String,
813
+ default: "mobile",
814
+ },
815
+ media_queries: {
816
+ type: Object,
817
+ default: function () {
818
+ return {
819
+ "(min-width: 500px)": "desktop",
820
+ };
821
+ },
822
+ },
823
+ compiled_templates: {
824
+ type: Object,
825
+ default: function () {
826
+ return TEMPLATES;
827
+ },
828
+ },
829
+ },
830
+ render(createElement) {
831
+ const tmpl = this.compiled_templates[this.device_mode];
832
+ return tmpl.render.call(this, createElement);
833
+ },
834
+ };
835
+
836
+ process_registry.add("zone_picking", ZonePicking);
837
+
838
+ export default ZonePicking;