@things-factory/worksheet-base 4.0.11 → 4.0.16

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 (106) 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 +159 -116
  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/index.js +2 -1
  24. package/dist-server/graphql/resolvers/pallet/index.js.map +1 -1
  25. package/dist-server/graphql/resolvers/pallet/pallet-outbound.js +1 -1
  26. package/dist-server/graphql/resolvers/pallet/pallet-outbound.js.map +1 -1
  27. package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js +6 -5
  28. package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js.map +1 -1
  29. package/dist-server/graphql/resolvers/worksheet/loading-worksheet.js +23 -2
  30. package/dist-server/graphql/resolvers/worksheet/loading-worksheet.js.map +1 -1
  31. package/dist-server/graphql/resolvers/worksheet/packing-worksheet.js +22 -0
  32. package/dist-server/graphql/resolvers/worksheet/packing-worksheet.js.map +1 -1
  33. package/dist-server/graphql/resolvers/worksheet/pending-cancellation-release-order.js +6 -3
  34. package/dist-server/graphql/resolvers/worksheet/pending-cancellation-release-order.js.map +1 -1
  35. package/dist-server/graphql/resolvers/worksheet/picking/activate-picking.js +0 -4
  36. package/dist-server/graphql/resolvers/worksheet/picking/activate-picking.js.map +1 -1
  37. package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js +30 -5
  38. package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js.map +1 -1
  39. package/dist-server/graphql/resolvers/worksheet/picking/fetch-and-assign-picking-task.js +72 -0
  40. package/dist-server/graphql/resolvers/worksheet/picking/fetch-and-assign-picking-task.js.map +1 -0
  41. package/dist-server/graphql/resolvers/worksheet/picking/index.js +2 -1
  42. package/dist-server/graphql/resolvers/worksheet/picking/index.js.map +1 -1
  43. package/dist-server/graphql/resolvers/worksheet/picking/picking.js +4 -4
  44. package/dist-server/graphql/resolvers/worksheet/picking/picking.js.map +1 -1
  45. package/dist-server/graphql/resolvers/worksheet/picking/scan-product-picking.js +4 -4
  46. package/dist-server/graphql/resolvers/worksheet/picking/scan-product-picking.js.map +1 -1
  47. package/dist-server/graphql/resolvers/worksheet/picking-worksheet.js +86 -57
  48. package/dist-server/graphql/resolvers/worksheet/picking-worksheet.js.map +1 -1
  49. package/dist-server/graphql/resolvers/worksheet/recommend-putway-location.js +40 -7
  50. package/dist-server/graphql/resolvers/worksheet/recommend-putway-location.js.map +1 -1
  51. package/dist-server/graphql/resolvers/worksheet/unloaded-inventories.js +6 -1
  52. package/dist-server/graphql/resolvers/worksheet/unloaded-inventories.js.map +1 -1
  53. package/dist-server/graphql/resolvers/worksheet/unloading-return-worksheet.js +2 -2
  54. package/dist-server/graphql/resolvers/worksheet/unloading-return-worksheet.js.map +1 -1
  55. package/dist-server/graphql/resolvers/worksheet-detail/generate-release-good-worksheet-details.js +48 -44
  56. package/dist-server/graphql/resolvers/worksheet-detail/generate-release-good-worksheet-details.js.map +1 -1
  57. package/dist-server/graphql/types/index.js +9 -4
  58. package/dist-server/graphql/types/index.js.map +1 -1
  59. package/dist-server/graphql/types/pallet/index.js +6 -3
  60. package/dist-server/graphql/types/pallet/index.js.map +1 -1
  61. package/dist-server/graphql/types/pallet/pallet.js +10 -0
  62. package/dist-server/graphql/types/pallet/pallet.js.map +1 -0
  63. package/dist-server/graphql/types/worksheet/index.js +7 -1
  64. package/dist-server/graphql/types/worksheet/index.js.map +1 -1
  65. package/dist-server/index.js +1 -0
  66. package/dist-server/index.js.map +1 -1
  67. package/dist-server/routes.js +4 -0
  68. package/dist-server/routes.js.map +1 -1
  69. package/dist-server/utils/inventory-util.js +50 -5
  70. package/dist-server/utils/inventory-util.js.map +1 -1
  71. package/package.json +16 -16
  72. package/server/constants/template.ts +1 -0
  73. package/server/controllers/ecommerce/sellercraft-controller.ts +3 -3
  74. package/server/controllers/inbound/putaway-worksheet-controller.ts +29 -8
  75. package/server/controllers/inbound/unloading-worksheet-controller.ts +83 -29
  76. package/server/controllers/index.ts +1 -0
  77. package/server/controllers/outbound/loading-worksheet-controller.ts +20 -0
  78. package/server/controllers/outbound/packing-worksheet-controller.ts +3 -5
  79. package/server/controllers/outbound/picking-worksheet-controller.ts +206 -154
  80. package/server/controllers/render-elccl-grn.ts +8 -6
  81. package/server/controllers/render-manifest.ts +68 -0
  82. package/server/controllers/worksheet-controller.ts +41 -2
  83. package/server/graphql/resolvers/pallet/index.ts +2 -0
  84. package/server/graphql/resolvers/pallet/pallet-outbound.ts +1 -2
  85. package/server/graphql/resolvers/worksheet/inventories-by-pallet.ts +10 -8
  86. package/server/graphql/resolvers/worksheet/loading-worksheet.ts +30 -4
  87. package/server/graphql/resolvers/worksheet/packing-worksheet.ts +28 -3
  88. package/server/graphql/resolvers/worksheet/pending-cancellation-release-order.ts +13 -7
  89. package/server/graphql/resolvers/worksheet/picking/activate-picking.ts +1 -6
  90. package/server/graphql/resolvers/worksheet/picking/complete-picking.ts +35 -4
  91. package/server/graphql/resolvers/worksheet/picking/fetch-and-assign-picking-task.ts +78 -0
  92. package/server/graphql/resolvers/worksheet/picking/index.ts +3 -1
  93. package/server/graphql/resolvers/worksheet/picking/picking.ts +6 -4
  94. package/server/graphql/resolvers/worksheet/picking/scan-product-picking.ts +7 -4
  95. package/server/graphql/resolvers/worksheet/picking-worksheet.ts +102 -62
  96. package/server/graphql/resolvers/worksheet/recommend-putway-location.ts +56 -6
  97. package/server/graphql/resolvers/worksheet/unloaded-inventories.ts +10 -1
  98. package/server/graphql/resolvers/worksheet/unloading-return-worksheet.ts +6 -4
  99. package/server/graphql/resolvers/worksheet-detail/generate-release-good-worksheet-details.ts +102 -76
  100. package/server/graphql/types/index.ts +9 -4
  101. package/server/graphql/types/pallet/index.ts +8 -2
  102. package/server/graphql/types/pallet/pallet.ts +7 -0
  103. package/server/graphql/types/worksheet/index.ts +8 -2
  104. package/server/index.ts +1 -0
  105. package/server/routes.ts +5 -0
  106. package/server/utils/inventory-util.ts +53 -9
