@things-factory/worksheet-base 4.3.82 → 4.3.87

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 (97) hide show
  1. package/dist-server/controllers/inbound/unloading-worksheet-controller.js +49 -49
  2. package/dist-server/controllers/inbound/unloading-worksheet-controller.js.map +1 -1
  3. package/dist-server/controllers/inspect/cycle-count-worksheet-controller.js +4 -2
  4. package/dist-server/controllers/inspect/cycle-count-worksheet-controller.js.map +1 -1
  5. package/dist-server/controllers/outbound/loading-worksheet-controller.js +4 -10
  6. package/dist-server/controllers/outbound/loading-worksheet-controller.js.map +1 -1
  7. package/dist-server/controllers/outbound/packing-worksheet-controller.js +20 -22
  8. package/dist-server/controllers/outbound/packing-worksheet-controller.js.map +1 -1
  9. package/dist-server/controllers/outbound/picking-worksheet-controller.js +154 -71
  10. package/dist-server/controllers/outbound/picking-worksheet-controller.js.map +1 -1
  11. package/dist-server/controllers/outbound/sorting-worksheet-controller.js +14 -12
  12. package/dist-server/controllers/outbound/sorting-worksheet-controller.js.map +1 -1
  13. package/dist-server/controllers/vas/vas-worksheet-controller.js +2 -1
  14. package/dist-server/controllers/vas/vas-worksheet-controller.js.map +1 -1
  15. package/dist-server/controllers/worksheet-controller.js +37 -2
  16. package/dist-server/controllers/worksheet-controller.js.map +1 -1
  17. package/dist-server/entities/worksheet-detail.js +2 -1
  18. package/dist-server/entities/worksheet-detail.js.map +1 -1
  19. package/dist-server/graphql/resolvers/worksheet/batch-picking-worksheet.js +0 -6
  20. package/dist-server/graphql/resolvers/worksheet/batch-picking-worksheet.js.map +1 -1
  21. package/dist-server/graphql/resolvers/worksheet/confirm-cancellation-release-order.js +2 -1
  22. package/dist-server/graphql/resolvers/worksheet/confirm-cancellation-release-order.js.map +1 -1
  23. package/dist-server/graphql/resolvers/worksheet/cycle-count-adjustment.js +6 -6
  24. package/dist-server/graphql/resolvers/worksheet/cycle-count-adjustment.js.map +1 -1
  25. package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js +1 -2
  26. package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js.map +1 -1
  27. package/dist-server/graphql/resolvers/worksheet/loading/complete-loading.js +28 -67
  28. package/dist-server/graphql/resolvers/worksheet/loading/complete-loading.js.map +1 -1
  29. package/dist-server/graphql/resolvers/worksheet/packing/activate-packing.js +8 -23
  30. package/dist-server/graphql/resolvers/worksheet/packing/activate-packing.js.map +1 -1
  31. package/dist-server/graphql/resolvers/worksheet/packing/complete-packing.js +7 -30
  32. package/dist-server/graphql/resolvers/worksheet/packing/complete-packing.js.map +1 -1
  33. package/dist-server/graphql/resolvers/worksheet/packing/packing.js +8 -23
  34. package/dist-server/graphql/resolvers/worksheet/packing/packing.js.map +1 -1
  35. package/dist-server/graphql/resolvers/worksheet/packing/scan-product-packing.js +8 -25
  36. package/dist-server/graphql/resolvers/worksheet/packing/scan-product-packing.js.map +1 -1
  37. package/dist-server/graphql/resolvers/worksheet/packing-worksheet.js +12 -59
  38. package/dist-server/graphql/resolvers/worksheet/packing-worksheet.js.map +1 -1
  39. package/dist-server/graphql/resolvers/worksheet/picking/activate-picking.js +25 -51
  40. package/dist-server/graphql/resolvers/worksheet/picking/activate-picking.js.map +1 -1
  41. package/dist-server/graphql/resolvers/worksheet/picking/complete-batch-picking.js +2 -2
  42. package/dist-server/graphql/resolvers/worksheet/picking/complete-batch-picking.js.map +1 -1
  43. package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js +118 -262
  44. package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js.map +1 -1
  45. package/dist-server/graphql/resolvers/worksheet/picking/fetch-and-assign-picking-task.js +38 -36
  46. package/dist-server/graphql/resolvers/worksheet/picking/fetch-and-assign-picking-task.js.map +1 -1
  47. package/dist-server/graphql/resolvers/worksheet/picking/scan-product-picking.js +4 -7
  48. package/dist-server/graphql/resolvers/worksheet/picking/scan-product-picking.js.map +1 -1
  49. package/dist-server/graphql/resolvers/worksheet/picking-worksheet.js +2 -3
  50. package/dist-server/graphql/resolvers/worksheet/picking-worksheet.js.map +1 -1
  51. package/dist-server/graphql/resolvers/worksheet/proceed-extra-products.js +4 -6
  52. package/dist-server/graphql/resolvers/worksheet/proceed-extra-products.js.map +1 -1
  53. package/dist-server/graphql/resolvers/worksheet/putaway/complete-putaway.js +14 -39
  54. package/dist-server/graphql/resolvers/worksheet/putaway/complete-putaway.js.map +1 -1
  55. package/dist-server/graphql/resolvers/worksheet/transfer.js +9 -9
  56. package/dist-server/graphql/resolvers/worksheet/transfer.js.map +1 -1
  57. package/dist-server/graphql/resolvers/worksheet/vas-transactions/common-utils.js +17 -17
  58. package/dist-server/graphql/resolvers/worksheet/vas-transactions/common-utils.js.map +1 -1
  59. package/dist-server/graphql/resolvers/worksheet-detail/regenerate-release-good-worksheet-details.js +4 -4
  60. package/dist-server/graphql/resolvers/worksheet-detail/regenerate-release-good-worksheet-details.js.map +1 -1
  61. package/dist-server/graphql/types/worksheet-detail/index.js +0 -1
  62. package/dist-server/graphql/types/worksheet-detail/index.js.map +1 -1
  63. package/dist-server/utils/inventory-util.js +98 -1
  64. package/dist-server/utils/inventory-util.js.map +1 -1
  65. package/package.json +17 -17
  66. package/server/controllers/inbound/unloading-worksheet-controller.ts +70 -49
  67. package/server/controllers/inspect/cycle-count-worksheet-controller.ts +4 -2
  68. package/server/controllers/outbound/loading-worksheet-controller.ts +3 -9
  69. package/server/controllers/outbound/packing-worksheet-controller.ts +31 -23
  70. package/server/controllers/outbound/picking-worksheet-controller.ts +219 -88
  71. package/server/controllers/outbound/sorting-worksheet-controller.ts +12 -12
  72. package/server/controllers/vas/vas-worksheet-controller.ts +2 -2
  73. package/server/controllers/worksheet-controller.ts +49 -5
  74. package/server/entities/worksheet-detail.ts +5 -0
  75. package/server/graphql/resolvers/worksheet/batch-picking-worksheet.ts +0 -6
  76. package/server/graphql/resolvers/worksheet/confirm-cancellation-release-order.ts +2 -1
  77. package/server/graphql/resolvers/worksheet/cycle-count-adjustment.ts +2 -2
  78. package/server/graphql/resolvers/worksheet/inventories-by-pallet.ts +1 -3
  79. package/server/graphql/resolvers/worksheet/loading/complete-loading.ts +33 -77
  80. package/server/graphql/resolvers/worksheet/packing/activate-packing.ts +9 -26
  81. package/server/graphql/resolvers/worksheet/packing/complete-packing.ts +9 -34
  82. package/server/graphql/resolvers/worksheet/packing/packing.ts +9 -26
  83. package/server/graphql/resolvers/worksheet/packing/scan-product-packing.ts +9 -28
  84. package/server/graphql/resolvers/worksheet/packing-worksheet.ts +13 -68
  85. package/server/graphql/resolvers/worksheet/picking/activate-picking.ts +30 -60
  86. package/server/graphql/resolvers/worksheet/picking/complete-batch-picking.ts +2 -2
  87. package/server/graphql/resolvers/worksheet/picking/complete-picking.ts +130 -288
  88. package/server/graphql/resolvers/worksheet/picking/fetch-and-assign-picking-task.ts +42 -41
  89. package/server/graphql/resolvers/worksheet/picking/scan-product-picking.ts +10 -30
  90. package/server/graphql/resolvers/worksheet/picking-worksheet.ts +2 -3
  91. package/server/graphql/resolvers/worksheet/proceed-extra-products.ts +4 -5
  92. package/server/graphql/resolvers/worksheet/putaway/complete-putaway.ts +15 -45
  93. package/server/graphql/resolvers/worksheet/transfer.ts +16 -18
  94. package/server/graphql/resolvers/worksheet/vas-transactions/common-utils.ts +2 -3
  95. package/server/graphql/resolvers/worksheet-detail/regenerate-release-good-worksheet-details.ts +1 -4
  96. package/server/graphql/types/worksheet-detail/index.ts +0 -1
  97. package/server/utils/inventory-util.ts +126 -1
