@things-factory/operato-wms 4.3.823 → 4.3.825

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 (42) hide show
  1. package/client/pages/adjustment/transfer-inventory.js +24 -64
  2. package/client/pages/components/select-product-popup.js +20 -0
  3. package/client/pages/constants/location.js +4 -0
  4. package/client/pages/master/location-list.js +140 -18
  5. package/client/pages/order/arrival-notice/create-arrival-notice.js +18 -0
  6. package/client/pages/order/draft-release-good/draft-release-good-list.js +1 -0
  7. package/client/pages/outbound/packing-product.js +10 -2
  8. package/dist-server/graphql/resolvers/index.js +2 -0
  9. package/dist-server/graphql/resolvers/index.js.map +1 -1
  10. package/dist-server/graphql/resolvers/outbound/get-loading-task.js +15 -5
  11. package/dist-server/graphql/resolvers/outbound/get-loading-task.js.map +1 -1
  12. package/dist-server/graphql/resolvers/transfer-location/check-transfer-location-recommendation.js +108 -0
  13. package/dist-server/graphql/resolvers/transfer-location/check-transfer-location-recommendation.js.map +1 -0
  14. package/dist-server/graphql/resolvers/transfer-location/index.js +7 -0
  15. package/dist-server/graphql/resolvers/transfer-location/index.js.map +1 -0
  16. package/dist-server/graphql/resolvers/zone-worksheet/get-zone-picking-task.js +17 -2
  17. package/dist-server/graphql/resolvers/zone-worksheet/get-zone-picking-task.js.map +1 -1
  18. package/dist-server/graphql/resolvers/zone-worksheet/zone-worksheet.js +13 -2
  19. package/dist-server/graphql/resolvers/zone-worksheet/zone-worksheet.js.map +1 -1
  20. package/dist-server/graphql/types/index.js +3 -0
  21. package/dist-server/graphql/types/index.js.map +1 -1
  22. package/dist-server/graphql/types/transfer-location/index.js +14 -0
  23. package/dist-server/graphql/types/transfer-location/index.js.map +1 -0
  24. package/dist-server/graphql/types/transfer-location/transfer-location-recommendation.js +13 -0
  25. package/dist-server/graphql/types/transfer-location/transfer-location-recommendation.js.map +1 -0
  26. package/dist-server/graphql/types/zone-worksheet/index.js +5 -1
  27. package/dist-server/graphql/types/zone-worksheet/index.js.map +1 -1
  28. package/package.json +6 -6
  29. package/server/graphql/resolvers/index.ts +2 -0
  30. package/server/graphql/resolvers/outbound/get-loading-task.ts +15 -5
  31. package/server/graphql/resolvers/transfer-location/check-transfer-location-recommendation.ts +123 -0
  32. package/server/graphql/resolvers/transfer-location/index.ts +7 -0
  33. package/server/graphql/resolvers/zone-worksheet/get-zone-picking-task.ts +17 -2
  34. package/server/graphql/resolvers/zone-worksheet/zone-worksheet.ts +17 -6
  35. package/server/graphql/types/index.ts +3 -0
  36. package/server/graphql/types/transfer-location/index.ts +13 -0
  37. package/server/graphql/types/transfer-location/transfer-location-recommendation.ts +7 -0
  38. package/server/graphql/types/zone-worksheet/index.ts +5 -1
  39. package/translations/en.json +12 -0
  40. package/translations/ko.json +12 -0
  41. package/translations/ms.json +12 -0
  42. package/translations/zh.json +12 -0
