@things-factory/worksheet-base 4.0.7 → 4.0.12

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 (94) hide show
  1. package/dist-server/constants/template.js +1 -0
  2. package/dist-server/constants/template.js.map +1 -1
  3. package/dist-server/controllers/ecommerce/sellercraft-controller.js +3 -3
  4. package/dist-server/controllers/ecommerce/sellercraft-controller.js.map +1 -1
  5. package/dist-server/controllers/inbound/putaway-worksheet-controller.js +24 -5
  6. package/dist-server/controllers/inbound/putaway-worksheet-controller.js.map +1 -1
  7. package/dist-server/controllers/inbound/unloading-worksheet-controller.js +67 -28
  8. package/dist-server/controllers/inbound/unloading-worksheet-controller.js.map +1 -1
  9. package/dist-server/controllers/index.js +1 -0
  10. package/dist-server/controllers/index.js.map +1 -1
  11. package/dist-server/controllers/outbound/loading-worksheet-controller.js +4 -0
  12. package/dist-server/controllers/outbound/loading-worksheet-controller.js.map +1 -1
  13. package/dist-server/controllers/outbound/packing-worksheet-controller.js +1 -3
  14. package/dist-server/controllers/outbound/packing-worksheet-controller.js.map +1 -1
  15. package/dist-server/controllers/outbound/picking-worksheet-controller.js +158 -113
  16. package/dist-server/controllers/outbound/picking-worksheet-controller.js.map +1 -1
  17. package/dist-server/controllers/render-elccl-grn.js +6 -6
  18. package/dist-server/controllers/render-elccl-grn.js.map +1 -1
  19. package/dist-server/controllers/render-manifest.js +64 -0
  20. package/dist-server/controllers/render-manifest.js.map +1 -0
  21. package/dist-server/controllers/worksheet-controller.js +28 -2
  22. package/dist-server/controllers/worksheet-controller.js.map +1 -1
  23. package/dist-server/graphql/resolvers/pallet/pallet-outbound.js +1 -1
  24. package/dist-server/graphql/resolvers/pallet/pallet-outbound.js.map +1 -1
  25. package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js +6 -5
  26. package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js.map +1 -1
  27. package/dist-server/graphql/resolvers/worksheet/loading-worksheet.js +23 -2
  28. package/dist-server/graphql/resolvers/worksheet/loading-worksheet.js.map +1 -1
  29. package/dist-server/graphql/resolvers/worksheet/packing-worksheet.js +22 -0
  30. package/dist-server/graphql/resolvers/worksheet/packing-worksheet.js.map +1 -1
  31. package/dist-server/graphql/resolvers/worksheet/pending-cancellation-release-order.js +6 -3
  32. package/dist-server/graphql/resolvers/worksheet/pending-cancellation-release-order.js.map +1 -1
  33. package/dist-server/graphql/resolvers/worksheet/picking/activate-picking.js +0 -4
  34. package/dist-server/graphql/resolvers/worksheet/picking/activate-picking.js.map +1 -1
  35. package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js +30 -5
  36. package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js.map +1 -1
  37. package/dist-server/graphql/resolvers/worksheet/picking/fetch-and-assign-picking-task.js +72 -0
  38. package/dist-server/graphql/resolvers/worksheet/picking/fetch-and-assign-picking-task.js.map +1 -0
  39. package/dist-server/graphql/resolvers/worksheet/picking/index.js +2 -1
  40. package/dist-server/graphql/resolvers/worksheet/picking/index.js.map +1 -1
  41. package/dist-server/graphql/resolvers/worksheet/picking/picking.js +4 -4
  42. package/dist-server/graphql/resolvers/worksheet/picking/picking.js.map +1 -1
  43. package/dist-server/graphql/resolvers/worksheet/picking/scan-product-picking.js +4 -4
  44. package/dist-server/graphql/resolvers/worksheet/picking/scan-product-picking.js.map +1 -1
  45. package/dist-server/graphql/resolvers/worksheet/picking-worksheet.js +86 -57
  46. package/dist-server/graphql/resolvers/worksheet/picking-worksheet.js.map +1 -1
  47. package/dist-server/graphql/resolvers/worksheet/recommend-putway-location.js +2 -2
  48. package/dist-server/graphql/resolvers/worksheet/recommend-putway-location.js.map +1 -1
  49. package/dist-server/graphql/resolvers/worksheet/unloaded-inventories.js +6 -1
  50. package/dist-server/graphql/resolvers/worksheet/unloaded-inventories.js.map +1 -1
  51. package/dist-server/graphql/resolvers/worksheet/unloading-return-worksheet.js +2 -2
  52. package/dist-server/graphql/resolvers/worksheet/unloading-return-worksheet.js.map +1 -1
  53. package/dist-server/graphql/types/index.js +1 -2
  54. package/dist-server/graphql/types/index.js.map +1 -1
  55. package/dist-server/graphql/types/worksheet/index.js +7 -1
  56. package/dist-server/graphql/types/worksheet/index.js.map +1 -1
  57. package/dist-server/routes.js +4 -0
  58. package/dist-server/routes.js.map +1 -1
  59. package/dist-server/utils/inventory-util.js +29 -4
  60. package/dist-server/utils/inventory-util.js.map +1 -1
  61. package/package.json +16 -16
  62. package/server/constants/template.ts +1 -0
  63. package/server/controllers/ecommerce/sellercraft-controller.ts +3 -3
  64. package/server/controllers/inbound/putaway-worksheet-controller.ts +29 -8
  65. package/server/controllers/inbound/unloading-worksheet-controller.ts +83 -29
  66. package/server/controllers/index.ts +1 -0
  67. package/server/controllers/outbound/loading-worksheet-controller.ts +20 -0
  68. package/server/controllers/outbound/packing-worksheet-controller.ts +3 -5
  69. package/server/controllers/outbound/picking-worksheet-controller.ts +201 -143
  70. package/server/controllers/render-elccl-grn.ts +8 -6
  71. package/server/controllers/render-manifest.ts +68 -0
  72. package/server/controllers/worksheet-controller.ts +41 -2
  73. package/server/graphql/resolvers/pallet/pallet-outbound.ts +1 -2
  74. package/server/graphql/resolvers/worksheet/inventories-by-pallet.ts +10 -8
  75. package/server/graphql/resolvers/worksheet/loading-worksheet.ts +30 -4
  76. package/server/graphql/resolvers/worksheet/packing-worksheet.ts +28 -3
  77. package/server/graphql/resolvers/worksheet/pending-cancellation-release-order.ts +13 -7
  78. package/server/graphql/resolvers/worksheet/picking/activate-picking.ts +1 -6
  79. package/server/graphql/resolvers/worksheet/picking/complete-picking.ts +35 -4
  80. package/server/graphql/resolvers/worksheet/picking/fetch-and-assign-picking-task.ts +78 -0
  81. package/server/graphql/resolvers/worksheet/picking/index.ts +3 -1
  82. package/server/graphql/resolvers/worksheet/picking/picking.ts +6 -4
  83. package/server/graphql/resolvers/worksheet/picking/scan-product-picking.ts +7 -4
  84. package/server/graphql/resolvers/worksheet/picking-worksheet.ts +102 -62
  85. package/server/graphql/resolvers/worksheet/recommend-putway-location.ts +4 -2
  86. package/server/graphql/resolvers/worksheet/unloaded-inventories.ts +10 -1
  87. package/server/graphql/resolvers/worksheet/unloading-return-worksheet.ts +6 -4
  88. package/server/graphql/types/index.ts +1 -2
  89. package/server/graphql/types/worksheet/index.ts +8 -2
  90. package/server/routes.ts +5 -0
  91. package/server/utils/inventory-util.ts +31 -9
  92. package/dist-server/graphql/types/pallet/index.js +0 -10
  93. package/dist-server/graphql/types/pallet/index.js.map +0 -1
  94. package/server/graphql/types/pallet/index.ts +0 -6
