@things-factory/worksheet-base 4.3.82 → 4.3.83

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/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 +151 -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/scan-product-picking.js +4 -7
  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 +2 -3
  48. package/dist-server/graphql/resolvers/worksheet/picking-worksheet.js.map +1 -1
  49. package/dist-server/graphql/resolvers/worksheet/proceed-extra-products.js +4 -6
  50. package/dist-server/graphql/resolvers/worksheet/proceed-extra-products.js.map +1 -1
  51. package/dist-server/graphql/resolvers/worksheet/putaway/complete-putaway.js +14 -39
  52. package/dist-server/graphql/resolvers/worksheet/putaway/complete-putaway.js.map +1 -1
  53. package/dist-server/graphql/resolvers/worksheet/transfer.js +9 -9
  54. package/dist-server/graphql/resolvers/worksheet/transfer.js.map +1 -1
  55. package/dist-server/graphql/resolvers/worksheet/vas-transactions/common-utils.js +17 -17
  56. package/dist-server/graphql/resolvers/worksheet/vas-transactions/common-utils.js.map +1 -1
  57. package/dist-server/graphql/resolvers/worksheet-detail/regenerate-release-good-worksheet-details.js +4 -4
  58. package/dist-server/graphql/resolvers/worksheet-detail/regenerate-release-good-worksheet-details.js.map +1 -1
  59. package/dist-server/graphql/types/worksheet-detail/index.js +0 -1
  60. package/dist-server/graphql/types/worksheet-detail/index.js.map +1 -1
  61. package/dist-server/utils/inventory-util.js +98 -1
  62. package/dist-server/utils/inventory-util.js.map +1 -1
  63. package/package.json +17 -17
  64. package/server/controllers/inbound/unloading-worksheet-controller.ts +70 -49
  65. package/server/controllers/inspect/cycle-count-worksheet-controller.ts +4 -2
  66. package/server/controllers/outbound/loading-worksheet-controller.ts +3 -9
  67. package/server/controllers/outbound/packing-worksheet-controller.ts +31 -23
  68. package/server/controllers/outbound/picking-worksheet-controller.ts +212 -85
  69. package/server/controllers/outbound/sorting-worksheet-controller.ts +12 -12
  70. package/server/controllers/vas/vas-worksheet-controller.ts +2 -2
  71. package/server/controllers/worksheet-controller.ts +49 -5
  72. package/server/entities/worksheet-detail.ts +5 -0
  73. package/server/graphql/resolvers/worksheet/batch-picking-worksheet.ts +0 -6
  74. package/server/graphql/resolvers/worksheet/confirm-cancellation-release-order.ts +2 -1
  75. package/server/graphql/resolvers/worksheet/cycle-count-adjustment.ts +2 -2
  76. package/server/graphql/resolvers/worksheet/inventories-by-pallet.ts +1 -3
  77. package/server/graphql/resolvers/worksheet/loading/complete-loading.ts +33 -77
  78. package/server/graphql/resolvers/worksheet/packing/activate-packing.ts +9 -26
  79. package/server/graphql/resolvers/worksheet/packing/complete-packing.ts +9 -34
  80. package/server/graphql/resolvers/worksheet/packing/packing.ts +9 -26
  81. package/server/graphql/resolvers/worksheet/packing/scan-product-packing.ts +9 -28
  82. package/server/graphql/resolvers/worksheet/packing-worksheet.ts +13 -68
  83. package/server/graphql/resolvers/worksheet/picking/activate-picking.ts +30 -60
  84. package/server/graphql/resolvers/worksheet/picking/complete-batch-picking.ts +2 -2
  85. package/server/graphql/resolvers/worksheet/picking/complete-picking.ts +130 -288
  86. package/server/graphql/resolvers/worksheet/picking/scan-product-picking.ts +10 -30
  87. package/server/graphql/resolvers/worksheet/picking-worksheet.ts +2 -3
  88. package/server/graphql/resolvers/worksheet/proceed-extra-products.ts +4 -5
  89. package/server/graphql/resolvers/worksheet/putaway/complete-putaway.ts +15 -45
  90. package/server/graphql/resolvers/worksheet/transfer.ts +16 -18
  91. package/server/graphql/resolvers/worksheet/vas-transactions/common-utils.ts +2 -3
  92. package/server/graphql/resolvers/worksheet-detail/regenerate-release-good-worksheet-details.ts +1 -4
  93. package/server/graphql/types/worksheet-detail/index.ts +0 -1
  94. 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> {
@@ -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,133 @@ 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
+ await this.trxMgr
565
+ .getRepository(OrderInventory)
566
+ .createQueryBuilder()
567
+ .update(OrderInventory)
568
+ .set(updateOiObj)
569
+ .where({ id: targetInventory.id })
570
+ .andWhere(`picked_qty + :pickedQty <= release_qty`, { pickedQty })
571
+ .execute()
572
+
573
+ if (targetInventory.pickedQty == releaseQty) {
574
+ //update worksheet details only when line item picking complete
575
+ await this.trxMgr
576
+ .getRepository(WorksheetDetail)
577
+ .createQueryBuilder()
578
+ .update(WorksheetDetail)
579
+ .set({
580
+ status: WORKSHEET_STATUS.DONE,
581
+ updater: this.user,
582
+ updatedAt: new Date()
583
+ })
584
+ .where('id = :id', { id: worksheetDetail.id })
585
+ .execute()
586
+
587
+ getConnection().transaction(async (tx: EntityManager) => {
588
+ let releaseUomValue = Math.round((pickedUomValue / pickedQty) * releaseQty * 100) / 100
589
+
590
+ let updateInvObj = {
591
+ qty: () => `"qty" - ${releaseQty}`,
592
+ lockedQty: () => `"locked_qty" - ${releaseQty}`,
593
+ uomValue: () => `"uom_value" - ${releaseUomValue}`,
594
+ lockedUomValue: () => `"locked_uom_value" - ${releaseUomValue}`,
595
+ updater: this.user,
596
+ updatedAt: new Date()
597
+ }
598
+
599
+ let remainingQty = await tx
600
+ .getRepository(Inventory)
601
+ .createQueryBuilder()
602
+ .update(Inventory)
603
+ .set(updateInvObj)
604
+ .where('id = :id', { id: targetInventory.inventory.id })
605
+ .returning(['qty'])
606
+ .execute()
607
+ .then(dt => {
608
+ return dt.raw[0].qty
609
+ })
610
+
611
+ await generateInventoryHistory(
612
+ inventory,
613
+ releaseGood,
614
+ INVENTORY_TRANSACTION_TYPE.PICKING,
615
+ -releaseQty,
616
+ -releaseUomValue,
617
+ this.user,
618
+ tx
619
+ )
620
+
621
+ let inventoryItems: InventoryItem = await tx
622
+ .getRepository(InventoryItem)
623
+ .find({ where: { outboundOrderId: releaseGood.id } })
624
+
625
+ if (inventoryItems.length > 0) {
626
+ inventoryItems.forEach((itm: InventoryItem) => {
627
+ itm.status = INVENTORY_STATUS.PICKED
628
+ itm.updater = this.user
629
+ })
630
+
631
+ await tx.getRepository(InventoryItem).save(inventoryItems)
632
+ }
633
+
634
+ if (remainingQty === 0) {
635
+ await tx
636
+ .getRepository(Inventory)
637
+ .createQueryBuilder()
638
+ .update(Inventory)
639
+ .set({ status: INVENTORY_STATUS.TERMINATED })
640
+ .where('id = :id', { id: targetInventory.inventory.id })
641
+ .execute()
642
+
643
+ await generateInventoryHistory(
644
+ inventory,
645
+ releaseGood,
646
+ INVENTORY_TRANSACTION_TYPE.TERMINATED,
647
+ 0,
648
+ 0,
649
+ this.user,
650
+ tx
651
+ )
652
+ }
653
+ })
654
+ }
655
+
656
+ // return worksheet details
657
+ worksheetDetail = await this.trxMgr
658
+ .getRepository(WorksheetDetail)
659
+ .createQueryBuilder('wd')
660
+ .innerJoin('wd.targetInventory', 'oi')
661
+ .innerJoinAndSelect('oi.releaseGood', 'rg')
662
+ .where('wd.id = :id', { id: worksheetDetail.id })
663
+ .getOne()
664
+
665
+ return worksheetDetail
543
666
  } catch (error) {
544
667
  throw error
545
668
  }
