@things-factory/operato-wms 3.7.15 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/client/pages/adjustment/transfer-inventory.js +364 -158
  2. package/client/pages/bulk-operation/bulk-operation.js +316 -0
  3. package/client/pages/bulk-operation/validate-ro-popup.js +445 -0
  4. package/client/pages/components/select-product-popup.js +1 -1
  5. package/client/pages/constants/inventory.js +1 -0
  6. package/client/pages/constants/location.js +33 -6
  7. package/client/pages/constants/worksheet.js +2 -2
  8. package/client/pages/inbound/inbound-worksheet.js +81 -15
  9. package/client/pages/inbound/putaway-product.js +60 -8
  10. package/client/pages/inbound/putaway-worksheet-generate-popup.js +29 -5
  11. package/client/pages/inbound/unload-product.js +80 -19
  12. package/client/pages/inbound/worksheet-putaway-return.js +14 -5
  13. package/client/pages/inbound/worksheet-putaway.js +13 -8
  14. package/client/pages/inbound/worksheet-unloading-return.js +14 -5
  15. package/client/pages/inventory/inventory-adjustment-approval.js +18 -8
  16. package/client/pages/inventory/inventory-adjustment.js +81 -76
  17. package/client/pages/inventory/inventory-by-product-detail.js +1 -1
  18. package/client/pages/inventory/inventory-by-product.js +1 -1
  19. package/client/pages/inventory/inventory-history-by-pallet.js +1 -1
  20. package/client/pages/inventory/inventory-history.js +2 -2
  21. package/client/pages/inventory/onhand-inventory.js +1 -2
  22. package/client/pages/inventory-check/create-cycle-count.js +1 -6
  23. package/client/pages/master/location-list.js +58 -17
  24. package/client/pages/order/arrival-notice/arrival-notice-detail.js +15 -8
  25. package/client/pages/order/arrival-notice/arrival-notice-list.js +87 -6
  26. package/client/pages/order/arrival-notice/arrival-notice-requests.js +83 -6
  27. package/client/pages/order/arrival-notice/create-arrival-notice.js +23 -2
  28. package/client/pages/order/arrival-notice/duplicate-arrival-notice.js +290 -25
  29. package/client/pages/order/arrival-notice/edit-product-popup.js +36 -5
  30. package/client/pages/order/release-order/b2b/b2b-order-requests.js +7 -7
  31. package/client/pages/order/release-order/b2c/b2c-order-requests.js +65 -5
  32. package/client/pages/order/release-order/release-extra-product-popup.js +12 -4
  33. package/client/pages/order/release-order/release-order-detail.js +1 -1
  34. package/client/pages/order/return-order/create-return-order.js +1 -1
  35. package/client/pages/order/return-order/return-order-detail.js +6 -5
  36. package/client/pages/order/transport-order/delivery-order-list.js +4 -1
  37. package/client/pages/outbound/inventory-assign-popup.js +1 -1
  38. package/client/pages/outbound/merged-outbound-worksheet.js +9 -5
  39. package/client/pages/outbound/picking-product.js +202 -162
  40. package/client/pages/outbound/picking-replacement-popup.js +2 -2
  41. package/client/pages/outbound/single-outbound-worksheet.js +47 -1
  42. package/client/pages/outbound/worksheet-loading.js +14 -5
  43. package/client/pages/outbound/worksheet-picking.js +10 -5
  44. package/client/pages/report/custom-elccl/elccl-inventory-report.js +31 -30
  45. package/client/pages/report/custom-elccl/elccl-inventory-summary-report.js +23 -26
  46. package/client/pages/report/inventory-pallet-storage-report.js +11 -10
  47. package/client/pages/report/inventory-report.js +41 -43
  48. package/client/pages/report/inventory-summary-report.js +25 -28
  49. package/client/route.js +5 -0
  50. package/dist-server/graphql/resolvers/custom/elccl/elccl-inventory-history-report.js +1 -1
  51. package/dist-server/graphql/resolvers/custom/elccl/elccl-inventory-history-report.js.map +1 -1
  52. package/dist-server/graphql/resolvers/custom/elccl/elccl-inventory-history-summary-report.js +1 -1
  53. package/dist-server/graphql/resolvers/index.js +3 -1
  54. package/dist-server/graphql/resolvers/index.js.map +1 -1
  55. package/dist-server/graphql/resolvers/shipping-provider/index.js +6 -0
  56. package/dist-server/graphql/resolvers/shipping-provider/index.js.map +1 -0
  57. package/dist-server/graphql/resolvers/shipping-provider/shipping-providers.js +20 -0
  58. package/dist-server/graphql/resolvers/shipping-provider/shipping-providers.js.map +1 -0
  59. package/dist-server/graphql/types/custom/elccl/elccl-inventory-report.js +1 -1
  60. package/dist-server/graphql/types/index.js +5 -2
  61. package/dist-server/graphql/types/index.js.map +1 -1
  62. package/dist-server/graphql/types/shipping-provider/index.js +10 -0
  63. package/dist-server/graphql/types/shipping-provider/index.js.map +1 -0
  64. package/dist-server/graphql/types/shipping-provider/shipping-provider-list.js +13 -0
  65. package/dist-server/graphql/types/shipping-provider/shipping-provider-list.js.map +1 -0
  66. package/dist-server/graphql/types/shipping-provider/shipping-provider.js +13 -0
  67. package/dist-server/graphql/types/shipping-provider/shipping-provider.js.map +1 -0
  68. package/package.json +37 -37
  69. package/server/graphql/resolvers/custom/elccl/elccl-inventory-history-report.ts +4 -2
  70. package/server/graphql/resolvers/custom/elccl/elccl-inventory-history-summary-report.ts +1 -1
  71. package/server/graphql/resolvers/index.ts +3 -1
  72. package/server/graphql/resolvers/shipping-provider/index.ts +5 -0
  73. package/server/graphql/resolvers/shipping-provider/shipping-providers.ts +20 -0
  74. package/server/graphql/types/custom/elccl/elccl-inventory-report.ts +1 -1
  75. package/server/graphql/types/index.ts +5 -2
  76. package/server/graphql/types/shipping-provider/index.ts +8 -0
  77. package/server/graphql/types/shipping-provider/shipping-provider-list.ts +7 -0
  78. package/server/graphql/types/shipping-provider/shipping-provider.ts +7 -0
  79. package/things-factory.config.js +6 -0
  80. package/translations/en.json +27 -0
  81. package/translations/ko.json +84 -36
  82. package/translations/ms.json +85 -37
  83. package/translations/zh.json +98 -51
