@things-factory/operato-wms 3.7.6 → 3.7.10

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 +32 -12
  19. package/client/pages/vas/reverse-kitting/popup-combination-sets.js +106 -10
  20. package/client/pages/vas/reverse-kitting/popup-reverse-kitting-template.js +130 -19
  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
@@ -1,6 +1,8 @@
1
1
  import '@things-factory/biz-ui'
2
+ import '@things-factory/barcode-ui'
2
3
  import '@things-factory/grist-ui'
3
4
  import '@things-factory/product-ui'
5
+ import '../../order/reverse-kitting-order/reverse-kitting-pallet-label-popup'
4
6
 
5
7
  import gql from 'graphql-tag'
6
8
  import { css, html } from 'lit-element'
@@ -26,6 +28,12 @@ class ReverseKittingOrderDetail extends connect(store)(localize(i18next)(PageVie
26
28
  flex-direction: column;
27
29
  overflow-x: auto;
28
30
  }
31
+ .form-container {
32
+ display: flex;
33
+ }
34
+ .form-container > form {
35
+ flex: 1;
36
+ }
29
37
  .container {
30
38
  flex: 1;
31
39
  display: flex;
@@ -80,6 +88,7 @@ class ReverseKittingOrderDetail extends connect(store)(localize(i18next)(PageVie
80
88
  inventoryGristConfig: Object,
81
89
  inventoryData: Object,
82
90
  _bizplaces: Object,
91
+ _bizplace: Object,
83
92
  _bizplaceId: String,
84
93
  _bizplaceName: String,
85
94
  locationSortingRules: Object,
@@ -99,24 +108,28 @@ class ReverseKittingOrderDetail extends connect(store)(localize(i18next)(PageVie
99
108
 
100
109
  render() {
101
110
  return html`
102
- <form name="reverseKittingOrder" class="multi-column-form" autocomplete="off">
103
- <fieldset>
104
- <legend>${i18next.t('title.reverse_kitting_no')}: ${this._reverseKittingNo}</legend>
105
- <label>${i18next.t('label.company')}</label>
106
- <input type="hidden" name="bizplaceId" value="${this._bizplaceId}" />
107
- <input
108
- readonly
109
- type="text"
110
- name="bizplaceName"
111
- value="${this._bizplaceName}"
112
- @click="${this._openBizplacesSelector.bind(this)}"
113
- />
114
-
115
- ${this._reverseKittingNo != 'new'
116
- ? html`<label>${i18next.t('label.status')}</label><input readonly type="text" name="status" />`
117
- : ''}
118
- </fieldset>
119
- </form>
111
+ <div class="form-container">
112
+ <form name="reverseKittingOrder" class="multi-column-form" autocomplete="off">
113
+ <fieldset>
114
+ <legend>${i18next.t('title.reverse_kitting_no')}: ${this._reverseKittingNo}</legend>
115
+ <label>${i18next.t('label.company')}</label>
116
+ <input type="hidden" name="bizplaceId" value="${this._bizplaceId}" />
117
+ <input
118
+ readonly
119
+ type="text"
120
+ name="bizplaceName"
121
+ value="${this._bizplaceName}"
122
+ @click="${this._openBizplacesSelector.bind(this)}"
123
+ />
124
+
125
+ ${!this._newOrder
126
+ ? html`<label>${i18next.t('label.status')}</label><input readonly type="text" name="status" />`
127
+ : ''}
128
+ </fieldset>
129
+ </form>
130
+
131
+ ${!this._newOrder ? html`<barcode-tag bcid="qrcode" .value=${this._reverseKittingNo}></barcode-tag>` : ''}
132
+ </div>
120
133
  <div class="container">
121
134
  <div class="grist">
122
135
  <h2><mwc-icon>list_alt</mwc-icon>${i18next.t('title.target_products')}</h2>
@@ -188,12 +201,19 @@ class ReverseKittingOrderDetail extends connect(store)(localize(i18next)(PageVie
188
201
  ...CommonButtonStyles.activate
189
202
  }
190
203
  ]
204
+ } else if (this._status === ORDER_STATUS.EXECUTING.value) {
205
+ actions.push({
206
+ title: i18next.t('button.lot_label_print'),
207
+ action: this._openLotLabelPrintPopup.bind(this),
208
+ ...CommonButtonStyles.label
209
+ })
191
210
  }
192
211
  }
193
212
 
194
213
  return {
195
214
  title: i18next.t('title.reverse_kitting_order_detail'),
196
215
  actions,
216
+ printable: { accept: ['preview'], content: this },
197
217
  help: 'operato-wms/reverse-kitting-order/reverse-kitting-order-detail'
198
218
  }
199
219
  }
@@ -203,6 +223,8 @@ class ReverseKittingOrderDetail extends connect(store)(localize(i18next)(PageVie
203
223
  if (this.active) {
204
224
  if (changes.resourceId) {
205
225
  this._reverseKittingNo = changes.resourceId
226
+ } else {
227
+ this._reverseKittingNo = 'new'
206
228
  }
207
229
 
208
230
  this._newOrder = this._reverseKittingNo == 'new' ? true : false
@@ -226,7 +248,7 @@ class ReverseKittingOrderDetail extends connect(store)(localize(i18next)(PageVie
226
248
  }
227
249
 
228
250
  _configureInventoryGrist() {
229
- let editable = this._bizplaceId ? true : false
251
+ let editable = this._bizplaceId ? (this._newOrder ? true : false) : false
230
252
 
231
253
  this.inventoryGristConfig = {
232
254
  pagination: { infinite: true },
@@ -304,6 +326,7 @@ class ReverseKittingOrderDetail extends connect(store)(localize(i18next)(PageVie
304
326
  },
305
327
  width: 250
306
328
  },
329
+ { name: 'batchId', hidden: true },
307
330
  {
308
331
  type: 'string',
309
332
  name: 'productSKU',
@@ -452,9 +475,11 @@ class ReverseKittingOrderDetail extends connect(store)(localize(i18next)(PageVie
452
475
  if (!response.errors) {
453
476
  const bizplaces = response.data.partnersBizplaces.items
454
477
  if (bizplaces.length == 1) {
478
+ this._bizplace = bizplaces[0]
455
479
  this._bizplaceId = bizplaces[0].id
456
480
  this._bizplaceName = bizplaces[0].name
457
481
  } else {
482
+ this._bizplace = null
458
483
  this._bizplaceId = ''
459
484
  this._bizplaceName = ''
460
485
  }
@@ -481,6 +506,8 @@ class ReverseKittingOrderDetail extends connect(store)(localize(i18next)(PageVie
481
506
  description
482
507
  }
483
508
  orderReverseKittings {
509
+ id
510
+ name
484
511
  set
485
512
  targetType
486
513
  targetBatchId
@@ -535,6 +562,7 @@ class ReverseKittingOrderDetail extends connect(store)(localize(i18next)(PageVie
535
562
  return {
536
563
  ...orderReverseKitting,
537
564
  ...orderReverseKitting.inventory,
565
+ orderReverseKittingId: orderReverseKitting.id,
538
566
  productSKU: orderReverseKitting.inventory.product.sku,
539
567
  productName: orderReverseKitting.inventory.product.name,
540
568
  productCombination: this.displayProductCombination(JSON.parse(orderReverseKitting.operationGuide))
@@ -838,40 +866,77 @@ class ReverseKittingOrderDetail extends connect(store)(localize(i18next)(PageVie
838
866
  )
839
867
  }
840
868
 
869
+ _openLotLabelPrintPopup() {
870
+ const _pallets = {
871
+ records: this.inventoryData.records.map(record => {
872
+ const operationGuide = JSON.parse(record.operationGuide)
873
+ let qty = operationGuide.data.productCombinationSets?.length || 0
874
+
875
+ return {
876
+ id: record.orderReverseKittingId,
877
+ palletId: record.palletId,
878
+ batchId: record.batchId,
879
+ product: record.product,
880
+ qty,
881
+ printQty: qty,
882
+ packingType: record.packingType,
883
+ bizplace: this._bizplace
884
+ }
885
+ })
886
+ }
887
+ openPopup(
888
+ html` <reverse-kitting-pallet-label-popup .pallets="${_pallets}"></reverse-kitting-pallet-label-popup> `,
889
+ {
890
+ backdrop: true,
891
+ size: 'large',
892
+ title: i18next.t('title.lot_label')
893
+ }
894
+ )
895
+ }
896
+
841
897
  _openProductCombinations(columns, data, column, record, rowIndex) {
842
- if (record.inventory.product.id) {
843
- openPopup(
844
- html`
845
- <product-combination-selection-popup
846
- .productId="${record.inventory.product.id}"
847
- .packingType="${record.packingType}"
848
- .packingSize="${record.packingSize}"
849
- .bizplaceId="${this._bizplaceId}"
850
- @selected="${e => {
851
- const operationGuide = { data: { ...e.detail } }
852
-
853
- this.inventoryGrist.dirtyData.records = this.inventoryGrist.dirtyData.records.map(item => {
854
- if (item.id == record.id) {
855
- item.operationGuide = operationGuide
856
- item.productCombination = this.displayProductCombination(operationGuide)
857
- }
898
+ if (this._newOrder) {
899
+ if (record.inventory.product.id) {
900
+ openPopup(
901
+ html`
902
+ <product-combination-selection-popup
903
+ .productId="${record.inventory.product.id}"
904
+ .packingType="${record.packingType}"
905
+ .packingSize="${record.packingSize}"
906
+ .bizplaceId="${this._bizplaceId}"
907
+ @selected="${e => {
908
+ let operationGuide = { data: { ...e.detail } }
909
+ let productCombinationSets = operationGuide.data.productCombinationSets.map(item => {
910
+ return {
911
+ ...item,
912
+ qty: item.qty * record.qty
913
+ }
914
+ })
915
+ operationGuide.data.productCombinationSets = productCombinationSets
916
+
917
+ this.inventoryGrist.dirtyData.records = this.inventoryGrist.dirtyData.records.map(item => {
918
+ if (item.id == record.id) {
919
+ item.operationGuide = operationGuide
920
+ item.productCombination = this.displayProductCombination(operationGuide)
921
+ }
858
922
 
859
- return item
860
- })
923
+ return item
924
+ })
861
925
 
862
- this.inventoryData = {
863
- ...this.inventoryData,
864
- records: [...this.inventoryGrist.dirtyData.records]
865
- }
866
- }}"
867
- ></product-combination-selection-popup>
868
- `,
869
- {
870
- backdrop: true,
871
- size: 'large',
872
- title: `${record.productSKU}`
873
- }
874
- )
926
+ this.inventoryData = {
927
+ ...this.inventoryData,
928
+ records: [...this.inventoryGrist.dirtyData.records]
929
+ }
930
+ }}"
931
+ ></product-combination-selection-popup>
932
+ `,
933
+ {
934
+ backdrop: true,
935
+ size: 'large',
936
+ title: `${record.productSKU}`
937
+ }
938
+ )
939
+ }
875
940
  }
876
941
  }
877
942
 
@@ -122,12 +122,7 @@ class ReverseKittingOrderList extends localize(i18next)(PageView) {
122
122
  icon: 'reorder',
123
123
  handlers: {
124
124
  click: (columns, data, column, record, rowIndex) => {
125
- const status = record.status
126
- if (status === ORDER_STATUS.REJECTED.value) {
127
- navigate(`rejected_vas_order/${record.name}`) // 1. move to rejected detail page
128
- } else {
129
- navigate(`reverse_kitting_order_detail/${record.name}`)
130
- }
125
+ navigate(`reverse_kitting_order_detail/${record.name}`)
131
126
  }
132
127
  }
133
128
  },
@@ -0,0 +1,239 @@
1
+ import '@things-factory/grist-ui'
2
+
3
+ import gql from 'graphql-tag'
4
+ import { css, html, LitElement } from 'lit-element'
5
+ import { connect } from 'pwa-helpers/connect-mixin'
6
+
7
+ import { DirectPrinter } from '@things-factory/barcode-base'
8
+ import { i18next, localize } from '@things-factory/i18n-base'
9
+ import { client, store } from '@things-factory/shell'
10
+ import { isMobileDevice } from '@things-factory/utils'
11
+
12
+ import { PALLET_LABEL_SETTING_KEY } from '../../constants'
13
+
14
+ class ReverseKittingPalletLabelPopup extends connect(store)(localize(i18next)(LitElement)) {
15
+ static get properties() {
16
+ return {
17
+ config: Object,
18
+ data: Object,
19
+ pallets: Object,
20
+ _palletLabel: Object
21
+ }
22
+ }
23
+
24
+ static get styles() {
25
+ return [
26
+ css`
27
+ :host {
28
+ padding: 10px;
29
+ display: flex;
30
+ flex-direction: column;
31
+ overflow-x: overlay;
32
+ background-color: var(--main-section-background-color);
33
+ }
34
+ .grist {
35
+ background-color: var(--main-section-background-color);
36
+ display: flex;
37
+ flex-direction: column;
38
+ flex: 1;
39
+ overflow-y: auto;
40
+ }
41
+ data-grist {
42
+ overflow-y: hidden;
43
+ flex: 1;
44
+ }
45
+ .button-container {
46
+ padding: var(--button-container-padding);
47
+ margin: var(--button-container-margin);
48
+ text-align: var(--button-container-align);
49
+ background-color: var(--button-container-background);
50
+ height: var(--button-container-height);
51
+ }
52
+ `
53
+ ]
54
+ }
55
+
56
+ firstUpdated() {
57
+ this.config = {
58
+ pagination: { infinite: true },
59
+ rows: { selectable: { multiple: true }, appendable: false },
60
+ list: { fields: ['batchId', 'palletQty', 'printQty'] },
61
+ columns: [
62
+ { type: 'gutter', gutterName: 'sequence' },
63
+ { type: 'gutter', gutterName: 'row-selector', multiple: true },
64
+ {
65
+ type: 'string',
66
+ name: 'batchId',
67
+ header: i18next.t('field.batch_id'),
68
+ width: 150
69
+ },
70
+ {
71
+ type: 'object',
72
+ name: 'product',
73
+ header: i18next.t('field.product'),
74
+ width: 250
75
+ },
76
+ {
77
+ type: 'integer',
78
+ name: 'qty',
79
+ header: i18next.t('field.qty'),
80
+ width: 80
81
+ },
82
+ {
83
+ type: 'integer',
84
+ name: 'printQty',
85
+ header: i18next.t('field.print_qty'),
86
+ record: { editable: true },
87
+ width: 80
88
+ }
89
+ ]
90
+ }
91
+ }
92
+
93
+ get dataGrist() {
94
+ return this.shadowRoot.querySelector('data-grist')
95
+ }
96
+
97
+ render() {
98
+ return html`
99
+ <div class="grist">
100
+ <data-grist
101
+ id="grist"
102
+ .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
103
+ .config=${this.config}
104
+ .data="${this.data}"
105
+ ></data-grist>
106
+ </div>
107
+
108
+ <div class="button-container">
109
+ <mwc-button raised @click="${this._printLabel.bind(this)}" label="${i18next.t('button.print')}"></mwc-button>
110
+ </div>
111
+ `
112
+ }
113
+
114
+ updated(changeProps) {
115
+ if (changeProps.has('pallets')) {
116
+ if (this.pallets && this.pallets.records && this.pallets.records.length) {
117
+ this.data = {
118
+ records: this.pallets.records.map(record => {
119
+ return {
120
+ ...record,
121
+ startSeq: 1
122
+ }
123
+ })
124
+ }
125
+ }
126
+ }
127
+ }
128
+
129
+ async _printLabel() {
130
+ try {
131
+ let labelId = this._palletLabel && this._palletLabel.id
132
+ let dateStr = new Date().toJSON().slice(0, 10).replace(/-/g, '/')
133
+ let _targetRows = this._validate()
134
+ const palletRuleType = 'vas_pallet_id' // pallet id rule type
135
+ const targets = _targetRows.map(target => {
136
+ return {
137
+ id: target.id,
138
+ printQty: target.printQty
139
+ }
140
+ })
141
+
142
+ const response = await client.query({
143
+ query: gql`
144
+ query generateReverseKittingPalletId($targets: [PalletInfo], $type: String!) {
145
+ generateReverseKittingPalletId(targets: $targets, type: $type) {
146
+ product {
147
+ sku
148
+ name
149
+ type
150
+ description
151
+ movement
152
+ auxUnit1
153
+ auxValue1
154
+ }
155
+ bizplace {
156
+ name
157
+ }
158
+ batchId
159
+ batchIdRef
160
+ packingType
161
+ palletId
162
+ remark
163
+ }
164
+ }
165
+ `,
166
+ variables: { targets, type: palletRuleType }
167
+ })
168
+
169
+ if (!response.errors) {
170
+ const results = response.data.generateReverseKittingPalletId
171
+
172
+ for (let i = 0; i < results.length; i++) {
173
+ let searchParams = new URLSearchParams()
174
+
175
+ searchParams.append('pallet', results[i].palletId)
176
+ searchParams.append('batch', results[i].batchId)
177
+ searchParams.append('product', results[i].product?.name)
178
+ searchParams.append('sku', results[i].product?.sku)
179
+ searchParams.append('auxUnit1', results[i].product?.auxUnit1)
180
+ searchParams.append('auxValue1', results[i].product?.auxValue1)
181
+ searchParams.append('type', results[i].product?.type)
182
+ searchParams.append('description', results[i].product?.description)
183
+ searchParams.append('packing', results[i].packingType)
184
+ searchParams.append('customer', results[i].bizplace?.name)
185
+ searchParams.append('date', dateStr)
186
+ searchParams.append('remark', results[i].remark)
187
+ searchParams.append('batchRef', results[i].batchIdRef)
188
+ searchParams.append('expirationDate', '')
189
+ try {
190
+ const response = await fetch(`label-command/${labelId}?${searchParams.toString()}`, {
191
+ method: 'GET'
192
+ })
193
+
194
+ if (response.status !== 200) {
195
+ throw `Error : Can't get label command from server (response: ${response.status})`
196
+ }
197
+
198
+ let command = await response.text()
199
+
200
+ if (!this.printer) {
201
+ this.printer = new DirectPrinter()
202
+ }
203
+
204
+ await this.printer.print(command)
205
+ } catch (ex) {
206
+ delete this.printer
207
+ throw ex
208
+ }
209
+ }
210
+ }
211
+ } catch (e) {
212
+ this._showToast(e)
213
+ }
214
+ }
215
+
216
+ _validate() {
217
+ let _targetRows = this.dataGrist.selected.length > 0 ? this.dataGrist.selected : this.dataGrist.dirtyData.records
218
+ if (!_targetRows.every(row => row.printQty)) throw new Error(i18next.t('text.print_qty_is_empty'))
219
+ return _targetRows
220
+ }
221
+
222
+ stateChanged(state) {
223
+ let palletLabelSetting = state.dashboard[PALLET_LABEL_SETTING_KEY]
224
+ this._palletLabel = (palletLabelSetting && palletLabelSetting.board) || {}
225
+ }
226
+
227
+ _showToast({ type, message }) {
228
+ document.dispatchEvent(
229
+ new CustomEvent('notify', {
230
+ detail: {
231
+ type,
232
+ message
233
+ }
234
+ })
235
+ )
236
+ }
237
+ }
238
+
239
+ window.customElements.define('reverse-kitting-pallet-label-popup', ReverseKittingPalletLabelPopup)
@@ -125,6 +125,24 @@ class DeliveryOrderList extends localize(i18next)(PageView) {
125
125
  ],
126
126
  props: { searchOper: 'eq' }
127
127
  },
128
+ {
129
+ label: i18next.t('field.ref_no'),
130
+ name: 'refNo',
131
+ type: 'text',
132
+ props: { searchOper: 'i_like' }
133
+ },
134
+ {
135
+ label: i18next.t('field.ref_no_2'),
136
+ name: 'refNo2',
137
+ type: 'text',
138
+ props: { searchOper: 'i_like' }
139
+ },
140
+ {
141
+ label: i18next.t('field.ref_no_3'),
142
+ name: 'refNo3',
143
+ type: 'text',
144
+ props: { searchOper: 'i_like' }
145
+ },
128
146
  {
129
147
  name: 'status',
130
148
  label: i18next.t('label.status'),
@@ -208,7 +226,23 @@ class DeliveryOrderList extends localize(i18next)(PageView) {
208
226
  type: 'string',
209
227
  name: 'refNo',
210
228
  header: i18next.t('field.ref_no'),
211
- imex: { header: i18next.t('field.ref_no'), key: 'refNo', width: 20, type: 'string' },
229
+ imex: { header: i18next.t('field.refNo'), key: 'refNo', width: 25, type: 'string' },
230
+ sortable: true,
231
+ width: 150
232
+ },
233
+ {
234
+ type: 'string',
235
+ name: 'refNo2',
236
+ header: i18next.t('field.ref_no_2'),
237
+ imex: { header: i18next.t('field.ref_no_2'), key: 'refNo2', width: 25, type: 'string' },
238
+ sortable: true,
239
+ width: 150
240
+ },
241
+ {
242
+ type: 'string',
243
+ name: 'refNo3',
244
+ header: i18next.t('field.ref_no_3'),
245
+ imex: { header: i18next.t('field.ref_no_3'), key: 'refNo3', width: 25, type: 'string' },
212
246
  sortable: true,
213
247
  width: 150
214
248
  },
@@ -272,7 +306,7 @@ class DeliveryOrderList extends localize(i18next)(PageView) {
272
306
  }
273
307
  }
274
308
 
275
- async fetchHandler({ page, limit, sorters = [{ name: 'createdAt', desc: true }] }) {
309
+ async fetchHandler({ page, limit, sorters = [] }) {
276
310
  let filters = this.searchForm.queryFilters
277
311
  var tzoffset = new Date().getTimezoneOffset() * 60
278
312
 
@@ -296,6 +330,8 @@ class DeliveryOrderList extends localize(i18next)(PageView) {
296
330
  name
297
331
  description
298
332
  refNo
333
+ refNo2
334
+ refNo3
299
335
  }
300
336
  ownCollection
301
337
  createdAt
@@ -324,7 +360,15 @@ class DeliveryOrderList extends localize(i18next)(PageView) {
324
360
  if (!response.errors) {
325
361
  return {
326
362
  total: response.data.deliveryOrders.total || 0,
327
- records: response.data.deliveryOrders.items
363
+ records:
364
+ response.data.deliveryOrders.items.map(dord => {
365
+ return {
366
+ ...dord,
367
+ refNo: dord?.releaseGood?.refNo || '',
368
+ refNo2: dord?.releaseGood?.refNo2 || '',
369
+ refNo3: dord?.releaseGood?.refNo3 || ''
370
+ }
371
+ }) || []
328
372
  }
329
373
  }
330
374
  }