@@ -17,7 +17,8 @@ import {
17
17
  INVENTORY_STATUS,
18
18
  INVENTORY_TRANSACTION_TYPE,
19
19
  Location,
20
- LOCATION_TYPE
20
+ LOCATION_TYPE,
21
+ LOCATION_STATUS
21
22
  } from '@things-factory/warehouse-base'
22
23
 
23
24
  import { TASK_NUMBER_RULE_TYPE, TASK_NUMBER_SETTING_KEY, WORKSHEET_STATUS, WORKSHEET_TYPE } from '../../constants'
@@ -190,7 +191,7 @@ export class PickingWorksheetController extends VasWorksheetController {
190
191
  if (vasWorksheet) {
191
192
  await this.activateVAS(vasWorksheet.name, vasWorksheet.worksheetDetails)
192
193
  }
193
- } catch (e) {}
194
+ } catch (e) { }
194
195
 
195
196
  const pendingSplitOIs: OrderInventory[] = await this.trxMgr.getRepository(OrderInventory).find({
196
197
  where: { domain: this.domain, releaseGood, status: ORDER_INVENTORY_STATUS.PENDING_SPLIT }
@@ -386,106 +387,92 @@ export class PickingWorksheetController extends VasWorksheetController {
386
387
  worksheetType: string,
387
388
  productBarcode: string,
388
389
  cartonId: string,
389
- binLocation?: string
390
- ): Promise<void> {
391
- let worksheetDetail: WorksheetDetail = await this.findExecutableWorksheetDetailByName(
392
- worksheetDetailName,
393
- worksheetType,
394
- [
395
- 'worksheet',
396
- 'worksheet.bizplace',
397
- 'targetInventory',
398
- 'targetInventory.releaseGood',
399
- 'targetInventory.inventory',
400
- 'targetInventory.product',
401
- 'targetInventory.product.productDetails',
402
- 'targetInventory.product.productDetails.product',
403
- 'targetInventory.product.productDetails.childProductDetail'
404
- ]
405
- )
390
+ binLocation?: string,
391
+ serialNumber?: string
392
+ ): Promise<OrderInventory> {
393
+ try {
394
+ let worksheetDetail: WorksheetDetail = await this.findExecutableWorksheetDetailByName(
395
+ worksheetDetailName,
396
+ worksheetType,
397
+ [
398
+ 'worksheet',
399
+ 'worksheet.bizplace',
400
+ 'targetInventory',
401
+ 'targetInventory.releaseGood',
402
+ 'targetInventory.inventory',
403
+ 'targetInventory.product',
404
+ 'targetInventory.product.productDetails',
405
+ 'targetInventory.product.productDetails.product',
406
+ 'targetInventory.product.productDetails.childProductDetail'
407
+ ]
408
+ )
406
409
 
407
- const releaseGood: ReleaseGood = worksheetDetail.targetInventory.releaseGood
408
- let targetInventory: OrderInventory = worksheetDetail.targetInventory
409
- const product: Product = targetInventory.product
410
- let inventory: Inventory = targetInventory.inventory
411
- const packingType: string = inventory.packingType
412
- const packingSize: number = inventory.packingSize
410
+ const releaseGood: ReleaseGood = worksheetDetail.targetInventory.releaseGood
411
+ let targetInventory: OrderInventory = worksheetDetail.targetInventory
412
+ const product: Product = targetInventory.product
413
+ let inventory: Inventory = targetInventory.inventory
413
414
 
414
- let pickedQty: number = 1
415
- const releaseQty: number = targetInventory.releaseQty
415
+ //validation to prevent duplicated picking
416
+ let oiValidate: OrderInventory = await this.trxMgr.getRepository(OrderInventory).findOne({
417
+ where: { domain: this.domain, id: targetInventory.id, status: ORDER_INVENTORY_STATUS.PICKING }
418
+ })
419
+ if (!oiValidate)
420
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `is done`))
416
421
 
417
- if (inventory.cartonId !== cartonId)
418
- throw new Error(this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE('Carton ID', cartonId, inventory.cartonId))
422
+ //validation to prevent over release
423
+ if (inventory.qty <= 0)
424
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `over release`))
419
425
 