@@ -366,19 +366,17 @@ export class PickingWorksheetController extends VasWorksheetController {
366
366
  await this.trxMgr.getRepository(WorksheetDetail).delete(worksheetDetailIds)
367
367
  await this.trxMgr.getRepository(OrderInventory).delete(targetInventoryIds)
368
368
 
369
- await this.trxMgr
370
- .getRepository(OrderInventory)
371
- .update(
372
- {
373
- refWorksheetId: worksheet.id,
374
- batchId,
375
- product: { id: productId },
376
- packingType,
377
- packingSize,
378
- status: ORDER_INVENTORY_STATUS.COMPLETE_SPLIT
379
- },
380
- { status: ORDER_INVENTORY_STATUS.PENDING_SPLIT, updater: this.user, updatedAt: new Date() }
381
- )
369
+ await this.trxMgr.getRepository(OrderInventory).update(
370
+ {
371
+ refWorksheetId: worksheet.id,
372
+ batchId,
373
+ product: { id: productId },
374
+ packingType,
375
+ packingSize,
376
+ status: ORDER_INVENTORY_STATUS.COMPLETE_SPLIT
377
+ },
378
+ { status: ORDER_INVENTORY_STATUS.PENDING_SPLIT, updater: this.user, updatedAt: new Date() }
379
+ )
382
380
  }