@@ -93,15 +93,13 @@ export class PackingWorksheetController extends VasWorksheetController {
93
93
  'targetInventory.releaseGood',
94
94
  'targetInventory.inventory',
95
95
  'targetInventory.inventory.location',
96
- 'targetInventory.product',
97
- 'targetInventory.productDetail'
96
+ 'targetInventory.product'
98
97
  ]
99
98
  )
100
- let targetInventory: OrderInventory = worksheetDetail.targetInventory
101
- let inventory: Inventory = targetInventory.inventory
102
99
  const releaseGood: ReleaseGood = worksheetDetail.targetInventory.releaseGood
100
+ let targetInventory: OrderInventory = worksheetDetail.targetInventory
103
101
  const product: Product = targetInventory.product
104
- const productDetail: ProductDetail = targetInventory.productDetail
102
+ let inventory: Inventory = targetInventory.inventory
105
103
  const pickedQty: number = targetInventory.releaseQty
106
104
 
107
105
  if (packedQty > pickedQty) {
@@ -116,7 +114,8 @@ export class PackingWorksheetController extends VasWorksheetController {
116
114
  }
117
115
 
118
116
  let foundSerialNumber: InventoryItem = await this.trxMgr.getRepository(InventoryItem).findOne({
119
- where: { domain: this.domain, serialNumber: serialNumber, productDetail }
117
+ where: { domain: this.domain, serialNumber: serialNumber, product },
118
+ relations: ['product', 'inventory']
120
119
  })
121
120
 
122
121
  if (foundSerialNumber) {
@@ -140,7 +139,6 @@ export class PackingWorksheetController extends VasWorksheetController {
140
139
  inventoryItem.source = INVENTORY_ITEM_SOURCE.OUTBOUND
141
140
  inventoryItem.outboundOrderId = releaseGood.id
142
141
  inventoryItem.product = product
143
- inventoryItem.productDetail = productDetail
144
142
  inventoryItem.inventory = inventory
145
143
  inventoryItem.domain = this.domain
146
144
 
@@ -196,28 +194,39 @@ export class PackingWorksheetController extends VasWorksheetController {
196
194
  'targetInventory.inventory.product',
197
195
  'targetInventory.inventory.product.productDetails',
198
196
  'targetInventory.inventory.product.productDetails.childProductDetail',
199
- 'targetInventory.inventory.location',
200
- 'targetInventory.productDetail'
197
+ 'targetInventory.inventory.location'
201
198
  ]
202
199
  )
200
+ const releaseGood: ReleaseGood = worksheetDetail.targetInventory.releaseGood
201
+ const product: Product = worksheetDetail.targetInventory.inventory.product
202
+ const filterProductDetails: ProductDetail[] = product?.productDetails.filter(detail => !detail.deletedAt)
203
203
  let targetInventory: OrderInventory = worksheetDetail.targetInventory
204
204
  let inventory: Inventory = targetInventory.inventory
205
205
  let packedQty: number = 1
206
206
  let pickedQty: number = targetInventory.releaseQty
207
- const releaseGood: ReleaseGood = targetInventory.releaseGood
208
- const product: Product = targetInventory.inventory.product
209
- const productDetail: ProductDetail = targetInventory.productDetail
210
207
 
211
208
  // search for matching product barcode
212
- const filterProductDetails: ProductDetail[] = product?.productDetails.filter(detail => !detail.deletedAt)
213
- const scannedProductDetail: ProductDetail = filterProductDetails.find(detail => detail.gtin == productBarcode)
214
- if (!scannedProductDetail) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
215
-
216
- // case for scanning parent packing type, packing size
217
- // when scannedProductDetail id is not the same as productDetail id, then it's not child gtin, proceed to get child qty
218
- if (scannedProductDetail.id !== productDetail.id && !product?.isRequireSerialNumberScanningOutbound) {
219
- let childQty = await this.getChildQty(filterProductDetails, productBarcode, productDetail, scannedProductDetail)
220
- pickedQty *= childQty
209
+ const productDetail: ProductDetail = product?.productDetails
210
+ .filter(detail => !detail.deletedAt)
211
+ .find(
212
+ detail =>
213
+ detail.gtin === productBarcode &&
214
+ detail.packingType === inventory.packingType &&
215
+ detail.packingSize === inventory.packingSize
216
+ )
217
+
218
+ if (!productDetail && !product?.isRequireSerialNumberScanningOutbound) {
219
+ let roProductDetail: ProductDetail = product?.productDetails.find(
220
+ (parentDetail: ProductDetail) =>
221
+ parentDetail.packingType === inventory.packingType && parentDetail.packingSize == inventory.packingSize
222
+ )
223
+
224
+ roProductDetail.product = product
225
+
226
+ let childQty = await this.getChildQty(filterProductDetails, productBarcode, roProductDetail)
227
+ packedQty *= childQty
228
+ } else if (!productDetail) {
229
+ throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
221
230
  }
222
231
 
223
232
  if (packedQty + targetInventory.packedQty > pickedQty) {
@@ -233,7 +242,7 @@ export class PackingWorksheetController extends VasWorksheetController {
233
242
 
234
243
  let foundSerialNumber: InventoryItem = await this.trxMgr
235
244
  .getRepository(InventoryItem)
236
- .findOne({ where: { domain: this.domain, serialNumber: serialNumber, productDetail } })
245
+ .findOne({ where: { domain: this.domain, serialNumber: serialNumber, product } })
237
246
 
238
247
  if (foundSerialNumber) {
239
248
  if (foundSerialNumber.inventoryId !== inventory.id) {
@@ -260,7 +269,6 @@ export class PackingWorksheetController extends VasWorksheetController {
260
269
  inventoryItem.outboundOrderId = releaseGood.id
261
270
  inventoryItem.source = INVENTORY_ITEM_SOURCE.OUTBOUND
262
271
  inventoryItem.product = product
263
- inventoryItem.productDetail = productDetail
264
272
  inventoryItem.inventory = inventory
265
273
  inventoryItem.domain = this.domain
266
274
 
@@ -1,11 +1,10 @@
1
- import { Equal, In, IsNull, Not, getRepository, getConnection } from 'typeorm'
1
+ import { EntityManager, Equal, getConnection, In, IsNull, Not } from 'typeorm'
2
2
 
3
3
  import { Bizplace } from '@things-factory/biz-base'
4
4
  import { generateId } from '@things-factory/id-rule-base'
5
5
  import { Product, ProductDetail } from '@things-factory/product-base'
6
- import { Sellercraft, SellercraftStatus } from '@things-factory/integration-sellercraft'
7
- import { logger } from '@things-factory/env'
8
6
  import {
7
+ GenerateBatchPickInfo,
9
8
  ORDER_INVENTORY_STATUS,
10
9
  ORDER_PRODUCT_STATUS,
11
10
  ORDER_STATUS,
@@ -16,8 +15,7 @@ import {
16
15
  OrderToteItem,
17
16
  OrderToteSeal,
18
17
  OrderVas,
19
- ReleaseGood,
20
- GenerateBatchPickInfo
18
+ ReleaseGood
21
19
  } from '@things-factory/sales-base'
22
20
  import { Setting } from '@things-factory/setting-base'
23
21
  import {
@@ -35,9 +33,8 @@ import {
35
33
 
36
34
  import { TASK_NUMBER_RULE_TYPE, TASK_NUMBER_SETTING_KEY, WORKSHEET_STATUS, WORKSHEET_TYPE } from '../../constants'
37
35
  import { Worksheet, WorksheetDetail } from '../../entities'
38
- import { WorksheetNoGenerator } from '../../utils'
36
+ import { generateInventoryHistory, WorksheetNoGenerator } from '../../utils'
39
37
  import { VasWorksheetController } from '../vas/vas-worksheet-controller'
40
- import { SellercraftController } from '../../controllers'
41
38
 
42
39
  export class PickingWorksheetController extends VasWorksheetController {
43
40
  async generatePickingWorksheet(releaseGoodNo: string, currentStatus: string = null): Promise<Worksheet> {
@@ -216,7 +213,7 @@ export class PickingWorksheetController extends VasWorksheetController {
216
213
  if (vasWorksheet) {
217
214
  await this.activateVAS(vasWorksheet.name, vasWorksheet.worksheetDetails)
218
215
  }
219
- } catch (e) {}
216
+ } catch (e) { }
220
217
 
221
218
  const pendingSplitOIs: OrderInventory[] = await this.trxMgr.getRepository(OrderInventory).find({
222
219
  where: { domain: this.domain, releaseGood, status: ORDER_INVENTORY_STATUS.PENDING_SPLIT }
@@ -419,69 +416,74 @@ export class PickingWorksheetController extends VasWorksheetController {
419
416
  binLocation?: string,
420
417
  serialNumber?: string,
421
418
  toteNo?: string,
422
- pickingQty?: number
423
- ): Promise<OrderInventory> {
419
+ pickedQty: number = 1
420
+ ): Promise<WorksheetDetail> {
424
421
  try {
425
- let worksheetDetail: WorksheetDetail = await this.findExecutableWorksheetDetailByName(
426
- worksheetDetailName,
427
- worksheetType,
428
- [
429
- 'worksheet',
430
- 'worksheet.bizplace',
431
- 'targetInventory',
432
- 'targetInventory.releaseGood',
433
- 'targetInventory.inventory',
434
- 'targetInventory.product',
435
- 'targetInventory.orderProduct',
436
- 'targetInventory.product.productDetails',
437
- 'targetInventory.product.productDetails.product',
438
- 'targetInventory.product.productDetails.childProductDetail',
439
- 'targetInventory.productDetail'
440
- ]
441
- )
422
+ //find existing worksheet detail
423
+ let worksheetDetail: WorksheetDetail = await this.trxMgr
424
+ .getRepository(WorksheetDetail)
425
+ .createQueryBuilder('wd')
426
+ .innerJoinAndSelect('wd.worksheet', 'ws')
427
+ .innerJoinAndSelect('ws.bizplace', 'bz')
428
+ .innerJoinAndSelect('wd.targetInventory', 'oi')
429
+ .innerJoinAndSelect('oi.releaseGood', 'rg')
430
+ .innerJoinAndSelect('oi.inventory', 'inv')
431
+ .leftJoinAndSelect('oi.orderProduct', 'op')
432
+ .innerJoinAndSelect('oi.product', 'prd')
433
+ .leftJoinAndSelect(
434
+ 'prd.productDetails',
435
+ 'pd',
436
+ 'pd.product_id = oi.product_id AND pd.deleted_at is null AND pd.packing_type = oi.packing_type AND pd.packing_size = oi.packing_size AND pd.uom = oi.uom'
437
+ )
438
+ .where('wd.name = :name', { name: worksheetDetailName })
439
+ .andWhere('wd.domain_id = :domainId', { domainId: this.domain.id })
440
+ .andWhere('wd.type = :type', { type: worksheetType })
441
+ .andWhere('wd.status = :status', { status: WORKSHEET_STATUS.EXECUTING })
442
+ .andWhere('inv.carton_id = :cartonId', { cartonId: cartonId })
443
+ .getOne()
442
444
 
443
- const releaseGood: ReleaseGood = worksheetDetail.targetInventory.releaseGood
444
- let targetInventory: OrderInventory = worksheetDetail.targetInventory
445
- let targetProduct: OrderProduct = targetInventory.orderProduct
446
- const product: Product = targetInventory.product
447
- const productDetail: ProductDetail = targetInventory.productDetail
448
- let inventory: Inventory = targetInventory.inventory
449
- let bizplace: Bizplace = worksheetDetail.worksheet.bizplace
445
+ //validation to check matching worksheet detail based on name
446
+ if (!worksheetDetail || !worksheetDetail.targetInventory)
447
+ throw new Error(this.ERROR_MSG.FIND.NO_RESULT(worksheetDetailName))
450
448
 
451
449
  //validation to prevent duplicated picking
452
- let oiValidate: OrderInventory = await this.trxMgr.getRepository(OrderInventory).findOne({
453
- where: { domain: this.domain, id: targetInventory.id, status: ORDER_INVENTORY_STATUS.PICKING }
454
- })
455
- if (!oiValidate) throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `is done`))
450
+ if (worksheetDetail?.targetInventory?.status != ORDER_INVENTORY_STATUS.PICKING)
451
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `is done`))
456
452
 
457
- //validation to prevent over release
458
- if (inventory.qty <= 0) throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `over release`))
453
+ let matchingProduct = await this.getDirectQty(
454
+ {
455
+ ...worksheetDetail?.targetInventory?.product?.productDetails[0],
456
+ product: worksheetDetail?.targetInventory?.product
457
+ },
458
+ productBarcode,
459
+ pickedQty
460
+ )
459
461
 
460
- if (inventory.cartonId !== cartonId)
461
- throw new Error(this.ERROR_MSG.VALIDITY.UNEXPECTED_FIELD_VALUE('Carton ID', cartonId, inventory.cartonId))
462
+ //validate matching product details based on scanned barcode
463
+ if (!matchingProduct) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
462
464
 
463
- let pickedQty: number = pickingQty ? pickingQty : 1
464
- const releaseQty: number = targetInventory.releaseQty
465
+ pickedQty = matchingProduct.qty
466
+ let pickedUomValue = matchingProduct.uomValue
465
467
 
466
- targetInventory = await this.checkAndSetBinPicking(targetInventory, binLocation)
468
+ //validation to prevent over release
469
+ if (
470
+ !worksheetDetail?.targetInventory ||
471
+ worksheetDetail?.targetInventory.inventory.qty < 1 ||
472
+ pickedQty + (worksheetDetail.targetInventory?.pickedQty || 0) > worksheetDetail.targetInventory.releaseQty
473
+ )
474
+ throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `over release`))
467
475
 
468
- // search for matching product barcode
469
- const productDetails: ProductDetail[] = product?.productDetails.filter(detail => !detail.deletedAt)
470
- // scannedProductDetail can be child or gtin
471
- const scannedProductDetail: ProductDetail = productDetails.find(detail => detail.gtin == productBarcode)
472
- if (!scannedProductDetail) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
473
-
474
- // case for scanning parent packing type, packing size
475
- // when scannedProductDetail id is not the same as productDetail id, then it's not child gtin, proceed to get child qty
476
- if (scannedProductDetail.id !== productDetail.id && !product?.isRequireSerialNumberScanningOutbound) {
477
- let childQty = await this.getChildQty(productDetails, productBarcode, productDetail, scannedProductDetail)
478
- pickedQty *= childQty
479
- }
476
+ const releaseGood: ReleaseGood = worksheetDetail.targetInventory.releaseGood
480
477
 
481
- if (pickedQty + targetInventory.pickedQty > releaseQty) {
482
- throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `over release`))
483
- }
478
+ let targetInventory: OrderInventory = worksheetDetail.targetInventory
479
+ let targetProduct: OrderProduct = targetInventory.orderProduct
480
+ let inventory: Inventory = targetInventory.inventory
481
+ let bizplace: Bizplace = worksheetDetail.worksheet.bizplace
482
+ const product: Product = targetInventory.product
483
+
484
+ targetInventory = await this.checkAndSetBinPicking(targetInventory, binLocation)
484
485
 
486
+ // for required outbound serial number scanning
485
487
  if (product?.isRequireSerialNumberScanningOutbound) {
486
488
  if (!serialNumber || serialNumber == '') {
487
489
  throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('picking', `require serial number`))
@@ -527,7 +529,6 @@ export class PickingWorksheetController extends VasWorksheetController {
527
529
  inventoryItem.outboundOrderId = releaseGood.id
528
530
  inventoryItem.source = INVENTORY_ITEM_SOURCE.OUTBOUND
529
531
  inventoryItem.product = product
530
- inventoryItem.productDetail = productDetail
531
532
  inventoryItem.inventory = inventory
532
533
  inventoryItem.domain = this.domain
533
534
 
@@ -535,11 +536,137 @@ export class PickingWorksheetController extends VasWorksheetController {
535
536
  }
536
537
  }
537
538
 
539
+ // for tote scanning
538
540
  if (toteNo) {
539
541
  await this.toteScanning(toteNo, targetProduct, targetInventory, pickedQty, releaseGood, bizplace)
540
542
  }
541
543
 
542
- await this.updatePickingTransaction(releaseGood, targetInventory, worksheetDetail, inventory, pickedQty)
544
+ // temporarily override with separate logic to handle transaction to speed up function
545
+ // await this.updatePickingTransaction(releaseGood, targetInventory, worksheetDetail, inventory, pickedQty)
546
+
547
+ const releaseQty: number = targetInventory.releaseQty
548
+
549
+ targetInventory.pickedQty = (targetInventory?.pickedQty || 0) + pickedQty
550
+
551
+ let updateOiObj = {
552
+ pickedQty: () => `"picked_qty" + ${pickedQty}`,
553
+ updatedAt: new Date(),
554
+ updater: this.user,
555
+ pickedBy: this.user.name,
556
+ pickedByUser: this.user,
557
+ pickedAt: new Date()
558
+ }
559
+
560
+ if (targetInventory.pickedQty == releaseQty) {
561
+ updateOiObj['status'] = ORDER_INVENTORY_STATUS.PICKED
562
+ }
563
+
564
+ if (targetInventory.binLocation) {
565
+ updateOiObj['binLocation'] = targetInventory.binLocation
566
+ }
567
+
568
+ await this.trxMgr
569
+ .getRepository(OrderInventory)
570
+ .createQueryBuilder()
571
+ .update(OrderInventory)
572
+ .set(updateOiObj)
573
+ .where({ id: targetInventory.id })
574
+ .andWhere(`picked_qty + :pickedQty <= release_qty`, { pickedQty })
575
+ .execute()
576
+
577
+ if (targetInventory.pickedQty == releaseQty) {
578
+ //update worksheet details only when line item picking complete
579
+ await this.trxMgr
580
+ .getRepository(WorksheetDetail)
581
+ .createQueryBuilder()
582
+ .update(WorksheetDetail)
583
+ .set({
584
+ status: WORKSHEET_STATUS.DONE,
585
+ updater: this.user,
586
+ updatedAt: new Date()
587
+ })
588
+ .where('id = :id', { id: worksheetDetail.id })
589
+ .execute()
590
+
591
+ getConnection().transaction(async (tx: EntityManager) => {
592
+ let releaseUomValue = Math.round((pickedUomValue / pickedQty) * releaseQty * 100) / 100
593
+
594
+ let updateInvObj = {
595
+ qty: () => `"qty" - ${releaseQty}`,
596
+ lockedQty: () => `"locked_qty" - ${releaseQty}`,
597
+ uomValue: () => `"uom_value" - ${releaseUomValue}`,
598
+ lockedUomValue: () => `"locked_uom_value" - ${releaseUomValue}`,
599
+ updater: this.user,
600
+ updatedAt: new Date()
601
+ }
602
+
603
+ let remainingQty = await tx
604
+ .getRepository(Inventory)
605
+ .createQueryBuilder()
606
+ .update(Inventory)
607
+ .set(updateInvObj)
608
+ .where('id = :id', { id: targetInventory.inventory.id })
609
+ .returning(['qty'])
610
+ .execute()
611
+ .then(dt => {
612
+ return dt.raw[0].qty
613
+ })
614
+
615
+ await generateInventoryHistory(
616
+ inventory,
617
+ releaseGood,
618
+ INVENTORY_TRANSACTION_TYPE.PICKING,
619
+ -releaseQty,
620
+ -releaseUomValue,
621
+ this.user,
622
+ tx
623
+ )
624
+
625
+ let inventoryItems: InventoryItem = await tx
626
+ .getRepository(InventoryItem)
627
+ .find({ where: { outboundOrderId: releaseGood.id } })
628
+
629
+ if (inventoryItems.length > 0) {
630
+ inventoryItems.forEach((itm: InventoryItem) => {
631
+ itm.status = INVENTORY_STATUS.PICKED
632
+ itm.updater = this.user
633
+ })
634
+
635
+ await tx.getRepository(InventoryItem).save(inventoryItems)
636
+ }
637
+
638
+ if (remainingQty === 0) {
639
+ await tx
640
+ .getRepository(Inventory)
641
+ .createQueryBuilder()
642
+ .update(Inventory)
643
+ .set({ status: INVENTORY_STATUS.TERMINATED })
644
+ .where('id = :id', { id: targetInventory.inventory.id })
645
+ .execute()
646
+
647
+ await generateInventoryHistory(
648
+ inventory,
649
+ releaseGood,
650
+ INVENTORY_TRANSACTION_TYPE.TERMINATED,
651
+ 0,
652
+ 0,
653
+ this.user,
654
+ tx
655
+ )
656
+ }
657
+ })
658
+ }
659
+
660
+ // return worksheet details
661
+ worksheetDetail = await this.trxMgr
662
+ .getRepository(WorksheetDetail)
663
+ .createQueryBuilder('wd')
664
+ .innerJoin('wd.targetInventory', 'oi')
665
+ .innerJoinAndSelect('oi.releaseGood', 'rg')
666
+ .where('wd.id = :id', { id: worksheetDetail.id })
667
+ .getOne()
668
+
669
+ return worksheetDetail
543
670
  } catch (error) {
544
671
  throw error
545
672
  }
@@ -567,15 +694,13 @@ export class PickingWorksheetController extends VasWorksheetController {
567
694
  'targetInventory.orderProduct',
568
695
  'targetInventory.inventory',
569
696
  'targetInventory.inventory.location',
570
- 'targetInventory.product',
571
- 'targetInventory.productDetail'
697
+ 'targetInventory.product'
572
698
  ]
573
699
  )
574
700
 
575
701
  const releaseGood: ReleaseGood = worksheetDetail.targetInventory.releaseGood
576
702
  let targetInventory: OrderInventory = worksheetDetail.targetInventory
577
703
  const product: Product = targetInventory.product
578
- const productDetail: ProductDetail = targetInventory.productDetail
579
704
  let inventory: Inventory = targetInventory.inventory
580
705
  let targetProduct: OrderProduct = targetInventory.orderProduct
581
706
  let bizplace: Bizplace = worksheetDetail.worksheet.bizplace
@@ -605,13 +730,13 @@ export class PickingWorksheetController extends VasWorksheetController {
605
730
  })
606
731
 
607
732
  let foundSerialNumber: InventoryItem = await this.trxMgr.getRepository(InventoryItem).findOne({
608
- where: { domain: this.domain, serialNumber: serialNumber, productDetail },
609
- relations: ['product', 'productDetail', 'inventory']
733
+ where: { domain: this.domain, serialNumber: serialNumber, product },
734
+ relations: ['product', 'inventory']
610
735
  })
611
736
 
612
737
  let scannedPalletIdInventory: Inventory = await this.trxMgr
613
738
  .getRepository(Inventory)
614
- .findOne({ where: { domain: this.domain, palletId }, relations: ['productDetail'] })
739
+ .findOne({ where: { domain: this.domain, palletId }, relations: ['product'] })
615
740
 
616
741
  if (foundSerialNumber) {
617
742
  if (foundSerialNumber.outboundOrderId) {
@@ -638,7 +763,6 @@ export class PickingWorksheetController extends VasWorksheetController {
638
763
  inventoryItem.source = INVENTORY_ITEM_SOURCE.OUTBOUND
639
764
  inventoryItem.outboundOrderId = releaseGood.id
640
765
  inventoryItem.product = product
641
- inventoryItem.productDetail = productDetail
642
766
  inventoryItem.inventory = scannedPalletIdInventory
643
767
  inventoryItem.domain = this.domain
644
768
 
@@ -664,7 +788,8 @@ export class PickingWorksheetController extends VasWorksheetController {
664
788
  )
665
789
  } else if (
666
790
  scannedPalletIdInventory.batchId == inventory.batchId &&
667
- scannedPalletIdInventory.productDetail.id == productDetail.id
791
+ scannedPalletIdInventory.product.id == product.id &&
792
+ scannedPalletIdInventory.product.packingType == product.packingType
668
793
  ) {
669
794
  //if replacement order inventory does not exist
670
795
  await this.serialNumberReplacement(
@@ -672,7 +797,6 @@ export class PickingWorksheetController extends VasWorksheetController {
672
797
  scannedPalletIdInventory,
673
798
  releaseGood,
674
799
  product,
675
- productDetail,
676
800
  worksheetDetail,
677
801
  foundSerialNumber
678
802
  )
@@ -848,19 +972,16 @@ export class PickingWorksheetController extends VasWorksheetController {
848
972
  'worksheetDetails.targetInventory.releaseGood',
849
973
  'worksheetDetails.targetInventory.inventory',
850
974
  'worksheetDetails.targetInventory.inventory.location',
851
- 'worksheetDetails.targetInventory.productDetail',
852
- 'worksheetDetails.targetInventory.productDetail.product',
975
+ 'worksheetDetails.targetInventory.product',
853
976
  'worksheetDetails.targetInventory.product.productDetails',
854
977
  'worksheetDetails.targetInventory.product.productDetails.childProductDetail'
855
978
  ]
856
979
  })
857
980
 
858
981
  const worksheetDetails: WorksheetDetail[] = worksheet.worksheetDetails
859
- const productDetail: ProductDetail = worksheetDetails
982
+ const product: Product = worksheetDetails
860
983
  .map((wsd: WorksheetDetail) => wsd.targetInventory.product)
861
- .find((productDetail: ProductDetail) => productDetail.id === inventory.productDetail.id)
862
-
863
- const product: Product = productDetail.product
984
+ .find((product: Product) => product.id === inventory.product.id)
864
985
 
865
986
  const batchId: string = inventory.batchId
866
987
  const packingType: string = inventory.packingType
@@ -879,14 +1000,26 @@ export class PickingWorksheetController extends VasWorksheetController {
879
1000
 
880
1001
  // search for matching product barcode
881
1002
  const productDetails: ProductDetail[] = product?.productDetails.filter(detail => !detail.deletedAt)
882
- // scannedProductDetail can be child or gtin
883
- const scannedProductDetail: ProductDetail = productDetails.find(detail => detail.gtin == productBarcode)
884
- if (!scannedProductDetail) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
1003
+ const isMatchingBarcode: boolean = productDetails.map(detail => detail.gtin).includes(productBarcode)
1004
+ if (!isMatchingBarcode) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(`GTIN (${productBarcode})`))
885
1005
 
886
1006
  // case for scanning parent packing type, packing size
887
- // when scannedProductDetail id is not the same as productDetail id, then it's not child gtin, proceed to get child qty
888
- if (scannedProductDetail.id !== productDetail.id) {
889
- let childQty = await this.getChildQty(productDetails, productBarcode, productDetail, scannedProductDetail)
1007
+ const foundProductDetail: ProductDetail = productDetails.find(
1008
+ (detail: ProductDetail) =>
1009
+ detail.gtin === productBarcode && detail.packingType === packingType && detail.packingSize == packingSize
1010
+ )
1011
+
1012
+ if (!foundProductDetail) {
1013
+ const roProductDetail: ProductDetail = productDetails.find(
1014
+ (parentDetail: ProductDetail) =>
1015
+ parentDetail.packingType === packingType && parentDetail.packingSize == packingSize
1016
+ )
1017
+ if (!roProductDetail)
1018
+ throw new Error(
1019
+ this.ERROR_MSG.FIND.NO_RESULT(`Packing Type ( ${packingType}) or Packing Size (${packingSize})`)
1020
+ )
1021
+
1022
+ let childQty = await this.getChildQty(productDetails, productBarcode, roProductDetail)
890
1023
  pickedQty *= childQty
891
1024
  }
892
1025
 
@@ -1121,7 +1254,7 @@ export class PickingWorksheetController extends VasWorksheetController {
1121
1254
  private async updatePickingTransaction(releaseGood, orderInventory, worksheetDetail, inventory, pickedQty) {
1122
1255
  const releaseQty: number = orderInventory.releaseQty
1123
1256
 
1124
- orderInventory.pickedQty = Boolean(orderInventory?.pickedQty) ? orderInventory.pickedQty + pickedQty : pickedQty
1257
+ orderInventory.pickedQty = (orderInventory?.pickedQty || 0) + pickedQty
1125
1258
  if (orderInventory.pickedQty == releaseQty) {
1126
1259
  const leftQty: number = inventory.qty - releaseQty
1127
1260
  if (leftQty < 0) {
@@ -1273,7 +1406,7 @@ export class PickingWorksheetController extends VasWorksheetController {
1273
1406
  await this.trxMgr.getRepository(WorksheetDetail).delete(worksheetDetail.ild)
1274
1407
  await this.trxMgr.getRepository(OrderInventory).delete(targetInventory.id)
1275
1408
  }
1276
- } catch (e) {}
1409
+ } catch (e) { }
1277
1410
  }
1278
1411
 
1279
1412
  private async serialNumberReplacement(
@@ -1281,7 +1414,6 @@ export class PickingWorksheetController extends VasWorksheetController {
1281
1414
  scannedPalletIdInventory,
1282
1415
  releaseGood,
1283
1416
  product,
1284
- productDetail,
1285
1417
  worksheetDetail,
1286
1418
  foundSerialNumber
1287
1419
  ) {
@@ -1346,7 +1478,6 @@ export class PickingWorksheetController extends VasWorksheetController {
1346
1478
  releaseUomValue: newOrderInventoryReleaseUomValue,
1347
1479
  pickedQty: 1,
1348
1480
  product,
1349
- productDetail,
1350
1481
  inventory: scannedPalletIdInventory,
1351
1482
  creator: this.user,
1352
1483
  updater: this.user
@@ -1390,7 +1521,7 @@ export class PickingWorksheetController extends VasWorksheetController {
1390
1521
  await this.trxMgr.getRepository(WorksheetDetail).delete(worksheetDetail.id)
1391
1522
  await this.trxMgr.getRepository(OrderInventory).delete(targetInventory.id)
1392
1523
  }
1393
- } catch (e) {}
1524
+ } catch (e) { }
1394
1525
  }
1395
1526
 
1396
1527
  private async toteScanning(toteNo, targetProduct, targetInventory, pickedQty, releaseGood, bizplace) {
@@ -95,8 +95,7 @@ export class SortingWorksheetController extends VasWorksheetController {
95
95
  'worksheetDetails.targetInventory.inventory.product',
96
96
  'worksheetDetails.targetInventory.inventory.product.productDetails',
97
97
  'worksheetDetails.targetInventory.inventory.product.productDetails.product',
98
- 'worksheetDetails.targetInventory.releaseGood',
99
- 'worksheetDetails.targetInventory.productDetail'
98
+ 'worksheetDetails.targetInventory.releaseGood'
100
99
  ]
101
100
  })
102
101
 
@@ -119,12 +118,17 @@ export class SortingWorksheetController extends VasWorksheetController {
119
118
  const matchingProductDetail: ProductDetail = productDetails.find(
120
119
  (productDetail: ProductDetail) => productDetail.gtin === productBarcode
121
120
  )
122
- if (!matchingProductDetail) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
121
+ if (!matchingProductDetail) throw new Error('Unable to find product barcode.')
123
122
  const packingType: string = matchingProductDetail.packingType
124
123
  const packingSize: number = matchingProductDetail.packingSize
124
+ if (!matchingProductDetail)
125
+ throw new Error(this.ERROR_MSG.PRODUCT.BARCODE_NOT_EXIST(productBarcode, packingType, packingSize))
125
126
 
126
127
  let matchingOIs: OrderInventory[] = orderInventories.filter(
127
- (oi: OrderInventory) => oi.productDetail.id === matchingProductDetail.id
128
+ (oi: OrderInventory) =>
129
+ oi.packingType === packingType &&
130
+ oi.packingSize === packingSize &&
131
+ oi.product?.id === matchingProductDetail.product?.id
128
132
  )
129
133
 
130
134
  let sortedQty: number = 1
@@ -138,7 +142,6 @@ export class SortingWorksheetController extends VasWorksheetController {
138
142
  const inventory: Inventory = matchingOI.inventory
139
143
  const releaseGood: ReleaseGood = matchingOI.releaseGood
140
144
  const product: Product = inventory.product
141
- const productDetail: ProductDetail = matchingOI.productDetail
142
145
 
143
146
  if (releaseQty != matchingOI?.sortedQty && sortedQty == 1) {
144
147
  // Serial Number scanning for batch picking
@@ -150,7 +153,7 @@ export class SortingWorksheetController extends VasWorksheetController {
150
153
 
151
154
  let foundSerialNumber: InventoryItem = await this.trxMgr
152
155
  .getRepository(InventoryItem)
153
- .findOne({ where: { domain: this.domain, serialNumber: serialNumber, productDetail } })
156
+ .findOne({ where: { domain: this.domain, serialNumber: serialNumber, product } })
154
157
 
155
158
  if (foundSerialNumber) {
156
159
  if (foundSerialNumber.inventoryId !== inventory.id) {
@@ -177,7 +180,6 @@ export class SortingWorksheetController extends VasWorksheetController {
177
180
  inventoryItem.outboundOrderId = releaseGood.id
178
181
  inventoryItem.source = INVENTORY_ITEM_SOURCE.OUTBOUND
179
182
  inventoryItem.product = product
180
- inventoryItem.productDetail = productDetail
181
183
  inventoryItem.inventory = inventory
182
184
  inventoryItem.domain = this.domain
183
185
 
@@ -261,8 +263,7 @@ export class SortingWorksheetController extends VasWorksheetController {
261
263
  'worksheetDetails.targetInventory.inventory.product',
262
264
  'worksheetDetails.targetInventory.inventory.product.productDetails',
263
265
  'worksheetDetails.targetInventory.inventory.product.productDetails.product',
264
- 'worksheetDetails.targetInventory.releaseGood',
265
- 'worksheetDetails.targetInventory.productDetail'
266
+ 'worksheetDetails.targetInventory.releaseGood'
266
267
  ]
267
268
  })
268
269
 
@@ -282,7 +283,6 @@ export class SortingWorksheetController extends VasWorksheetController {
282
283
  const inventory: Inventory = matchingOI.inventory
283
284
  const releaseGood: ReleaseGood = matchingOI.releaseGood
284
285
  const product: Product = matchingOI.inventory.product
285
- const productDetail: ProductDetail = matchingOI.productDetail
286
286
  const packingType: string = matchingOI.packingType
287
287
  const packingSize: number = matchingOI.packingSize
288
288
 
@@ -292,7 +292,8 @@ export class SortingWorksheetController extends VasWorksheetController {
292
292
  }
293
293
 
294
294
  let foundSerialNumber: InventoryItem = await this.trxMgr.getRepository(InventoryItem).findOne({
295
- where: { domain: this.domain, serialNumber: serialNumber, productDetail }
295
+ where: { domain: this.domain, serialNumber: serialNumber, product },
296
+ relations: ['product', 'inventory']
296
297
  })
297
298
 
298
299
  if (foundSerialNumber) {
@@ -316,7 +317,6 @@ export class SortingWorksheetController extends VasWorksheetController {
316
317
  inventoryItem.source = INVENTORY_ITEM_SOURCE.OUTBOUND
317
318
  inventoryItem.outboundOrderId = releaseGood.id
318
319
  inventoryItem.product = product
319
- inventoryItem.productDetail = productDetail
320
320
  inventoryItem.inventory = inventory
321
321
  inventoryItem.domain = this.domain
322
322