420
- // search for matching product barcode
421
- const productDetails: ProductDetail[] = product?.productDetails.filter(detail => !detail.deletedAt)
422
- const isMatchingBarcode: boolean = productDetails.map(detail => detail.gtin).includes(productBarcode)
423
- if (!isMatchingBarcode) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
426
+ if (inventory.cartonId !== cartonId)
427
+ throw new Error(this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE('Carton ID', cartonId, inventory.cartonId))
424
428
 
425
- // case for scanning parent packing type, packing size
426
- const foundProductDetail: ProductDetail = productDetails.find(
427
- (detail: ProductDetail) =>
428
- detail.gtin === productBarcode &&
429
- detail.packingType === packingType &&
430
- detail.packingSize == packingSize &&
431
- detail.product?.id === product.id
432
- )
429
+ const packingType: string = inventory.packingType
430
+ const packingSize: number = inventory.packingSize
433
431
 
434
- if (!foundProductDetail) {
435
- const roProductDetail: ProductDetail = productDetails.find(
436
- (parentDetail: ProductDetail) =>
437
- parentDetail.packingType === packingType && parentDetail.packingSize == packingSize
438
- )
439
-
440
- pickedQty = await this.getChildQty(productDetails, productBarcode, roProductDetail)
441
- if (pickedQty > releaseQty) {
442
- throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `over release`))
443
- }
444
- }
432
+ let pickedQty: number = 1
433
+ const releaseQty: number = targetInventory.releaseQty
445
434
 
446
- targetInventory.pickedQty = Boolean(targetInventory?.pickedQty) ? targetInventory.pickedQty + pickedQty : pickedQty
447
- if (targetInventory.pickedQty == releaseQty) {
448
- const leftQty: number = inventory.qty - releaseQty
449
- if (leftQty < 0) {
450
- throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `quantity can't exceed limitation`))
451
- }
435
+ targetInventory = await this.checkAndSetBinPicking(targetInventory, binLocation)
452
436
 
453
- targetInventory.status = ORDER_INVENTORY_STATUS.PICKED
437
+ // search for matching product barcode
438
+ const productDetails: ProductDetail[] = product?.productDetails.filter(detail => !detail.deletedAt)
439
+ const isMatchingBarcode: boolean = productDetails.map(detail => detail.gtin).includes(productBarcode)
440
+ if (!isMatchingBarcode) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
454
441
 