383
381
 
384
382
  async scanProductPicking(
@@ -386,106 +384,91 @@ export class PickingWorksheetController extends VasWorksheetController {
386
384
  worksheetType: string,
387
385
  productBarcode: string,
388
386
  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
- )
387
+ binLocation?: string,
388
+ serialNumber?: string
389
+ ): Promise<OrderInventory> {
390
+ try {
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
+ )
406
406
 
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
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
413
411
 
414
- let pickedQty: number = 1
415
- const releaseQty: number = targetInventory.releaseQty
412
+ //validation to prevent duplicated picking
413
+ let oiValidate: OrderInventory = await this.trxMgr.getRepository(OrderInventory).findOne({
414
+ where: { domain: this.domain, id: targetInventory.id, status: ORDER_INVENTORY_STATUS.PICKING }
415
+ })
416
+ if (!oiValidate) throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `is done`))
416
417
 
417
- if (inventory.cartonId !== cartonId)
418
- throw new Error(this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE('Carton ID', cartonId, inventory.cartonId))
418
+ //validation to prevent over release
419
+ if (inventory.qty <= 0) throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `over release`))
419
420
 
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))
421
+ if (inventory.cartonId !== cartonId)
422
+ throw new Error(this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE('Carton ID', cartonId, inventory.cartonId))
424
423
 
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
- )
433
-
434
- if (!foundProductDetail) {
435
- const roProductDetail: ProductDetail = productDetails.find(
436
- (parentDetail: ProductDetail) =>
437
- parentDetail.packingType === packingType && parentDetail.packingSize == packingSize
438
- )
424
+ const packingType: string = inventory.packingType
425
+ const packingSize: number = inventory.packingSize
439
426
 
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
- }
427
+ let pickedQty: number = 1
428
+ const releaseQty: number = targetInventory.releaseQty
445
429
 
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
- }
430
+ targetInventory = await this.checkAndSetBinPicking(targetInventory, binLocation)
452
431
 
453
- targetInventory.status = ORDER_INVENTORY_STATUS.PICKED
432
+ // search for matching product barcode
433
+ const productDetails: ProductDetail[] = product?.productDetails.filter(detail => !detail.deletedAt)
434
+ const isMatchingBarcode: boolean = productDetails.map(detail => detail.gtin).includes(productBarcode)
435
+ if (!isMatchingBarcode) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
454
436
 
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
- })
437
+ // case for scanning parent packing type, packing size
438
+ const foundProductDetail: ProductDetail = productDetails.find(
439
+ (detail: ProductDetail) =>
440
+ detail.gtin === productBarcode &&
441
+ detail.packingType === packingType &&
442
+ detail.packingSize == packingSize &&
443
+ detail.product?.id === product.id
444
+ )
459
445
 
460
- if (!foundBinLocation)
461
- throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `invalid bin location id`))
446
+ if (!foundProductDetail) {
447
+ const roProductDetail: ProductDetail = productDetails.find(
448
+ (parentDetail: ProductDetail) =>
449
+ parentDetail.packingType === packingType && parentDetail.packingSize == packingSize
450
+ )
462
451
 
463
- targetInventory.binLocation = foundBinLocation
452
+ pickedQty = await this.getChildQty(productDetails, productBarcode, roProductDetail)
453
+ if (pickedQty > releaseQty) {
454
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `over release`))
455
+ }
464
456
  }