@@ -567,15 +690,13 @@ export class PickingWorksheetController extends VasWorksheetController {
567
690
  'targetInventory.orderProduct',
568
691
  'targetInventory.inventory',
569
692
  'targetInventory.inventory.location',
570
- 'targetInventory.product',
571
- 'targetInventory.productDetail'
693
+ 'targetInventory.product'
572
694
  ]
573
695
  )
574
696
 
575
697
  const releaseGood: ReleaseGood = worksheetDetail.targetInventory.releaseGood
576
698
  let targetInventory: OrderInventory = worksheetDetail.targetInventory
577
699
  const product: Product = targetInventory.product
578
- const productDetail: ProductDetail = targetInventory.productDetail
579
700
  let inventory: Inventory = targetInventory.inventory
580
701
  let targetProduct: OrderProduct = targetInventory.orderProduct
581
702
  let bizplace: Bizplace = worksheetDetail.worksheet.bizplace
@@ -605,13 +726,13 @@ export class PickingWorksheetController extends VasWorksheetController {
605
726
  })
606
727
 
607
728
  let foundSerialNumber: InventoryItem = await this.trxMgr.getRepository(InventoryItem).findOne({
608
- where: { domain: this.domain, serialNumber: serialNumber, productDetail },
609
- relations: ['product', 'productDetail', 'inventory']
729
+ where: { domain: this.domain, serialNumber: serialNumber, product },
730
+ relations: ['product', 'inventory']
610
731
  })