455
- if (binLocation) {
456
- const foundBinLocation: Location = await this.trxMgr.getRepository(Location).findOne({
457
- where: { domain: this.domain, name: binLocation, type: LOCATION_TYPE.BIN }
458
- })
442
+ // case for scanning parent packing type, packing size
443
+ const foundProductDetail: ProductDetail = productDetails.find(
444
+ (detail: ProductDetail) =>
445
+ detail.gtin === productBarcode &&
446
+ detail.packingType === packingType &&
447
+ detail.packingSize == packingSize &&
448
+ detail.product?.id === product.id
449
+ )
459
450
 
460
- if (!foundBinLocation)
461
- throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `invalid bin location id`))
451
+ if (!foundProductDetail) {
452
+ const roProductDetail: ProductDetail = productDetails.find(
453
+ (parentDetail: ProductDetail) =>
454
+ parentDetail.packingType === packingType && parentDetail.packingSize == packingSize
455
+ )
462
456
 
463
- targetInventory.binLocation = foundBinLocation
457
+ pickedQty = await this.getChildQty(productDetails, productBarcode, roProductDetail)
458
+ if (pickedQty > releaseQty) {
459
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `over release`))
460
+ }
464
461
  }
465
- await this.updateOrderTargets([targetInventory])
466
462
 
467
- inventory.qty -= targetInventory.releaseQty
468
- inventory.uomValue = Math.round((inventory.uomValue - targetInventory.releaseUomValue) * 100) / 100
469
- inventory.lockedQty = inventory.lockedQty - targetInventory.releaseQty
470
- inventory.lockedUomValue = Math.round((inventory.lockedUomValue - targetInventory.releaseUomValue) * 100) / 100
471
- inventory = await this.transactionInventory(
472
- inventory,
473
- releaseGood,
474
- -targetInventory.releaseQty,
475
- -targetInventory.releaseUomValue,
476
- INVENTORY_TRANSACTION_TYPE.PICKING
477
- )
463
+ if (product?.isRequireSerialNumberScanning) {
464
+ if ((!serialNumber || serialNumber == ''))
465
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `require serial number`))
478
466
 
479
- worksheetDetail.status = WORKSHEET_STATUS.DONE
480
- worksheetDetail.updater = this.user
481
- await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
482
-
483
- if (leftQty === 0) {
484
- inventory.status = INVENTORY_STATUS.TERMINATED
485
- await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.TERMINATED)
467
+ if (serialNumber) {
468
+ targetInventory.serialNumber = JSON.stringify(targetInventory.serialNumber ? [...(JSON.parse(targetInventory.serialNumber)), serialNumber] : [serialNumber])
469
+ }
486
470
  }
487
- } else {
488
- await this.updateOrderTargets([targetInventory])
471
+
472
+ await this.updatePickingTransaction(releaseGood, targetInventory, worksheetDetail, inventory, pickedQty)
473
+
474
+ } catch (error) {
475
+ throw error
489
476
  }
490
477
  }
491
478
 
@@ -494,70 +481,75 @@ export class PickingWorksheetController extends VasWorksheetController {
494
481
  worksheetType: string,
495
482
  palletId: string,
496
483
  locationName: string,
497
- releaseQty: number
484
+ pickedQty: number,
485
+ binLocation?: string,
486
+ serialNumber?: string
498
487
  ): Promise<void> {
499
- let worksheetDetail: WorksheetDetail = await this.findExecutableWorksheetDetailByName(
500
- worksheetDetailName,
501
- worksheetType,
502
- [
503
- 'worksheet',
504
- 'targetInventory',
505
- 'targetInventory.releaseGood',
506
- 'targetInventory.inventory',
507
- 'targetInventory.inventory.location'
508
- ]
509
- )
510
- const releaseGood: ReleaseGood = worksheetDetail.targetInventory.releaseGood
511
- let targetInventory: OrderInventory = worksheetDetail.targetInventory
512
- let inventory: Inventory = targetInventory.inventory
513
- if (inventory.palletId !== palletId)
514
- throw new Error(this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE('Pallet ID', palletId, inventory.palletId))
515
-
516
- const leftQty: number = inventory.qty - releaseQty
517
- if (leftQty < 0) {
518
- throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `quantity can't exceed limitation`))
519
- }
488
+ try {
489
+ let worksheetDetail: WorksheetDetail = await this.findExecutableWorksheetDetailByName(
490
+ worksheetDetailName,
491
+ worksheetType,
492
+ [
493
+ 'worksheet',
494
+ 'targetInventory',
495
+ 'targetInventory.releaseGood',
496
+ 'targetInventory.inventory',
497
+ 'targetInventory.inventory.location',
498
+ 'targetInventory.product',
499
+ ]
500
+ )
520
501
 
521
- targetInventory.pickedQty = releaseQty
522
- targetInventory.status = ORDER_INVENTORY_STATUS.PICKED
523
- await this.updateOrderTargets([targetInventory])
524
-
525
- inventory.qty -= targetInventory.releaseQty
526
- inventory.uomValue = Math.round((inventory.uomValue - targetInventory.releaseUomValue) * 100) / 100
527
- inventory.lockedQty = inventory.lockedQty - targetInventory.releaseQty
528
- inventory.lockedUomValue = Math.round((inventory.lockedUomValue - targetInventory.releaseUomValue) * 100) / 100
529
- inventory = await this.transactionInventory(
530
- inventory,
531
- releaseGood,
532
- -targetInventory.releaseQty,
533
- -targetInventory.releaseUomValue,
534
- INVENTORY_TRANSACTION_TYPE.PICKING
535
- )
502
+ const releaseGood: ReleaseGood = worksheetDetail.targetInventory.releaseGood
503
+ let targetInventory: OrderInventory = worksheetDetail.targetInventory
504
+ const product: Product = targetInventory.product
505
+ let inventory: Inventory = targetInventory.inventory
536
506
 
537
- worksheetDetail.status = WORKSHEET_STATUS.DONE
538
- worksheetDetail.updater = this.user
539
- await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
507
+ //validation to prevent duplicated picking
508
+ let oiValidate: OrderInventory = await this.trxMgr.getRepository(OrderInventory).findOne({
509
+ where: { domain: this.domain, id: targetInventory.id, status: ORDER_INVENTORY_STATUS.PICKING }
510
+ })
511
+ if (!oiValidate)
512
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `is done`))
540
513
 
