@things-factory/operato-wms 3.8.5 → 3.8.9

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.
@@ -134,8 +134,6 @@ class BulkOperation extends localize(i18next)(PageView) {
134
134
 
135
135
  static get properties() {
136
136
  return {
137
- _files: Array,
138
- _releaseOrders: Array,
139
137
  _bizplaceId: String,
140
138
  _bizplaceName: String
141
139
  }
@@ -159,33 +157,13 @@ class BulkOperation extends localize(i18next)(PageView) {
159
157
  return this.shadowRoot.querySelector('#upload-document')
160
158
  }
161
159
 
162
- get _dummyData() {
163
- return this._releaseOrders.map(x => {
164
- x.orderInventories = x.orderInventories.map(y => {
165
- return {
166
- ...y,
167
- availableQty: Math.floor(Math.random() * 50) + 30
168
- }
169
- })
170
- return {
171
- ...x,
172
- releaseDate: new Date().toISOString().split('T')
173
- }
174
- })
175
- }
176
-
177
160
  render() {
178
- let subtitle = 'Release Order'
179
- let attachment = {
180
- path: ''
181
- }
182
-
183
161
  return html`
184
162
  <ul export-form>
185
163
  <li>
186
164
  <div subtitle>
187
- ${subtitle} &nbsp;
188
- <a href="${location.origin}/attachment/${attachment.path}" download>
165
+ Release Order &nbsp;
166
+ <a @click=${async () => await this._getReleaseOrderTemplate()}" download>
189
167
  <mwc-icon>file_download</mwc-icon>
190
168
  </a>
191
169
  </div>
@@ -223,17 +201,39 @@ class BulkOperation extends localize(i18next)(PageView) {
223
201
  `
224
202
  }
225
203
 
226
- updated(changeProps) {
227
- if (changeProps.has('_rawROData')) {
228
- if (this._releaseOrders.length) {
229
- // this._validateReleaseOrder(this._releaseOrders)
230
- this._validateReleaseOrder(this._rawROData)
204
+ async _getReleaseOrderTemplate() {
205
+ const data = [
206
+ {
207
+ refNo: '',
208
+ refNo2: '',
209
+ refNo3: '',
210
+ releaseDate: '',
211
+ attentionTo: '',
212
+ deliveryAddress1: '',
213
+ deliveryAddress2: '',
214
+ deliveryAddress3: '',
215
+ deliveryAddress4: '',
216
+ postalCode: '',
217
+ city: '',
218
+ state: '',
219
+ country: '',
220
+ phone1: '',
221
+ sku: '',
222
+ packingType: '',
223
+ packingSize: 0,
224
+ uom: '',
225
+ releaseQty: 0
231
226
  }
232
- }
233
- }
227
+ ]
228
+ /* make the worksheet */
229
+ const ws = XLSX.utils.json_to_sheet(data)
230
+
231
+ /* add to workbook */
232
+ const wb = XLSX.utils.book_new()
233
+ XLSX.utils.book_append_sheet(wb, ws)
234
234
 
235
- _getReleaseOrderTemplate() {
236
- /* download excel template for Create RO */
235
+ /* generate an XLSX file */
236
+ XLSX.writeFile(wb, 'release_orders.xlsx')
237
237
  }
238
238
 
239
239
  async _extractRawDataFromExcel() {
@@ -261,26 +261,41 @@ class BulkOperation extends localize(i18next)(PageView) {
261
261
  let rawData = XLSX.utils.sheet_to_json(worksheet)
262
262
  rawData = rawData.map(raw => {
263
263
  if (!raw.releaseDate || raw.releaseDate.constructor !== String) raw.releaseDate = ''
264
- else new Date(raw.releaseDate)
265
- return raw
264
+ //return entries without empty strings
265
+ return Object.fromEntries(Object.entries(raw).filter(([_, val]) => !/^\s*$/.test(val)))
266
266
  })
267
- /* return rawData to validate with inventory stocks */
268
267
  this._validateReleaseOrder(rawData)
269
268
  }
270
269
  } else if (_docs.files.length > 1)
271
- this._showToast({ level: 'error', message: i18next.t('text.you_can_only_upload_maximum_one_file') })
270
+ this._showToast({ level: 'error', message: i18next.t('text.you_can_only_upload_one_file_max') })
272
271
  else this._showToast({ level: 'error', message: i18next.t('text.please_attach_the_file') })
273
272
  } else this._showToast({ level: 'error', message: i18next.t('text.please_attach_the_file') })
274
273
  }
275
274
 
276
275
  async _validateReleaseOrder(records) {
277
276
  /* validate excel that user uploaded */
278
- openPopup(html` <validate-ro-popup .records=${records} .bizplaceId=${this._bizplaceId}></validate-ro-popup> `, {
279
- backdrop: true,
280
- escapable: false,
281
- size: 'large',
282
- title: i18next.t('title.import')
283
- })
277
+ openPopup(
278
+ html`
279
+ <validate-ro-popup
280
+ .records=${records.map(record => {
281
+ return {
282
+ ...record,
283
+ postalCode: String(record.postalCode || ''),
284
+ phone1: String(record.phone1 || ''),
285
+ releaseDate: String(record.releaseDate || ''),
286
+ releaseQty: Number(record.releaseQty || 0)
287
+ }
288
+ })}
289
+ .bizplaceId=${this._bizplaceId}
290
+ ></validate-ro-popup>
291
+ `,
292
+ {
293
+ backdrop: true,
294
+ escapable: false,
295
+ size: 'large',
296
+ title: i18next.t('title.import')
297
+ }
298
+ )
284
299
  }
285
300
 
286
301
  _openBizplacesSelector() {
@@ -7,7 +7,7 @@ import { css, html, LitElement } from 'lit-element'
7
7
  import { i18next, localize } from '@things-factory/i18n-base'
8
8
  import { client, CustomAlert } from '@things-factory/shell'
9
9
  import { ScrollbarStyles } from '@things-factory/styles'
10
- import { isMobileDevice, sleep } from '@things-factory/utils'
10
+ import { isMobileDevice } from '@things-factory/utils'
11
11
 
12
12
  class ValidateRoPopup extends localize(i18next)(LitElement) {
13
13
  static get properties() {
@@ -79,11 +79,11 @@ class ValidateRoPopup extends localize(i18next)(LitElement) {
79
79
  return {
80
80
  // if the condition not met, the grist row will be red
81
81
  emphasized:
82
- record.assignedQty <= 0 ||
82
+ record.assignedQty < record.releaseQty ||
83
83
  !record.refNo ||
84
84
  record?.refNo == '' ||
85
- !record.releaseDate ||
86
- record?.releaseDate == ''
85
+ record?.releaseDate == '' ||
86
+ record?.releaseDate < this._getStdDateStr(new Date())
87
87
  }
88
88
  }
89
89
  },
@@ -192,8 +192,8 @@ class ValidateRoPopup extends localize(i18next)(LitElement) {
192
192
  },
193
193
  {
194
194
  type: 'string',
195
- name: 'name',
196
- header: i18next.t('field.name'),
195
+ name: 'productInfo',
196
+ header: i18next.t('field.product_info'),
197
197
  width: 400
198
198
  },
199
199
  {
@@ -226,6 +226,18 @@ class ValidateRoPopup extends localize(i18next)(LitElement) {
226
226
  header: i18next.t('field.uom'),
227
227
  width: 100
228
228
  },
229
+ {
230
+ type: 'string',
231
+ name: 'packingType',
232
+ header: i18next.t('field.packing_type'),
233
+ width: 100
234
+ },
235
+ {
236
+ type: 'string',
237
+ name: 'packingSize',
238
+ header: i18next.t('field.packing_size'),
239
+ width: 100
240
+ },
229
241
  {
230
242
  type: 'string',
231
243
  name: 'remark',
@@ -295,6 +307,7 @@ class ValidateRoPopup extends localize(i18next)(LitElement) {
295
307
  country
296
308
  sku
297
309
  productId
310
+ productInfo
298
311
  batchId
299
312
  packingType
300
313
  packingSize
@@ -338,16 +351,21 @@ class ValidateRoPopup extends localize(i18next)(LitElement) {
338
351
 
339
352
  if (!response.errors) {
340
353
  this.records = response.data.bulkReleaseGoodsAvailableItems.map(item => {
354
+ let releaseDate = this._getStdDateStr(new Date(item.releaseDate || ''))
355
+
341
356
  return {
342
357
  ...item,
358
+ releaseDate,
343
359
  remark: !item.productId
344
360
  ? i18next.t('text.product_not_found')
345
361
  : item.releaseQty <= 0
346
362
  ? i18next.t('text.invalid_release_qty')
347
- : item.assignedQty == 0
363
+ : item.assignedQty < item.releaseQty
348
364
  ? i18next.t('text.insufficient_stock')
349
- : !item.releaseDate
365
+ : releaseDate == ''
350
366
  ? i18next.t('text.release_date_is_empty')
367
+ : releaseDate < this._getStdDateStr(new Date())
368
+ ? i18next.t('text.backdate_is_not_allowed')
351
369
  : !item.refNo
352
370
  ? i18next.t('text.ref_no_is_empty')
353
371
  : ''
@@ -374,11 +392,12 @@ class ValidateRoPopup extends localize(i18next)(LitElement) {
374
392
  `,
375
393
  variables: {
376
394
  rawReleaseGoods: this.records.map(x => {
395
+ // list out all properties again to avoid additional props added by user in excel
377
396
  return {
378
397
  refNo: x.refNo,
379
398
  refNo2: x.refNo2,
380
399
  refNo3: x.refNo3,
381
- releaseDate: String(x.releaseDate),
400
+ releaseDate: x.releaseDate,
382
401
  deliveryAddress1: x.deliveryAddress1,
383
402
  deliveryAddress2: x.deliveryAddress2,
384
403
  deliveryAddress3: x.deliveryAddress3,
@@ -401,21 +420,22 @@ class ValidateRoPopup extends localize(i18next)(LitElement) {
401
420
  }
402
421
  })
403
422
 
404
- this.dataGrist.hideSpinner()
405
- await sleep(1)
406
-
407
423
  if (!response.errors) {
408
424
  this._showToast({ message: i18next.t('text.release_order_created') })
409
425
  history.back()
426
+ } else {
427
+ let insufficientStockError = response.errors.find(err => err.extensions.exception.errorCode == 'ins1')
428
+ if (insufficientStockError) {
429
+ // if system suddenly found that any item is insufficient,
430
+ // display the available items again.
431
+ await this._getAvailableItems(this.records)
432
+ this._showToast({ message: i18next.t('text.please_recheck_your_request_data') })
433
+ }
410
434
  }
411
435
  } catch (e) {
412
- let insufficientStockError = response.errors.find(err => err.extensions.exception.errorCode == 'ins1')
413
- if (insufficientStockError) {
414
- // if system suddenly found that any item is insufficient,
415
- // display the available items again.
416
- await this._getAvailableItems(this.records)
417
- this._showToast({ message: i18next.t('text.please_recheck_your_request_data') })
418
- } else this._showToast(e)
436
+ this._showToast(e)
437
+ } finally {
438
+ this.dataGrist.hideSpinner()
419
439
  }
420
440
  }
421
441
 
@@ -423,11 +443,21 @@ class ValidateRoPopup extends localize(i18next)(LitElement) {
423
443
  if (this.records.some(record => !record.refNo || record?.refNo == ''))
424
444
  throw new Error(i18next.t('text.ref_no_is_required'))
425
445
 
426
- if (this.records.some(record => !record.releaseDate || record?.releaseDate == ''))
427
- throw new Error(i18next.t('text.release_date_is_required'))
428
-
429
446
  if (this.records.some(record => !record.releaseQty || record.releaseQty > record.assignedQty))
430
447
  throw new Error(i18next.t('text.invalid_release_qty'))
448
+
449
+ if (this.records.some(record => record?.releaseDate == ''))
450
+ throw new Error(i18next.t('text.release_date_is_required'))
451
+ else if (this.records.some(record => record.releaseDate < this._getStdDateStr(new Date())))
452
+ throw new Error(i18next.t('text.backdate_is_not_allowed'))
453
+ }
454
+
455
+ _getStdDateStr(date) {
456
+ if (isNaN(date.getFullYear())) return ''
457
+ else {
458
+ date.setHours(date.getHours() + 8)
459
+ return date.toISOString().split('T')[0]
460
+ }
431
461
  }
432
462
 
433
463
  _showToast({ type, message }) {
@@ -960,7 +960,7 @@ class ProductList extends localize(i18next)(PageView) {
960
960
  if (_.isEmpty(itm.uom) || '') {
961
961
  if (!errors.find(err => err.type == 'uom')) errors.push({ type: 'uom', value: 'UOM is required' })
962
962
  }
963
- if (!_.isNumber(itm.uomValue) || _.isNaN(itm.uomValue) || '' || itm?.uomValue < 1) {
963
+ if (!_.isNumber(itm.uomValue) || _.isNaN(itm.uomValue) || '' || itm?.uomValue <= 0) {
964
964
  if (!errors.find(err => err.type == 'uomValue'))
965
965
  errors.push({ type: 'uomValue', value: 'UOM Value is required' })
966
966
  }
@@ -1,6 +1,7 @@
1
1
  import '@things-factory/form-ui'
2
2
  import '@things-factory/grist-ui'
3
3
  import '../batch-picking-popup'
4
+ import '../batch-generate-single-picking-worksheet-popup'
4
5
 
5
6
  import gql from 'graphql-tag'
6
7
  import { css, html } from 'lit-element'
@@ -65,6 +66,11 @@ class B2bOrderRequests extends localize(i18next)(PageView) {
65
66
  title: i18next.t('button.batch_picking'),
66
67
  action: this._openBatchPickingPopup.bind(this),
67
68
  ...CommonButtonStyles.activate
69
+ },
70
+ {
71
+ title: i18next.t('button.generate_worksheet'),
72
+ action: this._openBatchGenerateSinglePickingWorksheetPopup.bind(this),
73
+ ...CommonButtonStyles.activate
68
74
  }
69
75
  ],
70
76
  exportable: {
@@ -442,6 +448,24 @@ class B2bOrderRequests extends localize(i18next)(PageView) {
442
448
  )
443
449
  }
444
450
 
451
+ _openBatchGenerateSinglePickingWorksheetPopup() {
452
+ openPopup(
453
+ html`
454
+ <batch-generate-single-picking-worksheet-popup
455
+ @generated="${() => {
456
+ this._showToast({ message: i18next.t('text.orders_has_been_activated') })
457
+ this.dataGrist.fetch()
458
+ }}"
459
+ ></batch-generate-single-picking-worksheet-popup>
460
+ `,
461
+ {
462
+ backdrop: true,
463
+ size: 'large',
464
+ title: i18next.t('title.generate_picking_worksheet')
465
+ }
466
+ )
467
+ }
468
+
445
469
  _compareValues(key, order = 'asc') {
446
470
  return function innerSort(a, b) {
447
471
  if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
@@ -1,6 +1,7 @@
1
1
  import '@things-factory/form-ui'
2
2
  import '@things-factory/grist-ui'
3
3
  import '../batch-picking-popup'
4
+ import '../batch-generate-single-picking-worksheet-popup'
4
5
 
5
6
  import gql from 'graphql-tag'
6
7
  import { css, html } from 'lit-element'
@@ -70,6 +71,11 @@ class B2cOrderRequests extends localize(i18next)(PageView) {
70
71
  title: i18next.t('button.batch_picking'),
71
72
  action: this._openBatchPickingPopup.bind(this),
72
73
  ...CommonButtonStyles.activate
74
+ },
75
+ {
76
+ title: i18next.t('button.generate_worksheet'),
77
+ action: this._openBatchGenerateSinglePickingWorksheetPopup.bind(this),
78
+ ...CommonButtonStyles.activate
73
79
  }
74
80
  ],
75
81
  exportable: {
@@ -209,6 +215,7 @@ class B2cOrderRequests extends localize(i18next)(PageView) {
209
215
  this.config = {
210
216
  rows: { selectable: { multiple: true }, appendable: false },
211
217
  list: { fields: ['name', 'bizplace', 'releaseDate', 'status', 'updatedAt'] },
218
+ pagination: { limit: 100, pages: [20, 50, 100, 200, 500] },
212
219
  columns: [
213
220
  { type: 'gutter', gutterName: 'sequence' },
214
221
  { type: 'gutter', gutterName: 'row-selector', multiple: true },
@@ -562,6 +569,43 @@ class B2cOrderRequests extends localize(i18next)(PageView) {
562
569
  }
563
570
  }
564
571
 
572
+ _openBatchGenerateSinglePickingWorksheetPopup() {
573
+ openPopup(
574
+ html`
575
+ <batch-generate-single-picking-worksheet-popup
576
+ @generated="${() => {
577
+ this._showToast({ message: i18next.t('text.orders_has_been_activated') })
578
+ this.dataGrist.fetch()
579
+ }}"
580
+ ></batch-generate-single-picking-worksheet-popup>
581
+ `,
582
+ {
583
+ backdrop: true,
584
+ size: 'large',
585
+ title: i18next.t('title.generate_picking_worksheet')
586
+ }
587
+ )
588
+ }
589
+
590
+ _compareValues(key, order = 'asc') {
591
+ return function innerSort(a, b) {
592
+ if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
593
+ return 0
594
+ }
595
+
596
+ const varA = typeof a[key] === 'string' ? a[key].toUpperCase() : a[key]
597
+ const varB = typeof b[key] === 'string' ? b[key].toUpperCase() : b[key]
598
+
599
+ let comparison = 0
600
+ if (varA > varB) {
601
+ comparison = 1
602
+ } else if (varA < varB) {
603
+ comparison = -1
604
+ }
605
+ return order === 'desc' ? comparison * -1 : comparison
606
+ }
607
+ }
608
+
565
609
  _modifyDateRange(e) {
566
610
  const fromDate = e.currentTarget.value
567
611
 
@@ -0,0 +1,314 @@
1
+ import '@things-factory/grist-ui'
2
+ import { MultiColumnFormStyles } from '@things-factory/form-ui'
3
+ import { openPopup } from '@things-factory/layout-base'
4
+ import { client, CustomAlert } from '@things-factory/shell'
5
+ import { i18next, localize } from '@things-factory/i18n-base'
6
+ import { isMobileDevice } from '@things-factory/utils'
7
+ import { css, html, LitElement } from 'lit-element'
8
+ import gql from 'graphql-tag'
9
+ import { ScrollbarStyles } from '@things-factory/styles'
10
+ import { ORDER_STATUS } from '../../constants'
11
+ import '@things-factory/biz-ui'
12
+
13
+ class BatchGenerateSinglePickingWorksheetPopup extends localize(i18next)(LitElement) {
14
+ static get properties() {
15
+ return {
16
+ _searchFields: Array,
17
+ config: Object,
18
+ data: Object
19
+ }
20
+ }
21
+
22
+ static get styles() {
23
+ return [
24
+ MultiColumnFormStyles,
25
+ ScrollbarStyles,
26
+ css`
27
+ :host {
28
+ display: flex;
29
+ flex-direction: column;
30
+ overflow: hidden;
31
+ background-color: white;
32
+ padding: var(--padding-default);
33
+ }
34
+ search-form {
35
+ overflow: visible;
36
+ }
37
+ .grist {
38
+ display: flex;
39
+ flex-direction: column;
40
+ flex: 1;
41
+ overflow-y: auto;
42
+ }
43
+ .grist-container {
44
+ overflow-y: hidden;
45
+ display: flex;
46
+ flex: 1;
47
+ }
48
+ data-grist {
49
+ overflow-y: hidden;
50
+ flex: 1;
51
+ }
52
+ h2 {
53
+ padding: var(--subtitle-padding);
54
+ font: var(--subtitle-font);
55
+ color: var(--subtitle-text-color);
56
+ border-bottom: var(--subtitle-border-bottom);
57
+ }
58
+ .grist h2 {
59
+ font: var(--grist-title-font);
60
+ }
61
+ .button-container {
62
+ padding: var(--button-container-padding);
63
+ margin: var(--button-container-margin);
64
+ text-align: var(--button-container-align);
65
+ background-color: var(--button-container-background);
66
+ height: var(--button-container-height);
67
+ }
68
+ `
69
+ ]
70
+ }
71
+
72
+ submit() {
73
+ this.dispatchEvent(new CustomEvent('submit'))
74
+ }
75
+
76
+ render() {
77
+ return html`
78
+ <search-form .fields=${this._searchFields} @submit=${() => this.releaseOrderGrist.fetch()}></search-form>
79
+
80
+ <div class="grist-container">
81
+ <div class="grist">
82
+ <h2>${i18next.t('title.release_order')}</h2>
83
+ <data-grist
84
+ id="releaseOrder"
85
+ .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
86
+ .config=${this.roConfig}
87
+ .fetchHandler="${this.fetchReadyToPickOrders.bind(this)}"
88
+ ></data-grist>
89
+ </div>
90
+ </div>
91
+
92
+ <div class="button-container">
93
+ <mwc-button
94
+ @click="${this.generatePickingWorksheet.bind(this)}"
95
+ raised
96
+ label="${i18next.t('button.generate_worksheet')}"
97
+ ></mwc-button>
98
+ </div>
99
+ `
100
+ }
101
+
102
+ async firstUpdated() {
103
+ const partners = await this._fetchPartners()
104
+ this._searchFields = [
105
+ {
106
+ label: i18next.t('field.company'),
107
+ name: 'bizplace',
108
+ type: 'select',
109
+ options: [
110
+ { value: '' },
111
+ ...partners
112
+ .map(partner => {
113
+ return {
114
+ name: `${partner.name} ${partner.description ? `(${partner.description})` : ''}`,
115
+ value: partner.id
116
+ }
117
+ })
118
+ .sort(this._compareValues('name', 'asc'))
119
+ ],
120
+ props: { searchOper: 'eq' }
121
+ },
122
+ {
123
+ label: i18next.t('field.release_date'),
124
+ name: 'releaseDate',
125
+ type: 'date',
126
+ props: { searchOper: 'lte' }
127
+ }
128
+ ]
129
+
130
+ this.roConfig = {
131
+ pagination: { pages: [100, 200, 300, 500], limit: 200 },
132
+ rows: {
133
+ selectable: { multiple: true },
134
+ appendable: false
135
+ },
136
+ list: { fields: ['name', 'refNo', 'bizplace', 'releaseDate'] },
137
+ columns: [
138
+ { type: 'gutter', gutterName: 'sequence' },
139
+ { type: 'gutter', gutterName: 'row-selector', multiple: true },
140
+ {
141
+ type: 'string',
142
+ name: 'name',
143
+ header: i18next.t('field.release_good_no'),
144
+ width: 150
145
+ },
146
+ {
147
+ type: 'string',
148
+ name: 'refNo',
149
+ header: i18next.t('field.ref_no'),
150
+ width: 130
151
+ },
152
+ {
153
+ type: 'object',
154
+ name: 'bizplace',
155
+ header: i18next.t('field.company'),
156
+ width: 200
157
+ },
158
+ {
159
+ type: 'date',
160
+ name: 'releaseDate',
161
+ header: i18next.t('field.release_date'),
162
+ sortable: true,
163
+ width: 150
164
+ }
165
+ ]
166
+ }
167
+ }
168
+
169
+ get searchForm() {
170
+ return this.renderRoot.querySelector('search-form')
171
+ }
172
+
173
+ get releaseOrderGrist() {
174
+ return this.shadowRoot.querySelector('data-grist#releaseOrder')
175
+ }
176
+
177
+ get orderInventoryGrist() {
178
+ return this.shadowRoot.querySelector('data-grist#orderInventory')
179
+ }
180
+
181
+ async _fetchPartners() {
182
+ const response = await client.query({
183
+ query: gql`
184
+ query partnersBizplaces($filters: [Filter!]) {
185
+ partnersBizplaces(filters: $filters) {
186
+ items {
187
+ id
188
+ name
189
+ description
190
+ }
191
+ }
192
+ }
193
+ `,
194
+ variables: { filters: [] }
195
+ })
196
+
197
+ if (!response.errors) {
198
+ return response.data.partnersBizplaces.items
199
+ }
200
+ }
201
+
202
+ async fetchReadyToPickOrders({ page, limit, sorters = [{ name: 'releaseDate' }] }) {
203
+ // if (!this.partnerBizplace) return { total: 0, records: [] }
204
+
205
+ const filters = [
206
+ ...(await this.searchForm.getQueryFilters()).filter(x => x.name != 'partnerBizplace'),
207
+ { name: 'status', operator: 'eq', value: ORDER_STATUS.PENDING_WORKSHEET.value },
208
+ { name: 'crossDocking', operator: 'eq', value: false }
209
+ ]
210
+
211
+ if (this.partnerBizplace) {
212
+ filters.push({ name: 'bizplaceId', operator: 'eq', value: this.partnerBizplace.id })
213
+ }
214
+
215
+ const pagination = { page, limit }
216
+ const sortings = sorters
217
+
218
+ const response = await client.query({
219
+ query: gql`
220
+ query releaseGoodRequests($filters: [Filter], $pagination: Pagination, $sortings: [Sorting]) {
221
+ releaseGoodRequests(filters: $filters, pagination: $pagination, sortings: $sortings) {
222
+ items {
223
+ id
224
+ name
225
+ refNo
226
+ releaseDate
227
+ type
228
+ bizplace {
229
+ id
230
+ name
231
+ description
232
+ }
233
+ }
234
+ total
235
+ }
236
+ }
237
+ `,
238
+ variables: { filters, pagination, sortings }
239
+ })
240
+ if (!response.errors) {
241
+ return {
242
+ total: response.data.releaseGoodRequests.total || 0,
243
+ records: response.data.releaseGoodRequests.items || []
244
+ }
245
+ }
246
+ }
247
+
248
+ async generatePickingWorksheet() {
249
+ try {
250
+ let releaseGoodNos = []
251
+ releaseGoodNos = this.releaseOrderGrist.selected.map(record => record.name)
252
+
253
+ if (releaseGoodNos.length <= 0) throw new Error('Please select one or more order to generate worksheet')
254
+
255
+ let result = await CustomAlert({
256
+ title: i18next.t('title.are_you_sure'),
257
+ text: i18next.t('text.generate_worksheet'),
258
+ confirmButton: { text: i18next.t('button.submit') },
259
+ cancelButton: { text: i18next.t('button.cancel') }
260
+ })
261
+
262
+ if (!result.value) return
263
+
264
+ const response = await client.mutate({
265
+ mutation: gql`
266
+ mutation generateMultipleReleaseGoodWorksheet($releaseGoodNos: [String!]) {
267
+ generateMultipleReleaseGoodWorksheet(releaseGoodNos: $releaseGoodNos)
268
+ }
269
+ `,
270
+ variables: {
271
+ releaseGoodNos
272
+ }
273
+ })
274
+
275
+ if (!response.errors) {
276
+ this.dispatchEvent(new CustomEvent('generated'))
277
+ history.back()
278
+ }
279
+ } catch (e) {
280
+ this._showToast(e)
281
+ }
282
+ }
283
+
284
+ _compareValues(key, order = 'asc') {
285
+ return function innerSort(a, b) {
286
+ if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
287
+ return 0
288
+ }
289
+
290
+ const varA = typeof a[key] === 'string' ? a[key].toUpperCase() : a[key]
291
+ const varB = typeof b[key] === 'string' ? b[key].toUpperCase() : b[key]
292
+
293
+ let comparison = 0
294
+ if (varA > varB) {
295
+ comparison = 1
296
+ } else if (varA < varB) {
297
+ comparison = -1
298
+ }
299
+ return order === 'desc' ? comparison * -1 : comparison
300
+ }
301
+ }
302
+
303
+ _showToast({ type, message }) {
304
+ document.dispatchEvent(
305
+ new CustomEvent('notify', {
306
+ detail: {
307
+ type,
308
+ message
309
+ }
310
+ })
311
+ )
312
+ }
313
+ }
314
+ window.customElements.define('batch-generate-single-picking-worksheet-popup', BatchGenerateSinglePickingWorksheetPopup)
@@ -433,7 +433,8 @@ class PrintProductLabel extends connect(store)(localize(i18next)(PageView)) {
433
433
  auxValue1: product.auxValue1 || '',
434
434
  auxUnit2: product.auxUnit2 || '',
435
435
  auxValue2: product.auxValue2 || '',
436
- bizplaceId: arrivalNotice.bizplace.id
436
+ bizplaceId: arrivalNotice.bizplace.id,
437
+ bizplaceName: arrivalNotice.bizplace.name
437
438
  }
438
439
 
439
440
  if (product.productDetails && product.productDetails.length) {
@@ -551,6 +552,7 @@ class PrintProductLabel extends connect(store)(localize(i18next)(PageView)) {
551
552
  auxUnit2: product.auxUnit2 || '',
552
553
  auxValue2: product.auxValue2 || '',
553
554
  bizplaceId: releaseGood.bizplace.id,
555
+ bizplaceName: releaseGood.bizplace.name,
554
556
  printQty: oi.releaseQty || 0
555
557
  }
556
558
 
@@ -590,7 +592,8 @@ class PrintProductLabel extends connect(store)(localize(i18next)(PageView)) {
590
592
  auxValue1: product.auxValue1 || '',
591
593
  auxUnit2: product.auxUnit2 || '',
592
594
  auxValue2: product.auxValue2 || '',
593
- bizplaceId: releaseGood.bizplace.id
595
+ bizplaceId: releaseGood.bizplace.id,
596
+ bizplaceName: releaseGood.bizplace.name
594
597
  }
595
598
 
596
599
  if (product.productDetails && product.productDetails.length) {
@@ -626,7 +629,7 @@ class PrintProductLabel extends connect(store)(localize(i18next)(PageView)) {
626
629
  async _fetchInventories(fetcherDetail, filters) {
627
630
  const response = await client.query({
628
631
  query: gql`
629
- query inventories($filters: [Filter], $pagination: Pagination, $sortings: [Sorting]) {
632
+ query inventories($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
630
633
  inventories(filters: $filters, pagination: $pagination, sortings: $sortings) {
631
634
  items {
632
635
  palletId
@@ -650,6 +653,7 @@ class PrintProductLabel extends connect(store)(localize(i18next)(PageView)) {
650
653
  }
651
654
  bizplace {
652
655
  id
656
+ name
653
657
  }
654
658
  expirationDate
655
659
  }
@@ -685,7 +689,8 @@ class PrintProductLabel extends connect(store)(localize(i18next)(PageView)) {
685
689
  auxUnit2: product.auxUnit2 || '',
686
690
  auxValue2: product.auxValue2 || '',
687
691
  productInfo: product.description ? `${product.name} (${product.description})` : `${product.name}`,
688
- bizplaceId: inventory.bizplace.id
692
+ bizplaceId: inventory.bizplace.id,
693
+ bizplaceName: inventory.bizplace.name
689
694
  }
690
695
 
691
696
  if (product.productDetails && product.productDetails.length) {
@@ -757,6 +762,7 @@ class PrintProductLabel extends connect(store)(localize(i18next)(PageView)) {
757
762
  searchParams.append('aux_value_2', record.auxValue2)
758
763
  searchParams.append('expiration_date', record.expirationDate)
759
764
  searchParams.append('location', record.location)
765
+ searchParams.append('company_name', record.bizplaceName)
760
766
 
761
767
  let printCounter = 0
762
768
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/operato-wms",
3
- "version": "3.8.5",
3
+ "version": "3.8.9",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "client/index.js",
6
6
  "things-factory": true,
@@ -46,7 +46,7 @@
46
46
  "@things-factory/attachment-ui": "^3.8.0",
47
47
  "@things-factory/auth-ui": "^3.8.0",
48
48
  "@things-factory/barcode-ui": "^3.8.0",
49
- "@things-factory/biz-ui": "^3.8.0",
49
+ "@things-factory/biz-ui": "^3.8.8",
50
50
  "@things-factory/board-service": "^3.8.0",
51
51
  "@things-factory/board-ui": "^3.8.0",
52
52
  "@things-factory/code-ui": "^3.8.0",
@@ -69,9 +69,9 @@
69
69
  "@things-factory/print-proxy-service": "^3.8.0",
70
70
  "@things-factory/print-service": "^3.8.0",
71
71
  "@things-factory/print-ui": "^3.8.0",
72
- "@things-factory/product-base": "^3.8.3",
72
+ "@things-factory/product-base": "^3.8.9",
73
73
  "@things-factory/resource-ui": "^3.8.0",
74
- "@things-factory/sales-ui": "^3.8.5",
74
+ "@things-factory/sales-ui": "^3.8.9",
75
75
  "@things-factory/scene-chartjs": "^3.7.5",
76
76
  "@things-factory/scene-clock": "^3.7.5",
77
77
  "@things-factory/scene-clone": "^3.7.5",
@@ -102,11 +102,11 @@
102
102
  "@things-factory/system-ui": "^3.8.0",
103
103
  "@things-factory/transport-base": "^3.8.0",
104
104
  "@things-factory/tutorial-ui": "^3.8.0",
105
- "@things-factory/warehouse-base": "^3.8.5",
106
- "@things-factory/worksheet-base": "^3.8.5"
105
+ "@things-factory/warehouse-base": "^3.8.9",
106
+ "@things-factory/worksheet-base": "^3.8.9"
107
107
  },
108
108
  "devDependencies": {
109
109
  "@things-factory/builder": "^3.7.5"
110
110
  },
111
- "gitHead": "1f8f8ca9c0d96737732388c9cc685e64b0759a96"
111
+ "gitHead": "7a9270f0a733762814364529eb6c54f258a7417f"
112
112
  }
@@ -1,4 +1,5 @@
1
1
  {
2
+ "title.generate_picking_worksheet": "generate picking worksheet",
2
3
  "arrival_notice_created": "arrival notice created",
3
4
  "button.activate": "activate",
4
5
  "button.add_edit": "add & edit",
@@ -1066,6 +1067,7 @@
1066
1067
  "text.gan_pending_company_approval": "GAN pending company approval",
1067
1068
  "text.gan_will_be_sent_for_company_approval": "GAN will be sent for company approval",
1068
1069
  "text.generate_putaway_worksheet": "generate putaway worksheet",
1070
+ "text.generate_worksheet": "generate worksheet",
1069
1071
  "text.goods_delivery_note_uploaded": "goods delivery note uploaded",
1070
1072
  "text.goods_received_note_has_been_received": "GRN has been marked received",
1071
1073
  "text.goods_received_note_has_been_sent_successfully": "GRN has been sent successfully",
@@ -1148,6 +1150,7 @@
1148
1150
  "text.picking_worksheet_will_be_activated": "picking worksheet will be activated",
1149
1151
  "text.picking_worksheet_will_be_generated": "picking worksheet will be generated",
1150
1152
  "text.pickup_info_is_not_completed": "pickup info is not completed",
1153
+ "text.please_attach_the_file": "please attach the file",
1151
1154
  "text.please_check_your_setting": "please check your setting",
1152
1155
  "text.please_check_your_vas_target": "please check your vas target",
1153
1156
  "text.please_key_in_new_serial_number": "please key in new serial number",
@@ -1157,6 +1160,7 @@
1157
1160
  "text.please_select_a_truck": "select a truck",
1158
1161
  "text.please_select_label_indicator": "please select label indicator",
1159
1162
  "text.please_select_release_order": "please select release order",
1163
+ "text.please_select_the_company": "please select the company",
1160
1164
  "text.please_select_the_contact_type": "please select the contact type",
1161
1165
  "text.please_select_the_location_again": "please select the location again",
1162
1166
  "text.please_select_the_location": "please select the location",
@@ -1190,6 +1194,7 @@
1190
1194
  "text.related_arrival_notice_will_be_deleted": "related arrival notice will be deleted",
1191
1195
  "text.related_release_order_will_be_rejected": "related release order will be rejected",
1192
1196
  "text.release_date_is_empty": "release date is empty",
1197
+ "text.backdate_is_not_allowed": "backdate is not allowed",
1193
1198
  "text.release_date_is_required": "release date is required",
1194
1199
  "text.release_order_confirmed": "release order confirmed",
1195
1200
  "text.release_order_created": "release order created",
@@ -1202,8 +1207,8 @@
1202
1207
  "text.release_order_rejected": "release order rejected",
1203
1208
  "text.release_order_will_be_deleted": "release order will be deleted",
1204
1209
  "text.release_qty_cannot_exceed_stored_qty": "release qty cannot exceed stored qty",
1205
- "text.release_qty_is_empty": "release quantity is empty",
1206
1210
  "text.release_qty_invalid": "release quantity is invalid",
1211
+ "text.release_qty_is_empty": "release quantity is empty",
1207
1212
  "text.release_qty_is_more_than_expected": "release qty is more than expected",
1208
1213
  "text.remark_is_empty": "remark is empty",
1209
1214
  "text.remark_updated": "remark updated",
@@ -1315,6 +1320,7 @@
1315
1320
  "text.x_should_be_positive": "{state.x} should be positive value",
1316
1321
  "text.yes": "yes",
1317
1322
  "text.you_can_only_select_one_transport_type": "you can only select one transport type",
1323
+ "text.you_can_only_upload_one_file_max": "you can only upload one file max",
1318
1324
  "text.you_wont_be_able_to_revert_this": "you won't be able to revert this",
1319
1325
  "text.you.are.now.in": "you are now in {state.text}",
1320
1326
  "text.your_work_has_completed": "your work has completed",
@@ -1,4 +1,5 @@
1
1
  {
2
+ "title.generate_picking_worksheet": "[ko]generate picking worksheet",
2
3
  "arrival_notice_created": "입고주문이 생성 되었습니다.",
3
4
  "arrival_notice_updated": "[ko]arrival notice updated",
4
5
  "button.activate": "활성화",
@@ -1232,6 +1233,7 @@
1232
1233
  "text.picking_worksheet_will_be_activated": "피킹 작업지시서가 활성화 됩니다",
1233
1234
  "text.picking_worksheet_will_be_generated": "피킹 작업지시서가 생성 됩니다",
1234
1235
  "text.pickup_info_is_not_completed": "픽업 정보가 완료되지 않았습니다",
1236
+ "text.please_attach_the_file": "[ko]please attach the file",
1235
1237
  "text.please_check_your_setting": "설정을 확인해 주세요",
1236
1238
  "text.please_check_your_vas_target": "[ko] please check your vas target",
1237
1239
  "text.please_key_in_new_serial_number": "[ko]please key in new serial number",
@@ -1246,6 +1248,7 @@
1246
1248
  "text.please_select_an_arrival_notice": "select arrival notice",
1247
1249
  "text.please_select_label_indicator": "라벨 포시기 선택",
1248
1250
  "text.please_select_release_order": "[ko] please select release order",
1251
+ "text.please_select_the_company": "[ko]please select the company",
1249
1252
  "text.please_select_the_contact_type": "연락처 유형 선택",
1250
1253
  "text.please_select_the_label_format": "please select the label format",
1251
1254
  "text.please_select_the_location_again": "로케이션을 다시 선택해 주세요",
@@ -1287,6 +1290,7 @@
1287
1290
  "text.related_arrival_notice_will_be_deleted": "관련된 입고주문이 삭제 됩니다",
1288
1291
  "text.related_release_order_will_be_rejected": "관련된 출고주문이 삭제 됩니다",
1289
1292
  "text.release_date_is_empty": "[ko]release date is empty",
1293
+ "text.backdate_is_not_allowed": "[ko]backdate is not allowed",
1290
1294
  "text.release_date_is_required": "[ko]release date is required",
1291
1295
  "text.release_order_confirmed": "출고주문 확인",
1292
1296
  "text.release_order_created": "출고주문 생성",
@@ -1300,6 +1304,7 @@
1300
1304
  "text.release_order_submit_for_cancellation": "release order submit for cancellation",
1301
1305
  "text.release_order_will_be_deleted": "출고주문이 삭제 됩니다",
1302
1306
  "text.release_qty_cannot_exceed_stored_qty": "출고수량은 재고수량을 초과 할 수 없습니다",
1307
+ "text.release_qty_invalid": "[ko] release quantity is invalid",
1303
1308
  "text.release_qty_is_empty": "출고수량이 없습니다",
1304
1309
  "text.release_qty_is_more_than_expected": "출고수량이 예상보다 많습니다",
1305
1310
  "text.remark_is_empty": "비고가 없습니다",
@@ -1431,6 +1436,7 @@
1431
1436
  "text.x_should_be_positive": "{state.x}은(는) 반드시 양의 값이여야 합니다",
1432
1437
  "text.yes": "예",
1433
1438
  "text.you_can_only_select_one_transport_type": "운송유형은 하나만 선택 할 수 있습니다",
1439
+ "text.you_can_only_upload_one_file_max": "[ko]you can only upload one file max",
1434
1440
  "text.you_wont_be_able_to_revert_this": "되돌릴 수 없습니다",
1435
1441
  "text.you.are.now.in": "당신은 {state} 입니다",
1436
1442
  "text.your_work_has_completed": "작업이 완료 되었습니다",
@@ -1602,6 +1608,7 @@
1602
1608
  "title.loaded": "상차 완료",
1603
1609
  "title.loading": "상차 중",
1604
1610
  "title.location_label_format": "로케이션 라벨 형식",
1611
+ "title.location_scanned_is_not_quarantine_zone": "[ko] Location scanned is not a quarantine zone!",
1605
1612
  "title.location_sorting_rule": "로케이션 정렬 규칙",
1606
1613
  "title.location": "로케이션",
1607
1614
  "title.lot_information": "lot 정보",
@@ -1818,6 +1825,5 @@
1818
1825
  "title.worksheet_vas": "부가서비스 작업지시서",
1819
1826
  "title.worksheet": "작업지시서",
1820
1827
  "vas_order_created": "부가서비스주문 생성됨",
1821
- "title.location_scanned_is_not_quarantine_zone": "[ko] Location scanned is not a quarantine zone!",
1822
- "text.release_qty_invalid": "[ko] release quantity is invalid"
1828
+ "text.generate_worksheet": "[ko] generate worksheet"
1823
1829
  }
@@ -1,4 +1,5 @@
1
1
  {
2
+ "title.generate_picking_worksheet": "[ms]generate picking worksheet",
2
3
  "arrival_notice_created": "notis ketibaan telah dicipta",
3
4
  "arrival_notice_updated": "notis ketibaan telah dikemaskinikan",
4
5
  "button.activate": "aktifkan",
@@ -1179,6 +1180,7 @@
1179
1180
  "text.picking_worksheet_will_be_activated": "lembaran kerja pengambilan akan diaktifkan",
1180
1181
  "text.picking_worksheet_will_be_generated": "lembaran kerja pengambilan akan dijana",
1181
1182
  "text.pickup_info_is_not_completed": "maklumat pengambilan tidak lengkap",
1183
+ "text.please_attach_the_file": "[ms]please attach the file",
1182
1184
  "text.please_check_your_setting": "tolong semak tetapan anda",
1183
1185
  "text.please_check_your_vas_target": "sila semak sasaran vas anda",
1184
1186
  "text.please_key_in_new_serial_number": "[ms]please key in new serial number",
@@ -1188,6 +1190,7 @@
1188
1190
  "text.please_select_a_truck": "sila pilih trak",
1189
1191
  "text.please_select_label_indicator": "sila pilih petunjuk label",
1190
1192
  "text.please_select_release_order": "[ms] please select release order",
1193
+ "text.please_select_the_company": "[ms]please select the company",
1191
1194
  "text.please_select_the_contact_type": "sila pilih jenis kenalan",
1192
1195
  "text.please_select_the_location_again": "sila pilih lokasi sekali lagi",
1193
1196
  "text.please_select_the_location": "sila pilih lokasi",
@@ -1223,6 +1226,7 @@
1223
1226
  "text.related_arrival_notice_will_be_deleted": "notis ketibaan yang berkaitan akan dipadam",
1224
1227
  "text.related_release_order_will_be_rejected": "pelepasan pesanan yang berkaitan akan ditolak",
1225
1228
  "text.release_date_is_empty": "[ms]release date is empty",
1229
+ "text.backdate_is_not_allowed": "[ms]backdate is not allowed",
1226
1230
  "text.release_date_is_required": "[ms]release date is required",
1227
1231
  "text.release_order_confirmed": "stok pelepasan pesanan disahkan",
1228
1232
  "text.release_order_created": "pelepasan pesanan dicipta",
@@ -1235,6 +1239,7 @@
1235
1239
  "text.release_order_rejected": "stok pelepasan pesanan keluar ditolak",
1236
1240
  "text.release_order_will_be_deleted": "stok pelepasan pesanan akan dipadam",
1237
1241
  "text.release_qty_cannot_exceed_stored_qty": "kuantiti pelepasan melebihi kuantiti disimpan dalam gudang",
1242
+ "text.release_qty_invalid": "[ms] release quantity is invalid",
1238
1243
  "text.release_qty_is_empty": "stok pelepasan kuantiti tiada nilai",
1239
1244
  "text.release_qty_is_more_than_expected": "kuantiti pelepasan melebihi",
1240
1245
  "text.remark_is_empty": "disemak tidak diisi",
@@ -1344,6 +1349,7 @@
1344
1349
  "text.x_should_be_positive": "{state.x} should be positive value",
1345
1350
  "text.yes": "ya",
1346
1351
  "text.you_can_only_select_one_transport_type": "you can only select one transport type",
1352
+ "text.you_can_only_upload_one_file_max": "[ms]you can only upload one file max",
1347
1353
  "text.you_wont_be_able_to_revert_this": "anda tidak boleh kembali selepas langkah ini",
1348
1354
  "text.you.are.now.in": "anda berada di {state}",
1349
1355
  "text.your_work_has_completed": "kerja anda telah selesai",
@@ -1496,6 +1502,7 @@
1496
1502
  "title.loaded": "telah muat naik",
1497
1503
  "title.loading": "muat naik",
1498
1504
  "title.location_label_format": "format label lokasi",
1505
+ "title.location_scanned_is_not_quarantine_zone": "[ms] Location scanned is not a quarantine zone!",
1499
1506
  "title.location_sorting_rule": "peraturan susunan lokasi",
1500
1507
  "title.location": "lokasi",
1501
1508
  "title.lot_information": "informasi lot",
@@ -1688,6 +1695,5 @@
1688
1695
  "title.worksheet_vas": "VAS worksheet",
1689
1696
  "title.worksheet": "lembaran kerja",
1690
1697
  "vas_order_created": "pesanan value added service telah dicipta",
1691
- "title.location_scanned_is_not_quarantine_zone": "[ms] Location scanned is not a quarantine zone!",
1692
- "text.release_qty_invalid": "[ms] release quantity is invalid"
1698
+ "text.generate_worksheet": "[ms] generate worksheet"
1693
1699
  }
@@ -1,4 +1,5 @@
1
1
  {
2
+ "title.generate_picking_worksheet": "[zh]generate picking worksheet",
2
3
  "arrival_notice_created": "arrival notice created",
3
4
  "button.activate": "activate",
4
5
  "button.add_edit": "add & edit",
@@ -1147,6 +1148,7 @@
1147
1148
  "text.picking_worksheet_will_be_activated": "picking worksheet will be activated",
1148
1149
  "text.picking_worksheet_will_be_generated": "picking worksheet will be generated",
1149
1150
  "text.pickup_info_is_not_completed": "pickup info is not completed",
1151
+ "text.please_attach_the_file": "[zh]please attach the file",
1150
1152
  "text.please_check_your_setting": "please check your setting",
1151
1153
  "text.please_check_your_vas_target": "[zh] please check your vas target",
1152
1154
  "text.please_key_in_new_serial_number": "[zh]please key in new serial number",
@@ -1156,6 +1158,7 @@
1156
1158
  "text.please_select_a_truck": "select a truck",
1157
1159
  "text.please_select_label_indicator": "please select label indicator",
1158
1160
  "text.please_select_release_order": "[zh] please select release order",
1161
+ "text.please_select_the_company": "[zh]please select the company",
1159
1162
  "text.please_select_the_contact_type": "please select the contact type",
1160
1163
  "text.please_select_the_location_again": "please select the location again",
1161
1164
  "text.please_select_the_location": "please select the location",
@@ -1189,6 +1192,7 @@
1189
1192
  "text.related_arrival_notice_will_be_deleted": "related arrival notice will be deleted",
1190
1193
  "text.related_release_order_will_be_rejected": "related release order will be rejected",
1191
1194
  "text.release_date_is_empty": "[zh]release date is empty",
1195
+ "text.backdate_is_not_allowed": "[zh]backdate is not allowed",
1192
1196
  "text.release_date_is_required": "[zh]release date is required",
1193
1197
  "text.release_order_confirmed": "release order confirmed",
1194
1198
  "text.release_order_created": "release order created",
@@ -1201,6 +1205,7 @@
1201
1205
  "text.release_order_rejected": "release order rejected",
1202
1206
  "text.release_order_will_be_deleted": "release order will be deleted",
1203
1207
  "text.release_qty_cannot_exceed_stored_qty": "release qty cannot exceed stored qty",
1208
+ "text.release_qty_invalid": "[zh] release quantity is invalid",
1204
1209
  "text.release_qty_is_empty": "release quantity is empty",
1205
1210
  "text.release_qty_is_more_than_expected": "release qty is more than expected",
1206
1211
  "text.remark_is_empty": "remark is empty",
@@ -1310,6 +1315,7 @@
1310
1315
  "text.x_should_be_positive": "{state.x} should be positive value",
1311
1316
  "text.yes": "yes",
1312
1317
  "text.you_can_only_select_one_transport_type": "you can only select one transport type",
1318
+ "text.you_can_only_upload_one_file_max": "[zh]you can only upload one file max",
1313
1319
  "text.you_wont_be_able_to_revert_this": "you won't be able to revert this",
1314
1320
  "text.you.are.now.in": "you are now in {state.text}",
1315
1321
  "text.your_work_has_completed": "your work has completed",
@@ -1453,6 +1459,7 @@
1453
1459
  "title.loaded": "loaded",
1454
1460
  "title.loading": "loading",
1455
1461
  "title.location_label_format": "location label format",
1462
+ "title.location_scanned_is_not_quarantine_zone": "[zh] Location scanned is not a quarantine zone!",
1456
1463
  "title.location_sorting_rule": "location sorting rule",
1457
1464
  "title.location": "location",
1458
1465
  "title.lot_information": "lot information",
@@ -1638,6 +1645,5 @@
1638
1645
  "title.worksheet_vas": "worksheet vas",
1639
1646
  "title.worksheet": "worksheet",
1640
1647
  "vas_order_created": "vas order created",
1641
- "title.location_scanned_is_not_quarantine_zone": "[zh] Location scanned is not a quarantine zone!",
1642
- "text.release_qty_invalid": "[zh] release quantity is invalid"
1648
+ "text.generate_worksheet": "[zh] generate worksheet"
1643
1649
  }