@@ -0,0 +1,445 @@
1
+ import '@material/mwc-button/mwc-button'
2
+ import '@things-factory/grist-ui'
3
+
4
+ import gql from 'graphql-tag'
5
+ import { css, html, LitElement } from 'lit-element'
6
+
7
+ import { i18next, localize } from '@things-factory/i18n-base'
8
+ import { client, CustomAlert } from '@things-factory/shell'
9
+ import { ScrollbarStyles } from '@things-factory/styles'
10
+ import { isMobileDevice, sleep } from '@things-factory/utils'
11
+
12
+ class ValidateRoPopup extends localize(i18next)(LitElement) {
13
+ static get properties() {
14
+ return {
15
+ _oiConfig: Object,
16
+ _roConfig: Object,
17
+ _selectedRoIndex: Number,
18
+ _selectedRoRecord: Object,
19
+ bizplaceId: String,
20
+ importHandler: Object,
21
+ oiConfig: Object,
22
+ records: Array,
23
+ roConfig: Object
24
+ }
25
+ }
26
+
27
+ static get styles() {
28
+ return [
29
+ ScrollbarStyles,
30
+ css`
31
+ :host {
32
+ display: flex;
33
+ flex-direction: column;
34
+ overflow: hidden;
35
+ background-color: white;
36
+
37
+ --grid-record-emphasized-background-color: #ffdbdb;
38
+ --grid-record-emphasized-color: #703f3f;
39
+ }
40
+
41
+ .grist {
42
+ display: flex;
43
+ flex-direction: column;
44
+ flex: 1;
45
+ overflow-y: auto;
46
+ }
47
+ data-grist {
48
+ overflow-y: hidden;
49
+ flex: 1;
50
+ }
51
+ h2 {
52
+ padding: var(--subtitle-padding);
53
+ font: var(--subtitle-font);
54
+ color: var(--subtitle-text-color);
55
+ border-bottom: var(--subtitle-border-bottom);
56
+ }
57
+ .button-container {
58
+ display: flex;
59
+ margin-left: auto;
60
+ }
61
+ .button-container > mwc-button {
62
+ padding: 10px;
63
+ }
64
+ `
65
+ ]
66
+ }
67
+
68
+ get dataGrist() {
69
+ return this.shadowRoot.querySelector('data-grist')
70
+ }
71
+
72
+ get _config() {
73
+ return {
74
+ list: {},
75
+ pagination: { infinite: true },
76
+ rows: {
77
+ appendable: false,
78
+ classifier: (record, rowIndex) => {
79
+ return {
80
+ // if the condition not met, the grist row will be red
81
+ emphasized:
82
+ record.assignedQty <= 0 ||
83
+ !record.refNo ||
84
+ record?.refNo == '' ||
85
+ !record.releaseDate ||
86
+ record?.releaseDate == ''
87
+ }
88
+ }
89
+ },
90
+ columns: [
91
+ { type: 'gutter', gutterName: 'sequence' },
92
+ {
93
+ type: 'gutter',
94
+ gutterName: 'button',
95
+ icon: 'close',
96
+ handlers: {
97
+ click: (columns, data, column, record, rowIndex) => {
98
+ this.records = [...data.records.filter((_, idx) => idx !== rowIndex)]
99
+ }
100
+ }
101
+ },
102
+ {
103
+ type: 'string',
104
+ name: 'refNo',
105
+ header: i18next.t('field.ref_no'),
106
+ width: 150
107
+ },
108
+ {
109
+ type: 'string',
110
+ name: 'refNo2',
111
+ header: i18next.t('field.ref_no_2'),
112
+ width: 150
113
+ },
114
+ {
115
+ type: 'string',
116
+ name: 'refNo3',
117
+ header: i18next.t('field.ref_no_3'),
118
+ width: 150
119
+ },
120
+ {
121
+ type: 'string',
122
+ name: 'releaseDate',
123
+ header: i18next.t('field.release_date'),
124
+ width: 150
125
+ },
126
+ {
127
+ type: 'string',
128
+ name: 'attentionTo',
129
+ header: i18next.t('field.attention_to'),
130
+ width: 150
131
+ },
132
+ {
133
+ type: 'string',
134
+ name: 'phone1',
135
+ header: i18next.t('field.phone'),
136
+ width: 150
137
+ },
138
+ {
139
+ type: 'string',
140
+ name: 'deliveryAddress1',
141
+ header: i18next.t('field.delivery_address_1'),
142
+ width: 150
143
+ },
144
+ {
145
+ type: 'string',
146
+ name: 'deliveryAddress2',
147
+ header: i18next.t('field.delivery_address_2'),
148
+ width: 150
149
+ },
150
+ {
151
+ type: 'string',
152
+ name: 'deliveryAddress3',
153
+ header: i18next.t('field.delivery_address_3'),
154
+ width: 150
155
+ },
156
+ {
157
+ type: 'string',
158
+ name: 'deliveryAddress4',
159
+ header: i18next.t('field.delivery_address_4'),
160
+ width: 150
161
+ },
162
+ {
163
+ type: 'string',
164
+ name: 'city',
165
+ header: i18next.t('field.city'),
166
+ width: 150
167
+ },
168
+ {
169
+ type: 'string',
170
+ name: 'postalCode',
171
+ header: i18next.t('field.postal_code'),
172
+ width: 150
173
+ },
174
+ {
175
+ type: 'string',
176
+ name: 'state',
177
+ header: i18next.t('field.state'),
178
+ width: 150
179
+ },
180
+ {
181
+ type: 'string',
182
+ name: 'country',
183
+ header: i18next.t('field.country'),
184
+ width: 150
185
+ },
186
+ ,
187
+ {
188
+ type: 'string',
189
+ name: 'sku',
190
+ header: i18next.t('field.sku'),
191
+ width: 150
192
+ },
193
+ {
194
+ type: 'string',
195
+ name: 'name',
196
+ header: i18next.t('field.name'),
197
+ width: 400
198
+ },
199
+ {
200
+ type: 'string',
201
+ name: 'batchId',
202
+ header: i18next.t('field.batch_no'),
203
+ width: 150
204
+ },
205
+ {
206
+ type: 'integer',
207
+ name: 'releaseQty',
208
+ header: i18next.t('field.release_qty'),
209
+ width: 150
210
+ },
211
+ {
212
+ type: 'integer',
213
+ name: 'assignedQty',
214
+ header: i18next.t('field.assigned_qty'),
215
+ width: 150
216
+ },
217
+ {
218
+ type: 'float',
219
+ name: 'assignedUomValue',
220
+ header: i18next.t('field.assigned_uom_value'),
221
+ width: 150
222
+ },
223
+ {
224
+ type: 'string',
225
+ name: 'uom',
226
+ header: i18next.t('field.uom'),
227
+ width: 100
228
+ },
229
+ {
230
+ type: 'string',
231
+ name: 'remark',
232
+ header: i18next.t('field.remark'),
233
+ width: 350
234
+ }
235
+ ]
236
+ }
237
+ }
238
+
239
+ render() {
240
+ return html`
241
+ <div class="grist">
242
+ <data-grist .mode=${isMobileDevice() ? 'LIST' : 'GRID'} .config=${this._roConfig}></data-grist>
243
+ </div>
244
+
245
+ <div class="button-container">
246
+ <mwc-button
247
+ @click=${async () => {
248
+ const answer = await CustomAlert({
249
+ title: i18next.t('label.create_release_orders'),
250
+ text: i18next.t('text.are_you_sure'),
251
+ confirmButton: { text: i18next.t('button.confirm') },
252
+ cancelButton: { text: i18next.t('button.cancel') }
253
+ })
254
+
255
+ if (!answer.value) return
256
+ await this._generateReleaseOrders()
257
+ }}
258
+ >${i18next.t('button.create_ro')}</mwc-button
259
+ >
260
+ <mwc-button @click=${e => history.back()}>${i18next.t('button.cancel')}</mwc-button>
261
+ </div>
262
+ `
263
+ }
264
+
265
+ async firstUpdated() {
266
+ this._roConfig = this._config
267
+ await this._getAvailableItems(this.records)
268
+ }
269
+
270
+ updated(changedProps) {
271
+ if (changedProps.has('records')) {
272
+ this.dataGrist.data = {
273
+ records: this.records,
274
+ total: this.records.length
275
+ }
276
+ }
277
+ }
278
+
279
+ async _getAvailableItems(rawData) {
280
+ const response = await client.query({
281
+ query: gql`
282
+ query bulkReleaseGoodsAvailableItems($rawReleaseGoods: [NewRawReleaseGood], $bizplaceId: String) {
283
+ bulkReleaseGoodsAvailableItems(rawReleaseGoods: $rawReleaseGoods, bizplaceId: $bizplaceId) {
284
+ refNo
285
+ refNo2
286
+ refNo3
287
+ releaseDate
288
+ deliveryAddress1
289
+ deliveryAddress2
290
+ deliveryAddress3
291
+ deliveryAddress4
292
+ attentionTo
293
+ city
294
+ state
295
+ country
296
+ sku
297
+ productId
298
+ batchId
299
+ packingType
300
+ packingSize
301
+ uom
302
+ releaseQty
303
+ assignedQty
304
+ assignedUomValue
305
+ postalCode
306
+ phone1
307
+ }
308
+ }
309
+ `,
310
+ variables: {
311
+ rawReleaseGoods: rawData.map(raw => {
312
+ return {
313
+ refNo: raw.refNo,
314
+ refNo2: raw.refNo2,
315
+ refNo3: raw.refNo3,
316
+ releaseDate: String(raw.releaseDate),
317
+ deliveryAddress1: raw.deliveryAddress1,
318
+ deliveryAddress2: raw.deliveryAddress2,
319
+ deliveryAddress3: raw.deliveryAddress3,
320
+ deliveryAddress4: raw.deliveryAddress4,
321
+ attentionTo: raw.attentionTo,
322
+ city: raw.city,
323
+ state: raw.state,
324
+ country: raw.country,
325
+ sku: raw.sku,
326
+ productId: raw.productId,
327
+ packingType: raw.packingType,
328
+ packingSize: raw.packingSize,
329
+ uom: raw.uom,
330
+ releaseQty: raw.releaseQty,
331
+ postalCode: String(raw.postalCode),
332
+ phone1: String(raw.phone1)
333
+ }
334
+ }),
335
+ bizplaceId: this.bizplaceId
336
+ }
337
+ })
338
+
339
+ if (!response.errors) {
340
+ this.records = response.data.bulkReleaseGoodsAvailableItems.map(item => {
341
+ return {
342
+ ...item,
343
+ remark: !item.productId
344
+ ? i18next.t('text.product_not_found')
345
+ : item.releaseQty <= 0
346
+ ? i18next.t('text.invalid_release_qty')
347
+ : item.assignedQty == 0
348
+ ? i18next.t('text.insufficient_stock')
349
+ : !item.releaseDate
350
+ ? i18next.t('text.release_date_is_empty')
351
+ : !item.refNo
352
+ ? i18next.t('text.ref_no_is_empty')
353
+ : ''
354
+ }
355
+ })
356
+ }
357
+ }
358
+
359
+ async _generateReleaseOrders() {
360
+ this.dataGrist.showSpinner()
361
+
362
+ try {
363
+ this._validateReleaseOrders()
364
+
365
+ const response = await client.mutate({
366
+ mutation: gql`
367
+ mutation bulkAddReleaseGoods($rawReleaseGoods: [NewRawReleaseGood], $bizplaceId: String) {
368
+ bulkAddReleaseGoods(rawReleaseGoods: $rawReleaseGoods, bizplaceId: $bizplaceId) {
369
+ items {
370
+ name
371
+ }
372
+ }
373
+ }
374
+ `,
375
+ variables: {
376
+ rawReleaseGoods: this.records.map(x => {
377
+ return {
378
+ refNo: x.refNo,
379
+ refNo2: x.refNo2,
380
+ refNo3: x.refNo3,
381
+ releaseDate: String(x.releaseDate),
382
+ deliveryAddress1: x.deliveryAddress1,
383
+ deliveryAddress2: x.deliveryAddress2,
384
+ deliveryAddress3: x.deliveryAddress3,
385
+ deliveryAddress4: x.deliveryAddress4,
386
+ attentionTo: x.attentionTo,
387
+ city: x.city,
388
+ state: x.state,
389
+ country: x.country,
390
+ sku: x.sku,
391
+ productId: x.productId,
392
+ packingType: x.packingType,
393
+ packingSize: x.packingSize,
394
+ uom: x.uom,
395
+ releaseQty: x.releaseQty,
396
+ postalCode: String(x.postalCode),
397
+ phone1: String(x.phone1)
398
+ }
399
+ }),
400
+ bizplaceId: this.bizplaceId
401
+ }
402
+ })
403
+
404
+ this.dataGrist.hideSpinner()
405
+ await sleep(1)
406
+
407
+ if (!response.errors) {
408
+ this._showToast({ message: i18next.t('text.release_order_created') })
409
+ history.back()
410
+ }
411
+ } 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)
419
+ }
420
+ }
421
+
422
+ _validateReleaseOrders() {
423
+ if (this.records.some(record => !record.refNo || record?.refNo == ''))
424
+ throw new Error(i18next.t('text.ref_no_is_required'))
425
+
426
+ if (this.records.some(record => !record.releaseDate || record?.releaseDate == ''))
427
+ throw new Error(i18next.t('text.release_date_is_required'))
428
+
429
+ if (this.records.some(record => !record.releaseQty || record.releaseQty > record.assignedQty))
430
+ throw new Error(i18next.t('text.invalid_release_qty'))
431
+ }
432
+
433
+ _showToast({ type, message }) {
434
+ document.dispatchEvent(
435
+ new CustomEvent('notify', {
436
+ detail: {
437
+ type,
438
+ message
439
+ }
440
+ })
441
+ )
442
+ }
443
+ }
444
+
445
+ window.customElements.define('validate-ro-popup', ValidateRoPopup)
@@ -190,7 +190,7 @@ class SelectProductPopup extends localize(i18next)(LitElement) {
190
190
 
191
191
  const response = await client.query({
192
192
  query: gql`
193
- query productDetails($filters: [Filter], $pagination: Pagination, $sortings: [Sorting]) {
193
+ query productDetails($filters: [Filter!]!, $pagination: Pagination, $sortings: [Sorting!]!) {
194
194
  productDetails(filters: $filters, pagination: $pagination, sortings: $sortings) {
195
195
  items {
196
196
  id
@@ -43,3 +43,4 @@ export const INVENTORY_STATUS = {
43
43
 
44
44
  export const PALLET = { name: 'pallet', value: 'PALLET' }
45
45
  export const CARTON = { name: 'carton', value: 'CARTON' }
46
+ export const LOT = { name: 'lot', value: 'LOT' }
@@ -1,14 +1,41 @@
1
+ export const LOCATION_STATUS = {
2
+ EMPTY: {
3
+ name: 'EMPTY',
4
+ value: 'EMPTY'
5
+ },
6
+ OCCUPIED: {
7
+ name: 'OCCUPIED',
8
+ value: 'OCCUPIED'
9
+ },
10
+ FULL: {
11
+ name: 'FULL',
12
+ value: 'FULL'
13
+ }
14
+ }
15
+
1
16
  export const LOCATION_TYPE = {
17
+ BIN: {
18
+ name: 'BIN',
19
+ value: 'BIN'
20
+ },
2
21
  BUFFER: {
3
- name: 'buffer_location',
22
+ name: 'BUFFER',
4
23
  value: 'BUFFER'
5
24
  },
6
- SHELF: {
7
- name: 'shelf_location',
8
- value: 'SHELF'
9
- },
10
25
  FLOOR: {
11
- name: 'floor_location',
26
+ name: 'FLOOR',
12
27
  value: 'FLOOR'
28
+ },
29
+ QUARANTINE: {
30
+ name: 'QUARANTINE',
31
+ value: 'QUARANTINE'
32
+ },
33
+ RESERVE: {
34
+ name: 'RESERVE',
35
+ value: 'RESERVE'
36
+ },
37
+ SHELF: {
38
+ name: 'SHELF',
39
+ value: 'SHELF'
13
40
  }
14
41
  }
@@ -77,11 +77,11 @@ export const WORKSHEET_STATUS = {
77
77
  value: 'ADJUSTED'
78
78
  },
79
79
  PENDING_APPROVAL: {
80
- name: 'pending_approval',
80
+ name: i18next.t('label.pending_approval'),
81
81
  value: 'PENDING_APPROVAL'
82
82
  },
83
83
  PENDING_ADJUSTMENT: {
84
- name: 'pending_adjustment',
84
+ name: i18next.t('label.pending_adjustment'),
85
85
  value: 'PENDING_ADJUSTMENT'
86
86
  },
87
87
  PARTIALLY_UNLOADED: {