@things-factory/operato-wms 4.3.797 → 4.3.799
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.
- package/client/pages/adjustment/transfer-inventory.js +940 -207
- package/client/pages/components/worksheet-information-popup.js +60 -8
- package/client/pages/constants/order.js +7 -1
- package/client/pages/inventory/inventory-history.js +33 -5
- package/client/pages/order/release-order/b2b/b2b-order-list.js +17 -1
- package/client/pages/order/release-order/release-order-detail.js +19 -0
- package/client/pages/order/transport-order/print-delivery-note.js +19 -1
- package/client/pages/outbound/loading-v2/load-by-qty.js +10 -0
- package/client/pages/outbound/loading-v2/loading-execution-base.js +22 -8
- package/client/pages/outbound/loading-v2/loading-execution.js +37 -8
- package/client/pages/outbound/loading-v2/loading.js +6 -0
- package/client/pages/outbound/loading-v2/release-good-info.js +3 -0
- package/client/pages/outbound/picking-product.js +25 -3
- package/client/pages/outbound/picking-v2/picking-execution-base.js +20 -2
- package/client/pages/outbound/picking-v2/picking-execution.js +4 -3
- package/client/pages/outbound/picking-v2/picking.js +3 -0
- package/client/pages/outbound/single-outbound-worksheet.js +18 -1
- package/client/pages/outbound/sorting-product.js +24 -1
- package/client/pages/outbound/worksheet-zone-picking.js +1 -0
- package/dist-server/graphql/resolvers/outbound/find-loadable-release-good-by-bin.js +9 -4
- package/dist-server/graphql/resolvers/outbound/find-loadable-release-good-by-bin.js.map +1 -1
- package/dist-server/graphql/resolvers/outbound/load-by-qty.js +1 -1
- package/dist-server/graphql/resolvers/outbound/load-by-qty.js.map +1 -1
- package/dist-server/graphql/resolvers/outbound/loading-worksheet-v2.js +5 -1
- package/dist-server/graphql/resolvers/outbound/loading-worksheet-v2.js.map +1 -1
- package/dist-server/graphql/resolvers/zone-worksheet/zone-worksheet.js +8 -2
- package/dist-server/graphql/resolvers/zone-worksheet/zone-worksheet.js.map +1 -1
- package/dist-server/validators/setting-validators.js +7 -1
- package/dist-server/validators/setting-validators.js.map +1 -1
- package/package.json +8 -8
- package/server/graphql/resolvers/outbound/find-loadable-release-good-by-bin.ts +7 -1
- package/server/graphql/resolvers/outbound/load-by-qty.ts +1 -1
- package/server/graphql/resolvers/outbound/loading-worksheet-v2.ts +9 -2
- package/server/graphql/resolvers/zone-worksheet/zone-worksheet.ts +32 -23
- package/server/validators/setting-validators.ts +13 -1
- package/translations/en.json +9 -0
- package/translations/ko.json +9 -0
- package/translations/ms.json +9 -0
- package/translations/zh.json +9 -0
|
@@ -9,6 +9,8 @@ import { isMobileDevice } from '@things-factory/utils'
|
|
|
9
9
|
import gql from 'graphql-tag'
|
|
10
10
|
import { css, html } from 'lit-element'
|
|
11
11
|
import { connect } from 'pwa-helpers/connect-mixin.js'
|
|
12
|
+
import { getCodeByName } from '@things-factory/code-base'
|
|
13
|
+
import { fetchSettingRule } from '../../fetch-setting-value'
|
|
12
14
|
import { CARTON, LOT } from '../constants'
|
|
13
15
|
import '../inbound/select-location-popup'
|
|
14
16
|
|
|
@@ -23,7 +25,14 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
23
25
|
refInventoryType: String,
|
|
24
26
|
_data: Object,
|
|
25
27
|
_gristConfig: Object,
|
|
26
|
-
_isExecuting: Boolean
|
|
28
|
+
_isExecuting: Boolean,
|
|
29
|
+
_showTransferForm: Boolean,
|
|
30
|
+
_showReasonField: Boolean,
|
|
31
|
+
_showRemarkField: Boolean,
|
|
32
|
+
_toLocationData: Object,
|
|
33
|
+
_transferCodes: Array,
|
|
34
|
+
_locations: Array,
|
|
35
|
+
_locationRecommendationChecked: Boolean
|
|
27
36
|
}
|
|
28
37
|
}
|
|
29
38
|
|
|
@@ -118,6 +127,148 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
118
127
|
color: var(--primary-color) !important;
|
|
119
128
|
margin-botton: 5px;
|
|
120
129
|
}
|
|
130
|
+
|
|
131
|
+
/* Mobile form styles - matching unload-product design */
|
|
132
|
+
.mobile-form {
|
|
133
|
+
display: flex;
|
|
134
|
+
flex-direction: column;
|
|
135
|
+
gap: 10px;
|
|
136
|
+
padding: 8px 0;
|
|
137
|
+
}
|
|
138
|
+
.mobile-form fieldset {
|
|
139
|
+
display: flex;
|
|
140
|
+
flex-direction: column;
|
|
141
|
+
align-items: flex-start !important;
|
|
142
|
+
border: none;
|
|
143
|
+
margin: 0;
|
|
144
|
+
padding: 0;
|
|
145
|
+
width: 100%;
|
|
146
|
+
box-sizing: border-box;
|
|
147
|
+
}
|
|
148
|
+
.mobile-form label {
|
|
149
|
+
display: block;
|
|
150
|
+
grid-column: unset !important;
|
|
151
|
+
text-align: left !important;
|
|
152
|
+
align-self: flex-start !important;
|
|
153
|
+
margin-bottom: 4px;
|
|
154
|
+
color: #333;
|
|
155
|
+
font-weight: bold;
|
|
156
|
+
font-size: 14px;
|
|
157
|
+
width: 100%;
|
|
158
|
+
text-transform: capitalize;
|
|
159
|
+
}
|
|
160
|
+
.mobile-form select,
|
|
161
|
+
.mobile-form input[type="text"],
|
|
162
|
+
.mobile-form input[type="date"] {
|
|
163
|
+
grid-column: unset !important;
|
|
164
|
+
width: 100%;
|
|
165
|
+
max-width: 100%;
|
|
166
|
+
height: 24px;
|
|
167
|
+
min-height: 24px;
|
|
168
|
+
border: 1px solid rgba(0, 0, 0, 0.2);
|
|
169
|
+
border-radius: 4px;
|
|
170
|
+
padding: 4px 8px;
|
|
171
|
+
font-size: 12px;
|
|
172
|
+
background-color: white;
|
|
173
|
+
box-sizing: border-box;
|
|
174
|
+
}
|
|
175
|
+
.mobile-form input[type="number"] {
|
|
176
|
+
grid-column: unset !important;
|
|
177
|
+
width: 100%;
|
|
178
|
+
max-width: 100%;
|
|
179
|
+
height: 24px;
|
|
180
|
+
min-height: 24px;
|
|
181
|
+
border: 1px solid rgba(0, 0, 0, 0.2);
|
|
182
|
+
border-radius: 4px;
|
|
183
|
+
padding: 4px 8px;
|
|
184
|
+
padding-right: 24px;
|
|
185
|
+
font-size: 12px;
|
|
186
|
+
background-color: white;
|
|
187
|
+
box-sizing: border-box;
|
|
188
|
+
-moz-appearance: textfield;
|
|
189
|
+
}
|
|
190
|
+
.mobile-form input[type="number"]::-webkit-inner-spin-button,
|
|
191
|
+
.mobile-form input[type="number"]::-webkit-outer-spin-button {
|
|
192
|
+
opacity: 1;
|
|
193
|
+
height: 16px;
|
|
194
|
+
}
|
|
195
|
+
.mobile-form select:focus,
|
|
196
|
+
.mobile-form input:focus {
|
|
197
|
+
outline: none;
|
|
198
|
+
border-color: #017E7F;
|
|
199
|
+
}
|
|
200
|
+
.mobile-form [custom-input] {
|
|
201
|
+
grid-column: unset !important;
|
|
202
|
+
width: 100%;
|
|
203
|
+
box-sizing: border-box;
|
|
204
|
+
border: var(--input-field-border, 1px solid rgba(0, 0, 0, 0.2));
|
|
205
|
+
border-radius: var(--input-field-border-radius, 4px);
|
|
206
|
+
}
|
|
207
|
+
.mobile-form barcode-scanable-input {
|
|
208
|
+
width: 100%;
|
|
209
|
+
max-width: 100%;
|
|
210
|
+
box-sizing: border-box;
|
|
211
|
+
min-width: 0;
|
|
212
|
+
height: 24px;
|
|
213
|
+
min-height: 24px;
|
|
214
|
+
}
|
|
215
|
+
.mobile-form input[disabled] {
|
|
216
|
+
background-color: #f5f5f5;
|
|
217
|
+
cursor: not-allowed;
|
|
218
|
+
}
|
|
219
|
+
.mobile-form .side-by-side-row {
|
|
220
|
+
display: flex;
|
|
221
|
+
flex-direction: row;
|
|
222
|
+
gap: 10px;
|
|
223
|
+
}
|
|
224
|
+
.mobile-form .side-by-side-row fieldset {
|
|
225
|
+
flex: 1;
|
|
226
|
+
min-width: 0;
|
|
227
|
+
}
|
|
228
|
+
/* End of mobile form styles */
|
|
229
|
+
|
|
230
|
+
/* Mobile info section */
|
|
231
|
+
.mobile-info-section {
|
|
232
|
+
padding: 8px 8px 12px 8px;
|
|
233
|
+
/* border-bottom: 1px solid #017e7f; */
|
|
234
|
+
margin-bottom: 4px;
|
|
235
|
+
background-color: #F5F7FB;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.mobile-info-row {
|
|
239
|
+
display: flex;
|
|
240
|
+
flex-direction: row;
|
|
241
|
+
align-items: center;
|
|
242
|
+
padding: 3px 0;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.mobile-info-label {
|
|
246
|
+
font-weight: bold;
|
|
247
|
+
min-width: 130px;
|
|
248
|
+
color: #3a5877;
|
|
249
|
+
font-size: 13px;
|
|
250
|
+
text-transform: capitalize;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.mobile-info-value {
|
|
254
|
+
flex: 1;
|
|
255
|
+
color: var(--primary-color);
|
|
256
|
+
font-size: 13px;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.mobile-section-title {
|
|
260
|
+
color: #017e7f;
|
|
261
|
+
font-weight: bold;
|
|
262
|
+
font-size: 14px;
|
|
263
|
+
margin: 12px 0 0 0;
|
|
264
|
+
padding: 6px 0;
|
|
265
|
+
border-bottom: 1px solid #017e7f;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
form#input-form.mobile-form {
|
|
269
|
+
background-color: #ffffff;
|
|
270
|
+
padding: 8px;
|
|
271
|
+
}
|
|
121
272
|
`
|
|
122
273
|
]
|
|
123
274
|
}
|
|
@@ -125,14 +276,33 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
125
276
|
get context() {
|
|
126
277
|
var actions = []
|
|
127
278
|
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
279
|
+
if (isMobileDevice()) {
|
|
280
|
+
if (this._showTransferForm) {
|
|
281
|
+
actions.push({
|
|
282
|
+
title: i18next.t('button.transfer'),
|
|
283
|
+
action: this._onMobileTransfer.bind(this),
|
|
284
|
+
...CommonButtonStyles.transfer,
|
|
285
|
+
emphasis: { raised: true }
|
|
286
|
+
})
|
|
287
|
+
actions.push({
|
|
288
|
+
title: i18next.t('button.back'),
|
|
289
|
+
action: this._onMobileBack.bind(this),
|
|
290
|
+
...CommonButtonStyles.back
|
|
291
|
+
})
|
|
292
|
+
} else if (this._selectedInventory) {
|
|
293
|
+
actions.push({
|
|
294
|
+
title: i18next.t('button.select'),
|
|
295
|
+
action: this._onMobileSelect.bind(this),
|
|
296
|
+
...CommonButtonStyles.save
|
|
297
|
+
})
|
|
298
|
+
}
|
|
299
|
+
} else {
|
|
300
|
+
if (this._palletId || this._cartonId) {
|
|
301
|
+
actions.push({
|
|
132
302
|
title: i18next.t('button.done'),
|
|
133
303
|
action: this.done.bind(this)
|
|
134
|
-
}
|
|
135
|
-
|
|
304
|
+
})
|
|
305
|
+
}
|
|
136
306
|
}
|
|
137
307
|
|
|
138
308
|
return {
|
|
@@ -180,6 +350,22 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
180
350
|
?.shadowRoot.querySelector('input')
|
|
181
351
|
}
|
|
182
352
|
|
|
353
|
+
get reasonSelect() {
|
|
354
|
+
return this.shadowRoot.querySelector('select[name=reason]')
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
get remarkTextarea() {
|
|
358
|
+
return this.shadowRoot.querySelector('textarea[name=remark]')
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
get productInfoInput() {
|
|
362
|
+
return this.shadowRoot.querySelector('barcode-scanable-input[name=productInfo]')?.shadowRoot.querySelector('input')
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
get searchLocationInput() {
|
|
366
|
+
return this.shadowRoot.querySelector('barcode-scanable-input[name=searchLocation]')?.shadowRoot.querySelector('input')
|
|
367
|
+
}
|
|
368
|
+
|
|
183
369
|
focusOnPalletInput() {
|
|
184
370
|
setTimeout(() => this.palletInput.focus(), 100)
|
|
185
371
|
}
|
|
@@ -201,166 +387,337 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
201
387
|
}
|
|
202
388
|
|
|
203
389
|
render() {
|
|
390
|
+
const isMobile = isMobileDevice()
|
|
204
391
|
return html`
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
392
|
+
${!isMobile
|
|
393
|
+
? html`
|
|
394
|
+
<form id="info-form" class="multi-column-form">
|
|
395
|
+
<fieldset>
|
|
396
|
+
<label>${i18next.t('label.inventory_type')}</label>
|
|
397
|
+
<select name="inventoryType" @change="${e => this.inventoryTypeChangeHandler(e.currentTarget.value)}">
|
|
398
|
+
${Object.keys(INVENTORY_TYPES).map(key =>
|
|
399
|
+
this.refInventoryType === INVENTORY_TYPES[key].value
|
|
400
|
+
? html`
|
|
401
|
+
<option value="${INVENTORY_TYPES[key].value}" selected>
|
|
402
|
+
${i18next.t(`label.${INVENTORY_TYPES[key].name}`)}
|
|
403
|
+
</option>
|
|
404
|
+
`
|
|
405
|
+
: html`
|
|
406
|
+
<option value="${INVENTORY_TYPES[key].value}">
|
|
407
|
+
${i18next.t(`label.${INVENTORY_TYPES[key].name}`)}
|
|
408
|
+
</option>
|
|
409
|
+
`
|
|
410
|
+
)}
|
|
411
|
+
</select>
|
|
412
|
+
|
|
413
|
+
${this.refInventoryType === INVENTORY_TYPES.LOT.value
|
|
414
|
+
? html`
|
|
415
|
+
<label>${i18next.t('label.id')}</label>
|
|
416
|
+
<barcode-scanable-input
|
|
417
|
+
name="palletId"
|
|
418
|
+
custom-input
|
|
419
|
+
@keypress="${e => {
|
|
420
|
+
if (e.keyCode === 13) {
|
|
421
|
+
e.preventDefault()
|
|
422
|
+
if (this.palletInput.value) {
|
|
423
|
+
this._palletId = this.palletInput.value
|
|
424
|
+
}
|
|
425
|
+
this.fetchInventory()
|
|
426
|
+
}
|
|
427
|
+
}}"
|
|
428
|
+
></barcode-scanable-input>
|
|
429
|
+
`
|
|
430
|
+
: html`
|
|
431
|
+
<label>${i18next.t('label.id')}</label>
|
|
432
|
+
<barcode-scanable-input
|
|
433
|
+
name="cartonId"
|
|
434
|
+
custom-input
|
|
435
|
+
@keypress="${e => {
|
|
436
|
+
if (e.keyCode === 13) {
|
|
437
|
+
e.preventDefault()
|
|
438
|
+
if (this.cartonInput.value) {
|
|
439
|
+
this._cartonId = this.cartonInput.value
|
|
440
|
+
}
|
|
441
|
+
this.fetchInventory()
|
|
442
|
+
}
|
|
443
|
+
}}"
|
|
444
|
+
></barcode-scanable-input>
|
|
445
|
+
`}
|
|
446
|
+
</fieldset>
|
|
447
|
+
<fieldset>
|
|
448
|
+
<label>${i18next.t('label.product_info')}</label>
|
|
449
|
+
<barcode-scanable-input
|
|
450
|
+
name="productInfo"
|
|
451
|
+
custom-input
|
|
452
|
+
@keypress="${e => {
|
|
453
|
+
if (e.keyCode === 13) {
|
|
454
|
+
e.preventDefault()
|
|
455
|
+
this.fetchInventory()
|
|
235
456
|
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
this._cartonId = this.cartonInput.value
|
|
248
|
-
this.fetchInventory(this.cartonInput.value)
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}}"
|
|
252
|
-
></barcode-scanable-input>`}
|
|
253
|
-
</fieldset>
|
|
254
|
-
</form>
|
|
255
|
-
|
|
256
|
-
<div class="grist">
|
|
257
|
-
<data-grist
|
|
258
|
-
.mode=${isMobileDevice() ? 'LIST' : 'GRID'}
|
|
259
|
-
.config=${this._gristConfig}
|
|
260
|
-
.data=${this._data}
|
|
261
|
-
></data-grist>
|
|
262
|
-
</div>
|
|
263
|
-
|
|
264
|
-
<div class="input-section">
|
|
265
|
-
<div class="left-column">
|
|
266
|
-
<div class="single-column-form">
|
|
267
|
-
<fieldset>
|
|
268
|
-
<label class="content-title">${i18next.t('label.lot_id')}</label>
|
|
269
|
-
<label class="content">${this?._selectedInventory?.palletId || '-'}</label>
|
|
270
|
-
|
|
271
|
-
<label class="content-title">${i18next.t('label.from_location')}</label>
|
|
272
|
-
<label class="content">${this?._selectedInventory?.location?.name || '-'}</label>
|
|
273
|
-
|
|
274
|
-
<label class="content-title">${i18next.t('label.product')}</label>
|
|
275
|
-
<label class="content"
|
|
276
|
-
>${this?._selectedInventory?.product
|
|
277
|
-
? '(' + this._selectedInventory.product.sku + ') ' + this?._selectedInventory?.product?.name
|
|
278
|
-
: '-'}</label
|
|
279
|
-
>
|
|
280
|
-
<label class="content-title">${i18next.t('label.packing_type')}</label>
|
|
281
|
-
<label class="content">${this?._selectedInventory?.packingType || '-'}</label>
|
|
282
|
-
|
|
283
|
-
<label class="content-title">${i18next.t('label.qty')}</label>
|
|
284
|
-
<label class="content">${(this?._selectedInventory?.qty || 0).toString()}</label>
|
|
285
|
-
|
|
286
|
-
<label class="content-title">${i18next.t('label.reserve_qty')}</label>
|
|
287
|
-
<label class="content">${(this?._selectedInventory?.lockedQty || 0).toString()}</label>
|
|
288
|
-
|
|
289
|
-
<label class="content-title">${i18next.t('label.available_qty')}</label>
|
|
290
|
-
<label class="content">${(this?._selectedInventory?.availableQty || 0).toString()}</label>
|
|
291
|
-
|
|
292
|
-
<!-- <input name="fromLocationName" readonly /> -->
|
|
293
|
-
</fieldset>
|
|
294
|
-
</div>
|
|
295
|
-
</div>
|
|
296
|
-
<div class="right-column">
|
|
297
|
-
<form id="input-form" class="single-column-form">
|
|
298
|
-
<fieldset>
|
|
299
|
-
<label class="content-title">${i18next.t('label.transfer_qty')}</label>
|
|
300
|
-
<input
|
|
301
|
-
type="number"
|
|
302
|
-
name="qty"
|
|
303
|
-
min="0"
|
|
304
|
-
@change="${e => {
|
|
305
|
-
let qtyInputValue = parseFloat(this.qtyInput.value) || null
|
|
306
|
-
if (!Number.isInteger(parseFloat(this.qtyInput.value))) {
|
|
307
|
-
this.qtyInput.value = qtyInputValue
|
|
308
|
-
}
|
|
309
|
-
if (qtyInputValue < 0) {
|
|
310
|
-
this.qtyInput.value = 0
|
|
311
|
-
}
|
|
312
|
-
if (this._selectedInventory) {
|
|
313
|
-
if (this._selectedInventory.availableQty >= qtyInputValue) {
|
|
314
|
-
this._requireNewId = true
|
|
315
|
-
} else {
|
|
316
|
-
if (qtyInputValue > this._selectedInventory.availableQty) {
|
|
317
|
-
this.qtyInput.value = null
|
|
318
|
-
this.showToast({ message: 'Transferred quantity cannot be more than available quantity' })
|
|
457
|
+
}}"
|
|
458
|
+
></barcode-scanable-input>
|
|
459
|
+
|
|
460
|
+
<label>${i18next.t('label.location')}</label>
|
|
461
|
+
<barcode-scanable-input
|
|
462
|
+
name="searchLocation"
|
|
463
|
+
custom-input
|
|
464
|
+
@keypress="${e => {
|
|
465
|
+
if (e.keyCode === 13) {
|
|
466
|
+
e.preventDefault()
|
|
467
|
+
this.fetchInventory()
|
|
319
468
|
}
|
|
320
|
-
|
|
469
|
+
}}"
|
|
470
|
+
></barcode-scanable-input>
|
|
471
|
+
</fieldset>
|
|
472
|
+
</form>
|
|
473
|
+
|
|
474
|
+
<div class="grist">
|
|
475
|
+
<data-grist
|
|
476
|
+
.mode=${'GRID'}
|
|
477
|
+
.config=${this._gristConfig}
|
|
478
|
+
.data=${this._data}
|
|
479
|
+
></data-grist>
|
|
480
|
+
</div>
|
|
481
|
+
|
|
482
|
+
<div class="input-section">
|
|
483
|
+
<div class="left-column">
|
|
484
|
+
<div class="single-column-form">
|
|
485
|
+
<fieldset>
|
|
486
|
+
<label class="content-title">${this.refInventoryType === INVENTORY_TYPES.LOT.value ? i18next.t('label.lot_id') : i18next.t('label.carton_id')}</label>
|
|
487
|
+
<label class="content">${this.refInventoryType === INVENTORY_TYPES.LOT.value ? this?._selectedInventory?.palletId || '-' : this?._selectedInventory?.cartonId || '-'}</label>
|
|
488
|
+
|
|
489
|
+
<label class="content-title">${i18next.t('label.from_location')}</label>
|
|
490
|
+
<label class="content">${this?._selectedInventory?.location?.name || '-'}</label>
|
|
491
|
+
|
|
492
|
+
<label class="content-title">${i18next.t('label.product')}</label>
|
|
493
|
+
<label class="content"
|
|
494
|
+
>${this?._selectedInventory?.product
|
|
495
|
+
? '(' + this._selectedInventory.product.sku + ') ' + this?._selectedInventory?.product?.name
|
|
496
|
+
: '-'}</label
|
|
497
|
+
>
|
|
498
|
+
<label class="content-title">${i18next.t('label.packing_type')}</label>
|
|
499
|
+
<label class="content">${this?._selectedInventory?.packingType || '-'}</label>
|
|
500
|
+
|
|
501
|
+
<label class="content-title">${i18next.t('label.qty')}</label>
|
|
502
|
+
<label class="content">${(this?._selectedInventory?.qty || 0).toString()}</label>
|
|
503
|
+
|
|
504
|
+
<label class="content-title">${i18next.t('label.reserve_qty')}</label>
|
|
505
|
+
<label class="content">${(this?._selectedInventory?.lockedQty || 0).toString()}</label>
|
|
506
|
+
|
|
507
|
+
<label class="content-title">${i18next.t('label.available_qty')}</label>
|
|
508
|
+
<label class="content">${(this?._selectedInventory?.availableQty || 0).toString()}</label>
|
|
509
|
+
</fieldset>
|
|
510
|
+
</div>
|
|
511
|
+
</div>
|
|
512
|
+
<div class="right-column">
|
|
513
|
+
<form id="input-form" class="single-column-form">
|
|
514
|
+
<fieldset>
|
|
515
|
+
<label class="content-title">${i18next.t('label.transfer_qty')}</label>
|
|
516
|
+
<input
|
|
517
|
+
type="number"
|
|
518
|
+
name="qty"
|
|
519
|
+
min="0"
|
|
520
|
+
@change="${e => {
|
|
521
|
+
let qtyInputValue = parseFloat(this.qtyInput.value) || null
|
|
522
|
+
if (!Number.isInteger(parseFloat(this.qtyInput.value))) {
|
|
523
|
+
this.qtyInput.value = qtyInputValue
|
|
524
|
+
}
|
|
525
|
+
if (qtyInputValue < 0) {
|
|
526
|
+
this.qtyInput.value = 0
|
|
527
|
+
}
|
|
528
|
+
if (this._selectedInventory) {
|
|
529
|
+
if (this._selectedInventory.availableQty >= qtyInputValue) {
|
|
530
|
+
this._requireNewId = true
|
|
531
|
+
} else {
|
|
532
|
+
if (qtyInputValue > this._selectedInventory.availableQty) {
|
|
533
|
+
this.qtyInput.value = null
|
|
534
|
+
this.showToast({ message: 'Transferred quantity cannot be more than available quantity' })
|
|
535
|
+
}
|
|
536
|
+
this._requireNewId = false
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}}"
|
|
540
|
+
@keypress="${e => {
|
|
541
|
+
if (e.keyCode === 13) {
|
|
542
|
+
e.preventDefault()
|
|
543
|
+
if (parseFloat(this.qtyInput.value) < 0) {
|
|
544
|
+
this.qtyInput.value = 0
|
|
545
|
+
} else if (this.qtyInput.value && this.toLocationNameInput.value === '') {
|
|
546
|
+
this.focusOnToLocationInput()
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}}"
|
|
550
|
+
/>
|
|
551
|
+
|
|
552
|
+
<label class="content-title">${i18next.t('label.to_location')}</label>
|
|
553
|
+
<barcode-scanable-input
|
|
554
|
+
name="toLocationName"
|
|
555
|
+
custom-input
|
|
556
|
+
@keypress="${this._handleToLocationEnter.bind(this)}"
|
|
557
|
+
@input="${() => { this._locationRecommendationChecked = false }}"
|
|
558
|
+
></barcode-scanable-input>
|
|
559
|
+
|
|
560
|
+
${this.refInventoryType === INVENTORY_TYPES.LOT.value
|
|
561
|
+
? this._requireNewId
|
|
562
|
+
? html`
|
|
563
|
+
<label class="content-title">${i18next.t('label.new_lot_id')}</label>
|
|
564
|
+
<barcode-scanable-input
|
|
565
|
+
name="newLotId"
|
|
566
|
+
custom-input
|
|
567
|
+
@keypress="${e => {
|
|
568
|
+
if (e.keyCode === 13) {
|
|
569
|
+
e.preventDefault()
|
|
570
|
+
this.transferInventory(e)
|
|
571
|
+
}
|
|
572
|
+
}}"
|
|
573
|
+
></barcode-scanable-input>
|
|
574
|
+
`
|
|
575
|
+
: ``
|
|
576
|
+
: html`
|
|
577
|
+
<label class="content-title">${i18next.t('label.new_carton_id')}</label>
|
|
578
|
+
<barcode-scanable-input
|
|
579
|
+
name="newCartonId"
|
|
580
|
+
custom-input
|
|
581
|
+
@keypress="${e => {
|
|
582
|
+
if (e.keyCode === 13) {
|
|
583
|
+
e.preventDefault()
|
|
584
|
+
this.transferInventory(e)
|
|
585
|
+
}
|
|
586
|
+
}}"
|
|
587
|
+
></barcode-scanable-input>
|
|
588
|
+
`}
|
|
589
|
+
|
|
590
|
+
${this._showReasonField ? html`
|
|
591
|
+
<label class="content-title">${i18next.t('label.reason')}</label>
|
|
592
|
+
<select name="reason" @change="${e => {
|
|
593
|
+
this._showRemarkField = e.currentTarget.value.toUpperCase() === 'OTHERS'
|
|
594
|
+
}}">
|
|
595
|
+
<option value=""></option>
|
|
596
|
+
${(this._transferCodes || []).map(code => html`
|
|
597
|
+
<option value="${code.name}">${code.description || code.name}</option>
|
|
598
|
+
`)}
|
|
599
|
+
</select>
|
|
600
|
+
` : ''}
|
|
601
|
+
|
|
602
|
+
${this._showRemarkField ? html`
|
|
603
|
+
<label class="content-title">${i18next.t('label.remark')}</label>
|
|
604
|
+
<textarea name="remark" rows="3"></textarea>
|
|
605
|
+
` : ''}
|
|
606
|
+
|
|
607
|
+
<div class="button-container">
|
|
608
|
+
<button @click=${this.transferInventory.bind(this)}>${i18next.t('button.transfer')}</button>
|
|
609
|
+
</div>
|
|
610
|
+
</fieldset>
|
|
611
|
+
</form>
|
|
612
|
+
</div>
|
|
613
|
+
</div>
|
|
614
|
+
`
|
|
615
|
+
: this._showTransferForm
|
|
616
|
+
? html`
|
|
617
|
+
<div class="mobile-info-section">
|
|
618
|
+
<div class="mobile-info-row">
|
|
619
|
+
<div class="mobile-info-label">${this.refInventoryType === INVENTORY_TYPES.LOT.value ? i18next.t('label.lot_id') : i18next.t('label.carton_id')}</div>
|
|
620
|
+
<div class="mobile-info-value">${this.refInventoryType === INVENTORY_TYPES.LOT.value ? this._selectedInventory?.palletId || '-' : this._selectedInventory?.cartonId || '-'}</div>
|
|
621
|
+
</div>
|
|
622
|
+
<div class="mobile-info-row">
|
|
623
|
+
<div class="mobile-info-label">${i18next.t('label.product')}</div>
|
|
624
|
+
<div class="mobile-info-value">${this._selectedInventory?.product ? '(' + this._selectedInventory.product.sku + ') ' + this._selectedInventory.product.name : '-'}</div>
|
|
625
|
+
</div>
|
|
626
|
+
<div class="mobile-info-row">
|
|
627
|
+
<div class="mobile-info-label">${i18next.t('label.from_location')}</div>
|
|
628
|
+
<div class="mobile-info-value">${this._selectedInventory?.location?.name || '-'}</div>
|
|
629
|
+
</div>
|
|
630
|
+
<div class="mobile-info-row">
|
|
631
|
+
<div class="mobile-info-label">${i18next.t('label.packing_type')}</div>
|
|
632
|
+
<div class="mobile-info-value">${this._selectedInventory?.packingType || '-'}</div>
|
|
633
|
+
</div>
|
|
634
|
+
<div class="mobile-info-row">
|
|
635
|
+
<div class="mobile-info-label">${i18next.t('label.qty')}</div>
|
|
636
|
+
<div class="mobile-info-value">${(this._selectedInventory?.qty || 0).toString()}</div>
|
|
637
|
+
</div>
|
|
638
|
+
<div class="mobile-info-row">
|
|
639
|
+
<div class="mobile-info-label">${i18next.t('label.reserve_qty')}</div>
|
|
640
|
+
<div class="mobile-info-value">${(this._selectedInventory?.lockedQty || 0).toString()}</div>
|
|
641
|
+
</div>
|
|
642
|
+
<div class="mobile-info-row">
|
|
643
|
+
<div class="mobile-info-label">${i18next.t('label.available_qty')}</div>
|
|
644
|
+
<div class="mobile-info-value">${(this._selectedInventory?.availableQty || 0).toString()}</div>
|
|
645
|
+
</div>
|
|
646
|
+
</div>
|
|
647
|
+
|
|
648
|
+
<form id="input-form" class="mobile-form">
|
|
649
|
+
<fieldset>
|
|
650
|
+
<label>${i18next.t('label.transfer_qty')}</label>
|
|
651
|
+
<input
|
|
652
|
+
type="number"
|
|
653
|
+
name="qty"
|
|
654
|
+
min="0"
|
|
655
|
+
@change="${_ => {
|
|
656
|
+
let qtyInputValue = parseFloat(this.qtyInput.value) || null
|
|
657
|
+
if (!Number.isInteger(parseFloat(this.qtyInput.value))) {
|
|
658
|
+
this.qtyInput.value = qtyInputValue
|
|
321
659
|
}
|
|
322
|
-
|
|
323
|
-
}}"
|
|
324
|
-
@keypress="${e => {
|
|
325
|
-
if (e.keyCode === 13) {
|
|
326
|
-
e.preventDefault()
|
|
327
|
-
if (parseFloat(this.qtyInput.value) < 0) {
|
|
660
|
+
if (qtyInputValue < 0) {
|
|
328
661
|
this.qtyInput.value = 0
|
|
329
|
-
} else if (this.qtyInput.value && this.toLocationNameInput.value === '') {
|
|
330
|
-
this.focusOnToLocationInput()
|
|
331
662
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
<label class="content-title">${i18next.t('label.to_location')}</label>
|
|
337
|
-
<barcode-scanable-input
|
|
338
|
-
name="toLocationName"
|
|
339
|
-
custom-input
|
|
340
|
-
@keypress="${e => {
|
|
341
|
-
if (e.keyCode === 13) {
|
|
342
|
-
e.preventDefault()
|
|
343
|
-
if (this.toLocationNameInput.value) {
|
|
344
|
-
if (this.refInventoryType === INVENTORY_TYPES.LOT.value) {
|
|
345
|
-
if (this._requireNewId) {
|
|
346
|
-
this.focusOnNewLotInput()
|
|
347
|
-
} else {
|
|
348
|
-
this.transferInventory(e)
|
|
349
|
-
}
|
|
663
|
+
if (this._selectedInventory) {
|
|
664
|
+
if (this._selectedInventory.availableQty >= qtyInputValue) {
|
|
665
|
+
this._requireNewId = true
|
|
350
666
|
} else {
|
|
351
|
-
this.
|
|
667
|
+
if (qtyInputValue > this._selectedInventory.availableQty) {
|
|
668
|
+
this.qtyInput.value = null
|
|
669
|
+
this.showToast({ message: 'Transferred quantity cannot be more than available quantity' })
|
|
670
|
+
}
|
|
671
|
+
this._requireNewId = false
|
|
352
672
|
}
|
|
353
|
-
// this.transferInventory(e)
|
|
354
673
|
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
|
|
674
|
+
}}"
|
|
675
|
+
@keypress="${e => {
|
|
676
|
+
if (e.keyCode === 13) {
|
|
677
|
+
e.preventDefault()
|
|
678
|
+
if (parseFloat(this.qtyInput.value) < 0) {
|
|
679
|
+
this.qtyInput.value = 0
|
|
680
|
+
} else if (this.qtyInput.value && this.toLocationNameInput.value === '') {
|
|
681
|
+
this.focusOnToLocationInput()
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}}"
|
|
685
|
+
/>
|
|
686
|
+
</fieldset>
|
|
687
|
+
|
|
688
|
+
<fieldset>
|
|
689
|
+
<label>${i18next.t('label.to_location')}</label>
|
|
690
|
+
<barcode-scanable-input
|
|
691
|
+
name="toLocationName"
|
|
692
|
+
custom-input
|
|
693
|
+
@keypress="${this._handleToLocationEnter.bind(this)}"
|
|
694
|
+
@input="${() => { this._locationRecommendationChecked = false }}"
|
|
695
|
+
></barcode-scanable-input>
|
|
696
|
+
</fieldset>
|
|
358
697
|
|
|
359
698
|
${this.refInventoryType === INVENTORY_TYPES.LOT.value
|
|
360
699
|
? this._requireNewId
|
|
361
|
-
? html`
|
|
700
|
+
? html`
|
|
701
|
+
<fieldset>
|
|
702
|
+
<label>${i18next.t('label.new_lot_id')}</label>
|
|
703
|
+
<barcode-scanable-input
|
|
704
|
+
name="newLotId"
|
|
705
|
+
custom-input
|
|
706
|
+
@keypress="${e => {
|
|
707
|
+
if (e.keyCode === 13) {
|
|
708
|
+
e.preventDefault()
|
|
709
|
+
this.transferInventory(e)
|
|
710
|
+
}
|
|
711
|
+
}}"
|
|
712
|
+
></barcode-scanable-input>
|
|
713
|
+
</fieldset>
|
|
714
|
+
`
|
|
715
|
+
: ``
|
|
716
|
+
: html`
|
|
717
|
+
<fieldset>
|
|
718
|
+
<label>${i18next.t('label.new_carton_id')}</label>
|
|
362
719
|
<barcode-scanable-input
|
|
363
|
-
name="
|
|
720
|
+
name="newCartonId"
|
|
364
721
|
custom-input
|
|
365
722
|
@keypress="${e => {
|
|
366
723
|
if (e.keyCode === 13) {
|
|
@@ -368,29 +725,127 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
368
725
|
this.transferInventory(e)
|
|
369
726
|
}
|
|
370
727
|
}}"
|
|
371
|
-
></barcode-scanable-input
|
|
372
|
-
|
|
373
|
-
: html`
|
|
374
|
-
<label class="content-title">${i18next.t('label.new_carton_id')}</label>
|
|
375
|
-
<barcode-scanable-input
|
|
376
|
-
name="newCartonId"
|
|
377
|
-
custom-input
|
|
378
|
-
@keypress="${e => {
|
|
379
|
-
if (e.keyCode === 13) {
|
|
380
|
-
e.preventDefault()
|
|
381
|
-
this.transferInventory(e)
|
|
382
|
-
}
|
|
383
|
-
}}"
|
|
384
|
-
></barcode-scanable-input>
|
|
728
|
+
></barcode-scanable-input>
|
|
729
|
+
</fieldset>
|
|
385
730
|
`}
|
|
386
731
|
|
|
387
|
-
|
|
388
|
-
<
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
732
|
+
${this._showReasonField ? html`
|
|
733
|
+
<fieldset>
|
|
734
|
+
<label>${i18next.t('label.reason')}</label>
|
|
735
|
+
<select name="reason" @change="${e => {
|
|
736
|
+
this._showRemarkField = e.currentTarget.value.toUpperCase() === 'OTHERS'
|
|
737
|
+
}}">
|
|
738
|
+
<option value=""></option>
|
|
739
|
+
${(this._transferCodes || []).map(code => html`
|
|
740
|
+
<option value="${code.name}">${code.description || code.name}</option>
|
|
741
|
+
`)}
|
|
742
|
+
</select>
|
|
743
|
+
</fieldset>
|
|
744
|
+
` : ''}
|
|
745
|
+
|
|
746
|
+
${this._showRemarkField ? html`
|
|
747
|
+
<fieldset>
|
|
748
|
+
<label>${i18next.t('label.remark')}</label>
|
|
749
|
+
<textarea name="remark" rows="3"></textarea>
|
|
750
|
+
</fieldset>
|
|
751
|
+
` : ''}
|
|
752
|
+
</form>
|
|
753
|
+
`
|
|
754
|
+
: html`
|
|
755
|
+
<form id="info-form" class="mobile-form">
|
|
756
|
+
<fieldset class="side-by-side-row">
|
|
757
|
+
<fieldset>
|
|
758
|
+
<label>${i18next.t('label.inventory_type')}</label>
|
|
759
|
+
<select name="inventoryType" @change="${e => this.inventoryTypeChangeHandler(e.currentTarget.value)}">
|
|
760
|
+
${Object.keys(INVENTORY_TYPES).map(key =>
|
|
761
|
+
this.refInventoryType === INVENTORY_TYPES[key].value
|
|
762
|
+
? html`
|
|
763
|
+
<option value="${INVENTORY_TYPES[key].value}" selected>
|
|
764
|
+
${i18next.t(`label.${INVENTORY_TYPES[key].name}`)}
|
|
765
|
+
</option>
|
|
766
|
+
`
|
|
767
|
+
: html`
|
|
768
|
+
<option value="${INVENTORY_TYPES[key].value}">
|
|
769
|
+
${i18next.t(`label.${INVENTORY_TYPES[key].name}`)}
|
|
770
|
+
</option>
|
|
771
|
+
`
|
|
772
|
+
)}
|
|
773
|
+
</select>
|
|
774
|
+
</fieldset>
|
|
775
|
+
<fieldset>
|
|
776
|
+
<label>${i18next.t('label.id')}</label>
|
|
777
|
+
${this.refInventoryType === INVENTORY_TYPES.LOT.value
|
|
778
|
+
? html`
|
|
779
|
+
<barcode-scanable-input
|
|
780
|
+
name="palletId"
|
|
781
|
+
custom-input
|
|
782
|
+
@keypress="${e => {
|
|
783
|
+
if (e.keyCode === 13) {
|
|
784
|
+
e.preventDefault()
|
|
785
|
+
if (this.palletInput.value) {
|
|
786
|
+
this._palletId = this.palletInput.value
|
|
787
|
+
}
|
|
788
|
+
this.fetchInventory()
|
|
789
|
+
}
|
|
790
|
+
}}"
|
|
791
|
+
></barcode-scanable-input>
|
|
792
|
+
`
|
|
793
|
+
: html`
|
|
794
|
+
<barcode-scanable-input
|
|
795
|
+
name="cartonId"
|
|
796
|
+
custom-input
|
|
797
|
+
@keypress="${e => {
|
|
798
|
+
if (e.keyCode === 13) {
|
|
799
|
+
e.preventDefault()
|
|
800
|
+
if (this.cartonInput.value) {
|
|
801
|
+
this._cartonId = this.cartonInput.value
|
|
802
|
+
}
|
|
803
|
+
this.fetchInventory()
|
|
804
|
+
}
|
|
805
|
+
}}"
|
|
806
|
+
></barcode-scanable-input>
|
|
807
|
+
`}
|
|
808
|
+
</fieldset>
|
|
809
|
+
</fieldset>
|
|
810
|
+
<fieldset class="side-by-side-row">
|
|
811
|
+
<fieldset>
|
|
812
|
+
<label>${i18next.t('label.product_info')}</label>
|
|
813
|
+
<barcode-scanable-input
|
|
814
|
+
name="productInfo"
|
|
815
|
+
custom-input
|
|
816
|
+
@keypress="${e => {
|
|
817
|
+
if (e.keyCode === 13) {
|
|
818
|
+
e.preventDefault()
|
|
819
|
+
this.fetchInventory()
|
|
820
|
+
}
|
|
821
|
+
}}"
|
|
822
|
+
></barcode-scanable-input>
|
|
823
|
+
</fieldset>
|
|
824
|
+
<fieldset>
|
|
825
|
+
<label>${i18next.t('label.location')}</label>
|
|
826
|
+
<barcode-scanable-input
|
|
827
|
+
name="searchLocation"
|
|
828
|
+
custom-input
|
|
829
|
+
@keypress="${e => {
|
|
830
|
+
if (e.keyCode === 13) {
|
|
831
|
+
e.preventDefault()
|
|
832
|
+
this.fetchInventory()
|
|
833
|
+
}
|
|
834
|
+
}}"
|
|
835
|
+
></barcode-scanable-input>
|
|
836
|
+
</fieldset>
|
|
837
|
+
</fieldset>
|
|
838
|
+
</form>
|
|
839
|
+
|
|
840
|
+
<div class="grist">
|
|
841
|
+
<data-grist
|
|
842
|
+
.mode=${'LIST'}
|
|
843
|
+
.config=${this._gristConfig}
|
|
844
|
+
.data=${this._data}
|
|
845
|
+
.selectedRecords=${this._selectedInventory ? [this._selectedInventory] : []}
|
|
846
|
+
></data-grist>
|
|
847
|
+
</div>
|
|
848
|
+
`}
|
|
394
849
|
`
|
|
395
850
|
}
|
|
396
851
|
|
|
@@ -399,7 +854,22 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
399
854
|
this._isExecuting = false
|
|
400
855
|
}
|
|
401
856
|
|
|
402
|
-
pageInitialized() {
|
|
857
|
+
async pageInitialized() {
|
|
858
|
+
this._transferCodes = await getCodeByName('TRANSFER_CODES')
|
|
859
|
+
|
|
860
|
+
const [locationRecommendationLevel, stackingOptionLimitStr] = await Promise.all([
|
|
861
|
+
fetchSettingRule('location-recommendation-level'),
|
|
862
|
+
fetchSettingRule('stacking-option-limit')
|
|
863
|
+
])
|
|
864
|
+
this._locationRecommendationLevel = (locationRecommendationLevel || '').toUpperCase().trim()
|
|
865
|
+
try {
|
|
866
|
+
const parsed = JSON.parse(stackingOptionLimitStr || '{}')
|
|
867
|
+
this._stackingOptionLimit = { min: Number(parsed.Min) || 1, max: Number(parsed.Max) || 1 }
|
|
868
|
+
} catch {
|
|
869
|
+
this._stackingOptionLimit = { min: 1, max: 1 }
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
await this._fetchLocations()
|
|
403
873
|
this.refInventoryType = INVENTORY_TYPES.LOT.value
|
|
404
874
|
this._gristConfig = {
|
|
405
875
|
list: {
|
|
@@ -424,9 +894,11 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
424
894
|
handlers: {
|
|
425
895
|
click: async (columns, data, column, record, rowIndex) => {
|
|
426
896
|
try {
|
|
427
|
-
if (this.
|
|
428
|
-
|
|
429
|
-
|
|
897
|
+
if (this._selectedInventory) this._selectedInventory['__selected__'] = false
|
|
898
|
+
record['__selected__'] = true
|
|
899
|
+
this._selectedInventory = record
|
|
900
|
+
this._resetReasonFields()
|
|
901
|
+
this.updateContext()
|
|
430
902
|
} catch (ex) {
|
|
431
903
|
console.log(ex)
|
|
432
904
|
} finally {
|
|
@@ -535,23 +1007,48 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
535
1007
|
else this.focusOnCartonInput()
|
|
536
1008
|
}
|
|
537
1009
|
|
|
538
|
-
|
|
1010
|
+
_resetReasonFields() {
|
|
1011
|
+
this._showReasonField = false
|
|
1012
|
+
this._showRemarkField = false
|
|
1013
|
+
this._locationRecommendationChecked = false
|
|
1014
|
+
if (this.reasonSelect) this.reasonSelect.value = ''
|
|
1015
|
+
if (this.remarkTextarea) this.remarkTextarea.value = ''
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
async fetchInventory() {
|
|
539
1019
|
try {
|
|
1020
|
+
this._resetReasonFields()
|
|
540
1021
|
let filters = []
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
filters.push({
|
|
549
|
-
name: 'cartonId',
|
|
550
|
-
operator: 'eq',
|
|
551
|
-
value: inventoryRefId
|
|
552
|
-
})
|
|
1022
|
+
|
|
1023
|
+
const idValue =
|
|
1024
|
+
this.refInventoryType === INVENTORY_TYPES.LOT.value ? this.palletInput?.value : this.cartonInput?.value
|
|
1025
|
+
|
|
1026
|
+
if (idValue) {
|
|
1027
|
+
const idField = this.refInventoryType === INVENTORY_TYPES.LOT.value ? 'palletId' : 'cartonId'
|
|
1028
|
+
filters.push({ name: idField, operator: 'eq', value: idValue })
|
|
553
1029
|
}
|
|
554
1030
|
|
|
1031
|
+
const productInfoValue = this.productInfoInput?.value?.trim()
|
|
1032
|
+
const searchLocationValue = this.searchLocationInput?.value?.trim()
|
|
1033
|
+
|
|
1034
|
+
if (searchLocationValue) {
|
|
1035
|
+
await this._fetchLocations()
|
|
1036
|
+
const locationExists = (this._locations || []).some(l => l.name === searchLocationValue)
|
|
1037
|
+
if (!locationExists) {
|
|
1038
|
+
throw new Error(i18next.t('text.location_not_found'))
|
|
1039
|
+
}
|
|
1040
|
+
filters.push({ name: 'locationName', operator: 'eq', value: searchLocationValue })
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
if (productInfoValue) {
|
|
1044
|
+
filters.push({ name: 'productInfo', operator: 'like', value: productInfoValue })
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
if (filters.length === 0) return
|
|
1048
|
+
|
|
1049
|
+
filters.push({ name: 'status', operator: 'eq', value: 'STORED' })
|
|
1050
|
+
filters.push({ name: 'refInventoryType', operator: 'eq', value: this.refInventoryType })
|
|
1051
|
+
|
|
555
1052
|
const response = await client.query({
|
|
556
1053
|
query: gql`
|
|
557
1054
|
query inventories($filters: [Filter!]) {
|
|
@@ -569,6 +1066,7 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
569
1066
|
sku
|
|
570
1067
|
name
|
|
571
1068
|
description
|
|
1069
|
+
allowStackingOption
|
|
572
1070
|
}
|
|
573
1071
|
qty
|
|
574
1072
|
lockedQty
|
|
@@ -584,22 +1082,24 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
584
1082
|
}
|
|
585
1083
|
}
|
|
586
1084
|
`,
|
|
587
|
-
variables: {
|
|
588
|
-
filters: [...filters, { name: 'status', operator: 'eq', value: 'STORED' }]
|
|
589
|
-
}
|
|
1085
|
+
variables: { filters }
|
|
590
1086
|
})
|
|
591
1087
|
|
|
592
1088
|
if (!response.errors) {
|
|
593
|
-
// let foundId = response.data.inventories.total
|
|
594
1089
|
if (response.data.inventories.total == 0) {
|
|
595
|
-
if (
|
|
596
|
-
this.
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
1090
|
+
if (idValue && !productInfoValue && !searchLocationValue) {
|
|
1091
|
+
if (this.refInventoryType === INVENTORY_TYPES.LOT.value) {
|
|
1092
|
+
this.focusOnPalletInput()
|
|
1093
|
+
throw new Error(i18next.t('text.lot_id_not_found'))
|
|
1094
|
+
} else {
|
|
1095
|
+
this.focusOnCartonInput()
|
|
1096
|
+
throw new Error(i18next.t('text.carton_id_not_found'))
|
|
1097
|
+
}
|
|
1098
|
+
} else if ((productInfoValue && !idValue && !searchLocationValue) || (searchLocationValue && !idValue && !productInfoValue)) {
|
|
1099
|
+
throw new Error(i18next.t('text.there_is_no_inventory_for_the_product'))
|
|
602
1100
|
}
|
|
1101
|
+
|
|
1102
|
+
this._selectedInventory = null
|
|
603
1103
|
}
|
|
604
1104
|
|
|
605
1105
|
this._data = {
|
|
@@ -612,7 +1112,7 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
612
1112
|
})
|
|
613
1113
|
}
|
|
614
1114
|
|
|
615
|
-
if (this.refInventoryType === INVENTORY_TYPES.LOT.value) {
|
|
1115
|
+
if (this.refInventoryType === INVENTORY_TYPES.LOT.value && !productInfoValue && !searchLocationValue && response.data.inventories.total > 0) {
|
|
616
1116
|
this._selectedInventory = this._data.records[0]
|
|
617
1117
|
}
|
|
618
1118
|
|
|
@@ -635,6 +1135,16 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
635
1135
|
this._isExecuting = true
|
|
636
1136
|
this._validate()
|
|
637
1137
|
|
|
1138
|
+
if (!this._locationRecommendationChecked) {
|
|
1139
|
+
const locationName = this.toLocationNameInput.value
|
|
1140
|
+
const confirmed = await this._checkLocationRecommendation(locationName)
|
|
1141
|
+
if (!confirmed) {
|
|
1142
|
+
this.toLocationNameInput.value = ''
|
|
1143
|
+
return
|
|
1144
|
+
}
|
|
1145
|
+
this._locationRecommendationChecked = true
|
|
1146
|
+
}
|
|
1147
|
+
|
|
638
1148
|
const result = await CustomAlert({
|
|
639
1149
|
title: i18next.t('title.are_you_sure'),
|
|
640
1150
|
text: i18next.t('text.transfer_inventory_to_different_location'),
|
|
@@ -652,7 +1162,9 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
652
1162
|
cartonId: this.refInventoryType === INVENTORY_TYPES.CARTON.value ? this.newCartonInput?.value : null,
|
|
653
1163
|
fromLocationName: this._selectedInventory.location.name,
|
|
654
1164
|
toLocationName: this.toLocationNameInput.value,
|
|
655
|
-
qty: parseFloat(this.qtyInput.value)
|
|
1165
|
+
qty: parseFloat(this.qtyInput.value),
|
|
1166
|
+
reason: this._showReasonField ? this.reasonSelect?.value || null : null,
|
|
1167
|
+
remark: this._showRemarkField ? this.remarkTextarea?.value?.trim() || null : null
|
|
656
1168
|
}
|
|
657
1169
|
|
|
658
1170
|
const response = await client.mutate({
|
|
@@ -664,6 +1176,8 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
664
1176
|
$fromLocationName: String!
|
|
665
1177
|
$toLocationName: String!
|
|
666
1178
|
$qty: Float!
|
|
1179
|
+
$reason: String
|
|
1180
|
+
$remark: String
|
|
667
1181
|
) {
|
|
668
1182
|
inventoryTransfer(
|
|
669
1183
|
originPalletId: $originPalletId
|
|
@@ -672,6 +1186,8 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
672
1186
|
fromLocationName: $fromLocationName
|
|
673
1187
|
toLocationName: $toLocationName
|
|
674
1188
|
qty: $qty
|
|
1189
|
+
reason: $reason
|
|
1190
|
+
remark: $remark
|
|
675
1191
|
)
|
|
676
1192
|
}
|
|
677
1193
|
`,
|
|
@@ -686,6 +1202,15 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
686
1202
|
this.updateContext()
|
|
687
1203
|
}
|
|
688
1204
|
} catch (e) {
|
|
1205
|
+
// HANDLE EDGE SCENARIOS
|
|
1206
|
+
if (e.message === 'Please select a reason') {
|
|
1207
|
+
this._showReasonField = true
|
|
1208
|
+
this.reasonSelect?.focus()
|
|
1209
|
+
} else if (e.message === 'Please enter a remark') {
|
|
1210
|
+
this._showReasonField = true
|
|
1211
|
+
this._showRemarkField = true
|
|
1212
|
+
this.remarkTextarea?.focus()
|
|
1213
|
+
}
|
|
689
1214
|
this.showToast(e)
|
|
690
1215
|
} finally {
|
|
691
1216
|
this._isExecuting = false
|
|
@@ -719,8 +1244,32 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
719
1244
|
throw new Error(i18next.t('text.from_location_is_same_as_to_location'))
|
|
720
1245
|
}
|
|
721
1246
|
|
|
722
|
-
if (this.refInventoryType === INVENTORY_TYPES.CARTON.value && this?.cartonInput?.value.trim() == '') {
|
|
723
|
-
|
|
1247
|
+
// if (this.refInventoryType === INVENTORY_TYPES.CARTON.value && this?.cartonInput?.value.trim() == '') {
|
|
1248
|
+
// throw new Error(i18next.t('text.required_carton_id'))
|
|
1249
|
+
// }
|
|
1250
|
+
|
|
1251
|
+
const toLocationName = this.toLocationNameInput.value
|
|
1252
|
+
const toLocation = (this._locations || []).find(l => l.name === toLocationName)
|
|
1253
|
+
const toIsSpecial = this._isSpecialLocationType(toLocation?.type)
|
|
1254
|
+
|
|
1255
|
+
const fromLocationName = this._selectedInventory?.location?.name
|
|
1256
|
+
const fromLocationType = (this._locations || []).find(l => l.name === fromLocationName)?.type
|
|
1257
|
+
const fromIsSpecial = this._isSpecialLocationType(fromLocationType)
|
|
1258
|
+
|
|
1259
|
+
if (toIsSpecial !== fromIsSpecial) {
|
|
1260
|
+
if (!this.reasonSelect?.value) {
|
|
1261
|
+
this._showReasonField = true
|
|
1262
|
+
this.reasonSelect?.focus()
|
|
1263
|
+
throw new Error(i18next.t('text.please_select_a_reason'))
|
|
1264
|
+
}
|
|
1265
|
+
if (this.reasonSelect.value.toUpperCase() === 'OTHERS' && !this.remarkTextarea?.value?.trim()) {
|
|
1266
|
+
this._showRemarkField = true
|
|
1267
|
+
this.remarkTextarea?.focus()
|
|
1268
|
+
throw new Error(i18next.t('text.please_enter_a_remark'))
|
|
1269
|
+
}
|
|
1270
|
+
} else {
|
|
1271
|
+
this._showReasonField = false
|
|
1272
|
+
this._showRemarkField = false
|
|
724
1273
|
}
|
|
725
1274
|
}
|
|
726
1275
|
|
|
@@ -733,12 +1282,196 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
|
|
|
733
1282
|
this.cartonInput.value = ''
|
|
734
1283
|
this.cartonId = ''
|
|
735
1284
|
}
|
|
1285
|
+
if (this?.productInfoInput) this.productInfoInput.value = ''
|
|
1286
|
+
if (this?.searchLocationInput) this.searchLocationInput.value = ''
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
_onMobileSelect() {
|
|
1290
|
+
if (!this._selectedInventory) return
|
|
1291
|
+
this._resetReasonFields()
|
|
1292
|
+
this._showTransferForm = true
|
|
1293
|
+
this.updateContext()
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
_onMobileBack() {
|
|
1297
|
+
this._resetReasonFields()
|
|
1298
|
+
this._showTransferForm = false
|
|
1299
|
+
this.updateContext()
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
_onMobileTransfer() {
|
|
1303
|
+
this.transferInventory({ stopPropagation: () => {}, preventDefault: () => {} })
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
async _fetchLocations() {
|
|
1307
|
+
try {
|
|
1308
|
+
const response = await client.query({
|
|
1309
|
+
query: gql`
|
|
1310
|
+
query {
|
|
1311
|
+
locations {
|
|
1312
|
+
items {
|
|
1313
|
+
id
|
|
1314
|
+
name
|
|
1315
|
+
type
|
|
1316
|
+
status
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
`
|
|
1321
|
+
})
|
|
1322
|
+
if (!response.errors) {
|
|
1323
|
+
this._locations = response.data.locations.items
|
|
1324
|
+
}
|
|
1325
|
+
} catch (e) {
|
|
1326
|
+
console.error('Failed to fetch locations', e)
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
_handleToLocationEnter(e) {
|
|
1331
|
+
if (e.keyCode === 13) {
|
|
1332
|
+
e.preventDefault()
|
|
1333
|
+
if (this.toLocationNameInput?.value) {
|
|
1334
|
+
this._validateAndProceedToLocation()
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
async _checkLocationRecommendation(toLocationName) {
|
|
1340
|
+
const level = this._locationRecommendationLevel
|
|
1341
|
+
if (!level) return true
|
|
1342
|
+
|
|
1343
|
+
const fromSku = this._selectedInventory?.product?.sku
|
|
1344
|
+
|
|
1345
|
+
const response = await client.query({
|
|
1346
|
+
query: gql`
|
|
1347
|
+
query inventories($filters: [Filter!]) {
|
|
1348
|
+
inventories(filters: $filters) {
|
|
1349
|
+
items {
|
|
1350
|
+
product { sku }
|
|
1351
|
+
}
|
|
1352
|
+
total
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
`,
|
|
1356
|
+
variables: {
|
|
1357
|
+
filters: [
|
|
1358
|
+
{ name: 'locationName', operator: 'eq', value: toLocationName },
|
|
1359
|
+
{ name: 'status', operator: 'eq', value: 'STORED' }
|
|
1360
|
+
]
|
|
1361
|
+
}
|
|
1362
|
+
})
|
|
1363
|
+
|
|
1364
|
+
if (response.errors) return true
|
|
1365
|
+
|
|
1366
|
+
const { items: inventoriesAtLocation = [], total: countAtLocation = 0 } = response.data.inventories
|
|
1367
|
+
|
|
1368
|
+
let warningMsg = null
|
|
1369
|
+
|
|
1370
|
+
switch (level) {
|
|
1371
|
+
case 'LEVEL 1': {
|
|
1372
|
+
await this._fetchLocations(); // REFRESH TO GET LATEST
|
|
1373
|
+
const toLocation = (this._locations || []).find(l => l.name === toLocationName)
|
|
1374
|
+
if (toLocation?.status?.toUpperCase() !== 'EMPTY') {
|
|
1375
|
+
warningMsg = i18next.t('text.reminder_location_assigned_to_another_sku')
|
|
1376
|
+
}
|
|
1377
|
+
break
|
|
1378
|
+
}
|
|
1379
|
+
case 'LEVEL 2': {
|
|
1380
|
+
const hasDifferentSku = inventoriesAtLocation.some(inv => inv.product?.sku !== fromSku)
|
|
1381
|
+
if (hasDifferentSku) {
|
|
1382
|
+
warningMsg = i18next.t('text.reminder_location_assigned_to_another_sku')
|
|
1383
|
+
}
|
|
1384
|
+
break
|
|
1385
|
+
}
|
|
1386
|
+
case 'LEVEL 3': {
|
|
1387
|
+
const hasDifferentSku = inventoriesAtLocation.some(inv => inv.product?.sku !== fromSku)
|
|
1388
|
+
const allowStacking = this._selectedInventory?.product?.allowStackingOption
|
|
1389
|
+
const stackingLimit = allowStacking ? this._stackingOptionLimit?.max : null
|
|
1390
|
+
const hitStackingLimit = stackingLimit != null && countAtLocation >= stackingLimit
|
|
1391
|
+
if (hasDifferentSku || hitStackingLimit) {
|
|
1392
|
+
warningMsg = i18next.t('text.reminder_location_occupied_by_different_sku_or_stacking_capacity')
|
|
1393
|
+
}
|
|
1394
|
+
break
|
|
1395
|
+
}
|
|
1396
|
+
default:
|
|
1397
|
+
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
if (!warningMsg) return true
|
|
1401
|
+
|
|
1402
|
+
const result = await CustomAlert({
|
|
1403
|
+
title: i18next.t('title.reminder'),
|
|
1404
|
+
text: warningMsg,
|
|
1405
|
+
confirmButton: { text: i18next.t('button.confirm') },
|
|
1406
|
+
cancelButton: { text: i18next.t('button.cancel') }
|
|
1407
|
+
})
|
|
1408
|
+
|
|
1409
|
+
return result.value
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
_isSpecialLocationType(type) {
|
|
1413
|
+
const t = type?.toUpperCase()
|
|
1414
|
+
return t === 'DAMAGE' || t === 'QUARANTINE'
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
async _validateAndProceedToLocation() {
|
|
1418
|
+
try {
|
|
1419
|
+
const locationName = this.toLocationNameInput.value
|
|
1420
|
+
const toLocation = (this._locations || []).find(l => l.name === locationName)
|
|
1421
|
+
|
|
1422
|
+
if (!toLocation) throw new Error(i18next.t('text.location_not_found'))
|
|
1423
|
+
|
|
1424
|
+
if (!this._locationRecommendationChecked) {
|
|
1425
|
+
const confirmed = await this._checkLocationRecommendation(locationName)
|
|
1426
|
+
if (!confirmed) {
|
|
1427
|
+
this.toLocationNameInput.value = ''
|
|
1428
|
+
return
|
|
1429
|
+
}
|
|
1430
|
+
this._locationRecommendationChecked = true
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
this._toLocationData = toLocation
|
|
1434
|
+
|
|
1435
|
+
const toIsSpecial = this._isSpecialLocationType(toLocation.type)
|
|
1436
|
+
const fromLocationName = this._selectedInventory?.location?.name
|
|
1437
|
+
const fromLocationType = (this._locations || []).find(l => l.name === fromLocationName)?.type
|
|
1438
|
+
const fromIsSpecial = this._isSpecialLocationType(fromLocationType)
|
|
1439
|
+
const requiresReason = toIsSpecial !== fromIsSpecial // FROM SPECIAL LOCATION -> NORMAL || NORMAL -> SPECIAL LOCATION
|
|
1440
|
+
|
|
1441
|
+
if (this.reasonSelect) this.reasonSelect.value = ''
|
|
1442
|
+
if (this.remarkTextarea) this.remarkTextarea.value = ''
|
|
1443
|
+
|
|
1444
|
+
if (requiresReason) {
|
|
1445
|
+
this._showReasonField = true
|
|
1446
|
+
this.reasonSelect?.focus()
|
|
1447
|
+
await this.updateComplete
|
|
1448
|
+
} else {
|
|
1449
|
+
this._showReasonField = false
|
|
1450
|
+
this._showRemarkField = false
|
|
1451
|
+
if (this.refInventoryType === INVENTORY_TYPES.LOT.value) {
|
|
1452
|
+
if (this._requireNewId) {
|
|
1453
|
+
this.focusOnNewLotInput()
|
|
1454
|
+
} else {
|
|
1455
|
+
this.transferInventory({ stopPropagation: () => {}, preventDefault: () => {} })
|
|
1456
|
+
}
|
|
1457
|
+
} else {
|
|
1458
|
+
this.focusOnNewCartonInput()
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
} catch (e) {
|
|
1462
|
+
this.showToast(e)
|
|
1463
|
+
}
|
|
736
1464
|
}
|
|
737
1465
|
|
|
738
1466
|
clearView() {
|
|
739
1467
|
this.inputForm?.reset()
|
|
740
1468
|
this._selectedInventory = null
|
|
741
1469
|
this._requireNewId = false
|
|
1470
|
+
this._showTransferForm = false
|
|
1471
|
+
this._showReasonField = false
|
|
1472
|
+
this._showRemarkField = false
|
|
1473
|
+
this._toLocationData = null
|
|
1474
|
+
this._locationRecommendationChecked = false
|
|
742
1475
|
this._data = { records: [] }
|
|
743
1476
|
if (this?.toLocationNameInput) this.toLocationNameInput.value = ''
|
|
744
1477
|
if (this?.newCartonInput) this.newCartonInput.value = ''
|