@@ -857,17 +857,8 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
857
857
  async pageInitialized() {
858
858
  this._transferCodes = await getCodeByName('TRANSFER_CODES')
859
859
 
860
- const [locationRecommendationLevel, stackingOptionLimitStr] = await Promise.all([
861
- fetchSettingRule('location-recommendation-level'),
862
- fetchSettingRule('stacking-option-limit')
863
- ])
860
+ const locationRecommendationLevel = await fetchSettingRule('location-recommendation-level')
864
861
  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
862
 
872
863
  await this._fetchLocations()
873
864
  this.refInventoryType = INVENTORY_TYPES.LOT.value
@@ -1340,73 +1331,42 @@ class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
1340
1331
  const level = this._locationRecommendationLevel
1341
1332
  if (!level) return true
1342
1333
 
1343
- const fromSku = this._selectedInventory?.product?.sku
1334
+ const originPalletId = this._selectedInventory?.palletId
1335
+ const qty = parseFloat(this.qtyInput?.value) || 0
1336
+
1337
+ // RECOMMENDATION LEVEL 4 -> QTY IS REQUIRED FOR CHECKING
1338
+ if (level === 'LEVEL 4' && qty <= 0) {
1339
+ throw new Error(i18next.t('text.please_enter_transfer_qty'))
1340
+ }
1344
1341
 
1345
1342
  const response = await client.query({
1346
1343
  query: gql`
1347
- query inventories($filters: [Filter!]) {
1348
- inventories(filters: $filters) {
1349
- items {
1350
- product { sku }
1351
- }
1352
- total
1344
+ query checkTransferLocationRecommendation($originPalletId: String!, $toLocationName: String!, $qty: Float!) {
1345
+ checkTransferLocationRecommendation(originPalletId: $originPalletId, toLocationName: $toLocationName, qty: $qty) {
1346
+ warningMessage
1353
1347
  }
1354
1348
  }
1355
1349
  `,
1356
- variables: {
1357
- filters: [
1358
- { name: 'locationName', operator: 'eq', value: toLocationName },
1359
- { name: 'status', operator: 'eq', value: 'STORED' }
1360
- ]
1361
- }
1350
+ variables: { originPalletId, toLocationName, qty }
1362
1351
  })
1363
1352
 
1364
- if (response.errors) return true
1353
+ if (!response.errors) {
1354
+ const warningKey = response.data?.checkTransferLocationRecommendation?.warningMessage
1355
+ if (!warningKey) return true
1365
1356
 
1366
- const { items: inventoriesAtLocation = [], total: countAtLocation = 0 } = response.data.inventories
1357
+ const warningMsg = i18next.t(`text.${warningKey}`)
1367
1358
 
1368
- let warningMsg = null
1359
+ const result = await CustomAlert({
1360
+ title: i18next.t('title.reminder'),
1361
+ text: level === 'LEVEL 4' ? `${warningMsg}\n\n${i18next.t('text.may_proceed_without_level_4_recommendation')}` : warningMsg,
1362
+ confirmButton: { text: i18next.t('button.proceed') },
1363
+ cancelButton: { text: i18next.t('button.cancel') }
1364
+ })
1369
1365
 
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
-
1366
+ return result.value
1398
1367
  }
1399
1368
 
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
1369
+ return false
1410
1370
  }
1411
1371
 