611
732
 
612
733
  let scannedPalletIdInventory: Inventory = await this.trxMgr
613
734
  .getRepository(Inventory)
614
- .findOne({ where: { domain: this.domain, palletId }, relations: ['productDetail'] })
735
+ .findOne({ where: { domain: this.domain, palletId }, relations: ['product'] })
615
736
 
616
737
  if (foundSerialNumber) {
617
738
  if (foundSerialNumber.outboundOrderId) {
@@ -638,7 +759,6 @@ export class PickingWorksheetController extends VasWorksheetController {
638
759
  inventoryItem.source = INVENTORY_ITEM_SOURCE.OUTBOUND
639
760
  inventoryItem.outboundOrderId = releaseGood.id
640
761
  inventoryItem.product = product
641
- inventoryItem.productDetail = productDetail
642
762
  inventoryItem.inventory = scannedPalletIdInventory
643
763
  inventoryItem.domain = this.domain
644
764
 
@@ -664,7 +784,8 @@ export class PickingWorksheetController extends VasWorksheetController {
664
784
  )
665
785
  } else if (
666
786
  scannedPalletIdInventory.batchId == inventory.batchId &&
667
- scannedPalletIdInventory.productDetail.id == productDetail.id
787
+ scannedPalletIdInventory.product.id == product.id &&
788
+ scannedPalletIdInventory.product.packingType == product.packingType
668
789
  ) {
669
790
  //if replacement order inventory does not exist
670
791
  await this.serialNumberReplacement(
@@ -672,7 +793,6 @@ export class PickingWorksheetController extends VasWorksheetController {
672
793
  scannedPalletIdInventory,
673
794
  releaseGood,
674
795
  product,
675
- productDetail,
676
796
  worksheetDetail,
677
797
  foundSerialNumber
678
798
  )
@@ -848,19 +968,16 @@ export class PickingWorksheetController extends VasWorksheetController {
848
968
  'worksheetDetails.targetInventory.releaseGood',
849
969
  'worksheetDetails.targetInventory.inventory',
850
970
  'worksheetDetails.targetInventory.inventory.location',
851
- 'worksheetDetails.targetInventory.productDetail',
852
- 'worksheetDetails.targetInventory.productDetail.product',
971
+ 'worksheetDetails.targetInventory.product',
853
972
  'worksheetDetails.targetInventory.product.productDetails',
854
973
  'worksheetDetails.targetInventory.product.productDetails.childProductDetail'
855
974
  ]
856
975
  })
857
976
 
858
977
  const worksheetDetails: WorksheetDetail[] = worksheet.worksheetDetails
859
- const productDetail: ProductDetail = worksheetDetails
978
+ const product: Product = worksheetDetails
860
979
  .map((wsd: WorksheetDetail) => wsd.targetInventory.product)
861
- .find((productDetail: ProductDetail) => productDetail.id === inventory.productDetail.id)
862
-
863
- const product: Product = productDetail.product
980
+ .find((product: Product) => product.id === inventory.product.id)
864
981
 
865
982
  const batchId: string = inventory.batchId
866
983
  const packingType: string = inventory.packingType
@@ -879,14 +996,26 @@ export class PickingWorksheetController extends VasWorksheetController {
879
996
 
880
997
  // search for matching product barcode
881
998
  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))
999
+ const isMatchingBarcode: boolean = productDetails.map(detail => detail.gtin).includes(productBarcode)
1000
+ if (!isMatchingBarcode) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(`GTIN (${productBarcode})`))
885
1001
 
