@things-factory/worksheet-base 4.0.10 → 4.0.14
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.
- package/dist-server/constants/template.js +1 -0
- package/dist-server/constants/template.js.map +1 -1
- package/dist-server/controllers/ecommerce/sellercraft-controller.js +3 -3
- package/dist-server/controllers/ecommerce/sellercraft-controller.js.map +1 -1
- package/dist-server/controllers/inbound/putaway-worksheet-controller.js +24 -5
- package/dist-server/controllers/inbound/putaway-worksheet-controller.js.map +1 -1
- package/dist-server/controllers/inbound/unloading-worksheet-controller.js +67 -28
- package/dist-server/controllers/inbound/unloading-worksheet-controller.js.map +1 -1
- package/dist-server/controllers/index.js +1 -0
- package/dist-server/controllers/index.js.map +1 -1
- package/dist-server/controllers/outbound/loading-worksheet-controller.js +4 -0
- package/dist-server/controllers/outbound/loading-worksheet-controller.js.map +1 -1
- package/dist-server/controllers/outbound/packing-worksheet-controller.js +1 -3
- package/dist-server/controllers/outbound/packing-worksheet-controller.js.map +1 -1
- package/dist-server/controllers/outbound/picking-worksheet-controller.js +159 -116
- package/dist-server/controllers/outbound/picking-worksheet-controller.js.map +1 -1
- package/dist-server/controllers/render-elccl-grn.js +6 -6
- package/dist-server/controllers/render-elccl-grn.js.map +1 -1
- package/dist-server/controllers/render-manifest.js +64 -0
- package/dist-server/controllers/render-manifest.js.map +1 -0
- package/dist-server/controllers/worksheet-controller.js +28 -2
- package/dist-server/controllers/worksheet-controller.js.map +1 -1
- package/dist-server/graphql/resolvers/pallet/index.js +2 -1
- package/dist-server/graphql/resolvers/pallet/index.js.map +1 -1
- package/dist-server/graphql/resolvers/pallet/pallet-outbound.js +1 -1
- package/dist-server/graphql/resolvers/pallet/pallet-outbound.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js +6 -5
- package/dist-server/graphql/resolvers/worksheet/inventories-by-pallet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/loading-worksheet.js +23 -2
- package/dist-server/graphql/resolvers/worksheet/loading-worksheet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/packing-worksheet.js +22 -0
- package/dist-server/graphql/resolvers/worksheet/packing-worksheet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/pending-cancellation-release-order.js +6 -3
- package/dist-server/graphql/resolvers/worksheet/pending-cancellation-release-order.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/picking/activate-picking.js +0 -4
- package/dist-server/graphql/resolvers/worksheet/picking/activate-picking.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js +30 -5
- package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/picking/fetch-and-assign-picking-task.js +72 -0
- package/dist-server/graphql/resolvers/worksheet/picking/fetch-and-assign-picking-task.js.map +1 -0
- package/dist-server/graphql/resolvers/worksheet/picking/index.js +2 -1
- package/dist-server/graphql/resolvers/worksheet/picking/index.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/picking/picking.js +4 -4
- package/dist-server/graphql/resolvers/worksheet/picking/picking.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/picking/scan-product-picking.js +4 -4
- package/dist-server/graphql/resolvers/worksheet/picking/scan-product-picking.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/picking-worksheet.js +86 -57
- package/dist-server/graphql/resolvers/worksheet/picking-worksheet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/recommend-putway-location.js +2 -2
- package/dist-server/graphql/resolvers/worksheet/recommend-putway-location.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/unloaded-inventories.js +6 -1
- package/dist-server/graphql/resolvers/worksheet/unloaded-inventories.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/unloading-return-worksheet.js +2 -2
- package/dist-server/graphql/resolvers/worksheet/unloading-return-worksheet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet-detail/generate-release-good-worksheet-details.js +48 -44
- package/dist-server/graphql/resolvers/worksheet-detail/generate-release-good-worksheet-details.js.map +1 -1
- package/dist-server/graphql/types/index.js +9 -4
- package/dist-server/graphql/types/index.js.map +1 -1
- package/dist-server/graphql/types/pallet/index.js +6 -3
- package/dist-server/graphql/types/pallet/index.js.map +1 -1
- package/dist-server/graphql/types/pallet/pallet.js +10 -0
- package/dist-server/graphql/types/pallet/pallet.js.map +1 -0
- package/dist-server/graphql/types/worksheet/index.js +7 -1
- package/dist-server/graphql/types/worksheet/index.js.map +1 -1
- package/dist-server/index.js +1 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/routes.js +4 -0
- package/dist-server/routes.js.map +1 -1
- package/dist-server/utils/inventory-util.js +29 -4
- package/dist-server/utils/inventory-util.js.map +1 -1
- package/package.json +16 -16
- package/server/constants/template.ts +1 -0
- package/server/controllers/ecommerce/sellercraft-controller.ts +3 -3
- package/server/controllers/inbound/putaway-worksheet-controller.ts +29 -8
- package/server/controllers/inbound/unloading-worksheet-controller.ts +83 -29
- package/server/controllers/index.ts +1 -0
- package/server/controllers/outbound/loading-worksheet-controller.ts +20 -0
- package/server/controllers/outbound/packing-worksheet-controller.ts +3 -5
- package/server/controllers/outbound/picking-worksheet-controller.ts +206 -154
- package/server/controllers/render-elccl-grn.ts +8 -6
- package/server/controllers/render-manifest.ts +68 -0
- package/server/controllers/worksheet-controller.ts +41 -2
- package/server/graphql/resolvers/pallet/index.ts +2 -0
- package/server/graphql/resolvers/pallet/pallet-outbound.ts +1 -2
- package/server/graphql/resolvers/worksheet/inventories-by-pallet.ts +10 -8
- package/server/graphql/resolvers/worksheet/loading-worksheet.ts +30 -4
- package/server/graphql/resolvers/worksheet/packing-worksheet.ts +28 -3
- package/server/graphql/resolvers/worksheet/pending-cancellation-release-order.ts +13 -7
- package/server/graphql/resolvers/worksheet/picking/activate-picking.ts +1 -6
- package/server/graphql/resolvers/worksheet/picking/complete-picking.ts +35 -4
- package/server/graphql/resolvers/worksheet/picking/fetch-and-assign-picking-task.ts +78 -0
- package/server/graphql/resolvers/worksheet/picking/index.ts +3 -1
- package/server/graphql/resolvers/worksheet/picking/picking.ts +6 -4
- package/server/graphql/resolvers/worksheet/picking/scan-product-picking.ts +7 -4
- package/server/graphql/resolvers/worksheet/picking-worksheet.ts +102 -62
- package/server/graphql/resolvers/worksheet/recommend-putway-location.ts +4 -2
- package/server/graphql/resolvers/worksheet/unloaded-inventories.ts +10 -1
- package/server/graphql/resolvers/worksheet/unloading-return-worksheet.ts +6 -4
- package/server/graphql/resolvers/worksheet-detail/generate-release-good-worksheet-details.ts +102 -76
- package/server/graphql/types/index.ts +9 -4
- package/server/graphql/types/pallet/index.ts +8 -2
- package/server/graphql/types/pallet/pallet.ts +7 -0
- package/server/graphql/types/worksheet/index.ts +8 -2
- package/server/index.ts +1 -0
- package/server/routes.ts +5 -0
- package/server/utils/inventory-util.ts +31 -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
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
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
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
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
|
-
|
|
415
|
-
|
|
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
|
-
|
|
418
|
-
throw new Error(this.ERROR_MSG.VALIDITY.
|
|
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
|
-
|
|
421
|
-
|
|
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
|
-
|
|
426
|
-
|
|
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 =
|
|
441
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
456
|
-
|
|
457
|
-
|
|
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
|
-
|
|
461
|
-
|
|
446
|
+
if (!foundProductDetail) {
|
|
447
|
+
const roProductDetail: ProductDetail = productDetails.find(
|
|
448
|
+
(parentDetail: ProductDetail) =>
|
|
449
|
+
parentDetail.packingType === packingType && parentDetail.packingSize == packingSize
|
|
450
|
+
)
|
|
462
451
|
|
|
463
|
-
|
|
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
|
-
|
|
468
|
-
|
|
469
|
-
|
|
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
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
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
|
-
|
|
488
|
-
await this.
|
|
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
|
-
|
|
480
|
+
pickedQty: number,
|
|
481
|
+
binLocation?: string,
|
|
482
|
+
serialNumber?: string
|
|
498
483
|
): Promise<void> {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
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
|
-
|
|
522
|
-
|
|
523
|
-
|
|
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
|
-
|
|
538
|
-
|
|
539
|
-
|
|
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
|
-
|
|
542
|
-
inventory.
|
|
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
|
-
|
|
547
|
-
|
|
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 (
|
|
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
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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.
|
|
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.
|
|
976
|
+
childQty = scannedProductDetail.packingSize
|
|
938
977
|
} else {
|
|
939
978
|
while (hasChildRelation && !hasMatchingChild) {
|
|
940
979
|
hasChildRelation = Boolean(currentProductDetail?.childProductDetail)
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { EntityManager, In } from 'typeorm'
|
|
2
|
-
|
|
3
1
|
import { User } from '@things-factory/auth-base'
|
|
4
2
|
import { Bizplace } from '@things-factory/biz-base'
|
|
5
3
|
import { ReleaseGood } from '@things-factory/sales-base'
|
|
6
4
|
import { Domain } from '@things-factory/shell'
|
|
7
5
|
import { Pallet, PalletHistory } from '@things-factory/warehouse-base'
|
|
6
|
+
import { EntityManager, getRepository, In } from 'typeorm'
|
|
8
7
|
|
|
9
8
|
export const palletOutbound = {
|
|
10
9
|
async palletOutbound(_: any, { refOrderNo, patches }, context: any) {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {
|
|
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 {
|
|
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
|
)
|