@things-factory/operato-wms 3.7.6 → 3.7.7

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 (27) hide show
  1. package/client/pages/components/select-product-popup.js +5 -1
  2. package/client/pages/constants/order.js +10 -0
  3. package/client/pages/inventory-check/inspecting-product.js +9 -8
  4. package/client/pages/manifest/create-loading-manifest.js +314 -0
  5. package/client/pages/manifest/dispatcher-verification-popup.js +86 -0
  6. package/client/pages/manifest/loading-manifest-detail.js +345 -0
  7. package/client/pages/manifest/loading-manifest-list.js +305 -0
  8. package/client/pages/order/goods-received-note/received-note-list.js +138 -6
  9. package/client/pages/order/release-order/b2b/b2b-order-list.js +1 -1
  10. package/client/pages/order/release-order/b2b/b2b-order-requests.js +1 -1
  11. package/client/pages/order/release-order/b2c/b2c-order-requests.js +111 -14
  12. package/client/pages/order/reverse-kitting-order/reverse-kitting-order-detail.js +115 -50
  13. package/client/pages/order/reverse-kitting-order/reverse-kitting-order-list.js +1 -6
  14. package/client/pages/order/reverse-kitting-order/reverse-kitting-pallet-label-popup.js +239 -0
  15. package/client/pages/order/transport-order/delivery-order-list.js +47 -3
  16. package/client/pages/outbound/picking-product.js +200 -66
  17. package/client/pages/outbound/serial-number-popup.js +280 -0
  18. package/client/pages/vas/reverse-kitting/execute-reverse-kitting.js +30 -12
  19. package/client/pages/vas/reverse-kitting/popup-combination-sets.js +75 -5
  20. package/client/pages/vas/reverse-kitting/popup-reverse-kitting-template.js +113 -18
  21. package/client/route.js +12 -0
  22. package/package.json +10 -10
  23. package/things-factory.config.js +12 -0
  24. package/translations/en.json +42 -6
  25. package/translations/ko.json +35 -1
  26. package/translations/ms.json +36 -1
  27. package/translations/zh.json +35 -1