1412
1372
  _isSpecialLocationType(type) {
@@ -215,6 +215,11 @@ class SelectProductPopup extends localize(i18next)(LitElement) {
215
215
  uom
216
216
  uomValue
217
217
  costPrice
218
+ lengthUnit
219
+ width
220
+ depth
221
+ height
222
+ volume
218
223
  product {
219
224
  id
220
225
  name
@@ -269,6 +274,11 @@ class SelectProductPopup extends localize(i18next)(LitElement) {
269
274
  isError: false,
270
275
  productBrand: record.brand,
271
276
  unitPrice: parseFloat(record.costPrice).toFixed(2),
277
+ lengthUnit: record.lengthUnit || null,
278
+ width: record.width || null,
279
+ depth: record.depth || null,
280
+ height: record.height || null,
281
+ volume: record.volume || null,
272
282
  product: {
273
283
  id: record.productId,
274
284
  name: record.name,
@@ -302,6 +312,11 @@ class SelectProductPopup extends localize(i18next)(LitElement) {
302
312
  isError: false,
303
313
  productBrand: selectedProduct.brand,
304
314
  unitPrice: parseFloat(selectedProduct.costPrice).toFixed(2),
315
+ lengthUnit: selectedProduct.lengthUnit || null,
316
+ width: selectedProduct.width || null,
317
+ depth: selectedProduct.depth || null,
318
+ height: selectedProduct.height || null,
319
+ volume: selectedProduct.volume || null,
305
320
  product: {
306
321
  id: selectedProduct.productId,
307
322
  name: selectedProduct.name,
@@ -336,6 +351,11 @@ class SelectProductPopup extends localize(i18next)(LitElement) {
336
351
  isError: false,
337
352
  unitPrice: parseFloat(itm.costPrice).toFixed(2),
338
353
  productBrand: itm.brand,
354
+ lengthUnit: itm.lengthUnit || null,
355
+ width: itm.width || null,
356
+ depth: itm.depth || null,
357
+ height: itm.height || null,
358
+ volume: itm.volume || null,
339
359
  product: {
340
360
  id: itm.productId,
341
361
  name: itm.name,
@@ -45,5 +45,9 @@ export const LOCATION_TYPE = {
45
45
  DAMAGE: {
46
46
  name: 'DAMAGE',
47
47
  value: 'DAMAGE'
48
+ },
49
+ PICKFACE: {
50
+ name: 'PICKFACE',
51
+ value: 'PICKFACE'
48
52
  }
49
53
  }
@@ -70,7 +70,7 @@ class LocationList extends connect(store)(localize(i18next)(PageView)) {
70
70
  .config=${this.config}
71
71
  .fetchHandler="${this.fetchHandler.bind(this)}"
72
72
  @select-record-change=${e => (this._selectedRecords = e.detail.selectedRecords)}
73
- }
73
+ @record-change=${this._onRecordChange.bind(this)}
74
74
  ></data-grist>
75
75
  `
76
76
  }
@@ -275,6 +275,41 @@ class LocationList extends connect(store)(localize(i18next)(PageView)) {
275
275
  sortable: true,
276
276
  width: 80
277
277
  },
278
+ {
279
+ type: 'float',
280
+ name: 'length',
281
+ header: i18next.t('field.length_m'),
282
+ record: { editable: true },
283
+ imex: { header: i18next.t('field.length_m'), key: 'length', width: 25, type: 'float' },
284
+ sortable: true,
285
+ width: 80
286
+ },
287
+ {
288
+ type: 'float',
289
+ name: 'width',
290
+ header: i18next.t('field.width_m'),
291
+ record: { editable: true },
292
+ imex: { header: i18next.t('field.width_m'), key: 'width', width: 25, type: 'float' },
293
+ sortable: true,
294
+ width: 80
295
+ },
296
+ {
297
+ type: 'float',
298
+ name: 'height',
299
+ header: i18next.t('field.height_m'),
300
+ record: { editable: true },
301
+ imex: { header: i18next.t('field.height_m'), key: 'height', width: 25, type: 'float' },
302
+ sortable: true,
303
+ width: 80
304
+ },
305
+ {
306
+ type: 'float',
307
+ name: 'volume',
308
+ header: i18next.t('field.volume_m3'),
309
+ record: { editable: false },
310
+ sortable: true,
311
+ width: 80
312
+ },
278
313
  {
279
314
  type: 'select',
280
315
  name: 'status',
@@ -302,6 +337,15 @@ class LocationList extends connect(store)(localize(i18next)(PageView)) {
302
337
  sortable: true,
303
338
  width: 80
304
339
  },
340
+ {
341
+ type: 'string',
342
+ name: 'locationClass',
343
+ header: i18next.t('field.class'),
344
+ record: { editable: true },
345
+ imex: { header: i18next.t('field.class'), key: 'locationClass', width: 50, type: 'string' },
346
+ sortable: true,
347
+ width: 120
348
+ },
305
349
  {
306
350
  type: 'datetime',
307
351
  name: 'updatedAt',
@@ -336,8 +380,18 @@ class LocationList extends connect(store)(localize(i18next)(PageView)) {
336
380
  .records=${records}
337
381
  .config=${{
338
382
  rows: this.config.rows,
339
- columns: [...this.config.columns.filter(column => column.imex !== undefined)]
383
+ columns: [
384
+ ...this.config.columns.filter(column => column.imex !== undefined),
385
+ {
386
+ type: 'string',
387
+ name: 'errMsg',
388
+ header: i18next.t('field.error_message'),
389
+ record: { editable: false },
390
+ width: 300
391
+ }
392
+ ]
340
393
  }}
394
+ .enableRowErrors=${true}
341
395
  .importHandler="${this.importHandler.bind(this)}"
342
396
  ></import-pop-up>
343
397
  `,
@@ -373,6 +427,11 @@ class LocationList extends connect(store)(localize(i18next)(PageView)) {
373
427
  column
374
428
  shelf
375
429
  status
430
+ length
431
+ width
432
+ height
433
+ volume
434
+ locationClass
376
435
  updatedAt
377
436
  updater {
378
437
  id
@@ -394,16 +453,10 @@ class LocationList extends connect(store)(localize(i18next)(PageView)) {
394
453
  if (!response.errors) {
395
454
  var responseItems = response.data.locations.items || []
396
455
  var total = response.data.locations.total || 0
397
-
398
- if (this._locationList.length > 0) {
399
- let generatedItems = this._locationList
400
- var records = [...responseItems, ...generatedItems]
401
- total += generatedItems.length
402
- }
403
456
  }
404
457
 
405
458
  return {
406
- records: records || responseItems || [],
459
+ records: responseItems || [],
407
460
  total: total || 0
408
461
  }
409
462
  }
@@ -419,7 +472,10 @@ class LocationList extends connect(store)(localize(i18next)(PageView)) {
419
472
  const locationType = Object.keys(LOCATION_TYPE)
420
473
  const locationStatus = Object.keys(LOCATION_STATUS)
421
474
 
475
+ let hasError = false
422
476
  patches = patches.map(itm => {
477
+ itm.errMsg = ''
478
+
423
479
  // Error if there is an empty value
424
480
  if (
425
481
  isEmpty(itm.name) ||
@@ -430,30 +486,56 @@ class LocationList extends connect(store)(localize(i18next)(PageView)) {
430
486
  isEmpty(itm.status) ||
431
487
  ''
432
488
  ) {
433
- throw new Error(i18next.t('text.empty_value_in_list'))
489
+ itm.errMsg = i18next.t('text.empty_value_in_list')
490
+ hasError = true
491
+ return itm
434
492
  }
435
493
  // Error if location name is already existed
436
494
  if (records.find(exist => exist.name == itm.name)) {
437
- throw new Error(i18next.t('text.location_name(s)_already_existed'))
495
+ itm.errMsg = i18next.t('text.location_name(s)_already_existed')
496
+ hasError = true
497
+ return itm
438
498
  }
439
499
 
440
- // Error if location status does not exist
500
+ // Error if location type does not exist
441
501
  let foundLocationType = locationType.find(exist => exist == itm.type)
442
502
  if (!foundLocationType) {
443
- throw new Error(i18next.t('text.location_type_does_not_exist'))
503
+ itm.errMsg = i18next.t('text.location_type_does_not_exist')
504
+ hasError = true
505
+ return itm
444
506
  }
445
- // Error if location type does not exist
507
+
508
+ // Error if Class has data for Quarantine or Damage location type
509
+ const isRestricted = [LOCATION_TYPE.QUARANTINE.value, LOCATION_TYPE.DAMAGE.value].includes(itm.type)
510
+ if (isRestricted && itm.locationClass) {
511
+ itm.errMsg = i18next.t('text.cannot_update_class_for_quarantine_or_damage_location')
512
+ hasError = true
513
+ return itm
514
+ }
515
+
516
+ // Error if location status does not exist
446
517
  let foundLocationStatus = locationStatus.find(exist => exist == itm.status)
447
518
  if (!foundLocationStatus) {
448
- throw new Error(i18next.t('text.location_status_does_not_exist'))
519
+ itm.errMsg = i18next.t('text.location_status_does_not_exist')
520
+ hasError = true
521
+ return itm
449
522
  }
523
+
450
524
  return itm
451
525
  })
526
+
527
+ if (hasError) return patches
528
+
452
529
  if (patches && patches.length) {
453
530
  patches = patches.map(patch => {
454
531
  if (this._warehouseId) {
455
532
  patch.warehouse = { id: this._warehouseId }
456
533
  }
534
+ delete patch.errMsg
535
+ delete patch.volume
536
+ patch.length = patch.length || null
537
+ patch.width = patch.width || null
538
+ patch.height = patch.height || null
457
539
  return patch
458
540
  })
459
541
  const response = await client.mutate({
@@ -502,6 +584,7 @@ class LocationList extends connect(store)(localize(i18next)(PageView)) {
502
584
  if (this._warehouseId && !patch.warehouse) {
503
585
  patch.warehouse = { id: this._warehouseId }
504
586
  }
587
+ delete patch.volume
505
588
  return patch
506
589
  })
507
590
 
@@ -650,9 +733,11 @@ class LocationList extends connect(store)(localize(i18next)(PageView)) {
650
733
  openPopup(
651
734
  html`
652
735
  <generate-location-list
653
- @generated="${e => {
654
- this._locationList = e.detail
655
- this.dataGrist.fetch()
736
+ @generated="${async e => {
737
+ await this.dataGrist.fetch()
738
+ this.dataGrist._data.records.push(...e.detail)
739
+ this.dataGrist._data.total += e.detail.length
740
+ this.dataGrist.refresh()
656
741
  }}"
657
742
  ></generate-location-list>
658
743
  `,
@@ -783,6 +868,43 @@ class LocationList extends connect(store)(localize(i18next)(PageView)) {
783
868
  }
784
869
  }
785
870
 
871
+ _onRecordChange(e) {
872
+ const { column, after } = e.detail
873
+
874
+ if (column.name === 'type') {
875
+ const isRestricted = [LOCATION_TYPE.QUARANTINE.value, LOCATION_TYPE.DAMAGE.value].includes(after.type)
876
+ if (isRestricted) after.locationClass = null
877
+ return
878
+ }
879
+
880
+ if (column.name === 'locationClass') {
881
+ const isRestricted = [LOCATION_TYPE.QUARANTINE.value, LOCATION_TYPE.DAMAGE.value].includes(after.type)
882
+ if (isRestricted) {
883
+ after.locationClass = null
884
+ showToast(new Error(i18next.t('text.cannot_update_class_for_quarantine_or_damage_location')))
885
+ }
886
+ return
887
+ }
888
+
889
+ if (!['length', 'width', 'height'].includes(column.name)) return
890
+
891
+ const value = parseFloat(after[column.name])
892
+ if (!isNaN(value) && value <= 0) {
893
+ showToast(new Error(i18next.t('text.value_must_be_greater_than_zero')))
894
+ after[column.name] = null
895
+ } else if (!isNaN(value)) {
896
+ after[column.name] = parseFloat(value.toFixed(2))
897
+ }
898
+
899
+ const length = after.length
900
+ const width = after.width
901
+ const height = after.height
902
+
903
+ after.volume = length > 0 && width > 0 && height > 0
904
+ ? parseFloat((parseFloat(length) * parseFloat(width) * parseFloat(height)).toFixed(2))
905
+ : null
906
+ }
907
+
786
908
  stateChanged(state) {
787
909
  var locationLabelSetting = state.dashboard[LOCATION_LABEL_SETTING_KEY]
788
910
  this._locationLabel = (locationLabelSetting && locationLabelSetting.board) || {}
@@ -46,6 +46,7 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
46
46
  _disableCrossDockingSetting: Boolean,
47
47
  _hideCrossDockingSetting: Boolean,
48
48
  _strictProductSelection: Boolean,
49
+ _locationRecommendationLevel: String,
49
50
  containerSizes: Array,
50
51
  productGristConfig: Object,
51
52
  vasGristConfig: Object,
@@ -477,6 +478,7 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
477
478
  this._hideCrossDockingSetting = await fetchSettingRule('hide-cross-dock')
478
479
  this._bizplaces = await this.fetchBizplaces()
479
480
  this.enableDirectInbound = await fetchSettingRule('enable-direct-gan-order')
481
+ this._locationRecommendationLevel = (await fetchSettingRule('location-recommendation-level') || '').toUpperCase().trim()
480
482
 
481
483
  this._validateTransport()
482
484
 
@@ -1223,6 +1225,22 @@ class CreateArrivalNotice extends localize(i18next)(PageView) {
1223
1225
  this._validateProducts()
1224
1226
  this._validateVas()
1225
1227
 
1228
+ if (this._locationRecommendationLevel === 'LEVEL 4') {
1229
+ const records = this.productGrist.dirtyData.records
1230
+ const invalidProduct = records.find(record =>
1231
+ !record.lengthUnit || (record.volume == null && (!record.width || !record.depth || !record.height))
1232
+ )
1233
+ if (invalidProduct) {
1234
+ const result = await CustomAlert({
1235
+ title: i18next.t('title.reminder'),
1236
+ text: i18next.t('text.missing_product_dimensions_for_level_4'),
1237
+ confirmButton: { text: i18next.t('button.proceed') },
1238
+ cancelButton: { text: i18next.t('button.cancel') }
1239
+ })
1240
+ if (!result.value) return
1241
+ }
1242
+ }
1243
+
1226
1244
  const result = await CustomAlert({
1227
1245
  title: i18next.t('title.are_you_sure'),
1228
1246
  text: i18next.t('text.create_arrival_notice'),
@@ -241,6 +241,7 @@ class DraftReleaseGoodList extends localize(i18next)(PageView) {
241
241
  { name: 'Shopify', value: 'SPF' },
242
242
  { name: 'Tiktok', value: 'TTK' },
243
243
  { name: 'Magento', value: 'MGT' },
244
+ { name: 'Xilnex', value: 'XILNEX' },
244
245
  { name: 'Generic', value: 'GENERIC' }
245
246
  ]
246
247
  }
@@ -722,11 +722,11 @@ class PackingProduct extends connect(store)(localize(i18next)(PageView)) {
722
722
  this.focusOnReleaseQtyInput()
723
723
  }
724
724
 
725
- if (worksheetInfo.source == 'POWRUP') {
725
+ if (worksheetInfo.source == 'POWRUP' && !releaseGood.lmdOption) {
726
726
  this.fetchPowrupOrderDocument(worksheetInfo.orderPackage.id)
727
727
  }
728
728
 
729
- if (worksheetInfo.source == 'WEBSPERT') {
729
+ if (worksheetInfo.source == 'WEBSPERT' && !releaseGood.lmdOption) {
730
730
  this.fetchWebspertOrderDocument(worksheetInfo.orderPackage.id)
731
731
  }
732
732
 
@@ -1536,6 +1536,14 @@ class PackingProduct extends connect(store)(localize(i18next)(PageView)) {
1536
1536
  }
1537
1537
 
1538
1538
  async complete() {
1539
+ if (this._isLmdOption && (!this.airwayBill || String(this.airwayBill).trim() === '')) {
1540
+ this.showToast({
1541
+ message:
1542
+ 'It appears that we are unable to retrieve the AWB from the platform. Please reach out to support for assistance.'
1543
+ })
1544
+ return
1545
+ }
1546
+
1539
1547
  if (this._enablePackingGrossWeight) {
1540
1548
  const grossWeightValue = this.grossWeightInput.value
1541
1549
 
@@ -33,6 +33,7 @@ const OpaMenu = __importStar(require("./opa-menu"));
33
33
  const Reports = __importStar(require("./reports"));
34
34
  const InventoryComparison = __importStar(require("./inventory-comparison"));
35
35
  const ShippingProviders = __importStar(require("./shipping-provider"));
36
+ const TransferLocation = __importStar(require("./transfer-location"));
36
37
  const WarehouseInventoryAdjustment = __importStar(require("./warehouse-inventory-adjustment"));
37
38
  const RouteLabel = __importStar(require("./route-label"));
38
39
  const ZoneWorksheet = __importStar(require("./zone-worksheet"));
@@ -47,6 +48,7 @@ exports.queries = [
47
48
  Other.Query,
48
49
  Reports.Query,
49
50
  ShippingProviders.Query,
51
+ TransferLocation.Query,
50
52
  RouteLabel.Query,
51
53
  ZoneWorksheet.Query,
52
54
  Outbound.Query
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/graphql/resolvers/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,8DAA+C;AAC/C,4DAA6C;AAC7C,8DAA+C;AAC/C,uDAAwC;AACxC,+CAAgC;AAChC,oDAAqC;AACrC,mDAAoC;AACpC,4EAA6D;AAC7D,uEAAwD;AACxD,+FAAgF;AAChF,0DAA2C;AAC3C,gEAAiD;AACjD,qDAAsC;AAEzB,QAAA,OAAO,GAAG;IACrB,YAAY,CAAC,KAAK;IAClB,WAAW,CAAC,KAAK;IACjB,YAAY,CAAC,KAAK;IAClB,SAAS,CAAC,KAAK;IACf,mBAAmB,CAAC,KAAK;IACzB,OAAO,CAAC,KAAK;IACb,KAAK,CAAC,KAAK;IACX,OAAO,CAAC,KAAK;IACb,iBAAiB,CAAC,KAAK;IACvB,UAAU,CAAC,KAAK;IAChB,aAAa,CAAC,KAAK;IACnB,QAAQ,CAAC,KAAK;CACf,CAAA;AAEY,QAAA,SAAS,GAAG;IACvB,KAAK,CAAC,QAAQ;IACd,4BAA4B,CAAC,QAAQ;IACrC,UAAU,CAAC,QAAQ;IACnB,aAAa,CAAC,QAAQ;IACtB,QAAQ,CAAC,QAAQ;CAClB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/graphql/resolvers/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,8DAA+C;AAC/C,4DAA6C;AAC7C,8DAA+C;AAC/C,uDAAwC;AACxC,+CAAgC;AAChC,oDAAqC;AACrC,mDAAoC;AACpC,4EAA6D;AAC7D,uEAAwD;AACxD,sEAAuD;AACvD,+FAAgF;AAChF,0DAA2C;AAC3C,gEAAiD;AACjD,qDAAsC;AAEzB,QAAA,OAAO,GAAG;IACrB,YAAY,CAAC,KAAK;IAClB,WAAW,CAAC,KAAK;IACjB,YAAY,CAAC,KAAK;IAClB,SAAS,CAAC,KAAK;IACf,mBAAmB,CAAC,KAAK;IACzB,OAAO,CAAC,KAAK;IACb,KAAK,CAAC,KAAK;IACX,OAAO,CAAC,KAAK;IACb,iBAAiB,CAAC,KAAK;IACvB,gBAAgB,CAAC,KAAK;IACtB,UAAU,CAAC,KAAK;IAChB,aAAa,CAAC,KAAK;IACnB,QAAQ,CAAC,KAAK;CACf,CAAA;AAEY,QAAA,SAAS,GAAG;IACvB,KAAK,CAAC,QAAQ;IACd,4BAA4B,CAAC,QAAQ;IACrC,UAAU,CAAC,QAAQ;IACnB,aAAa,CAAC,QAAQ;IACtB,QAAQ,CAAC,QAAQ;CAClB,CAAA"}
@@ -31,28 +31,38 @@ exports.getLoadingTask = {
31
31
  .andWhere('wsd.status NOT IN (:...status)', { status: [worksheet_base_1.WORKSHEET_STATUS.DONE, worksheet_base_1.WORKSHEET_STATUS.DEACTIVATED] })
32
32
  .getOne();
33
33
  // 2. If no assigned worksheet, find and assign next available one
34
+ // FOR UPDATE OF ws SKIP LOCKED: under concurrent clicks, two callers
35
+ // used to SELECT the same row and the second UPDATE would re-evaluate,
36
+ // find sorter_id no longer NULL, update zero rows, and the user would
37
+ // see a confusing "no suitable worksheet found" error even though other
38
+ // unassigned rows existed. SKIP LOCKED makes concurrent callers pick
39
+ // different rows. `OF ws` scopes the row lock to the worksheets table
40
+ // only (not the joined release_goods / worksheet_details rows). Inner
41
+ // transaction is independent so the row lock is released as soon as
42
+ // the UPDATE commits.
34
43
  if (!worksheet) {
35
44
  let updatedWorksheets = await (0, typeorm_1.getConnection)().transaction(async (tx2) => {
36
45
  let x = await tx2.query(`
37
- UPDATE worksheets ws SET
46
+ UPDATE worksheets ws SET
38
47
  sorter_id = $2,
39
48
  updated_at = NOW(),
40
49
  updater_id = $2
41
50
  FROM (
42
- SELECT ws.id
51
+ SELECT ws.id
43
52
  FROM worksheets ws
44
53
  INNER JOIN release_goods rg ON rg.id = ws.release_good_id
45
54
  INNER JOIN worksheet_details wsd ON wsd.worksheet_id = ws.id
46
- WHERE ws.domain_id = $1
55
+ WHERE ws.domain_id = $1
47
56
  AND ws.type = 'LOADING'
48
57
  AND ws.status IN ('EXECUTING', 'DEACTIVATED')
49
58
  AND ws.sorter_id IS NULL
50
59
  AND rg.status IN ('LOADING', 'PROCESSING', 'PARTIAL_PROCESSING')
51
60
  AND wsd.status NOT IN ('DONE', 'DEACTIVATED')
52
61
  AND (rg.sorted_by_id = $2 OR rg.sorted_by_id IS NULL)
53
- ORDER BY rg.created_at
62
+ ORDER BY rg.created_at
54
63
  LIMIT 1
55
- ) src
64
+ FOR UPDATE OF ws SKIP LOCKED
65
+ ) src
56
66
  WHERE src.id = ws.id
57
67
  RETURNING ws.id
58
68
  `, [domain.id, user.id]);
@@ -1 +1 @@
1
- {"version":3,"file":"get-loading-task.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/outbound/get-loading-task.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"get-loading-task.js","sourceRoot":"","sources":["../../../../server/graphql/resolvers/outbound/get-loading-task.ts"],"names":[],"mappings":";;;AAAA,qCAA0D;AAI1D,2DAAsE;AACtE,mEAA4F;AAC5F,iEAA2D;AAE9C,QAAA,cAAc,GAAG;IAC5B,KAAK,CAAC,cAAc,CAAC,CAAM,EAAE,EAAE,EAAE,OAAY;QAC3C,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAsD,OAAO,CAAC,KAAK,CAAA;QAE7F,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,EAAE;YACzC,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;SAC/B;QACD,IAAI;YACF,6BAA6B;YAC7B,IAAI,SAAS,GAAc,MAAM,EAAE;iBAChC,aAAa,CAAC,0BAAS,CAAC;iBACxB,kBAAkB,CAAC,IAAI,CAAC;iBACxB,kBAAkB,CAAC,aAAa,EAAE,KAAK,CAAC;iBACxC,kBAAkB,CAAC,gBAAgB,EAAE,IAAI,CAAC;iBAC1C,SAAS,CAAC,qBAAqB,EAAE,KAAK,CAAC;iBACvC,KAAK,CAAC;gBACL,MAAM;gBACN,IAAI,EAAE,+BAAc,CAAC,OAAO;gBAC5B,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,IAAA,YAAE,EAAC,CAAC,iCAAgB,CAAC,SAAS,EAAE,iCAAgB,CAAC,WAAW,CAAC,CAAC;aACvE,CAAC;iBACD,QAAQ,CAAC,2BAA2B,EAAE;gBACrC,MAAM,EAAE,CAAC,yBAAY,CAAC,OAAO,EAAE,yBAAY,CAAC,UAAU,EAAE,yBAAY,CAAC,kBAAkB,CAAC;aACzF,CAAC;iBACD,QAAQ,CAAC,gCAAgC,EAAE,EAAE,MAAM,EAAE,CAAC,iCAAgB,CAAC,IAAI,EAAE,iCAAgB,CAAC,WAAW,CAAC,EAAE,CAAC;iBAC7G,MAAM,EAAE,CAAA;YAEX,kEAAkE;YAClE,qEAAqE;YACrE,uEAAuE;YACvE,sEAAsE;YACtE,wEAAwE;YACxE,qEAAqE;YACrE,sEAAsE;YACtE,sEAAsE;YACtE,oEAAoE;YACpE,sBAAsB;YACtB,IAAI,CAAC,SAAS,EAAE;gBACd,IAAI,iBAAiB,GAAG,MAAM,IAAA,uBAAa,GAAE,CAAC,WAAW,CAAC,KAAK,EAAE,GAAkB,EAAE,EAAE;oBACrF,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,KAAK,CACrB;;;;;;;;;;;;;;;;;;;;;;;WAuBD,EACC,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,CACrB,CAAA;oBAED,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;gBACb,CAAC,CAAC,CAAA;gBAEF,IAAI,iBAAiB,CAAC,MAAM,IAAI,CAAC;oBAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;gBAEjF,kBAAkB;gBAClB,SAAS,GAAG,MAAM,EAAE;qBACjB,aAAa,CAAC,0BAAS,CAAC;qBACxB,kBAAkB,CAAC,IAAI,CAAC;qBACxB,kBAAkB,CAAC,gBAAgB,EAAE,IAAI,CAAC;qBAC1C,KAAK,CAAC,aAAa,EAAE,EAAE,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;qBACrD,QAAQ,CAAC,wBAAwB,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;qBACvD,MAAM,EAAE,CAAA;aACZ;YAED,wCAAwC;YACxC,IAAI,CAAC,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;YAErF,IAAI,SAAS,CAAC,MAAM,IAAI,iCAAgB,CAAC,WAAW,EAAE;gBACpD,MAAM,EAAE,CAAC,aAAa,CAAC,0BAAS,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE;oBACrD,MAAM,EAAE,iCAAgB,CAAC,SAAS;oBAClC,SAAS,EAAE,IAAI,IAAI,EAAE;iBACtB,CAAC,CAAA;aACH;YAED,8BAA8B;YAC9B,IAAI,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,WAAW,CAAC,QAAQ,KAAI,IAAI,EAAE;gBAC3C,MAAM,EAAE,CAAC,aAAa,CAAC,wBAAW,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,EAAE;oBACnE,QAAQ,EAAE,IAAI;iBACf,CAAC,CAAA;aACH;YAED,OAAO,yCAAkB,CAAC,kBAAkB,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC,CAAA;SACjH;QAAC,OAAO,KAAK,EAAE;YACd,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YACpB,MAAM,KAAK,CAAA;SACZ;gBAAS;YACR,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,EAAE;gBACzC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;aAClC;SACF;IACH,CAAC;CACF,CAAA"}