465
- await this.updateOrderTargets([targetInventory])
466
457
 
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
- )
458
+ if (product?.isRequireSerialNumberScanning) {
459
+ if (!serialNumber || serialNumber == '')
460
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `require serial number`))
478
461
 
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)
462
+ if (serialNumber) {
463
+ targetInventory.serialNumber = JSON.stringify(
464
+ targetInventory.serialNumber ? [...JSON.parse(targetInventory.serialNumber), serialNumber] : [serialNumber]
465
+ )
466
+ }
486
467
  }
487
- } else {
488
- await this.updateOrderTargets([targetInventory])
468
+
469
+ await this.updatePickingTransaction(releaseGood, targetInventory, worksheetDetail, inventory, pickedQty)
470
+ } catch (error) {
471
+ throw error
489
472
  }
490
473
  }
491
474
 
@@ -494,70 +477,74 @@ export class PickingWorksheetController extends VasWorksheetController {
494
477
  worksheetType: string,
495
478
  palletId: string,
496
479
  locationName: string,
497
- releaseQty: number
480
+ pickedQty: number,
481
+ binLocation?: string,
482
+ serialNumber?: string
498
483
  ): 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
- }
484
+ try {
485
+ let worksheetDetail: WorksheetDetail = await this.findExecutableWorksheetDetailByName(
486
+ worksheetDetailName,
487
+ worksheetType,
488
+ [
489
+ 'worksheet',
490
+ 'targetInventory',
491
+ 'targetInventory.releaseGood',
492
+ 'targetInventory.inventory',
493
+ 'targetInventory.inventory.location',
494
+ 'targetInventory.product'
495
+ ]
496
+ )
520
497
 
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
- )
498
+ const releaseGood: ReleaseGood = worksheetDetail.targetInventory.releaseGood
499
+ let targetInventory: OrderInventory = worksheetDetail.targetInventory
500
+ const product: Product = targetInventory.product
501
+ let inventory: Inventory = targetInventory.inventory
536
502
 
537
- worksheetDetail.status = WORKSHEET_STATUS.DONE
538
- worksheetDetail.updater = this.user
539
- await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
503
+ //validation to prevent duplicated picking
504
+ let oiValidate: OrderInventory = await this.trxMgr.getRepository(OrderInventory).findOne({
505
+ where: { domain: this.domain, id: targetInventory.id, status: ORDER_INVENTORY_STATUS.PICKING }
506
+ })
507
+ if (!oiValidate) throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `is done`))
540
508
 
541
- if (leftQty === 0) {
542
- inventory.status = INVENTORY_STATUS.TERMINATED
543
- await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.TERMINATED)
544
- }
509
+ //validation to prevent over release
510
+ if (inventory.qty <= 0) throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `over release`))
545
511
 
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
- })
512
+ if (inventory.palletId !== palletId)
513
+ throw new Error(this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE('Pallet ID', palletId, inventory.palletId))
552
514
 
553
- if (!toLocation) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(locationName))
515
+ if (product?.isRequireSerialNumberScanning) {
516
+ if (!serialNumber || serialNumber == '')
517
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `require serial number`))
554
518
 
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)
519
+ if (serialNumber) {
520
+ targetInventory.serialNumber = JSON.stringify(
521
+ targetInventory.serialNumber ? [...JSON.parse(targetInventory.serialNumber), serialNumber] : [serialNumber]
522
+ )
523
+ }
560
524
  }