@@ -0,0 +1,280 @@
1
+ import '@things-factory/barcode-ui'
2
+ import '@things-factory/grist-ui'
3
+
4
+ import gql from 'graphql-tag'
5
+ import { css, html, LitElement } from 'lit-element'
6
+
7
+ import { MultiColumnFormStyles, SingleColumnFormStyles } from '@things-factory/form-ui'
8
+ import { i18next, localize } from '@things-factory/i18n-base'
9
+ import { client } from '@things-factory/shell'
10
+ import { isMobileDevice } from '@things-factory/utils'
11
+
12
+ class SerialNumberPopup extends localize(i18next)(LitElement) {
13
+ static get styles() {
14
+ return [
15
+ MultiColumnFormStyles,
16
+ SingleColumnFormStyles,
17
+ css`
18
+ :host {
19
+ padding: 10px;
20
+ display: flex;
21
+ flex-direction: column;
22
+ overflow-x: overlay;
23
+ background-color: var(--main-section-background-color);
24
+ }
25
+ .grist {
26
+ background-color: var(--main-section-background-color);
27
+ display: flex;
28
+ flex-direction: column;
29
+ flex: 1;
30
+ overflow-y: auto;
31
+ }
32
+ data-grist {
33
+ overflow-y: hidden;
34
+ flex: 1;
35
+ }
36
+ .button-container {
37
+ padding: 10px 0 12px 0;
38
+ text-align: center;
39
+ display: flex;
40
+ flex-direction: column;
41
+ }
42
+
43
+ @media (max-width: 460px) {
44
+ .single-column-form {
45
+ max-width: 100%;
46
+ }
47
+ .mobile-full-width {
48
+ grid-column: span 12 / auto;
49
+ }
50
+ }
51
+ `
52
+ ]
53
+ }
54
+
55
+ static get properties() {
56
+ return {
57
+ orderInventory: Object,
58
+ config: Object,
59
+ data: Object,
60
+ _currentSerialNumber: String
61
+ }
62
+ }
63
+
64
+ get selectedSerialInput() {
65
+ return this.shadowRoot.querySelector('input[name=selectedSerialNumber]')
66
+ }
67
+
68
+ get serialInput() {
69
+ return this.shadowRoot.querySelector('barcode-scanable-input[name=serialNumber]').shadowRoot.querySelector('input')
70
+ }
71
+
72
+ get dataGrist() {
73
+ return this.shadowRoot.querySelector('data-grist')
74
+ }
75
+
76
+ constructor() {
77
+ super()
78
+ this.clearView()
79
+ }
80
+
81
+ render() {
82
+ return html`
83
+ <form class="multi-column-form">
84
+ <fieldset>
85
+ <legend>${i18next.t('title.serial_number_list')}</legend>
86
+ </fieldset>
87
+ </form>
88
+
89
+ <div class="grist">
90
+ <data-grist
91
+ .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
92
+ .config=${this.config}
93
+ .data="${this.data}"
94
+ ></data-grist>
95
+ </div>
96
+
97
+ <form id="input-form" class="single-column-form">
98
+ <input
99
+ name="selectedSerialNumber"
100
+ placeholder="-- Selected Serial Number --"
101
+ disabled
102
+ readonly
103
+ class="mobile-full-width"
104
+ value="${this._currentSerialNumber}"
105
+ />
106
+ <barcode-scanable-input name="serialNumber" class="mobile-full-width" custom-input></barcode-scanable-input>
107
+
108
+ <mwc-button
109
+ name="setSerialNumber"
110
+ class="mobile-full-width"
111
+ raised
112
+ @click=${this.updateSerialNumber.bind(this)}
113
+ label="${i18next.t('button.update')}"
114
+ ></mwc-button>
115
+ </form>
116
+
117
+ <div class="button-container">
118
+ <mwc-button
119
+ danger
120
+ @click=${() => {
121
+ history.back()
122
+ }}
123
+ raised
124
+ label="${i18next.t('button.back')}"
125
+ ></mwc-button>
126
+ </div>
127
+ `
128
+ }
129
+
130
+ async firstUpdated() {
131
+ this.clearView()
132
+
133
+ this.config = {
134
+ rows: {
135
+ appendable: false,
136
+ classifier: (record, rowIndex) => {
137
+ return {
138
+ emphasized: record.completed == true
139
+ }
140
+ },
141
+ handlers: {
142
+ click: async (columns, data, column, record, rowIndex) => {
143
+ try {
144
+ this.dataGrist.showSpinner()
145
+ this._currentSerialNumber = record.serialNumber
146
+ // this.selectedSerialInput.value = record.serialNumber
147
+ } catch (ex) {
148
+ console.log(ex)
149
+ } finally {
150
+ this.dataGrist.hideSpinner()
151
+ }
152
+ }
153
+ }
154
+ },
155
+ pagination: { infinite: true },
156
+ list: {
157
+ fields: ['serialNumber']
158
+ },
159
+ columns: [
160
+ { type: 'gutter', gutterName: 'sequence' },
161
+ {
162
+ type: 'string',
163
+ name: 'serialNumber',
164
+ header: i18next.t('field.serial_number'),
165
+ width: 140
166
+ }
167
+ ]
168
+ }
169
+ await this.fetchOrderInventory()
170
+ console.log()
171
+
172
+ // await this.getPalletInfo(this.replacePalletId)
173
+ }
174
+
175
+ // async pageUpdated(changes, lifecycle) {
176
+ // if (this.active) {
177
+ // await this.fetchOrderInventory()
178
+ // console.log()
179
+ // }
180
+ // }
181
+
182
+ clearView() {
183
+ this.targetInventory = null
184
+ this.data = { records: [] }
185
+ this._currentSerialNumber = ''
186
+ if (this.serialNumber) this.serialInput.value = ''
187
+ }
188
+
189
+ async fetchOrderInventory() {
190
+ try {
191
+ this.dataGrist.showSpinner()
192
+ if (this?.orderInventory?.id) {
193
+ const response = await client.query({
194
+ query: gql`
195
+ query orderInventory($id: String!) {
196
+ orderInventory(id: $id) {
197
+ id
198
+ name
199
+ serialNumber
200
+ }
201
+ }
202
+ `,
203
+ variables: { id: this.orderInventory.id }
204
+ })
205
+
206
+ if (!response.errors) {
207
+ this.orderInventory = response.data.orderInventory
208
+ this.data = {
209
+ records: (JSON.parse(response.data.orderInventory.serialNumber) || []).map(x => {
210
+ return { serialNumber: x }
211
+ })
212
+ }
213
+ }
214
+ }
215
+ } catch (error) {
216
+ throw error
217
+ } finally {
218
+ this.dataGrist.hideSpinner()
219
+ }
220
+ }
221
+
222
+ async updateSerialNumber() {
223
+ try {
224
+ this.validate()
225
+
226
+ let orderInventory = this.orderInventory
227
+ let serialNumber = JSON.parse(orderInventory.serialNumber)
228
+ let index = serialNumber.indexOf(this.selectedSerialInput.value)
229
+
230
+ if (index >= 0) {
231
+ serialNumber.splice(index, 1, this.serialInput.value)
232
+ orderInventory.serialNumber = JSON.stringify(serialNumber)
233
+
234
+ const response = await client.mutate({
235
+ mutation: gql`
236
+ mutation updateOrderInventorySerialNumber($orderInventory: OrderInventoryPatch!) {
237
+ updateOrderInventorySerialNumber(orderInventory: $orderInventory) {
238
+ id
239
+ name
240
+ serialNumber
241
+ }
242
+ }
243
+ `,
244
+ variables: {
245
+ orderInventory
246
+ }
247
+ })
248
+
249
+ if (!response.errors) {
250
+ this._currentSerialNumber = ''
251
+ this.serialInput.value = ''
252
+
253
+ this.fetchOrderInventory()
254
+ }
255
+ }
256
+ } catch (e) {
257
+ this._showToast(e)
258
+ }
259
+ }
260
+
261
+ validate() {
262
+ // validate for previous picking execution (multiple picking scanning)
263
+ if (this.selectedSerialInput.value == '') throw new Error(i18next.t('text.no_serial_number_selected'))
264
+
265
+ if (this.serialInput.value == '') throw new Error(i18next.t('text.please_key_in_new_serial_number'))
266
+ }
267
+
268
+ _showToast({ type, message }) {
269
+ document.dispatchEvent(
270
+ new CustomEvent('notify', {
271
+ detail: {
272
+ type,
273
+ message
274
+ }
275
+ })
276
+ )
277
+ }
278
+ }
279
+
280
+ window.customElements.define('serial-number-popup', SerialNumberPopup)
@@ -72,9 +72,6 @@ class ExecuteReverseKitting extends connect(store)(localize(i18next)(PageView))
72
72
  ? html`<form class="multi-column-form" id="info-form">
73
73
  <fieldset>
74
74
  <legend>${`${i18next.t('title.order_no')}: ${this._orderNo}`}</legend>
75
-
76
- <!-- <label>${i18next.t('label.company')}</label>
77
- <input name="bizplaceName" readonly /> -->
78
75
  </fieldset>
79
76
  </form>
80
77
 
@@ -109,8 +106,11 @@ class ExecuteReverseKitting extends connect(store)(localize(i18next)(PageView))
109
106
 
110
107
  get completable() {
111
108
  let completable = false
112
- if (this.orderData.records.length > 0) {
113
- completable = this.orderData.records.every(item => item.completed)
109
+ const orderDataWithIssues = this.orderData.records.filter(orderReverseKitting => !orderReverseKitting.completed)
110
+ if (!orderDataWithIssues?.length) {
111
+ completable = this.orderData.records.every(record => record.completed)
112
+ } else {
113
+ completable = orderDataWithIssues.every(record => record.issue)
114
114
  }
115
115
 
116
116
  return completable
@@ -131,7 +131,7 @@ class ExecuteReverseKitting extends connect(store)(localize(i18next)(PageView))
131
131
  pageInitialized() {
132
132
  this.orderGristConfig = {
133
133
  pagination: { infinite: true },
134
- list: { fields: ['completed', 'batchId', 'palletId', 'product', 'qty'] },
134
+ list: { fields: ['completed', 'batchId', 'palletId', 'product', 'qty', 'issue'] },
135
135
  rows: {
136
136
  appendable: false,
137
137
  handlers: {
@@ -179,6 +179,13 @@ class ExecuteReverseKitting extends connect(store)(localize(i18next)(PageView))
179
179
  header: i18next.t('field.uom_value'),
180
180
  label: true,
181
181
  width: 60
182
+ },
183
+ {
184
+ type: 'string',
185
+ name: 'issue',
186
+ header: i18next.t('field.issue'),
187
+ label: true,
188
+ width: 200
182
189
  }
183
190
  ]
184
191
  }
@@ -236,6 +243,7 @@ class ExecuteReverseKitting extends connect(store)(localize(i18next)(PageView))
236
243
  otherTarget
237
244
  operationGuide
238
245
  status
246
+ issue
239
247
  description
240
248
  remark
241
249
  }
@@ -336,7 +344,6 @@ class ExecuteReverseKitting extends connect(store)(localize(i18next)(PageView))
336
344
 
337
345
  _clearView() {
338
346
  this.orderData = { records: [] }
339
- this.inputForm.reset()
340
347
  this._selectedParentInventory = null
341
348
  this.updateContext()
342
349
  }
@@ -346,11 +353,22 @@ class ExecuteReverseKitting extends connect(store)(localize(i18next)(PageView))
346
353
  }
347
354
 
348
355
  _openPopupCombinationSets(record) {
349
- openPopup(html` <popup-combination-sets .orderNo="${this._orderNo}" .data="${record}"></popup-combination-sets> `, {
350
- backdrop: true,
351
- size: 'large',
352
- title: record.palletId
353
- })
356
+ openPopup(
357
+ html`
358
+ <popup-combination-sets
359
+ .orderNo="${this._orderNo}"
360
+ .data="${record}"
361
+ @order-reverse-kitting-data="${e => {
362
+ this.fetchReverseKittingOrder(this._orderNo)
363
+ }}"
364
+ ></popup-combination-sets>
365
+ `,
366
+ {
367
+ backdrop: true,
368
+ size: 'large',
369
+ title: record.palletId
370
+ }
371
+ )
354
372
  }
355
373
 
356
374
  _showToast({ type, message }) {
@@ -1,10 +1,13 @@
1
1
  import '../../vas/reverse-kitting/popup-reverse-kitting-template'
2
+ import '../../components/popup-note'
2
3
 
4
+ import gql from 'graphql-tag'
3
5
  import { css, html, LitElement } from 'lit-element'
4
6
 
5
7
  import { MultiColumnFormStyles } from '@things-factory/form-ui'
6
8
  import { i18next, localize } from '@things-factory/i18n-base'
7
9
  import { openPopup } from '@things-factory/layout-base'
10
+ import { client } from '@things-factory/shell'
8
11
  import { isMobileDevice } from '@things-factory/utils'
9
12
 
10
13
  class PopupCombinationSets extends localize(i18next)(LitElement) {
@@ -53,12 +56,15 @@ class PopupCombinationSets extends localize(i18next)(LitElement) {
53
56
  font-size: var(--grist-title-icon-size);
54
57
  color: var(--grist-title-icon-color);
55
58
  }
59
+ .grist {
60
+ display: flex;
61
+ flex-direction: column;
62
+ flex: 1;
63
+ overflow-y: auto;
64
+ }
56
65
  .button-container {
57
- padding: var(--button-container-padding);
58
- margin: var(--button-container-margin);
59
- text-align: var(--button-container-align);
60
- background-color: var(--button-container-background);
61
- height: var(--button-container-height);
66
+ padding: 10px 0 12px 0;
67
+ text-align: center;
62
68
  }
63
69
  `