886
1002
  // 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)
1003
+ const foundProductDetail: ProductDetail = productDetails.find(
1004
+ (detail: ProductDetail) =>
1005
+ detail.gtin === productBarcode && detail.packingType === packingType && detail.packingSize == packingSize
1006
+ )
1007
+
1008
+ if (!foundProductDetail) {
1009
+ const roProductDetail: ProductDetail = productDetails.find(
1010
+ (parentDetail: ProductDetail) =>
1011
+ parentDetail.packingType === packingType && parentDetail.packingSize == packingSize
1012
+ )
1013
+ if (!roProductDetail)
1014
+ throw new Error(
1015
+ this.ERROR_MSG.FIND.NO_RESULT(`Packing Type ( ${packingType}) or Packing Size (${packingSize})`)
1016
+ )
1017
+
1018
+ let childQty = await this.getChildQty(productDetails, productBarcode, roProductDetail)
890
1019
  pickedQty *= childQty
891
1020
  }
892
1021
 
@@ -1121,7 +1250,7 @@ export class PickingWorksheetController extends VasWorksheetController {
1121
1250
  private async updatePickingTransaction(releaseGood, orderInventory, worksheetDetail, inventory, pickedQty) {
1122
1251
  const releaseQty: number = orderInventory.releaseQty
1123
1252
 
1124
- orderInventory.pickedQty = Boolean(orderInventory?.pickedQty) ? orderInventory.pickedQty + pickedQty : pickedQty
1253
+ orderInventory.pickedQty = (orderInventory?.pickedQty || 0) + pickedQty
1125
1254
  if (orderInventory.pickedQty == releaseQty) {
1126
1255
  const leftQty: number = inventory.qty - releaseQty
1127
1256
  if (leftQty < 0) {
@@ -1281,7 +1410,6 @@ export class PickingWorksheetController extends VasWorksheetController {
1281
1410
  scannedPalletIdInventory,
1282
1411
  releaseGood,
1283
1412
  product,
1284
- productDetail,
1285
1413
  worksheetDetail,
1286
1414
  foundSerialNumber
1287
1415
  ) {
@@ -1346,7 +1474,6 @@ export class PickingWorksheetController extends VasWorksheetController {
1346
1474
  releaseUomValue: newOrderInventoryReleaseUomValue,
1347
1475
  pickedQty: 1,
1348
1476
  product,
1349
- productDetail,
1350
1477
  inventory: scannedPalletIdInventory,
1351
1478
  creator: this.user,
1352
1479
  updater: this.user
@@ -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
 
@@ -22,8 +22,7 @@ import {
22
22
  InventoryNoGenerator,
23
23
  Location,
24
24
  LOCATION_TYPE,
25
- Warehouse,
26
- generateInventoryHistory
25
+ Warehouse
27
26
  } from '@things-factory/warehouse-base'
28
27
 
29
28
  import { WORKSHEET_STATUS, WORKSHEET_TYPE } from '../../constants'
@@ -37,6 +36,7 @@ import {
37
36
  RefOrderType
38
37
  } from '../../graphql/resolvers/worksheet/vas-transactions'
39
38
  import { PackingUnits } from '../../graphql/resolvers/worksheet/vas-transactions/interfaces/repackaging'
39
+ import { generateInventoryHistory } from '../../utils'
40
40
  import { ReferenceOrderType, WorksheetController } from '../worksheet-controller'
41
41
 
42
42
  type CompleteTransactionType = (trxMgr: EntityManager, orderVas: OrderVas, user: User) => Promise<void>