541
- if (leftQty === 0) {
542
- inventory.status = INVENTORY_STATUS.TERMINATED
543
- await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.TERMINATED)
544
- }
514
+ //validation to prevent over release
515
+ if (inventory.qty <= 0)
516
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `over release`))
545
517
 
546
- const fromLocation: Location = targetInventory.inventory.location
547
- if (locationName) {
548
- const toLocation: Location = await this.trxMgr.getRepository(Location).findOne({
549
- where: { domain: this.domain, name: locationName },
550
- relations: ['warehouse']
551
- })
518
+ if (inventory.palletId !== palletId)
519
+ throw new Error(this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE('Pallet ID', palletId, inventory.palletId))
552
520
 
553
- if (!toLocation) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(locationName))
554
521
 
555
- if (fromLocation.id !== toLocation.id) {
556
- inventory.location = toLocation
557
- inventory.warehouse = toLocation.warehouse
558
- inventory.zone = toLocation.zone
559
- inventory = await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.RELOCATE)
522
+ if (product?.isRequireSerialNumberScanning) {
523
+ if ((!serialNumber || serialNumber == ''))
524
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `require serial number`))
525
+
526
+ if (serialNumber) {
527
+ targetInventory.serialNumber = JSON.stringify(targetInventory.serialNumber ? [...(JSON.parse(targetInventory.serialNumber)), serialNumber] : [serialNumber])
528
+ }
560
529
  }
530
+
531
+ targetInventory = await this.checkAndSetBinPicking(targetInventory, binLocation)
532
+
533
+ await this.updatePickingTransaction(releaseGood, targetInventory, worksheetDetail, inventory, pickedQty)
534
+
535
+ const fromLocation: Location = targetInventory.inventory.location
536
+ if (locationName) {
537
+ const toLocation: Location = await this.trxMgr.getRepository(Location).findOne({
538
+ where: { domain: this.domain, name: locationName },
539
+ relations: ['warehouse']
540
+ })
541
+
542
+ if (!toLocation) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(locationName))
543
+
544
+ if (fromLocation.id !== toLocation.id) {
545
+ inventory.location = toLocation
546
+ inventory.warehouse = toLocation.warehouse
547
+ inventory.zone = toLocation.zone
548
+ inventory = await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.RELOCATE)
549
+ }
550
+ }
551
+ } catch (error) {
552
+ throw error
561
553
  }
562
554
  }
563
555
 
@@ -937,4 +929,70 @@ export class PickingWorksheetController extends VasWorksheetController {
937
929
 
938
930
  return worksheetDetails
939
931
  }
