odoo-addon-shopfloor-mobile 16.0.1.0.0.8__py3-none-any.whl → 16.0.1.1.0__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.

Potentially problematic release.


This version of odoo-addon-shopfloor-mobile might be problematic. Click here for more details.

@@ -7,7 +7,7 @@ Shopfloor mobile
7
7
  !! This file is generated by oca-gen-addon-readme !!
8
8
  !! changes will be overwritten. !!
9
9
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10
- !! source digest: sha256:cd664d31e2a374f629474683de47781fd6a0463a2939ab5d86ad0ab5b8f4e0d5
10
+ !! source digest: sha256:ec3d467f63cb02754093fc0b29a29951595f4f681dc519eea793cd8fa8fcae84
11
11
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12
12
 
13
13
  .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
@@ -5,7 +5,7 @@
5
5
  {
6
6
  "name": "Shopfloor mobile",
7
7
  "summary": "Mobile frontend for WMS Shopfloor app",
8
- "version": "16.0.1.0.0",
8
+ "version": "16.0.1.1.0",
9
9
  "depends": ["shopfloor", "shopfloor_mobile_base"],
10
10
  "author": "Camptocamp, BCIM, Akretion, Odoo Community Association (OCA)",
11
11
  "maintainers": ["simahawk"],
@@ -12,3 +12,4 @@ msgstr ""
12
12
  "Content-Type: text/plain; charset=UTF-8\n"
13
13
  "Content-Transfer-Encoding: \n"
14
14
  "Plural-Forms: nplurals=2; plural=n != 1;\n"
15
+
@@ -8,11 +8,10 @@
8
8
 
9
9
  /*
10
10
  :Author: David Goodger (goodger@python.org)
11
- :Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
11
+ :Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
12
12
  :Copyright: This stylesheet has been placed in the public domain.
13
13
 
14
14
  Default cascading style sheet for the HTML output of Docutils.
15
- Despite the name, some widely supported CSS2 features are used.
16
15
 
17
16
  See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
18
17
  customize this style sheet.
@@ -275,7 +274,7 @@ pre.literal-block, pre.doctest-block, pre.math, pre.code {
275
274
  margin-left: 2em ;
276
275
  margin-right: 2em }
277
276
 
278
- pre.code .ln { color: gray; } /* line numbers */
277
+ pre.code .ln { color: grey; } /* line numbers */
279
278
  pre.code, code { background-color: #eeeeee }
280
279
  pre.code .comment, code .comment { color: #5C6576 }
281
280
  pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
@@ -301,7 +300,7 @@ span.option {
301
300
  span.pre {
302
301
  white-space: pre }
303
302
 
304
- span.problematic, pre.problematic {
303
+ span.problematic {
305
304
  color: red }
306
305
 
307
306
  span.section-subtitle {
@@ -367,7 +366,7 @@ ul.auto-toc {
367
366
  !! This file is generated by oca-gen-addon-readme !!
368
367
  !! changes will be overwritten. !!
369
368
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
370
- !! source digest: sha256:cd664d31e2a374f629474683de47781fd6a0463a2939ab5d86ad0ab5b8f4e0d5
369
+ !! source digest: sha256:ec3d467f63cb02754093fc0b29a29951595f4f681dc519eea793cd8fa8fcae84
371
370
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
372
371
  <p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/wms/tree/16.0/shopfloor_mobile"><img alt="OCA/wms" src="https://img.shields.io/badge/github-OCA%2Fwms-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/wms-16-0/wms-16-0-shopfloor_mobile"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/wms&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
373
372
  <p>Frontend for Shopfloor app.</p>
@@ -539,9 +538,7 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
539
538
  <div class="section" id="maintainers">
540
539
  <h1>Maintainers</h1>
541
540
  <p>This module is maintained by the OCA.</p>
542
- <a class="reference external image-reference" href="https://odoo-community.org">
543
- <img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
544
- </a>
541
+ <a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
545
542
  <p>OCA, or the Odoo Community Association, is a nonprofit organization whose
546
543
  mission is to support the collaborative development of Odoo features and
547
544
  promote its widespread use.</p>
@@ -60,12 +60,12 @@ Vue.component("detail-transfer", {
60
60
  },
61
61
  {path: "lot.name", label: "Lot", action_val_path: "lot.name"},
62
62
  {
63
- path: "product.qty_reserved",
63
+ path: "quantity",
64
64
  label: "Qty reserved",
65
65
  render_component: "packaging-qty-picker-display",
66
66
  render_props: function (record) {
67
67
  return self.utils.wms.move_line_qty_picker_props(record, {
68
- qtyInit: record.product.qty_reserved,
68
+ qtyInit: record.quantity,
69
69
  });
70
70
  },
71
71
  },
@@ -20,7 +20,6 @@
20
20
  "location_content_transfer.start_single.scan_placeholder": "Scannez une boite / un produit / un lot",
21
21
  "misc.btn_get_work": "Obtenir du travail",
22
22
  "misc.btn_manual_selection": "Sélection manuelle",
23
- "misc.lines_count": "Nombre de lignes",
24
23
  "misc.stock_zero_check.confirm_stock_not_zero": "Confirmer le stock",
25
24
  "misc.stock_zero_check.confirm_stock_zero": "Rupture de stock",
26
25
  "scan_placeholder_translation": "Scannez un emplacement"
@@ -92,7 +92,7 @@ const Checkout = {
92
92
  :key="make_state_component_key(['detail-picking-select'])"
93
93
  />
94
94
  <div class="button-list button-vertical-list full">
95
- <v-row align="center">
95
+ <v-row align="center" v-if="state.data.package_allowed">
96
96
  <v-col class="text-center" cols="12">
97
97
  <btn-action
98
98
  @click="state.on_existing_pack"
@@ -100,7 +100,7 @@ const Checkout = {
100
100
  >Existing pack</btn-action>
101
101
  </v-col>
102
102
  </v-row>
103
- <v-row align="center">
103
+ <v-row align="center" v-if="state.data.package_allowed">
104
104
  <v-col class="text-center" cols="12">
105
105
  <btn-action
106
106
  @click="state.on_new_pack"
@@ -234,6 +234,21 @@ const Checkout = {
234
234
  </v-row>
235
235
  </div>
236
236
  </div>
237
+ <div v-if="state_is('select_child_location')">
238
+ <item-detail-card
239
+ :key="make_state_component_key(['picking'])"
240
+ :record="state.data.picking"
241
+ :options="{key_title: 'location_dest.name'}"
242
+ :card_color="utils.colors.color_for('screen_step_todo')"
243
+ />
244
+ <div class="button-list button-vertical-list full">
245
+ <v-row align="center">
246
+ <v-col class="text-center" cols="12">
247
+ <btn-back />
248
+ </v-col>
249
+ </v-row>
250
+ </div>
251
+ </div>
237
252
  </Screen>
238
253
  `,
239
254
  computed: {
@@ -278,6 +293,20 @@ const Checkout = {
278
293
  {path: "origin"},
279
294
  {path: "carrier.name", label: "Carrier"},
280
295
  {path: "move_line_count", label: "Lines"},
296
+ {
297
+ path: "priority",
298
+ render_component: "priority-widget",
299
+ render_options: function (record) {
300
+ const priority = parseInt(record.priority);
301
+ // We need to pass the label to the component as an option instead of using "display_no_value"
302
+ // because pickings with no priority will still have a string value of "0"
303
+ // and the label would always be displayed.
304
+ return {
305
+ priority,
306
+ label: priority ? "Priority: " : null,
307
+ };
308
+ },
309
+ },
281
310
  ],
282
311
  },
283
312
  };
@@ -63,7 +63,8 @@ export const checkout_states = function ($instance) {
63
63
  $instance.odoo.call("scan_line", {
64
64
  picking_id: $instance.state.data.picking.id,
65
65
  barcode: scanned.text,
66
- confirm_pack_all: $instance.state.data.need_confirm_pack_all,
66
+ confirm_pack_all:
67
+ $instance.state.data.need_confirm_pack_all || "",
67
68
  })
68
69
  );
69
70
  },
@@ -376,5 +377,26 @@ export const checkout_states = function ($instance) {
376
377
  $instance.reset_notification();
377
378
  },
378
379
  },
380
+ select_child_location: {
381
+ display_info: {
382
+ title: "Set destination location",
383
+ scan_placeholder: "Scan location",
384
+ },
385
+ events: {
386
+ go_back: "on_back",
387
+ },
388
+ on_scan: (scanned) => {
389
+ $instance.wait_call(
390
+ $instance.odoo.call("scan_dest_location", {
391
+ picking_id: $instance.state.data.picking.id,
392
+ barcode: scanned.text,
393
+ })
394
+ );
395
+ },
396
+ on_back: () => {
397
+ $instance.state_to("summary");
398
+ $instance.reset_notification();
399
+ },
400
+ },
379
401
  };
380
402
  };
@@ -7,6 +7,8 @@
7
7
  import {ScenarioBaseMixin} from "/shopfloor_mobile_base/static/wms/src/scenario/mixins.js";
8
8
  import {process_registry} from "/shopfloor_mobile_base/static/wms/src/services/process_registry.js";
9
9
 
10
+ // TODO: consider replacing the dynamic "autofocus" in the searchbar by an event.
11
+ // At the moment, we need autofocus to be disabled if there's a user popup.
10
12
  const ClusterPicking = {
11
13
  mixins: [ScenarioBaseMixin],
12
14
  template: `
@@ -20,6 +22,7 @@ const ClusterPicking = {
20
22
  :input_placeholder="search_input_placeholder"
21
23
  :input_type="searchbar_input_type"
22
24
  :input_model="searchbar_input_type"
25
+ :autofocus="!screen_info.user_popup"
23
26
  />
24
27
  <get-work
25
28
  v-if="state_is('start')"
@@ -351,7 +354,7 @@ const ClusterPicking = {
351
354
  title: this.$t("cluster_picking.unload_all.title"),
352
355
  scan_placeholder: this.$t("scan_placeholder_translation"),
353
356
  },
354
- on_scan: (scanned, confirmation = false) => {
357
+ on_scan: (scanned, confirmation = "") => {
355
358
  this.state_set_data({location_barcode: scanned.text});
356
359
  this.wait_call(
357
360
  this.odoo.call("set_destination_all", {
@@ -367,23 +370,12 @@ const ClusterPicking = {
367
370
  title: this.$t("cluster_picking.confirm_unload_all.title"),
368
371
  scan_placeholder: this.$t("scan_placeholder_translation"),
369
372
  },
370
- on_user_confirm: (answer) => {
371
- // TODO: check if this used
372
- // -> no flag is set to enable the confirmation dialog,
373
- // we only display a message, unlike `confirm_start`
374
- if (answer == "yes") {
375
- // Reuse data from unload_all
376
- const scan_data = this.state_get_data("unload_all");
377
- this.state.on_scan(scan_data.location_barcode, true);
378
- } else {
379
- this.state_to("scan_destination");
380
- }
381
- },
382
373
  on_scan: (scanned, confirmation = true) => {
383
374
  this.on_state_exit();
384
375
  // FIXME: use state_load or traverse the state
385
376
  // this.current_state_key = "unload_all";
386
377
  // this.state.on_scan(scanned, confirmation);
378
+ confirmation = this.state.data.confirmation || "";
387
379
  this.states.unload_all.on_scan(scanned, confirmation);
388
380
  },
389
381
  },
@@ -432,7 +424,7 @@ const ClusterPicking = {
432
424
  picking_batch_id: this.current_batch().id,
433
425
  package_id: null, // FIXME: where does it come from? backend data?
434
426
  barcode: scanned.text,
435
- confirmation: true,
427
+ confirmation: this.state.data.confirmation || "",
436
428
  })
437
429
  );
438
430
  },
@@ -7,6 +7,8 @@
7
7
  import {ScenarioBaseMixin} from "/shopfloor_mobile_base/static/wms/src/scenario/mixins.js";
8
8
  import {process_registry} from "/shopfloor_mobile_base/static/wms/src/services/process_registry.js";
9
9
 
10
+ // TODO: consider replacing the dynamic "autofocus" in the searchbar by an event.
11
+ // At the moment, we need autofocus to be disabled if there's a user popup.
10
12
  const LocationContentTransfer = {
11
13
  mixins: [ScenarioBaseMixin],
12
14
  template: `
@@ -18,6 +20,7 @@ const LocationContentTransfer = {
18
20
  v-if="state.on_scan"
19
21
  v-on:found="on_scan"
20
22
  :input_placeholder="search_input_placeholder"
23
+ :autofocus="!screen_info.user_popup"
21
24
  />
22
25
  <template v-if="state_in(['scan_location']) && state.data.location">
23
26
  <item-detail-card
@@ -271,7 +274,7 @@ const LocationContentTransfer = {
271
274
  this.odoo.call("set_destination_all", {
272
275
  location_id: data.location.id,
273
276
  barcode: scanned.text,
274
- confirmation: data.confirmation_required,
277
+ confirmation: data.confirmation_required || "",
275
278
  })
276
279
  );
277
280
  },
@@ -334,7 +337,7 @@ const LocationContentTransfer = {
334
337
  package_level_id: data.package_level.id,
335
338
  location_id: data.package_level.location_src.id,
336
339
  barcode: scanned.text,
337
- confirmation: data.confirmation_required,
340
+ confirmation: data.confirmation_required || "",
338
341
  };
339
342
  } else {
340
343
  endpoint = "set_destination_line";
@@ -342,7 +345,7 @@ const LocationContentTransfer = {
342
345
  move_line_id: data.move_line.id,
343
346
  location_id: data.move_line.location_src.id,
344
347
  barcode: scanned.text,
345
- confirmation: data.confirmation_required,
348
+ confirmation: data.confirmation_required || "",
346
349
  quantity: this.scan_destination_qty,
347
350
  };
348
351
  }
@@ -24,7 +24,7 @@ export var SinglePackStatesMixin = {
24
24
  this.wait_call(
25
25
  this.odoo.call("start", {
26
26
  barcode: scanned.text,
27
- confirmation: data.confirmation_required,
27
+ confirmation: data.confirmation_required || "",
28
28
  })
29
29
  );
30
30
  },
@@ -43,7 +43,7 @@ export var SinglePackStatesMixin = {
43
43
  package_level_id: data.id,
44
44
  location_barcode: scanned.text,
45
45
  confirmation:
46
- confirmation || data.confirmation_required,
46
+ confirmation || data.confirmation_required || "",
47
47
  })
48
48
  );
49
49
  },
@@ -60,6 +60,8 @@ export var SinglePackStatesMixin = {
60
60
  },
61
61
  };
62
62
 
63
+ // TODO: consider replacing the dynamic "autofocus" in the searchbar by an event.
64
+ // At the moment, we need autofocus to be disabled if there's a user popup.
63
65
  const SinglePackTransfer = {
64
66
  mixins: [ScenarioBaseMixin, SinglePackStatesMixin],
65
67
  template: `
@@ -67,8 +69,19 @@ const SinglePackTransfer = {
67
69
  <template v-slot:header>
68
70
  <state-display-info :info="state.display_info" v-if="state.display_info"/>
69
71
  </template>
70
- <searchbar v-if="state_is(initial_state_key)" v-on:found="on_scan" :input_placeholder="search_input_placeholder"></searchbar>
71
- <searchbar v-if="state_is('scan_location')" v-on:found="on_scan" :input_placeholder="search_input_placeholder" :input_data_type="'location'"></searchbar>
72
+ <searchbar
73
+ v-if="state_is(initial_state_key)"
74
+ v-on:found="on_scan"
75
+ :autofocus="!screen_info.user_popup"
76
+ :input_placeholder="search_input_placeholder"
77
+ ></searchbar>
78
+ <searchbar
79
+ v-if="state_is('scan_location')"
80
+ v-on:found="on_scan"
81
+ :autofocus="!screen_info.user_popup"
82
+ :input_placeholder="search_input_placeholder"
83
+ :input_data_type="'location'"
84
+ ></searchbar>
72
85
  <div v-if="state.key != 'show_completion_info' && _.result(state, 'data.picking')">
73
86
  <item-detail-card
74
87
  :key="make_state_component_key(['package', state.data.id])"
@@ -7,6 +7,8 @@
7
7
  import {ScenarioBaseMixin} from "/shopfloor_mobile_base/static/wms/src/scenario/mixins.js";
8
8
  import {process_registry} from "/shopfloor_mobile_base/static/wms/src/services/process_registry.js";
9
9
 
10
+ // TODO: consider replacing the dynamic "autofocus" in the searchbar by an event.
11
+ // At the moment, we need autofocus to be disabled if there's a user popup.
10
12
  const template_mobile = `
11
13
  <Screen :screen_info="screen_info">
12
14
  <template v-slot:header>
@@ -16,6 +18,7 @@ const template_mobile = `
16
18
  v-if="state.on_scan"
17
19
  v-on:found="on_scan"
18
20
  :input_placeholder="search_input_placeholder"
21
+ :autofocus="!screen_info.user_popup"
19
22
  />
20
23
 
21
24
  <div v-if="state_is('scan_location')">
@@ -58,7 +61,7 @@ const template_mobile = `
58
61
  <div v-if="state_is('select_line')">
59
62
  <item-detail-card
60
63
  v-if="device_mode == 'mobile'"
61
- v-for="line in state.data.move_lines"
64
+ v-for="line in select_line_detail_card_items()"
62
65
  :key="make_state_component_key(['line', line.id])"
63
66
  :record="line"
64
67
  :options="select_line_move_line_detail_options()"
@@ -118,12 +121,23 @@ const template_mobile = `
118
121
  :card_color="utils.colors.color_for('screen_step_done')"
119
122
  />
120
123
  <item-detail-card
121
- v-if="state_in(['set_line_destination', 'stock_issue', 'change_pack_lot'])"
124
+ v-if="state_in(['set_line_destination', 'stock_issue', 'change_pack_lot']) && !hide_qty_picker()"
122
125
  :key="make_state_component_key(['detail-move-line-product', state.data.move_line.id])"
123
126
  :record="state.data.move_line"
124
127
  :options="utils.wms.move_line_product_detail_options(state.data.move_line, {fields_blacklist: ['quantity']})"
125
128
  :card_color="utils.colors.color_for(state_in(['set_line_destination']) ? 'screen_step_done': 'screen_step_todo')"
126
129
  />
130
+
131
+
132
+ <item-detail-card
133
+ v-if="hide_qty_picker()"
134
+ :key="make_state_component_key(['detail-move-line-dest-pack', state.data.move_line.id])"
135
+ :record="state.data.move_line"
136
+ :options="{main: true, key_title: 'package_src.name', title_action_field: {action_val_path: 'package_src.name'}}"
137
+ :card_color="utils.colors.color_for(state_in(['set_line_destination']) ? 'screen_step_done': 'screen_step_todo')"
138
+ />
139
+
140
+
127
141
  <item-detail-card
128
142
  v-if="state_in(['set_line_destination'])"
129
143
  :key="make_state_component_key(['detail-move-line-loc-dest', state.data.move_line.id])"
@@ -131,7 +145,7 @@ const template_mobile = `
131
145
  :options="{main: true, key_title: 'location_dest.name', title_action_field: {action_val_path: 'location_dest.barcode'}}"
132
146
  :card_color="utils.colors.color_for('screen_step_todo')"
133
147
  />
134
- <v-card v-if="state_in(['set_line_destination', 'change_pack_lot'])"
148
+ <v-card v-if="state_in(['set_line_destination', 'change_pack_lot']) && !hide_qty_picker()"
135
149
  class="pa-2" :color="utils.colors.color_for('screen_step_todo')">
136
150
  <packaging-qty-picker
137
151
  :key="make_state_component_key(['packaging-qty-picker', state.data.move_line.id])"
@@ -384,33 +398,138 @@ const ZonePicking = {
384
398
  },
385
399
  select_line_table_items: function () {
386
400
  const self = this;
401
+ // For line with a complete mix package only show one line per package
402
+ // with the name of the package
403
+ var full_package_handeled = [];
387
404
  // Convert to v-data-table keys
388
405
  const items = _.map(this.state.data.move_lines, function (record) {
389
406
  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);
407
+ if (record.handle_complete_mix_pack) {
408
+ if (full_package_handeled.includes(record.package_src.name)) {
409
+ return {};
394
410
  }
395
- });
396
- item_data._origin = record;
411
+ full_package_handeled.push(record.package_src.name);
412
+ _.forEach(self.package_list_fields(true), function (field) {
413
+ item_data[field.path] = _.result(record, field.path);
414
+ if (field.renderer) {
415
+ item_data[field.path] = field.renderer(record, field);
416
+ }
417
+ });
418
+ item_data._origin = record;
419
+ } else {
420
+ _.forEach(self.move_line_list_fields(true), function (field) {
421
+ item_data[field.path] = _.result(record, field.path);
422
+ if (field.renderer) {
423
+ item_data[field.path] = field.renderer(record, field);
424
+ }
425
+ });
426
+ item_data._origin = record;
427
+ }
397
428
  return item_data;
398
429
  });
430
+ return items.filter((value) => JSON.stringify(value) !== "{}");
431
+ },
432
+ select_line_detail_card_items: function () {
433
+ var items = [];
434
+ var full_package_handeled = [];
435
+
436
+ for (const line of this.state.data.move_lines) {
437
+ if (line.handle_complete_mix_pack) {
438
+ if (full_package_handeled.includes(line.package_src.name)) {
439
+ continue;
440
+ }
441
+ full_package_handeled.push(line.package_src.name);
442
+ }
443
+ items.push(line);
444
+ }
399
445
  return items;
400
446
  },
401
447
  select_line_move_line_detail_options: function () {
402
448
  const options = {
403
449
  key_title: "location_src.name",
404
450
  loud_labels: true,
405
- title_action_field: {action_val_path: "product.barcode"},
451
+ title_action_field: {
452
+ action_val_path: function (record, field) {
453
+ return record.handle_complete_mix_pack
454
+ ? "package_src.name"
455
+ : "product.barcode";
456
+ },
457
+ },
406
458
  fields: this.move_line_list_fields(),
407
459
  };
408
460
  return options;
409
461
  },
462
+
463
+ package_list_fields: function (table_mode = false) {
464
+ const self = this;
465
+ const fields = [
466
+ {
467
+ path: "product.display_name",
468
+ label: table_mode ? "Product" : null,
469
+ renderer: function (rec, field) {
470
+ return "";
471
+ },
472
+ },
473
+ {
474
+ path: "package_src.name",
475
+ label: "Pack / Lot",
476
+ renderer: function (rec, field) {
477
+ const pkg = _.result(rec, "package_src.name", "");
478
+ const lot = _.result(rec, "lot.name", "");
479
+ return lot ? pkg + "\n" + lot : pkg;
480
+ },
481
+ },
482
+ {
483
+ path: "quantity",
484
+ label: "Qty",
485
+ renderer: function (rec, field) {
486
+ return rec.handle_complete_mix_pack
487
+ ? rec.package_src.total_quantity
488
+ : rec.quantity;
489
+ },
490
+ },
491
+ {path: "package_src.weight", label: "Weight"},
492
+ {
493
+ path: "picking.scheduled_date",
494
+ label: "Date",
495
+ renderer: function (rec, field) {
496
+ return self.utils.display.render_field_date(rec, field);
497
+ },
498
+ },
499
+ {
500
+ path: "priority",
501
+ label: table_mode ? "Priority" : null,
502
+ render_component: "priority-widget",
503
+ render_options: function (record) {
504
+ return {priority: parseInt(record.priority || "0", 10)};
505
+ },
506
+ },
507
+ {
508
+ path: "location_will_be_empty",
509
+ render_component: "empty-location-icon",
510
+ display_no_value: true,
511
+ },
512
+ ];
513
+ if (table_mode) {
514
+ fields.unshift({path: "location_src.name", label: "Location"});
515
+ }
516
+ return fields;
517
+ },
518
+
410
519
  move_line_list_fields: function (table_mode = false) {
411
520
  const self = this;
412
521
  const fields = [
413
- {path: "product.display_name", label: table_mode ? "Product" : null},
522
+ {
523
+ path: "product.display_name",
524
+ label: table_mode ? "Product" : null,
525
+ renderer: function (rec, field) {
526
+ if (rec.handle_complete_mix_pack) {
527
+ return "";
528
+ } else {
529
+ return rec.product.display_name;
530
+ }
531
+ },
532
+ },
414
533
  {
415
534
  path: "package_src.name",
416
535
  label: "Pack / Lot",
@@ -426,7 +545,9 @@ const ZonePicking = {
426
545
  render_component: "packaging-qty-picker-display",
427
546
  render_props: function (record) {
428
547
  return self.utils.wms.move_line_qty_picker_props(record, {
429
- qtyInit: record.quantity,
548
+ qtyInit: record.handle_complete_mix_pack
549
+ ? record.package_src.total_quantity
550
+ : record.quantity,
430
551
  });
431
552
  },
432
553
  },
@@ -475,7 +596,7 @@ const ZonePicking = {
475
596
  scan_source(barcode) {
476
597
  let data = {
477
598
  barcode: barcode,
478
- confirmation: this.state.data.confirmation_required,
599
+ confirmation: this.state.data.confirmation_required || "",
479
600
  };
480
601
  if (this.state_is("select_line") && this.state.data.product) {
481
602
  data.product_id = this.state.data.product.id;
@@ -516,6 +637,36 @@ const ZonePicking = {
516
637
  picking_summary_move_line_detail_fields: function () {
517
638
  return [{path: "package_src.name", klass: "loud"}];
518
639
  },
640
+ hide_qty_picker: function () {
641
+ if ("handle_complete_mix_pack" in this.state.data) {
642
+ return this.state.data.handle_complete_mix_pack;
643
+ }
644
+ return false;
645
+ },
646
+ all_lines_with_package: function () {
647
+ const move_lines = this.state.data.move_lines;
648
+ if (!move_lines) {
649
+ return false;
650
+ }
651
+ for (let line_id = 0; line_id < move_lines.length; line_id++) {
652
+ if (!move_lines[line_id].package_src) {
653
+ return false;
654
+ }
655
+ }
656
+ return true;
657
+ },
658
+ any_line_with_lot: function () {
659
+ const move_lines = this.state.data.move_lines;
660
+ if (!move_lines) {
661
+ return false;
662
+ }
663
+ for (let line_id = 0; line_id < move_lines.length; line_id++) {
664
+ if (move_lines[line_id].lot) {
665
+ return true;
666
+ }
667
+ }
668
+ return false;
669
+ },
519
670
  },
520
671
  computed: {
521
672
  sort_lines_by_btn_label() {
@@ -613,16 +764,36 @@ const ZonePicking = {
613
764
  title: "Select move",
614
765
  scan_placeholder: () => {
615
766
  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";
767
+ const pack = this.state.data.package;
768
+ if (this.state.data.scan_location_or_pack_first) {
769
+ if (!pack && this.all_lines_with_package()) {
770
+ return "Scan pack";
771
+ }
772
+ if (!sublocation && !pack) {
773
+ return "Scan location / pack";
774
+ }
775
+ if (this.any_line_with_lot()) {
776
+ return "Scan product / lot";
777
+ }
778
+ return "Scan product";
621
779
  }
622
780
  if (sublocation) {
623
- return "Scan product / lot / package";
781
+ if (pack) {
782
+ if (this.any_line_with_lot()) {
783
+ return "Scan product / lot";
784
+ }
785
+ return "Scan product";
786
+ } else {
787
+ if (this.any_line_with_lot()) {
788
+ return "Scan pack / product / lot";
789
+ }
790
+ return "Scan pack / product";
791
+ }
792
+ }
793
+ if (this.any_line_with_lot()) {
794
+ return "Scan location / pack / product / lot";
624
795
  }
625
- return "Scan location / pack / product / lot";
796
+ return "Scan location / pack / product";
626
797
  },
627
798
  },
628
799
  events: {
@@ -658,33 +829,68 @@ const ZonePicking = {
658
829
  },
659
830
  },
660
831
  set_line_destination: {
832
+ enter: () => {
833
+ // When entering this screen, we show a different message if:
834
+ // - We only allow scanning locations.
835
+ // - We allow scanning locations and packages.
836
+ const is_scan_package_allowed =
837
+ this.state.data.allow_alternative_destination_package;
838
+ const placeholder = is_scan_package_allowed
839
+ ? this.state.display_info.scan_placeholder_full
840
+ : this.state.display_info.scan_placeholder_location;
841
+ this.state.display_info.scan_placeholder = placeholder;
842
+ },
661
843
  display_info: {
662
844
  title: "Set destination",
663
845
  scan_placeholder: "Scan location or package",
664
846
  scan_placeholder_full: "Scan location or package",
665
- scan_placeholder_partial: "Scan package",
847
+ scan_placeholder_package: "Scan package",
848
+ scan_placeholder_location: "Scan location",
666
849
  },
667
850
  events: {
668
851
  qty_edit: "on_qty_update",
669
852
  },
670
853
  on_qty_update: (qty) => {
671
854
  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;
855
+
856
+ // Display different placeholder messages (package / location / both).
857
+ const is_scan_package_allowed =
858
+ this.state.data.allow_alternative_destination_package;
859
+ const full_qty = this.state.data.move_line.quantity === qty;
860
+
861
+ const display_info = this.state.display_info;
862
+ if (!is_scan_package_allowed) {
863
+ // Only locations are allowed.
864
+ display_info.scan_placeholder =
865
+ display_info.scan_placeholder_location;
675
866
  } else {
676
- this.state.display_info.scan_placeholder =
677
- this.state.display_info.scan_placeholder_full;
867
+ if (!full_qty) {
868
+ // Only packages are allowed.
869
+ display_info.scan_placeholder =
870
+ display_info.scan_placeholder_package;
871
+ } else {
872
+ // Both are allowed.
873
+ display_info.scan_placeholder =
874
+ display_info.scan_placeholder_full;
875
+ }
678
876
  }
679
877
  },
680
878
  on_scan: (scanned) => {
681
879
  const data = this.state.data;
880
+ // When handling a complete pack the quantity picker is hidden
881
+ // because all move line of the package will be handled.
882
+ // So for that case we pass a positive quantity
883
+ const quantity = data.handle_complete_mix_pack
884
+ ? data.move_line.quantity
885
+ : this.scan_destination_qty;
682
886
  this.wait_call(
683
887
  this.odoo.call("set_destination", {
684
888
  move_line_id: data.move_line.id,
685
889
  barcode: scanned.text,
686
- quantity: this.scan_destination_qty,
687
- confirmation: data.confirmation_required,
890
+ quantity: quantity,
891
+ confirmation: data.confirmation_required || "",
892
+ // package_id: data.is_complete_mix_pack ? data.move_line.package_src.id : null,
893
+ handle_complete_mix_pack: data.handle_complete_mix_pack,
688
894
  })
689
895
  );
690
896
  },
@@ -712,7 +918,8 @@ const ZonePicking = {
712
918
  this.wait_call(
713
919
  this.odoo.call("set_destination_all", {
714
920
  barcode: scanned.text,
715
- confirmation: this.state.data.confirmation_required,
921
+ confirmation:
922
+ this.state.data.confirmation_required || "",
716
923
  })
717
924
  );
718
925
  },
@@ -744,7 +951,8 @@ const ZonePicking = {
744
951
  this.odoo.call("unload_set_destination", {
745
952
  package_id: this.state.data.move_line.package_dest.id,
746
953
  barcode: scanned.text,
747
- confirmation: this.state.data.confirmation_required,
954
+ confirmation:
955
+ this.state.data.confirmation_required || "",
748
956
  })
749
957
  );
750
958
  },
@@ -176,20 +176,38 @@ export class WMSUtils {
176
176
  });
177
177
  return res;
178
178
  }
179
-
179
+ /**
180
+ * Get only the 1st line for each package.
181
+ *
182
+ * @param {*} lines: list of move lines
183
+ * @returns 1 line per package.
184
+ *
185
+ * Other lines in the same package are attached to the single line
186
+ * with special attribute `_pack_lines`.
187
+ */
188
+ /**
189
+ * TODO: this func is used only in `checkout.select_line`
190
+ * to display only one line list item
191
+ * when you have multiple lines in the same pack.
192
+ * It's a bit of an hack and it works because
193
+ * the checkout endpoints will take care of selecting all the lines
194
+ * when you scan or tap on the line.
195
+ * We should probably consider to adopt the same approach of `checkout.summary`
196
+ * where the lines are explicitly grouped by package and show a dropdown.
197
+ * The dropdown could be optional.
198
+ */
180
199
  only_one_package(lines) {
200
+ const grouped = this.group_by_pack(lines);
181
201
  const res = [];
182
- const pkg_seen = [];
183
- lines.forEach(function (line) {
184
- if (line.package_dest) {
185
- if (!pkg_seen.includes(line.package_dest.id)) {
186
- // Got a pack
187
- res.push(line);
188
- pkg_seen.push(line.package_dest.id);
189
- }
202
+ grouped.forEach(function (group) {
203
+ if (group.pack) {
204
+ let single_line = group.records[0];
205
+ single_line._grouped_by_pack = true;
206
+ single_line._pack_lines = group.records;
207
+ res.push(single_line);
190
208
  } else {
191
209
  // No pack
192
- res.push(line);
210
+ res.push(...group.records);
193
211
  }
194
212
  });
195
213
  return res;
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: odoo-addon-shopfloor-mobile
3
- Version: 16.0.1.0.0.8
3
+ Version: 16.0.1.1.0
4
4
  Summary: Mobile frontend for WMS Shopfloor app
5
5
  Home-page: https://github.com/OCA/wms
6
6
  Author: Camptocamp, BCIM, Akretion, Odoo Community Association (OCA)
@@ -25,7 +25,7 @@ Shopfloor mobile
25
25
  !! This file is generated by oca-gen-addon-readme !!
26
26
  !! changes will be overwritten. !!
27
27
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
28
- !! source digest: sha256:cd664d31e2a374f629474683de47781fd6a0463a2939ab5d86ad0ab5b8f4e0d5
28
+ !! source digest: sha256:ec3d467f63cb02754093fc0b29a29951595f4f681dc519eea793cd8fa8fcae84
29
29
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
30
30
 
31
31
  .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
@@ -1,8 +1,8 @@
1
- odoo/addons/shopfloor_mobile/README.rst,sha256=CGXjLN0CFKgQtUm4e3aULWoyuY6vSkN7WRlbLolbD3k,7148
1
+ odoo/addons/shopfloor_mobile/README.rst,sha256=9gLVbzo0KE7b0RUGZT5f8OgDGGQGUQw2-7nIYE-U-uM,7148
2
2
  odoo/addons/shopfloor_mobile/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- odoo/addons/shopfloor_mobile/__manifest__.py,sha256=VDgLbnVfY0aY7bGzj0mwDHDmPHJNAQIgNSJ_NBmTQPA,683
3
+ odoo/addons/shopfloor_mobile/__manifest__.py,sha256=OWExu24J2Dg4rXHVVJ5clUcZhHQP6n4IbgDjLfbyrFI,683
4
4
  odoo/addons/shopfloor_mobile/i18n/es_AR.po,sha256=8mGWCcMew3na_BE6yzC9aGqTSHNwLq_fu1r-JnZnYGE,1149
5
- odoo/addons/shopfloor_mobile/i18n/it.po,sha256=70bJ8f0IgeWxthAa8dpCCJ2VujuUWH7uSpJBUnYo8GI,411
5
+ odoo/addons/shopfloor_mobile/i18n/it.po,sha256=Fuhk7nf_wDaq10_RJlCCe4xE6u8qKIml2r_4nUJ1O1w,412
6
6
  odoo/addons/shopfloor_mobile/i18n/pt_BR.po,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  odoo/addons/shopfloor_mobile/i18n/shopfloor_mobile.pot,sha256=leB6MlaWiU1sPOdcOTxNVY5KVORnHv0MfD14HgQJIIs,341
8
8
  odoo/addons/shopfloor_mobile/readme/CONTRIBUTORS.rst,sha256=AEECRuaiP1U4xBwIQOYsHFr-Tgx2-LqBQPmFejH6OIs,392
@@ -12,10 +12,10 @@ odoo/addons/shopfloor_mobile/readme/HISTORY.rst,sha256=Ibf54quZVYNg74R-oWzny0XeM
12
12
  odoo/addons/shopfloor_mobile/readme/ROADMAP.rst,sha256=Nm8uyGJvPQWMQtYwwxt8P4WBuLLpUZjZ_p8eqTrFRbM,1726
13
13
  odoo/addons/shopfloor_mobile/readme/USAGE.rst,sha256=5NNHChxhLwFVo4m6XhCaSlagf_bpNaZgsF8oSGSQ2WY,677
14
14
  odoo/addons/shopfloor_mobile/static/description/icon.png,sha256=6xBPJauaFOF0KDHfHgQopSc28kKvxMaeoQFQWZtfZDo,9455
15
- odoo/addons/shopfloor_mobile/static/description/index.html,sha256=bHEvWLDRhH3ldVhIj0bu46qvDKBsPWPf4twk74wOqJY,18026
15
+ odoo/addons/shopfloor_mobile/static/description/index.html,sha256=HYjGAEIdGWsmS0C6QzQPMmrIiVglsKBAIrLphwzgwiM,17943
16
16
  odoo/addons/shopfloor_mobile/static/wms/.gitignore,sha256=rQCFL3FQm3Lll35BRUETzj1HYlakdld--GvTGLPeHpE,214
17
17
  odoo/addons/shopfloor_mobile/static/wms/src/screen.js,sha256=77TQgYSfpnErCuhV9FjQujMFlrKU7EZ6OdeTJnZutV8,1461
18
- odoo/addons/shopfloor_mobile/static/wms/src/wms_utils.js,sha256=6fPt-64R5FEyvWLLzmJny1FoYJxOFW9Lwi9JOF094iY,11104
18
+ odoo/addons/shopfloor_mobile/static/wms/src/wms_utils.js,sha256=-UWOXl0G7uRGa8WzpruGfc_Lzf3ZMctM10lHzWF3Gj8,11936
19
19
  odoo/addons/shopfloor_mobile/static/wms/src/components/batch_picking_detail.js,sha256=eyehbELMbEkDp0dREIDR3O7s8hsGh4QXoDcyhlQO8Ms,2175
20
20
  odoo/addons/shopfloor_mobile/static/wms/src/components/batch_picking_line_detail.js,sha256=4d32G1yQAlzmjOGr9ta4VC8olCLREN_U-xbkJGf8XSU,4772
21
21
  odoo/addons/shopfloor_mobile/static/wms/src/components/manual_select_color.js,sha256=O07YP4zYDSZk1edV8ogvNJCkKyDWIiX7L_g_JzHS5Es,932
@@ -27,7 +27,7 @@ odoo/addons/shopfloor_mobile/static/wms/src/components/detail/detail_operation.j
27
27
  odoo/addons/shopfloor_mobile/static/wms/src/components/detail/detail_package.js,sha256=FPT_WDXVDPg4m5wLrA9MunjLL9nsDe59qxW-yiLQpM4,2746
28
28
  odoo/addons/shopfloor_mobile/static/wms/src/components/detail/detail_picking.js,sha256=PeavOYvJjfkKNeA-TGU9UGugyPD1DjeW3A02Cr0LY1k,1123
29
29
  odoo/addons/shopfloor_mobile/static/wms/src/components/detail/detail_product.js,sha256=drMFbpcOsWOxyGlvscLEnu0yVMAy_ADaRMAQS4JaJZE,2546
30
- odoo/addons/shopfloor_mobile/static/wms/src/components/detail/detail_transfer.js,sha256=nH6AOAC_wADB4ogCYeQ1LZpfxLwQtxgTnjmh316e7G4,4705
30
+ odoo/addons/shopfloor_mobile/static/wms/src/components/detail/detail_transfer.js,sha256=xUiKj-MAkJ4YIvE0o6wKK-iuoeslLfuh9e0rUyH3d_g,4681
31
31
  odoo/addons/shopfloor_mobile/static/wms/src/components/forms/form_edit_stock_picking.js,sha256=lgn_2rG50gbLH7h2K6iqZHeEFeWguemJPURAR1eWJeU,1153
32
32
  odoo/addons/shopfloor_mobile/static/wms/src/components/scenario_picking_detail/mixins.js,sha256=ExPE5POHn6PCe32Kt6S70wNwTZ8UJZg21uPKXO1xaEU,4119
33
33
  odoo/addons/shopfloor_mobile/static/wms/src/components/scenario_picking_detail/picking_select.js,sha256=k6hf4t4m0078_6m0XJtDTgoMlLV7CpLbaS62Ju5zXQo,4887
@@ -43,16 +43,16 @@ odoo/addons/shopfloor_mobile/static/wms/src/demo/demo.single_pack_transfer.js,sh
43
43
  odoo/addons/shopfloor_mobile/static/wms/src/demo/demo.zone_picking.js,sha256=BE8pzEGHq5j_Q49Oz-h4bRP89mJG-XSKNZsCRC9nVDQ,8467
44
44
  odoo/addons/shopfloor_mobile/static/wms/src/i18n/add_translations_to_registry.js,sha256=rcYYDwMWOrEpWi83WwsNz1C6IJfwIKFE-VDqqrSCcNE,280
45
45
  odoo/addons/shopfloor_mobile/static/wms/src/i18n/en.json,sha256=gn981MlQXNBYiVZHWOV4o0LzdrCqZ2Z9ptjPArF8C-Q,1944
46
- odoo/addons/shopfloor_mobile/static/wms/src/i18n/fr.json,sha256=HNBXPkTX3FTOX0BUkwdGN8VImAm7255oYl8YQUyy8Wc,1983
47
- odoo/addons/shopfloor_mobile/static/wms/src/scenario/checkout.js,sha256=NCcUI9o3ZupjnsPlhphw0ryjQCUdmpADzPFQ5vwRIfw,17816
48
- odoo/addons/shopfloor_mobile/static/wms/src/scenario/checkout_states.js,sha256=cre6oYeWtCyCZ77fUahc2sXyayadN_OD2gNyRP48Jp4,14140
49
- odoo/addons/shopfloor_mobile/static/wms/src/scenario/cluster_picking.js,sha256=ey7_L4LS27CmFrbYFt4ppiFP52kCWOWdixyyyvodmtw,20875
46
+ odoo/addons/shopfloor_mobile/static/wms/src/i18n/fr.json,sha256=-nRVyM2PsggBL1WjxYzyeRdC4kwx7HzSOXAN83TJehE,1941
47
+ odoo/addons/shopfloor_mobile/static/wms/src/scenario/checkout.js,sha256=JTa7E7ZwLQXTBBq5CwpB_vPvqVRnbBNaXSHy3TIM13w,19412
48
+ odoo/addons/shopfloor_mobile/static/wms/src/scenario/checkout_states.js,sha256=stvKy_qT-am-1N6IPDV0_4gAomOtY1wfJYMuBvo0u5k,14885
49
+ odoo/addons/shopfloor_mobile/static/wms/src/scenario/cluster_picking.js,sha256=W-22xBhtdWDR_ZZvdrONYNFrXLxgrv4sa6jjUE0hON8,20515
50
50
  odoo/addons/shopfloor_mobile/static/wms/src/scenario/delivery.js,sha256=mYPBRAjRcI38BgdSVxbhaQnV_vXuD546ysz_0JUZ55Y,15001
51
- odoo/addons/shopfloor_mobile/static/wms/src/scenario/location_content_transfer.js,sha256=18wrorVv5Tv86pwibYgFt2B28XIbqulavbG1ISd1j4Y,17859
52
- odoo/addons/shopfloor_mobile/static/wms/src/scenario/single_pack_transfer.js,sha256=x07S3aKRXLsZm9gobC837lt-84ilTIoUmn0f7Lq5Dl8,5700
53
- odoo/addons/shopfloor_mobile/static/wms/src/scenario/zone_picking.js,sha256=6BXzGcEijS1n5r2nobebZ6rY_X6qhrzTKhsRUC1Snq4,35375
51
+ odoo/addons/shopfloor_mobile/static/wms/src/scenario/location_content_transfer.js,sha256=XtBc29PCjfR1H8J9iyBwvy0R2cVS_6piJsDmnINJv9g,18088
52
+ odoo/addons/shopfloor_mobile/static/wms/src/scenario/single_pack_transfer.js,sha256=0Tpi9bVUamT0Ij1JCJHLo4IwyM7IAkXfAxHw87g-doM,6114
53
+ odoo/addons/shopfloor_mobile/static/wms/src/scenario/zone_picking.js,sha256=ftcQ7tbSev66wFg09TQ3LCL-3lCzt7H_l1J3ftdc60U,44958
54
54
  odoo/addons/shopfloor_mobile/templates/assets.xml,sha256=QAiHXcCpybR9h4B3WuuDcFZ1DnJcGg2cQ63RCUw2niY,7873
55
- odoo_addon_shopfloor_mobile-16.0.1.0.0.8.dist-info/METADATA,sha256=RXEbyEZz9VakA06DoTumqXSXLi9GPQL5SJbIWDBZHfM,7828
56
- odoo_addon_shopfloor_mobile-16.0.1.0.0.8.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
57
- odoo_addon_shopfloor_mobile-16.0.1.0.0.8.dist-info/top_level.txt,sha256=qBj40grFkGOfDZ2WDSw3y1RnDlgG0u8rP8pvGNdbz4w,5
58
- odoo_addon_shopfloor_mobile-16.0.1.0.0.8.dist-info/RECORD,,
55
+ odoo_addon_shopfloor_mobile-16.0.1.1.0.dist-info/METADATA,sha256=8nc5TokbYG-qhYjm6dkcwuT5ijiKfUGl0ZUq27hvnqo,7826
56
+ odoo_addon_shopfloor_mobile-16.0.1.1.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
57
+ odoo_addon_shopfloor_mobile-16.0.1.1.0.dist-info/top_level.txt,sha256=qBj40grFkGOfDZ2WDSw3y1RnDlgG0u8rP8pvGNdbz4w,5
58
+ odoo_addon_shopfloor_mobile-16.0.1.1.0.dist-info/RECORD,,