@things-factory/worksheet-base 4.3.284 → 4.3.286
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/controllers/ecommerce/ecommerce-controller.js +49 -21
- package/dist-server/controllers/ecommerce/ecommerce-controller.js.map +1 -1
- package/dist-server/controllers/outbound/packing-worksheet-controller.js +100 -121
- package/dist-server/controllers/outbound/packing-worksheet-controller.js.map +1 -1
- package/dist-server/controllers/worksheet-controller.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/packing/scan-product-packing.js +7 -3
- package/dist-server/graphql/resolvers/worksheet/packing/scan-product-packing.js.map +1 -1
- package/dist-server/utils/inventory-util.js +6 -6
- package/dist-server/utils/inventory-util.js.map +1 -1
- package/dist-server/utils/lmd-util.js +3 -2
- package/dist-server/utils/lmd-util.js.map +1 -1
- package/package.json +9 -9
- package/server/controllers/ecommerce/ecommerce-controller.ts +47 -21
- package/server/controllers/outbound/packing-worksheet-controller.ts +117 -133
- package/server/controllers/worksheet-controller.ts +1 -1
- package/server/graphql/resolvers/worksheet/packing/scan-product-packing.ts +7 -3
- package/server/utils/inventory-util.ts +6 -6
- package/server/utils/lmd-util.ts +3 -2
|
@@ -306,176 +306,154 @@ export class PackingWorksheetController extends VasWorksheetController {
|
|
|
306
306
|
}
|
|
307
307
|
|
|
308
308
|
async scanProductPacking(orderPackageItemId: string, productBarcode: string, serialNumber?: string): Promise<any> {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
let packedQty: number = 1
|
|
309
|
+
try {
|
|
310
|
+
let packedQty: number = 1
|
|
311
|
+
let orderPackageItem: OrderPackageItem = await this.trxMgr.getRepository(OrderPackageItem).findOne({
|
|
312
|
+
where: { id: orderPackageItemId }, relations: ['orderProduct', 'orderProduct.releaseGood']
|
|
313
|
+
})
|
|
314
|
+
const orderProduct: OrderProduct = orderPackageItem.orderProduct
|
|
315
|
+
const releaseGood: ReleaseGood = orderProduct.releaseGood
|
|
317
316
|
|
|
318
|
-
|
|
319
|
-
let worksheetDetail: WorksheetDetail = await this.trxMgr
|
|
320
|
-
.getRepository(WorksheetDetail)
|
|
321
|
-
.createQueryBuilder('wd')
|
|
322
|
-
.innerJoinAndSelect('wd.bizplace', 'b')
|
|
323
|
-
.innerJoinAndSelect('wd.targetInventory', 'oi')
|
|
324
|
-
.innerJoinAndSelect('oi.releaseGood', 'rg')
|
|
325
|
-
.innerJoinAndSelect('oi.inventory', 'inv')
|
|
326
|
-
.leftJoinAndSelect('oi.orderProduct', 'op')
|
|
317
|
+
let orderInventory: OrderInventory = await this.trxMgr.getRepository(OrderInventory).createQueryBuilder('oi')
|
|
327
318
|
.innerJoinAndSelect('oi.product', 'prd')
|
|
328
319
|
.innerJoinAndSelect('oi.productDetail', 'pd')
|
|
329
|
-
.innerJoinAndSelect('
|
|
330
|
-
.where('oi.
|
|
320
|
+
.innerJoinAndSelect('oi.inventory', 'inv')
|
|
321
|
+
.where('oi.order_product_id = :id', { id: orderProduct.id })
|
|
322
|
+
.andWhere('oi.packed_qty <> oi.picked_qty')
|
|
323
|
+
.orderBy('oi.created_at')
|
|
324
|
+
.addOrderBy('oi.name')
|
|
331
325
|
.getOne()
|
|
332
326
|
|
|
333
|
-
let targetInventory: OrderInventory = worksheetDetail.targetInventory
|
|
334
|
-
|
|
335
|
-
let inventory: Inventory = targetInventory.inventory
|
|
336
|
-
let pickedQty: number = targetInventory.releaseQty
|
|
337
|
-
const releaseGood: ReleaseGood = targetInventory.releaseGood
|
|
338
|
-
const product: Product = targetInventory.product
|
|
339
|
-
const productDetail: ProductDetail = targetInventory.productDetail
|
|
340
|
-
const productBarcodes: [ProductBarcode] = productDetail.productBarcodes
|
|
341
|
-
let matchingProduct
|
|
342
327
|
|
|
343
|
-
|
|
344
|
-
|
|
328
|
+
// Validation: PackQty cannot be more than ReleaseQty
|
|
329
|
+
if (orderPackageItem !== null && orderInventory == null) {
|
|
330
|
+
throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('packing', `unable to find suitable item`))
|
|
345
331
|
}
|
|
346
332
|
|
|
347
|
-
|
|
333
|
+
const product: Product = orderInventory.product
|
|
334
|
+
const productDetail: ProductDetail = orderInventory.productDetail
|
|
335
|
+
const inventory: Inventory = orderInventory.inventory
|
|
336
|
+
const releaseQty: number = orderInventory.releaseQty
|
|
337
|
+
|
|
338
|
+
const matchingProduct = await this.getDirectQty(
|
|
348
339
|
{
|
|
349
340
|
...productDetail,
|
|
350
|
-
product:
|
|
341
|
+
product: product
|
|
351
342
|
},
|
|
352
343
|
productBarcode,
|
|
353
344
|
packedQty
|
|
354
345
|
)
|
|
355
|
-
|
|
356
|
-
//validate matching product details based on scanned barcode
|
|
357
|
-
if (!matchingProduct) throw new Error(this.ERROR_MSG.FIND.NO_RESULT(productBarcode))
|
|
358
|
-
|
|
359
346
|
packedQty = matchingProduct.qty
|
|
360
347
|
|
|
361
|
-
|
|
362
|
-
|
|
348
|
+
// Validation: PackQty cannot be more than ReleaseQty
|
|
349
|
+
if ((packedQty + orderInventory.packedQty) > orderInventory.releaseQty) {
|
|
350
|
+
throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('packing', `packed quantity can't exceed release qty`))
|
|
363
351
|
}
|
|
364
352
|
|
|
365
|
-
// Serial Number scanning for batch picking
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
let foundSerialNumber: InventoryItem = await this.trxMgr
|
|
373
|
-
.getRepository(InventoryItem)
|
|
374
|
-
.findOne({ where: { domain: this.domain, serialNumber: serialNumber, productDetail } })
|
|
375
|
-
|
|
376
|
-
if (foundSerialNumber) {
|
|
377
|
-
if (foundSerialNumber.inventoryId !== inventory.id) {
|
|
378
|
-
throw new Error('Serial Number scanned is in another inventory')
|
|
379
|
-
}
|
|
353
|
+
// Validation: Serial Number scanning for batch picking
|
|
354
|
+
let inventoryItem: Partial<InventoryItem>
|
|
355
|
+
if (orderInventory?.refWorksheetId && product?.isRequireSerialNumberScanningOutbound) {
|
|
356
|
+
if (!serialNumber || serialNumber == '') {
|
|
357
|
+
throw new Error(this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('packing', `require serial number`))
|
|
358
|
+
}
|
|
380
359
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
.findOne({ where: { id: foundSerialNumber.outboundOrderId } })
|
|
385
|
-
throw new Error(`Inventory Item is already picked/packed in ${releaseGood.name}`)
|
|
386
|
-
}
|
|
360
|
+
inventoryItem = await this.trxMgr.getRepository(InventoryItem).findOne({
|
|
361
|
+
where: { domain: this.domain, serialNumber: serialNumber, productDetail }
|
|
362
|
+
})
|
|
387
363
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
364
|
+
if (inventoryItem) {
|
|
365
|
+
if (inventoryItem.inventoryId !== inventory.id) {
|
|
366
|
+
throw new Error('Serial Number scanned is in another inventory')
|
|
367
|
+
}
|
|
391
368
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
inventoryItem.name = InventoryNoGenerator.inventoryItemName()
|
|
396
|
-
inventoryItem.serialNumber = serialNumber
|
|
397
|
-
inventoryItem.status = INVENTORY_STATUS.PACKING
|
|
398
|
-
inventoryItem.outboundOrderId = releaseGood.id
|
|
399
|
-
inventoryItem.source = INVENTORY_ITEM_SOURCE.OUTBOUND
|
|
400
|
-
inventoryItem.product = product
|
|
401
|
-
inventoryItem.productDetail = productDetail
|
|
402
|
-
inventoryItem.inventory = inventory
|
|
403
|
-
inventoryItem.domain = this.domain
|
|
369
|
+
if (inventoryItem.outboundOrderId !== releaseGood.id) {
|
|
370
|
+
throw new Error(`Inventory Item is already picked/packed in ${releaseGood.name}`)
|
|
371
|
+
}
|
|
404
372
|
|
|
405
|
-
|
|
373
|
+
inventoryItem = {
|
|
374
|
+
...inventoryItem,
|
|
375
|
+
status: INVENTORY_STATUS.PACKING,
|
|
376
|
+
updater: this.user,
|
|
377
|
+
}
|
|
378
|
+
} else {
|
|
379
|
+
inventoryItem = {
|
|
380
|
+
name: InventoryNoGenerator.inventoryItemName(),
|
|
381
|
+
serialNumber: serialNumber,
|
|
382
|
+
status: INVENTORY_STATUS.PACKING,
|
|
383
|
+
outboundOrderId: releaseGood.id,
|
|
384
|
+
source: INVENTORY_ITEM_SOURCE.OUTBOUND,
|
|
385
|
+
product: product,
|
|
386
|
+
productDetail: productDetail,
|
|
387
|
+
inventory: inventory,
|
|
388
|
+
domain: this.domain,
|
|
406
389
|
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
390
|
|
|
410
|
-
|
|
411
|
-
? targetInventory.packedQty + packedQty
|
|
412
|
-
: packedQty
|
|
413
|
-
if (targetInventory.packedQty > pickedQty) {
|
|
414
|
-
throw new Error(
|
|
415
|
-
this.ERROR_MSG.VALIDITY.CANT_PROCEED_STEP_BY('pack', `packed quantity can't exceed release qty`)
|
|
416
|
-
)
|
|
391
|
+
}
|
|
417
392
|
}
|
|
418
393
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
let packedBy: string[] =
|
|
394
|
+
// set orderInventory Value
|
|
395
|
+
orderInventory.packedQty = (orderInventory?.packedQty || 0) + packedQty
|
|
396
|
+
orderInventory.packedAt = new Date()
|
|
397
|
+
let packedBy: string[] = orderInventory.packedBy ? orderInventory.packedBy.split(',') : []
|
|
423
398
|
if (!packedBy.find(x => x == this.user.name)) {
|
|
424
399
|
packedBy.push(this.user.name)
|
|
425
|
-
|
|
400
|
+
orderInventory.packedBy = packedBy.join(',')
|
|
426
401
|
}
|
|
427
402
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
403
|
+
// set orderPackageItem Value
|
|
404
|
+
let updateOrderPackageItem: Partial<OrderPackageItem> = {
|
|
405
|
+
packedQty: (orderPackageItem?.packedQty || 0) + packedQty,
|
|
406
|
+
updatedAt: new Date(),
|
|
407
|
+
updater: this.user
|
|
408
|
+
}
|
|
409
|
+
if (updateOrderPackageItem.packedQty === orderPackageItem.releaseQty) {
|
|
410
|
+
updateOrderPackageItem.status = ORDER_STATUS.DONE
|
|
411
|
+
}
|
|
436
412
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
413
|
+
if (inventoryItem) {
|
|
414
|
+
await this.trxMgr.getRepository(InventoryItem).save(inventoryItem)
|
|
415
|
+
}
|
|
416
|
+
orderInventory = (await this.updateOrderTargets([orderInventory]))[0]
|
|
440
417
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
itm.status = INVENTORY_STATUS.PACKED
|
|
444
|
-
itm.updater = this.user
|
|
445
|
-
})
|
|
418
|
+
await this.trxMgr.getRepository(OrderPackageItem).update({ id: orderPackageItem.id }, updateOrderPackageItem)
|
|
419
|
+
updateOrderPackageItem = await this.trxMgr.getRepository(OrderPackageItem).findOne({ where: { id: orderPackageItem.id } })
|
|
446
420
|
|
|
447
|
-
|
|
448
|
-
}
|
|
449
|
-
} else {
|
|
450
|
-
await this.trxMgr.getRepository(OrderInventory).save(targetInventory)
|
|
451
|
-
}
|
|
452
|
-
break
|
|
453
|
-
}
|
|
421
|
+
await this.trxMgr.getRepository(OrderPackage).update({ id: orderPackageItem.orderPackageId }, { updatedAt: new Date(), updater: this.user })
|
|
454
422
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
423
|
+
if (orderInventory.packedQty === releaseQty) {
|
|
424
|
+
orderInventory.status = ORDER_INVENTORY_STATUS.PACKED
|
|
425
|
+
await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.PACKING)
|
|
426
|
+
await this.trxMgr.getRepository(WorksheetDetail).update({ targetInventory: { id: orderInventory.id }, type: 'PACKING' },
|
|
427
|
+
{
|
|
428
|
+
status: WORKSHEET_STATUS.DONE,
|
|
429
|
+
updater: this.user,
|
|
430
|
+
updatedAt: new Date()
|
|
431
|
+
}
|
|
432
|
+
)
|
|
458
433
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
434
|
+
//// update related inventoryItems related with the releaseOrder
|
|
435
|
+
await this.trxMgr.getRepository(InventoryItem).update({ outboundOrderId: releaseGood.id },
|
|
436
|
+
{
|
|
437
|
+
status: INVENTORY_STATUS.PACKED,
|
|
438
|
+
updater: this.user,
|
|
439
|
+
updatedAt: new Date()
|
|
440
|
+
}
|
|
441
|
+
)
|
|
442
|
+
}
|
|
464
443
|
|
|
465
|
-
await this.trxMgr.getRepository(OrderPackageItem).save(orderPackageItem)
|
|
466
|
-
await this.trxMgr
|
|
467
|
-
.getRepository(OrderPackage)
|
|
468
|
-
.update({ id: orderPackageItem.orderPackage.id }, { updatedAt: new Date() })
|
|
469
444
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
445
|
+
return {
|
|
446
|
+
worksheetDetailInfos: [
|
|
447
|
+
{
|
|
448
|
+
id: updateOrderPackageItem.id,
|
|
449
|
+
releaseQty: updateOrderPackageItem.releaseQty,
|
|
450
|
+
packedQty: updateOrderPackageItem.packedQty,
|
|
451
|
+
status: updateOrderPackageItem.status
|
|
452
|
+
}
|
|
453
|
+
]
|
|
454
|
+
}
|
|
455
|
+
} catch (error) {
|
|
456
|
+
throw error
|
|
479
457
|
}
|
|
480
458
|
}
|
|
481
459
|
|
|
@@ -526,6 +504,12 @@ export class PackingWorksheetController extends VasWorksheetController {
|
|
|
526
504
|
if (releaseGood?.courierOption) orderStatus = ORDER_STATUS.DONE
|
|
527
505
|
else orderStatus = ORDER_STATUS.LOADING
|
|
528
506
|
|
|
507
|
+
//update releaseGood TrackingNo
|
|
508
|
+
await this.trxMgr.getRepository(ReleaseGood).update(
|
|
509
|
+
{ id: orderPackage.orderProduct.releaseGood.id },
|
|
510
|
+
{ trackingNo: `${releaseGood.trackingNo.split(',').push(orderPackage.trackingNo).join(',')}` }
|
|
511
|
+
)
|
|
512
|
+
|
|
529
513
|
return await this.completeWorksheet(worksheet, orderStatus)
|
|
530
514
|
} else {
|
|
531
515
|
return worksheet
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { EntityManager } from 'typeorm'
|
|
2
2
|
|
|
3
|
+
const { PerformanceObserver, performance } = require('node:perf_hooks');
|
|
4
|
+
|
|
3
5
|
import { User } from '@things-factory/auth-base'
|
|
4
6
|
import { Domain } from '@things-factory/shell'
|
|
5
7
|
|
|
@@ -20,7 +22,7 @@ export async function scanProductPacking(
|
|
|
20
22
|
productBarcode: string,
|
|
21
23
|
serialNumber?: string
|
|
22
24
|
) {
|
|
23
|
-
|
|
25
|
+
performance.mark(`start:${orderPackageItemId} - ${productBarcode}`)
|
|
24
26
|
try {
|
|
25
27
|
const worksheetController: PackingWorksheetController = new PackingWorksheetController(tx, domain, user)
|
|
26
28
|
const inventoryItems = await worksheetController.scanProductPacking(
|
|
@@ -29,10 +31,12 @@ export async function scanProductPacking(
|
|
|
29
31
|
serialNumber
|
|
30
32
|
)
|
|
31
33
|
|
|
32
|
-
console.timeEnd(`execution time to scan for packing ${orderPackageItemId} - ${productBarcode}`)
|
|
33
34
|
return inventoryItems
|
|
34
35
|
} catch (error) {
|
|
35
|
-
console.timeEnd(`execution time to scan for packing ${orderPackageItemId} - ${productBarcode}`)
|
|
36
36
|
throw error
|
|
37
|
+
} finally {
|
|
38
|
+
performance.mark(`end:${orderPackageItemId} - ${productBarcode}`)
|
|
39
|
+
let perf = performance.measure(`scanProductPacking: ${orderPackageItemId} - ${productBarcode}`, `start:${orderPackageItemId} - ${productBarcode}`, `end:${orderPackageItemId} - ${productBarcode}`)
|
|
40
|
+
console.info(perf.toJSON())
|
|
37
41
|
}
|
|
38
42
|
}
|
|
@@ -170,7 +170,7 @@ export async function inventoriesByStrategy(
|
|
|
170
170
|
|
|
171
171
|
switch (pickingStrategy.toUpperCase()) {
|
|
172
172
|
case 'FIFO':
|
|
173
|
-
qb.
|
|
173
|
+
qb.addOrderBy('"INV"."created_at"', 'ASC')
|
|
174
174
|
if (locationSortingRules) {
|
|
175
175
|
for (const key in locationSortingRules) {
|
|
176
176
|
qb.addOrderBy(`LOC.${key}`, locationSortingRules[key])
|
|
@@ -179,7 +179,7 @@ export async function inventoriesByStrategy(
|
|
|
179
179
|
break
|
|
180
180
|
|
|
181
181
|
case 'LIFO':
|
|
182
|
-
qb.
|
|
182
|
+
qb.addOrderBy('"INV"."created_at"', 'DESC')
|
|
183
183
|
if (locationSortingRules) {
|
|
184
184
|
for (const key in locationSortingRules) {
|
|
185
185
|
qb.addOrderBy(`LOC.${key}`, locationSortingRules[key])
|
|
@@ -188,7 +188,7 @@ export async function inventoriesByStrategy(
|
|
|
188
188
|
break
|
|
189
189
|
|
|
190
190
|
case 'FEFO':
|
|
191
|
-
qb.
|
|
191
|
+
qb.addOrderBy('"INV"."expiration_date"', 'ASC')
|
|
192
192
|
qb.addOrderBy('"INV"."created_at"', 'ASC')
|
|
193
193
|
if (locationSortingRules) {
|
|
194
194
|
for (const key in locationSortingRules) {
|
|
@@ -198,7 +198,7 @@ export async function inventoriesByStrategy(
|
|
|
198
198
|
break
|
|
199
199
|
|
|
200
200
|
case 'FMFO':
|
|
201
|
-
qb.
|
|
201
|
+
qb.addOrderBy('"INV"."manufacture_date"', 'ASC')
|
|
202
202
|
qb.addOrderBy('"INV"."created_at"', 'ASC')
|
|
203
203
|
if (locationSortingRules) {
|
|
204
204
|
for (const key in locationSortingRules) {
|
|
@@ -211,13 +211,13 @@ export async function inventoriesByStrategy(
|
|
|
211
211
|
if (locationSortingRules) {
|
|
212
212
|
for (const key in locationSortingRules) {
|
|
213
213
|
if (locIdx === 0) {
|
|
214
|
-
qb.
|
|
214
|
+
qb.addOrderBy(`LOC.${key}`, locationSortingRules[key])
|
|
215
215
|
} else {
|
|
216
216
|
qb.addOrderBy(`LOC.${key}`, locationSortingRules[key])
|
|
217
217
|
}
|
|
218
218
|
++locIdx
|
|
219
219
|
}
|
|
220
|
-
} else qb.
|
|
220
|
+
} else qb.addOrderBy('"LOC"."name"', 'DESC')
|
|
221
221
|
break
|
|
222
222
|
}
|
|
223
223
|
|
package/server/utils/lmd-util.ts
CHANGED
|
@@ -20,7 +20,7 @@ export async function createLmdParcel(releaseGoods, tx) {
|
|
|
20
20
|
try {
|
|
21
21
|
let parcelsRequest = []
|
|
22
22
|
for (let releaseGood of releaseGoods) {
|
|
23
|
-
|
|
23
|
+
let lmd: LastMileDelivery = releaseGood.lastMileDelivery
|
|
24
24
|
|
|
25
25
|
const bizplace: Bizplace = await tx.getRepository(Bizplace).findOne({
|
|
26
26
|
where: { domain: releaseGood.domain },
|
|
@@ -38,7 +38,8 @@ export async function createLmdParcel(releaseGoods, tx) {
|
|
|
38
38
|
if(lmd?.platform=='NINJA_VAN'){
|
|
39
39
|
const currentTimestamp: number = Math.floor(Date.now() / 1000)
|
|
40
40
|
if (currentTimestamp >= lmd?.expiresIn) {
|
|
41
|
-
await refreshAccessTokenNinjavan(lmd?.id,{state:{ tx }})
|
|
41
|
+
const lastMileDelivery= await refreshAccessTokenNinjavan(lmd?.id,{state:{ tx }})
|
|
42
|
+
lmd.accessToken=lastMileDelivery.accessToken
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
45
|
|