932
+
933
+ private async checkAndSetBinPicking(orderInventory, binLocation) {
934
+ // bin picking validation
935
+ const binPickingSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
936
+ where: {
937
+ domain: this.domain,
938
+ name: 'enable-bin-picking'
939
+ }
940
+ })
941
+ if (binPickingSetting != undefined && (binPickingSetting.value).toLowerCase() == 'true') {
942
+ if (binLocation) {
943
+ const foundBinLocation: Location = await this.trxMgr.getRepository(Location).findOne({
944
+ where: { domain: this.domain, name: binLocation, type: LOCATION_TYPE.BIN }
945
+ })
946
+
947
+ if (!foundBinLocation)
948
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `invalid bin location id`))
949
+
950
+ orderInventory.binLocation = foundBinLocation
951
+ } else {
952
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `invalid bin location id`))
953
+ }
954
+ }
955
+
956
+ return orderInventory
957
+ }
958
+
959
+ private async updatePickingTransaction(releaseGood, orderInventory, worksheetDetail, inventory, pickedQty) {
960
+ const releaseQty: number = orderInventory.releaseQty
961
+
962
+ orderInventory.pickedQty = Boolean(orderInventory?.pickedQty) ? orderInventory.pickedQty + pickedQty : pickedQty
963
+ if (orderInventory.pickedQty == releaseQty) {
964
+ const leftQty: number = inventory.qty - releaseQty
965
+ if (leftQty < 0) {
966
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `quantity can't exceed limitation`))
967
+ }
968
+
969
+ orderInventory.status = ORDER_INVENTORY_STATUS.PICKED
970
+
971
+ inventory.qty -= orderInventory.releaseQty
972
+ inventory.uomValue = Math.round((inventory.uomValue - orderInventory.releaseUomValue) * 100) / 100
973
+ inventory.lockedQty = inventory.lockedQty - orderInventory.releaseQty
974
+ inventory.lockedUomValue = Math.round((inventory.lockedUomValue - orderInventory.releaseUomValue) * 100) / 100
975
+ inventory = await this.transactionInventory(
976
+ inventory,
977
+ releaseGood,
978
+ -orderInventory.releaseQty,
979
+ -orderInventory.releaseUomValue,
980
+ INVENTORY_TRANSACTION_TYPE.PICKING
981
+ )
982
+
983
+ worksheetDetail.status = WORKSHEET_STATUS.DONE
984
+ worksheetDetail.updater = this.user
985
+ await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
986
+
987
+ if (leftQty === 0) {
988
+ inventory.status = INVENTORY_STATUS.TERMINATED
989
+ await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.TERMINATED)
990
+ }
991
+ }
992
+
993
+ await this.updateOrderTargets([orderInventory])
994
+
995
+ return orderInventory
996
+ }
940
997
  }
998
+
@@ -1,11 +1,13 @@
1
+ import FormData from 'form-data'
2
+ import fetch from 'node-fetch'
3
+ import { EntityManager, getManager, getRepository } from 'typeorm'
4
+
1
5
  import { Attachment, STORAGE } from '@things-factory/attachment-base'
2
6
  import { Bizplace, ContactPoint } from '@things-factory/biz-base'
3
7
  import { config } from '@things-factory/env'
4
8
  import { ArrivalNotice, GoodsReceivalNote, ORDER_PRODUCT_STATUS, ORDER_STATUS } from '@things-factory/sales-base'
5
9
  import { Domain } from '@things-factory/shell'
6
- import FormData from 'form-data'
7
- import fetch from 'node-fetch'
8
- import { EntityManager, getManager, getRepository } from 'typeorm'
10
+
9
11
  import { TEMPLATE_TYPE, TRANSACTION_TYPE } from '../constants'
10
12
  import { Worksheet } from '../entities'
11
13
  import { DateTimeConverter } from '../utils/datetime-util'
