@things-factory/operato-wms 3.8.4 → 3.8.8

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.
@@ -803,14 +803,18 @@ class PutawayProduct extends connect(store)(localize(i18next)(PageView)) {
803
803
  if (this._enableCartonLabel) {
804
804
  let worksheetDetail = this._getSelectedOrderProducts(this.cartonInput.value)
805
805
  worksheetDetailNames.push(worksheetDetail[0].name)
806
- if (worksheetDetail[0].expirationPeriod > 0 && locationDetails.type !== 'QUARANTINE') {
807
- await this._expiryAlert()
808
- }
806
+ await this._checkExpiry(
807
+ worksheetDetail[0].expirationPeriod,
808
+ new Date(worksheetDetail[0].expirationDate),
809
+ locationDetails.type
810
+ )
809
811
  } else {
810
812
  worksheetDetailNames.push(this._selectedOrderProduct.name)
811
- if (this._selectedOrderProduct.expirationPeriod > 0 && locationDetails.type !== 'QUARANTINE') {
812
- await this._expiryAlert()
813
- }
813
+ await this._checkExpiry(
814
+ this._selectedOrderProduct.expirationPeriod,
815
+ new Date(this._selectedOrderProduct.expirationDate),
816
+ locationDetails.type
817
+ )
814
818
  }
815
819
 
816
820
  const response = await client.mutate({
@@ -874,16 +878,20 @@ class PutawayProduct extends connect(store)(localize(i18next)(PageView)) {
874
878
  const locationDetails = await this._fetchLocation(this.locationInput.value.trim())
875
879
 
876
880
  if (this._enableCartonLabel) {
877
- worksheetDetailNames.push(worksheetDetail[0].name)
878
881
  let worksheetDetail = this._getSelectedOrderProducts(this.cartonInput.value)
879
- if (worksheetDetail[0].expirationPeriod > 0 && locationDetails.type !== 'QUARANTINE') {
880
- await this._expiryAlert()
881
- }
882
+ worksheetDetailNames.push(worksheetDetail[0].name)
883
+ await this._checkExpiry(
884
+ worksheetDetail[0].expirationPeriod,
885
+ new Date(worksheetDetail[0].expirationDate),
886
+ locationDetails.type
887
+ )
882
888
  } else {
883
889
  worksheetDetailNames.push(this._selectedOrderProduct.name)
884
- if (this._selectedOrderProduct.expirationPeriod > 0 && locationDetails.type !== 'QUARANTINE') {
885
- await this._expiryAlert()
886
- }
890
+ await this._checkExpiry(
891
+ this._selectedOrderProduct.expirationPeriod,
892
+ new Date(this._selectedOrderProduct.expirationDate),
893
+ locationDetails.type
894
+ )
887
895
  }
888
896
 
889
897
  const response = await client.mutate({
@@ -945,8 +953,10 @@ class PutawayProduct extends connect(store)(localize(i18next)(PageView)) {
945
953
  await this._validatePutaway()
946
954
  if (!this.incompleteLocationName) {
947
955
  let worksheetDetailNames = []
948
- if (this._enableCartonLabel) worksheetDetailNames = this._getSelectedOrderProducts(this.cartonInput.value)
949
- else worksheetDetailNames.push(this._selectedOrderProduct.name)
956
+ if (this._enableCartonLabel) {
957
+ const selectedWorksheetDetailName = this._getSelectedOrderProducts(this.cartonInput.value)
958
+ worksheetDetailNames.push(selectedWorksheetDetailName[0].name)
959
+ } else worksheetDetailNames.push(this._selectedOrderProduct.name)
950
960
 
951
961
  const response = await client.mutate({
952
962
  mutation: gql`
@@ -1096,6 +1106,15 @@ class PutawayProduct extends connect(store)(localize(i18next)(PageView)) {
1096
1106
  }
1097
1107
  }
1098
1108
 
1109
+ async _checkExpiry(expirationPeriod, expiryDate, locationType) {
1110
+ let date = new Date()
1111
+ let acceptBefore = new Date(date.setDate(date.getDate() + expirationPeriod))
1112
+
1113
+ if (expirationPeriod > 0) {
1114
+ if (expiryDate < acceptBefore && locationType !== 'QUARANTINE') await this._expiryAlert()
1115
+ }
1116
+ }
1117
+
1099
1118
  _validateTransfer() {
1100
1119
  // 1. validate for order selection
1101
1120
  if (!this._selectedOrderProduct) throw new Error(i18next.t('text.target_is_not_selected'))
@@ -328,7 +328,7 @@ class UnloadProduct extends connect(store)(localize(i18next)(PageView)) {
328
328
  <input name="batchIdRef" readonly />
329
329
 
330
330
  <label>${i18next.t('label.packing_type')}</label>
331
- <input name="packingTypeSize" readonly />
331
+ <input name="packingType" readonly />
332
332
 
333
333
  <label>${i18next.t('label.total_pallet_qty')}</label>
334
334
  <input name="palletQty" type="number" readonly />
@@ -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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/operato-wms",
3
- "version": "3.8.4",
3
+ "version": "3.8.8",
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",
@@ -71,7 +71,7 @@
71
71
  "@things-factory/print-ui": "^3.8.0",
72
72
  "@things-factory/product-base": "^3.8.3",
73
73
  "@things-factory/resource-ui": "^3.8.0",
74
- "@things-factory/sales-ui": "^3.8.3",
74
+ "@things-factory/sales-ui": "^3.8.8",
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.3",
106
- "@things-factory/worksheet-base": "^3.8.4"
105
+ "@things-factory/warehouse-base": "^3.8.8",
106
+ "@things-factory/worksheet-base": "^3.8.8"
107
107
  },
108
108
  "devDependencies": {
109
109
  "@things-factory/builder": "^3.7.5"
110
110
  },
111
- "gitHead": "9dedf75962d3a804204ae3341588ee91533c63dd"
111
+ "gitHead": "3f0cf4cd9eba27f4b4a7688c462cc3183dd9df00"
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",
@@ -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": "활성화",
@@ -1819,5 +1820,6 @@
1819
1820
  "title.worksheet": "작업지시서",
1820
1821
  "vas_order_created": "부가서비스주문 생성됨",
1821
1822
  "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"
1823
+ "text.release_qty_invalid": "[ko] release quantity is invalid",
1824
+ "text.generate_worksheet": "[ko] generate worksheet"
1823
1825
  }
@@ -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",
@@ -1689,5 +1690,6 @@
1689
1690
  "title.worksheet": "lembaran kerja",
1690
1691
  "vas_order_created": "pesanan value added service telah dicipta",
1691
1692
  "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"
1693
+ "text.release_qty_invalid": "[ms] release quantity is invalid",
1694
+ "text.generate_worksheet": "[ms] generate worksheet"
1693
1695
  }
@@ -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",
@@ -1639,5 +1640,6 @@
1639
1640
  "title.worksheet": "worksheet",
1640
1641
  "vas_order_created": "vas order created",
1641
1642
  "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"
1643
+ "text.release_qty_invalid": "[zh] release quantity is invalid",
1644
+ "text.generate_worksheet": "[zh] generate worksheet"
1643
1645
  }