525
+
526
+ targetInventory = await this.checkAndSetBinPicking(targetInventory, binLocation)
527
+
528
+ await this.updatePickingTransaction(releaseGood, targetInventory, worksheetDetail, inventory, pickedQty)
529
+
530
+ const fromLocation: Location = targetInventory.inventory.location
531
+ if (locationName) {
532
+ const toLocation: Location = await this.trxMgr.getRepository(Location).findOne({
533
+ where: { domain: this.domain, name: locationName },
534
+ relations: ['warehouse']
535
+ })
536
+
537
+ if (!toLocation) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(locationName))
538
+
539
+ if (fromLocation.id !== toLocation.id) {
540
+ inventory.location = toLocation
541
+ inventory.warehouse = toLocation.warehouse
542
+ inventory.zone = toLocation.zone
543
+ inventory = await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.RELOCATE)
544
+ }
545
+ }
546
+ } catch (error) {
547
+ throw error
561
548
  }
562
549
  }
563
550
 
@@ -937,4 +924,69 @@ export class PickingWorksheetController extends VasWorksheetController {
937
924
 
938
925
  return worksheetDetails
939
926
  }
927
+
928
+ private async checkAndSetBinPicking(orderInventory, binLocation) {
929
+ // bin picking validation
930
+ const binPickingSetting: Setting = await this.trxMgr.getRepository(Setting).findOne({
931
+ where: {
932
+ domain: this.domain,
933
+ name: 'enable-bin-picking'
934
+ }
935
+ })
936
+ if (binPickingSetting?.value && binPickingSetting.value.toLowerCase() === 'true') {
937
+ if (binLocation) {
938
+ const foundBinLocation: Location = await this.trxMgr.getRepository(Location).findOne({
939
+ where: { domain: this.domain, name: binLocation, type: LOCATION_TYPE.BIN }
940
+ })
941
+
942
+ if (!foundBinLocation)
943
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `invalid bin location id`))
944
+
945
+ orderInventory.binLocation = foundBinLocation
946
+ } else {
947
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `invalid bin location id`))
948
+ }
949
+ }
950
+
951
+ return orderInventory
952
+ }
953
+
954
+ private async updatePickingTransaction(releaseGood, orderInventory, worksheetDetail, inventory, pickedQty) {
955
+ const releaseQty: number = orderInventory.releaseQty
956
+
957
+ orderInventory.pickedQty = Boolean(orderInventory?.pickedQty) ? orderInventory.pickedQty + pickedQty : pickedQty
958
+ if (orderInventory.pickedQty == releaseQty) {
959
+ const leftQty: number = inventory.qty - releaseQty
960
+ if (leftQty < 0) {
961
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `quantity can't exceed limitation`))
962
+ }
963
+
964
+ orderInventory.status = ORDER_INVENTORY_STATUS.PICKED
965
+
966
+ inventory.qty -= orderInventory.releaseQty
967
+ inventory.uomValue = Math.round((inventory.uomValue - orderInventory.releaseUomValue) * 100) / 100
968
+ inventory.lockedQty = inventory.lockedQty - orderInventory.releaseQty
969
+ inventory.lockedUomValue = Math.round((inventory.lockedUomValue - orderInventory.releaseUomValue) * 100) / 100
970
+ inventory = await this.transactionInventory(
971
+ inventory,
972
+ releaseGood,
973
+ -orderInventory.releaseQty,
974
+ -orderInventory.releaseUomValue,
975
+ INVENTORY_TRANSACTION_TYPE.PICKING
976
+ )
977
+
978
+ worksheetDetail.status = WORKSHEET_STATUS.DONE
979
+ worksheetDetail.updater = this.user
980
+ await this.trxMgr.getRepository(WorksheetDetail).save(worksheetDetail)
981
+
982
+ if (leftQty === 0) {
983
+ inventory.status = INVENTORY_STATUS.TERMINATED
984
+ await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.TERMINATED)
985
+ }
986
+ }
987
+
988
+ await this.updateOrderTargets([orderInventory])
989
+
990
+ return orderInventory
991
+ }
940
992
  }
@@ -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)
@@ -3,3 +3,5 @@ import { palletOutbound } from './pallet-outbound'
3
3
  export const Mutation = {
4
4
  ...palletOutbound
5
5
  }
6
+
7
+ export const Query = {}
@@ -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
  )