64
70
  ]
@@ -129,6 +135,15 @@ class PopupCombinationSets extends localize(i18next)(LitElement) {
129
135
  ></data-grist>
130
136
  </div>`
131
137
  : ''}
138
+ ${this.data
139
+ ? html`<div class="button-container">
140
+ <mwc-button
141
+ raised
142
+ @click=${this._openIssueNote.bind(this)}
143
+ label="${i18next.t('button.issue')}"
144
+ ></mwc-button>
145
+ </div>`
146
+ : ''}
132
147
  `
133
148
  }
134
149
 
@@ -214,6 +229,31 @@ class PopupCombinationSets extends localize(i18next)(LitElement) {
214
229
  }
215
230
  }
216
231
 
232
+ async updateReverseKittingIssue(orderReverseKitting, issue) {
233
+ try {
234
+ if (!issue) return
235
+ const response = await client.mutate({
236
+ mutation: gql`
237
+ mutation updateOrderReverseKitting($id: String!, $patch: OrderReverseKittingPatch!) {
238
+ updateOrderReverseKitting(id: $id, patch: $patch) {
239
+ id
240
+ name
241
+ }
242
+ }
243
+ `,
244
+ variables: { id: orderReverseKitting.id, patch: { issue } }
245
+ })
246
+
247
+ if (!response.errors) {
248
+ this._showToast({ message: i18next.t('text.issue_updated') })
249
+ this.dispatchEvent(new CustomEvent('order-reverse-kitting-data', { detail: this.data }))
250
+ history.back()
251
+ }
252
+ } catch (e) {
253
+ this._showToast(e)
254
+ }
255
+ }
256
+
217
257
  getProductCombination() {
218
258
  let operationGuide = JSON.parse(this.data.operationGuide)
219
259
  this.productCombinationSets = {
@@ -229,6 +269,25 @@ class PopupCombinationSets extends localize(i18next)(LitElement) {
229
269
  }
230
270
  }
231
271
 
272
+ _openIssueNote() {
273
+ openPopup(
274
+ html`
275
+ <popup-note
276
+ .title="${i18next.t('title.issue')}"
277
+ .value="${this.data.issue}"
278
+ @submit="${async e => {
279
+ await this.updateReverseKittingIssue(this.data, e.detail.value)
280
+ }}"
281
+ ></popup-note>
282
+ `,
283
+ {
284
+ backdrop: true,
285
+ size: 'medium',
286
+ title: i18next.t('title.issue')
287
+ }
288
+ )
289
+ }
290
+
232
291
  _openPopupReverseKittingTemplate(record) {
233
292
  openPopup(
234
293
  html`
@@ -247,6 +306,17 @@ class PopupCombinationSets extends localize(i18next)(LitElement) {
247
306
  }
248
307
  )
249
308
  }
309
+
310
+ _showToast({ type, message }) {
311
+ document.dispatchEvent(
312
+ new CustomEvent('notify', {
313
+ detail: {
314
+ type,
315
+ message
316
+ }
317
+ })
318
+ )
319
+ }
250
320
  }
251
321
 
252
322
  window.customElements.define('popup-combination-sets', PopupCombinationSets)