@@ -117,19 +119,19 @@ export async function renderElcclGRN({ grnNo }, context: any) {
117
119
  `
118
120
  create temp table tmp2 on commit drop as(
119
121
  select id,seq,ref_order_id,order_no,"name",pallet_id,batch_id,product_id,warehouse_id,location_id,"zone",order_ref_no,packing_type,uom as unit,qty,
120
- opening_qty,uom_value,opening_weight,description,status,transaction_type,created_at,updated_at,domain_id,bizplace_id,creator_id,updater_id,
122
+ opening_qty,uom_value,description,status,transaction_type,created_at,updated_at,domain_id,bizplace_id,creator_id,updater_id,
121
123
  reusable_pallet_id,release_order_id,release_qty,inbound_qty,remaining_qty, inbound_qty as loose_amt, release_uom_value, inbound_uom_value,remaining_uom_value,
122
124
  inbound_uom_value as loose_wgt, null as cross_dock, inventory_id
123
125
  from tmp where release_qty > 0 or release_qty is null
124
126
  union all
125
127
  select id,seq,ref_order_id,order_no,"name",pallet_id,batch_id,product_id,warehouse_id,location_id,"zone",order_ref_no,packing_type,uom as unit,qty,
126
- opening_qty,uom_value,opening_weight,description,status,transaction_type,created_at,updated_at,domain_id,bizplace_id,creator_id,updater_id,
128
+ opening_qty,uom_value,description,status,transaction_type,created_at,updated_at,domain_id,bizplace_id,creator_id,updater_id,
127
129
  reusable_pallet_id,release_order_id,release_qty,inbound_qty,remaining_qty, remaining_qty as loose_amt, release_uom_value, inbound_uom_value,remaining_uom_value,
128
130
  remaining_uom_value as loose_wgt, null as cross_dock, inventory_id
129
131
  from tmp where release_qty < 0 and remaining_qty > 0
130
132
  union all
131
133
  select id,seq,ref_order_id,order_no,"name",pallet_id,batch_id,product_id,warehouse_id,location_id,"zone",order_ref_no,packing_type,uom as unit,qty,
132
- opening_qty,uom_value,opening_weight,description,status,transaction_type,created_at,updated_at,domain_id,bizplace_id,creator_id,updater_id,
134
+ opening_qty,uom_value,description,status,transaction_type,created_at,updated_at,domain_id,bizplace_id,creator_id,updater_id,
133
135
  reusable_pallet_id,release_order_id,release_qty,inbound_qty,remaining_qty, -release_qty as loose_amt, release_uom_value,inbound_uom_value,remaining_uom_value,
134
136
  -release_uom_value as loose_wgt, '[C/D]' as cross_dock, inventory_id
135
137
  from tmp where release_qty < 0
@@ -0,0 +1,68 @@
1
+ import FormData from 'form-data'
2
+ import fetch from 'node-fetch'
3
+ import { getRepository } from 'typeorm'
4
+
5
+ import { Attachment, STORAGE } from '@things-factory/attachment-base'
6
+ import { config } from '@things-factory/env'
7
+ import { Manifest, ReleaseGood } from '@things-factory/sales-base'
8
+ import { Domain } from '@things-factory/shell'
9
+
10
+ import { TEMPLATE_TYPE } from '../constants'
11
+ import { DateTimeConverter } from '../utils/datetime-util'
12
+
13
+ const REPORT_API_URL = config.get('reportApiUrl', 'http://localhost:8888/rest/report/show_html')
14
+
15
+ export async function renderManifest({ manifestNo }, context: any) {
16
+ // 1. find domain
17
+ const domain: Domain = await getRepository(Domain).findOne({
18
+ where: { id: context.state.domain.id }
19
+ })
20
+
21
+ // 2. find manifest
22
+ const manifest: Manifest = await getRepository(Manifest).findOne({
23
+ where: { domain, name: manifestNo },
24
+ relations: ['domain']
25
+ })
26
+
27
+ // find release good
28
+ const releaseGoods: ReleaseGood[] = await getRepository(ReleaseGood).find({
29
+ where: { domain, manifest }
30
+ })
31
+
32
+ // 7. find grn template based on category
33
+ const foundTemplate: Attachment = await getRepository(Attachment).findOne({
34
+ where: { domain, category: TEMPLATE_TYPE.MANIFEST_TEMPLATE }
35
+ })
36
+
37
+ const template = await STORAGE.readFile(foundTemplate.path, 'utf-8')
38
+
39
+ const data = {
40
+ shipping_provider: manifest?.shippingProvider,
41
+ manifest_no: manifest?.name,
42
+ manifest_date: DateTimeConverter.date(manifest?.createdAt).toString(),
43
+ total_list: releaseGoods?.length || 0,
44
+ product_list: releaseGoods.map((item, idx) => {
45
+ return {
46
+ list_no: idx + 1,
47
+ order_no: item?.refNo,
48
+ tracking_no: item?.trackingNo,
49
+ phone: item?.phone1,
50
+ delivery_date: DateTimeConverter.date(manifest?.dispatchedAt).toString(),
51
+ attention_to: item?.attentionTo,
52
+ delivery_address: item?.deliveryAddress1,
53
+ postal_code_city: `${item?.postalCode}, ${item?.city}`
54
+ }
55
+ })
56
+ }
57
+
58
+ const formData = new FormData()
59
+ formData.append('template', template)
60
+ formData.append('jsonString', JSON.stringify(data))
61
+
62
+ const response = await fetch(REPORT_API_URL, {
63
+ method: 'POST',
64
+ body: formData
65
+ })
66
+
67
+ return await response.text()
68
+ }
@@ -555,6 +555,44 @@ export class WorksheetController {
555
555
  return worksheet
556
556
  }
557
557
 
558
+ // @chernhaoee I think the naming of this function is not proper. Seems like it should be something like "updateLoadingWorksheet" since the logic targets only Loading Order Target
559
+ async updateWorksheet(
560
+ worksheetType: string,
561
+ refOrder: ReferenceOrderType,
562
+ worksheet: Worksheet,
563
+ orderTargets: OrderTargetTypes[],
564
+ refOrderStatus: string,
565
+ orderTargetStatus: string
566
+ ): Promise<Worksheet> {
567
+ let newOrderTarget = []
568
+
569
+ orderTargets.forEach((orderTarget: OrderTargetTypes) => {
570
+ orderTarget.status = orderTargetStatus
571
+ })
572
+ orderTargets = await this.updateOrderTargets(orderTargets)
573
+
574
+ for (let orderTarget of orderTargets) {
575
+ try {
576
+ await this.findWorksheetDetail({
577
+ targetInventory: orderTarget.id,
578
+ type: WORKSHEET_TYPE.LOADING
579
+ })
580
+ } catch (e) {
581
+ newOrderTarget.push(orderTarget)
582
+ }
583
+ }
584
+
585
+ worksheet.worksheetDetails = await this.createWorksheetDetails(worksheet, worksheetType, newOrderTarget)
586
+
587
+ // find worksheet details that doesnt exist based on order inventory
588
+ //worksheet.worksheetDetails = await this.findWorksheetDetail(worksheet.id)
589
+
590
+ refOrder.status = refOrderStatus
591
+ await this.updateRefOrder(refOrder)
592
+
593
+ return worksheet
594
+ }
595
+
558
596
  async generateBatchWorksheet(
559
597
  worksheetType: string,
560
598
  batchPickingWorksheet: Worksheet,
@@ -669,6 +707,7 @@ export class WorksheetController {
669
707
  } else if (
670
708
  worksheetType === WORKSHEET_TYPE.PUTAWAY ||
671
709
  worksheetType === WORKSHEET_TYPE.PICKING ||
710
+ worksheetType === WORKSHEET_TYPE.PACKING ||
672
711
  worksheetType === WORKSHEET_TYPE.LOADING ||
673
712
  worksheetType === WORKSHEET_TYPE.WAREHOUSE_RETURN ||
674
713
  worksheetType === WORKSHEET_TYPE.UNLOADING_RETURN
@@ -928,13 +967,13 @@ export class WorksheetController {
928
967
  )
929
968
  if (!currentProductDetail)
930
969
  throw new Error(this.ERROR_MSG.FIND.NOT_MATCH('inner pack', `GTIN (${productBarcode})`))
931
- childQty = scannedProductDetail.childQty
970
+ childQty = scannedProductDetail.packingSize
932
971
  } else {
933
972
  throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
934
973
  }
935
974
 
936
975
  if (hasMatchingChild) {
937
- childQty = scannedProductDetail.childQty
976
+ childQty = scannedProductDetail.packingSize
938
977
  } else {
939
978
  while (hasChildRelation && !hasMatchingChild) {
940
979
  hasChildRelation = Boolean(currentProductDetail?.childProductDetail)
@@ -1,10 +1,9 @@
1
- import { EntityManager, In } from 'typeorm'
2
-
3
1
  import { User } from '@things-factory/auth-base'
4
2
  import { Bizplace } from '@things-factory/biz-base'
5
3
  import { ReleaseGood } from '@things-factory/sales-base'
6
4
  import { Domain } from '@things-factory/shell'
7
5
  import { Pallet, PalletHistory } from '@things-factory/warehouse-base'
6
+ import { EntityManager, getRepository, In } from 'typeorm'
8
7
 
9
8
  export const palletOutbound = {
10
9
  async palletOutbound(_: any, { refOrderNo, patches }, context: any) {
@@ -1,10 +1,10 @@
1
- import { buildQuery, buildCondition } from '@things-factory/shell'
2
- import { Domain } from '@things-factory/shell'
3
- import { getRepository, SelectQueryBuilder, Brackets } from 'typeorm'
1
+ import { Brackets, getRepository, SelectQueryBuilder } from 'typeorm'
2
+
3
+ import { User } from '@things-factory/auth-base'
4
4
  import { getPermittedBizplaceIds } from '@things-factory/biz-base'
5
- import { Inventory } from '@things-factory/warehouse-base'
6
5
  import { ORDER_INVENTORY_STATUS } from '@things-factory/sales-base'
7
- import { User } from '@things-factory/auth-base'
6
+ import { buildCondition, buildQuery, Domain } from '@things-factory/shell'
7
+ import { Inventory, LOCATION_TYPE } from '@things-factory/warehouse-base'
8
8
 
9
9
  export const inventoriesByPalletResolver = {
10
10
  async inventoriesByPallet(_: any, { filters, pagination, sortings, locationSortingRules }, context: any) {
@@ -41,10 +41,11 @@ export const inventoriesByPalletResolver = {
41
41
  .andWhere('iv.qty > 0')
42
42
  .andWhere('CASE WHEN iv.lockedQty IS NULL THEN 0 ELSE iv.lockedQty END >= 0')
43
43
  .andWhere('iv.qty - CASE WHEN iv.lockedQty IS NULL THEN 0 ELSE iv.lockedQty END > 0')
44
+ .andWhere(`location.type NOT IN ('${LOCATION_TYPE.QUARANTINE}', '${LOCATION_TYPE.RESERVE}')`)
44
45
  .andWhere(
45
- `(iv.batch_id, product.name, iv.packing_type) NOT IN (
46
+ `(iv.batch_id, product.name, iv.packing_type, product.brand) NOT IN (
46
47
  SELECT
47
- oi.batch_id, p2.name, oi.packing_type
48
+ oi.batch_id, p2.name, oi.packing_type, p2.brand
48
49
  FROM
49
50
  order_inventories oi
50
51
  LEFT JOIN
@@ -112,7 +113,8 @@ export const inventoriesByPalletResolver = {
112
113
  remainUomValueWithUom: remainUomValue + ' ' + item.uom,
113
114
  // product: item.product,
114
115
  productName: item.product.name,
115
- productSKU: item.product.sku
116
+ productSKU: item.product.sku,
117
+ productBrand: item.product.brand
116
118
  }
117
119
  })
118
120
  )