@things-factory/worksheet-base 4.3.190 → 4.3.193
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/outbound/picking-worksheet-controller.js +1 -1
- package/dist-server/controllers/outbound/picking-worksheet-controller.js.map +1 -1
- package/dist-server/controllers/outbound/sorting-worksheet-controller.js +1 -1
- package/dist-server/controllers/outbound/sorting-worksheet-controller.js.map +1 -1
- package/dist-server/controllers/worksheet-controller.js +1 -1
- package/dist-server/controllers/worksheet-controller.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/confirm-cancellation-release-order.js +3 -2
- package/dist-server/graphql/resolvers/worksheet/confirm-cancellation-release-order.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/packing-worksheet.js +40 -45
- package/dist-server/graphql/resolvers/worksheet/packing-worksheet.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/picking/complete-batch-picking.js +30 -1
- package/dist-server/graphql/resolvers/worksheet/picking/complete-batch-picking.js.map +1 -1
- package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js +25 -0
- package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js.map +1 -1
- package/dist-server/utils/lmd-util.js +138 -1
- package/dist-server/utils/lmd-util.js.map +1 -1
- package/package.json +9 -8
- package/server/controllers/outbound/picking-worksheet-controller.ts +34 -9
- package/server/controllers/outbound/sorting-worksheet-controller.ts +18 -5
- package/server/controllers/worksheet-controller.ts +34 -12
- package/server/graphql/resolvers/worksheet/confirm-cancellation-release-order.ts +2 -1
- package/server/graphql/resolvers/worksheet/packing-worksheet.ts +38 -45
- package/server/graphql/resolvers/worksheet/picking/complete-batch-picking.ts +34 -2
- package/server/graphql/resolvers/worksheet/picking/complete-picking.ts +27 -1
- package/server/utils/lmd-util.ts +186 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/worksheet-base",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.193",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"browser": "client/index.js",
|
|
6
6
|
"things-factory": true,
|
|
@@ -28,17 +28,18 @@
|
|
|
28
28
|
"@things-factory/document-template-base": "^4.3.179",
|
|
29
29
|
"@things-factory/id-rule-base": "^4.3.187",
|
|
30
30
|
"@things-factory/integration-accounting": "^4.3.190",
|
|
31
|
-
"@things-factory/integration-lmd": "^4.3.
|
|
32
|
-
"@things-factory/integration-marketplace": "^4.3.
|
|
33
|
-
"@things-factory/integration-sellercraft": "^4.3.
|
|
31
|
+
"@things-factory/integration-lmd": "^4.3.193",
|
|
32
|
+
"@things-factory/integration-marketplace": "^4.3.193",
|
|
33
|
+
"@things-factory/integration-sellercraft": "^4.3.193",
|
|
34
34
|
"@things-factory/integration-sftp": "^4.3.190",
|
|
35
|
-
"@things-factory/marketplace-base": "^4.3.
|
|
35
|
+
"@things-factory/marketplace-base": "^4.3.193",
|
|
36
36
|
"@things-factory/notification": "^4.3.186",
|
|
37
|
-
"@things-factory/sales-base": "^4.3.
|
|
37
|
+
"@things-factory/sales-base": "^4.3.193",
|
|
38
38
|
"@things-factory/setting-base": "^4.3.186",
|
|
39
39
|
"@things-factory/shell": "^4.3.179",
|
|
40
40
|
"@things-factory/transport-base": "^4.3.179",
|
|
41
|
-
"@things-factory/warehouse-base": "^4.3.
|
|
41
|
+
"@things-factory/warehouse-base": "^4.3.193",
|
|
42
|
+
"uuid": "^9.0.0"
|
|
42
43
|
},
|
|
43
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "8cba442aa16d21e21fa20c2bd22ba039e0a9bb5a"
|
|
44
45
|
}
|
|
@@ -1,10 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
EntityManager,
|
|
3
|
+
Equal,
|
|
4
|
+
getConnection,
|
|
5
|
+
getManager,
|
|
6
|
+
In,
|
|
7
|
+
IsNull,
|
|
8
|
+
Not
|
|
9
|
+
} from 'typeorm'
|
|
2
10
|
|
|
3
11
|
import { ApplicationType } from '@things-factory/auth-base'
|
|
4
12
|
import { Bizplace } from '@things-factory/biz-base'
|
|
13
|
+
import { logger } from '@things-factory/env'
|
|
5
14
|
import { generateId } from '@things-factory/id-rule-base'
|
|
6
|
-
import {
|
|
7
|
-
|
|
15
|
+
import {
|
|
16
|
+
Sellercraft,
|
|
17
|
+
SellercraftStatus
|
|
18
|
+
} from '@things-factory/integration-sellercraft'
|
|
19
|
+
import {
|
|
20
|
+
Product,
|
|
21
|
+
ProductBarcode,
|
|
22
|
+
ProductDetail
|
|
23
|
+
} from '@things-factory/product-base'
|
|
8
24
|
import {
|
|
9
25
|
GenerateBatchPickInfo,
|
|
10
26
|
ORDER_INVENTORY_STATUS,
|
|
@@ -17,8 +33,7 @@ import {
|
|
|
17
33
|
OrderToteItem,
|
|
18
34
|
OrderToteSeal,
|
|
19
35
|
OrderVas,
|
|
20
|
-
ReleaseGood
|
|
21
|
-
Replenishment
|
|
36
|
+
ReleaseGood
|
|
22
37
|
} from '@things-factory/sales-base'
|
|
23
38
|
import { Setting } from '@things-factory/setting-base'
|
|
24
39
|
import {
|
|
@@ -35,12 +50,22 @@ import {
|
|
|
35
50
|
TOTE_STATUS
|
|
36
51
|
} from '@things-factory/warehouse-base'
|
|
37
52
|
|
|
38
|
-
import {
|
|
53
|
+
import {
|
|
54
|
+
TASK_NUMBER_RULE_TYPE,
|
|
55
|
+
TASK_NUMBER_SETTING_KEY,
|
|
56
|
+
WORKSHEET_STATUS,
|
|
57
|
+
WORKSHEET_TYPE
|
|
58
|
+
} from '../../constants'
|
|
39
59
|
import { SellercraftController } from '../../controllers'
|
|
40
|
-
import {
|
|
41
|
-
|
|
60
|
+
import {
|
|
61
|
+
Worksheet,
|
|
62
|
+
WorksheetDetail
|
|
63
|
+
} from '../../entities'
|
|
64
|
+
import {
|
|
65
|
+
isInventoryObsolete,
|
|
66
|
+
WorksheetNoGenerator
|
|
67
|
+
} from '../../utils'
|
|
42
68
|
import { VasWorksheetController } from '../vas/vas-worksheet-controller'
|
|
43
|
-
import { logger } from '@things-factory/env'
|
|
44
69
|
|
|
45
70
|
export class PickingWorksheetController extends VasWorksheetController {
|
|
46
71
|
async generatePickingWorksheet(releaseGoodNo: string, currentStatus: string = null): Promise<Worksheet> {
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
In,
|
|
3
|
+
IsNull
|
|
4
|
+
} from 'typeorm'
|
|
2
5
|
|
|
3
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
Product,
|
|
8
|
+
ProductBarcode,
|
|
9
|
+
ProductDetail
|
|
10
|
+
} from '@things-factory/product-base'
|
|
4
11
|
import {
|
|
5
12
|
ORDER_INVENTORY_STATUS,
|
|
6
13
|
ORDER_STATUS,
|
|
@@ -21,8 +28,14 @@ import {
|
|
|
21
28
|
TOTE_STATUS
|
|
22
29
|
} from '@things-factory/warehouse-base'
|
|
23
30
|
|
|
24
|
-
import {
|
|
25
|
-
|
|
31
|
+
import {
|
|
32
|
+
WORKSHEET_STATUS,
|
|
33
|
+
WORKSHEET_TYPE
|
|
34
|
+
} from '../../constants'
|
|
35
|
+
import {
|
|
36
|
+
Worksheet,
|
|
37
|
+
WorksheetDetail
|
|
38
|
+
} from '../../entities'
|
|
26
39
|
import { VasWorksheetController } from '../vas/vas-worksheet-controller'
|
|
27
40
|
|
|
28
41
|
export class SortingWorksheetController extends VasWorksheetController {
|
|
@@ -227,7 +240,7 @@ export class SortingWorksheetController extends VasWorksheetController {
|
|
|
227
240
|
await this.updateOrderTargets([matchingOI])
|
|
228
241
|
await this.transactionInventory(inventory, releaseGood, 0, 0, INVENTORY_TRANSACTION_TYPE.SORTING)
|
|
229
242
|
|
|
230
|
-
let worksheetDetail = worksheetDetails.find(wd => (wd.targetInventory.id
|
|
243
|
+
let worksheetDetail = worksheetDetails.find(wd => (wd.targetInventory.id == matchingOI.id))
|
|
231
244
|
await this.trxMgr
|
|
232
245
|
.getRepository(WorksheetDetail)
|
|
233
246
|
.update({ id: worksheetDetail.id }, { status: WORKSHEET_STATUS.DONE, updater: this.user })
|
|
@@ -1,9 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
EntityManager,
|
|
3
|
+
EntitySchema,
|
|
4
|
+
Equal,
|
|
5
|
+
FindOneOptions,
|
|
6
|
+
getRepository,
|
|
7
|
+
In,
|
|
8
|
+
Not
|
|
9
|
+
} from 'typeorm'
|
|
2
10
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
11
|
+
import {
|
|
12
|
+
Role,
|
|
13
|
+
User
|
|
14
|
+
} from '@things-factory/auth-base'
|
|
15
|
+
import {
|
|
16
|
+
Bizplace,
|
|
17
|
+
getDomainUsers
|
|
18
|
+
} from '@things-factory/biz-base'
|
|
19
|
+
import {
|
|
20
|
+
Product,
|
|
21
|
+
ProductDetail
|
|
22
|
+
} from '@things-factory/product-base'
|
|
7
23
|
import {
|
|
8
24
|
ArrivalNotice,
|
|
9
25
|
DeliveryOrder,
|
|
@@ -15,21 +31,27 @@ import {
|
|
|
15
31
|
OrderProduct,
|
|
16
32
|
OrderVas,
|
|
17
33
|
ReleaseGood,
|
|
34
|
+
Replenishment,
|
|
18
35
|
ReturnOrder,
|
|
19
|
-
VasOrder
|
|
20
|
-
Replenishment
|
|
36
|
+
VasOrder
|
|
21
37
|
} from '@things-factory/sales-base'
|
|
22
38
|
import { Domain } from '@things-factory/shell'
|
|
23
39
|
import {
|
|
40
|
+
generateInventoryHistory,
|
|
24
41
|
Inventory,
|
|
25
42
|
INVENTORY_STATUS,
|
|
26
43
|
InventoryItem,
|
|
27
|
-
Pallet
|
|
28
|
-
generateInventoryHistory
|
|
44
|
+
Pallet
|
|
29
45
|
} from '@things-factory/warehouse-base'
|
|
30
46
|
|
|
31
|
-
import {
|
|
32
|
-
|
|
47
|
+
import {
|
|
48
|
+
WORKSHEET_STATUS,
|
|
49
|
+
WORKSHEET_TYPE
|
|
50
|
+
} from '../constants'
|
|
51
|
+
import {
|
|
52
|
+
Worksheet,
|
|
53
|
+
WorksheetDetail
|
|
54
|
+
} from '../entities'
|
|
33
55
|
import { WorksheetNoGenerator } from '../utils'
|
|
34
56
|
|
|
35
57
|
export type ReferenceOrderType =
|
|
@@ -1101,7 +1123,7 @@ export class WorksheetController {
|
|
|
1101
1123
|
union all
|
|
1102
1124
|
select pd.product_id as "productId", pd.id, pd.packing_size as "packingSize",
|
|
1103
1125
|
pd.packing_type as "packingType", pd.uom,
|
|
1104
|
-
dt1.qty * pd.
|
|
1126
|
+
dt1.qty * pd.uom_value as "uomValue", dt1.qty * pd.packing_size as "qty", pb.gtin
|
|
1105
1127
|
from product_details pd
|
|
1106
1128
|
inner join product_barcodes pb on pb.product_detail_id = pd.id
|
|
1107
1129
|
inner join cte dt1 on dt1.id = pd.child_product_detail_id
|
|
@@ -246,7 +246,8 @@ export const confirmCancellationReleaseOrder = {
|
|
|
246
246
|
pickupAccountId: releaseGood.lastMileDelivery?.pickupAccountId,
|
|
247
247
|
token: releaseGood.lastMileDelivery?.accessToken,
|
|
248
248
|
parcelId: op.parcelId,
|
|
249
|
-
warehouse: domain?.name
|
|
249
|
+
warehouse: domain?.name,
|
|
250
|
+
staging: releaseGood.lastMileDelivery?.staging
|
|
250
251
|
})
|
|
251
252
|
if (!res?.status) throw new Error('cannot cancel consignment note')
|
|
252
253
|
}
|
|
@@ -27,6 +27,10 @@ import { Worksheet } from '../../../entities'
|
|
|
27
27
|
|
|
28
28
|
export const packingWorksheetResolver = {
|
|
29
29
|
async packingWorksheet(_: any, { releaseGoodNo }, context: any) {
|
|
30
|
+
// Performance tracker
|
|
31
|
+
let timeflag = releaseGoodNo
|
|
32
|
+
console.time(`packingWorksheet(${timeflag})`)
|
|
33
|
+
|
|
30
34
|
try {
|
|
31
35
|
const { tx, domain, user }: { tx: EntityManager; domain: Domain; user: User } = context.state
|
|
32
36
|
let releaseGood: ReleaseGood = await tx.getRepository(ReleaseGood).findOne({
|
|
@@ -42,19 +46,23 @@ export const packingWorksheetResolver = {
|
|
|
42
46
|
|
|
43
47
|
// Find Release Order based on Bin
|
|
44
48
|
if (!releaseGood) {
|
|
49
|
+
console.time(`packingWorksheet-findingBin(${timeflag})`)
|
|
45
50
|
binLocation = await tx.getRepository(Location).findOne({
|
|
46
51
|
where: { domain, name: releaseGoodNo }
|
|
47
52
|
})
|
|
48
53
|
|
|
49
54
|
if (binLocation) {
|
|
55
|
+
|
|
56
|
+
// find unique release goods id based on READY_TO_PACK, PACKING, PACKED order inventories within bins
|
|
50
57
|
const qb: SelectQueryBuilder<OrderInventory> = tx
|
|
51
58
|
.getRepository(OrderInventory)
|
|
52
59
|
.createQueryBuilder('orderInventory')
|
|
53
60
|
|
|
54
|
-
qb.
|
|
55
|
-
.
|
|
56
|
-
.
|
|
57
|
-
.
|
|
61
|
+
qb.select('releaseGood.id', 'id')
|
|
62
|
+
.innerJoin('orderInventory.releaseGood', 'releaseGood')
|
|
63
|
+
.innerJoin('releaseGood.bizplace', 'bizplace')
|
|
64
|
+
.innerJoin('bizplace.domain', 'domain')
|
|
65
|
+
.innerJoin(
|
|
58
66
|
'worksheets',
|
|
59
67
|
'ws',
|
|
60
68
|
`orderInventory.release_good_id = ws.release_good_id AND ws.type = 'PACKING' AND (ws.status = 'EXECUTING' OR ws.status = 'DEACTIVATED')`
|
|
@@ -71,54 +79,37 @@ export const packingWorksheetResolver = {
|
|
|
71
79
|
.andWhere('releaseGood.status IN (:...status)', {
|
|
72
80
|
status: [ORDER_STATUS.READY_TO_PACK, ORDER_STATUS.PACKING]
|
|
73
81
|
})
|
|
74
|
-
.orderBy(
|
|
75
|
-
.addOrderBy('
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
.getRepository(OrderPackage)
|
|
95
|
-
.createQueryBuilder('opk')
|
|
96
|
-
.innerJoinAndSelect('opk.releaseGood', 'rg')
|
|
97
|
-
.innerJoinAndSelect('rg.bizplace', 'bizplace')
|
|
98
|
-
.innerJoinAndSelect('bizplace.domain', 'domain')
|
|
99
|
-
.innerJoinAndSelect('rg.orderInventories', 'oi')
|
|
100
|
-
.where('rg.id = :releaseGoodId', { releaseGoodId: roId })
|
|
101
|
-
.getMany()
|
|
102
|
-
|
|
103
|
-
if (orderPackages?.length) {
|
|
104
|
-
releaseGood = orderPackages[0].releaseGood
|
|
105
|
-
}
|
|
106
|
-
})
|
|
107
|
-
)
|
|
108
|
-
releaseGoodNo = releaseGood?.name
|
|
109
|
-
isBatchPicking = releaseGood?.orderInventories[0]?.refWorksheetId ? true : false
|
|
110
|
-
} else {
|
|
111
|
-
releaseGoodNo = orderInventoriesByBin[0].releaseGood.name
|
|
112
|
-
releaseGood = orderInventoriesByBin[0].releaseGood
|
|
113
|
-
isBatchPicking = orderInventoriesByBin[0]?.refWorksheetId ? true : false
|
|
82
|
+
.orderBy('ws.created_at', 'ASC')
|
|
83
|
+
.addOrderBy('releaseGood.name', 'ASC')
|
|
84
|
+
.groupBy('ws.created_at')
|
|
85
|
+
.addGroupBy('releaseGood.name')
|
|
86
|
+
.addGroupBy('releaseGood.id')
|
|
87
|
+
|
|
88
|
+
const orderInventoriesByBin = await qb.getRawMany()
|
|
89
|
+
const totalInventoriesByBin = orderInventoriesByBin.length
|
|
90
|
+
|
|
91
|
+
if (totalInventoriesByBin > 0) {
|
|
92
|
+
//find first release good of order inventory within the bin
|
|
93
|
+
releaseGood = await tx.getRepository(ReleaseGood).findOne({
|
|
94
|
+
where: { id: orderInventoriesByBin[0].id },
|
|
95
|
+
relations: ['bizplace', 'bizplace.domain', 'orderInventories']
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
//query worksheet to find does the order associated with batch picking
|
|
99
|
+
let worksheet: Worksheet = null
|
|
100
|
+
if (releaseGood.orderInventories[0].refWorksheetId) {
|
|
101
|
+
worksheet = await tx.getRepository(Worksheet).findOne({ where: { id: releaseGood.orderInventories[0].refWorksheetId, type: WORKSHEET_TYPE.BATCH_PICKING } })
|
|
114
102
|
}
|
|
115
103
|
|
|
116
|
-
|
|
104
|
+
releaseGoodNo = releaseGood.name
|
|
105
|
+
isBatchPicking = worksheet ? true : false
|
|
106
|
+
releaseGood.totalInventoriesByBin = totalInventoriesByBin
|
|
117
107
|
releaseGood.isOrderInventoryBin = true
|
|
118
108
|
} else {
|
|
119
109
|
throw new Error(`Bin do not have any existing order.`)
|
|
120
110
|
}
|
|
121
111
|
}
|
|
112
|
+
console.timeEnd(`packingWorksheet-findingBin(${timeflag})`)
|
|
122
113
|
}
|
|
123
114
|
|
|
124
115
|
if (!releaseGood) throw new Error(`Release good do not exist.`)
|
|
@@ -263,6 +254,7 @@ export const packingWorksheetResolver = {
|
|
|
263
254
|
let processingOrderPackage: OrderPackage[] =
|
|
264
255
|
orderPackages.filter(opk => opk.status == ORDER_STATUS.PROCESSING) || []
|
|
265
256
|
|
|
257
|
+
console.timeEnd(`packingWorksheet(${timeflag})`)
|
|
266
258
|
return {
|
|
267
259
|
worksheetInfo: {
|
|
268
260
|
releaseGood,
|
|
@@ -321,6 +313,7 @@ export const packingWorksheetResolver = {
|
|
|
321
313
|
})
|
|
322
314
|
}
|
|
323
315
|
} catch (error) {
|
|
316
|
+
console.timeEnd(`packingWorksheet(${timeflag})`)
|
|
324
317
|
console.error(error)
|
|
325
318
|
throw error
|
|
326
319
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EntityManager, getManager, In } from 'typeorm'
|
|
1
|
+
import { EntityManager, getManager, In, getConnection } from 'typeorm'
|
|
2
2
|
|
|
3
3
|
import { ApplicationType, User } from '@things-factory/auth-base'
|
|
4
4
|
import { Bizplace, getMyBizplace } from '@things-factory/biz-base'
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import { Setting } from '@things-factory/setting-base'
|
|
17
17
|
import { Domain } from '@things-factory/shell'
|
|
18
18
|
import { Inventory } from '@things-factory/warehouse-base'
|
|
19
|
+
import { logger } from '@things-factory/env'
|
|
19
20
|
|
|
20
21
|
import {
|
|
21
22
|
PackingWorksheetController,
|
|
@@ -190,8 +191,39 @@ export async function completeBatchPicking(
|
|
|
190
191
|
}
|
|
191
192
|
|
|
192
193
|
// trigger LMD API to create parcel
|
|
193
|
-
if (
|
|
194
|
+
if (
|
|
195
|
+
foundReleaseGood?.orderPackages?.length &&
|
|
196
|
+
foundReleaseGood.lmdOption &&
|
|
197
|
+
foundReleaseGood.lastMileDelivery &&
|
|
198
|
+
foundReleaseGood?.orderPackages?.some(op => op.parcelId == null)
|
|
199
|
+
) {
|
|
194
200
|
await createLmdParcel([foundReleaseGood], tx)
|
|
201
|
+
// trigger RTS
|
|
202
|
+
try {
|
|
203
|
+
const orderSource: string = foundReleaseGood.source
|
|
204
|
+
|
|
205
|
+
if (orderSource == ApplicationType.SELLERCRAFT) {
|
|
206
|
+
const sellercraft: Sellercraft = await tx.getRepository(Sellercraft).findOne({
|
|
207
|
+
domain: foundReleaseGood.bizplace.domain,
|
|
208
|
+
status: SellercraftStatus.ACTIVE
|
|
209
|
+
})
|
|
210
|
+
if (sellercraft) {
|
|
211
|
+
await getConnection().transaction(async tx => {
|
|
212
|
+
const sellercraftCtrl: SellercraftController = new SellercraftController(tx, null, null)
|
|
213
|
+
const rtsTriggerLevel: Setting = await tx.getRepository(Setting).findOne({
|
|
214
|
+
where: { domain: foundReleaseGood.domain, category: 'id-rule', name: 'rts-trigger-level' }
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
if (rtsTriggerLevel && parseInt(rtsTriggerLevel?.value || 0) == 1) {
|
|
218
|
+
await sellercraftCtrl.initiateOrderShipment(sellercraft, foundReleaseGood)
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
} catch (e) {
|
|
224
|
+
logger.error(`[get-lmd-awb-sof-trigger]: ${e}`)
|
|
225
|
+
}
|
|
226
|
+
//
|
|
195
227
|
}
|
|
196
228
|
//
|
|
197
229
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EntityManager, getManager, In } from 'typeorm'
|
|
1
|
+
import { EntityManager, getManager, In, getConnection } from 'typeorm'
|
|
2
2
|
|
|
3
3
|
import { ApplicationType, User } from '@things-factory/auth-base'
|
|
4
4
|
import { Bizplace, ContactPoint, getMyBizplace } from '@things-factory/biz-base'
|
|
@@ -460,6 +460,32 @@ export async function completePicking(
|
|
|
460
460
|
releaseGood?.orderPackages?.some(op => op.parcelId == null)
|
|
461
461
|
) {
|
|
462
462
|
await createLmdParcel([releaseGood], tx)
|
|
463
|
+
// trigger RTS
|
|
464
|
+
try {
|
|
465
|
+
const orderSource: string = releaseGood.source
|
|
466
|
+
|
|
467
|
+
if (orderSource == ApplicationType.SELLERCRAFT) {
|
|
468
|
+
const sellercraft: Sellercraft = await tx.getRepository(Sellercraft).findOne({
|
|
469
|
+
domain: releaseGood.bizplace.domain,
|
|
470
|
+
status: SellercraftStatus.ACTIVE
|
|
471
|
+
})
|
|
472
|
+
if (sellercraft) {
|
|
473
|
+
await getConnection().transaction(async tx => {
|
|
474
|
+
const sellercraftCtrl: SellercraftController = new SellercraftController(tx, null, null)
|
|
475
|
+
const rtsTriggerLevel: Setting = await tx.getRepository(Setting).findOne({
|
|
476
|
+
where: { domain: releaseGood.domain, category: 'id-rule', name: 'rts-trigger-level' }
|
|
477
|
+
})
|
|
478
|
+
|
|
479
|
+
if (rtsTriggerLevel && parseInt(rtsTriggerLevel?.value || 0) == 1) {
|
|
480
|
+
await sellercraftCtrl.initiateOrderShipment(sellercraft, releaseGood)
|
|
481
|
+
}
|
|
482
|
+
})
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
} catch (e) {
|
|
486
|
+
logger.error(`[get-lmd-awb-sof-trigger]: ${e}`)
|
|
487
|
+
}
|
|
488
|
+
//
|
|
463
489
|
}
|
|
464
490
|
//
|
|
465
491
|
} else {
|
package/server/utils/lmd-util.ts
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
|
+
import { getRepository, getConnection, SelectQueryBuilder } from 'typeorm'
|
|
2
|
+
import { v4 as uuidv4 } from 'uuid'
|
|
3
|
+
|
|
1
4
|
import { LastMileAPI, LastMileDelivery } from '@things-factory/integration-lmd'
|
|
2
5
|
import { logger } from '@things-factory/env'
|
|
3
6
|
import { GeoArea } from '@things-factory/geography'
|
|
4
7
|
import { Bizplace } from '@things-factory/biz-base'
|
|
5
8
|
import { ReleaseGood, OrderPackage } from '@things-factory/sales-base'
|
|
9
|
+
import { Board } from '@things-factory/board-service'
|
|
10
|
+
import { headlessModel, pdf } from '@things-factory/board-service'
|
|
11
|
+
import { Attachment, uploadAwb } from '@things-factory/attachment-base'
|
|
12
|
+
import { Sellercraft, SellercraftStatus } from '@things-factory/integration-sellercraft'
|
|
13
|
+
import { ApplicationType } from '@things-factory/auth-base'
|
|
14
|
+
import { Setting } from '@things-factory/setting-base'
|
|
15
|
+
|
|
16
|
+
// import { SellercraftController } from '../controllers'
|
|
17
|
+
|
|
18
|
+
const LMD_BOARDS = {
|
|
19
|
+
// dhl: 'operato-lmd-dhl-awb',
|
|
20
|
+
airspeed: 'operato-lmd-airspeed-awb'
|
|
21
|
+
}
|
|
6
22
|
|
|
7
23
|
export async function createLmdParcel(releaseGoods, tx) {
|
|
8
24
|
try {
|
|
9
25
|
let parcelsRequest = []
|
|
10
26
|
for (let releaseGood of releaseGoods) {
|
|
11
|
-
|
|
12
27
|
const lmd: LastMileDelivery = releaseGood.lastMileDelivery
|
|
13
28
|
|
|
14
29
|
const bizplace: Bizplace = await tx.getRepository(Bizplace).findOne({
|
|
@@ -27,6 +42,7 @@ export async function createLmdParcel(releaseGoods, tx) {
|
|
|
27
42
|
pickupAccountId: lmd?.pickupAccountId,
|
|
28
43
|
soldToAccountId: lmd?.soldToAccountId,
|
|
29
44
|
token: lmd?.accessToken,
|
|
45
|
+
staging: lmd?.staging,
|
|
30
46
|
|
|
31
47
|
recipient: releaseGood.attentionTo,
|
|
32
48
|
phone: releaseGood.phone1,
|
|
@@ -46,6 +62,8 @@ export async function createLmdParcel(releaseGoods, tx) {
|
|
|
46
62
|
pDistrict: senderGeoArea.cityName,
|
|
47
63
|
pState: senderGeoArea.stateName,
|
|
48
64
|
pCountry: senderGeoArea.countryCode,
|
|
65
|
+
|
|
66
|
+
handoverMethod: 1
|
|
49
67
|
}
|
|
50
68
|
|
|
51
69
|
let unprocessedOrderPackages: OrderPackage[] = releaseGood.orderPackages.filter(op => !op.parcelId)
|
|
@@ -79,8 +97,175 @@ export async function createLmdParcel(releaseGoods, tx) {
|
|
|
79
97
|
for (let parcel of res) {
|
|
80
98
|
await tx.getRepository(OrderPackage).update({ id: parcel.refNo }, { parcelId: parcel.parcelId })
|
|
81
99
|
}
|
|
100
|
+
|
|
101
|
+
const qb: SelectQueryBuilder<OrderPackage> = tx.getRepository(OrderPackage)
|
|
102
|
+
.createQueryBuilder('op')
|
|
103
|
+
.innerJoinAndSelect('op.releaseGood', 'rg')
|
|
104
|
+
.innerJoinAndSelect('rg.domain', 'd')
|
|
105
|
+
.innerJoinAndSelect('rg.bizplace', 'b')
|
|
106
|
+
.innerJoinAndSelect('b.domain', 'd2')
|
|
107
|
+
.leftJoinAndSelect('rg.lastMileDelivery', 'lmd')
|
|
108
|
+
.where('op.id IN (:...orderPackageIds)', { orderPackageIds: res.map(parcel => { return parcel.refNo }) })
|
|
109
|
+
|
|
110
|
+
const orderPackages: OrderPackage[] = await qb.getMany()
|
|
111
|
+
await processAwbAndTrackingNo(orderPackages, tx)
|
|
82
112
|
}
|
|
83
113
|
} catch (e) {
|
|
84
114
|
logger.error(`[lmd-create-parcel]: ${e}`)
|
|
85
115
|
}
|
|
86
116
|
}
|
|
117
|
+
|
|
118
|
+
export async function processAwbAndTrackingNo(orderPackages, tx) {
|
|
119
|
+
let releaseOrders: ReleaseGood = []
|
|
120
|
+
|
|
121
|
+
for (let orderPackage of orderPackages) {
|
|
122
|
+
// await getConnection().transaction(async tx => {
|
|
123
|
+
try {
|
|
124
|
+
let awbRes = await LastMileAPI.getAwb(
|
|
125
|
+
{ ...orderPackage.releaseGood.lastMileDelivery, platform: 'lmdMiddleware' },
|
|
126
|
+
{ parcelId: orderPackage.parcelId, staging: orderPackage.releaseGood.lastMileDelivery?.staging }
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
if (awbRes) {
|
|
130
|
+
let awbContent: any
|
|
131
|
+
const { deliveryConfirmationNo, tracking_no } = awbRes
|
|
132
|
+
if (awbRes.content) {
|
|
133
|
+
awbContent = Buffer.from(awbRes.content, 'base64')
|
|
134
|
+
} else {
|
|
135
|
+
awbContent = await constructAwb(orderPackage, awbRes)
|
|
136
|
+
}
|
|
137
|
+
const awb = await uploadAwbToS3(awbContent, orderPackage)
|
|
138
|
+
await tx.getRepository(OrderPackage).update(
|
|
139
|
+
{ id: orderPackage.id },
|
|
140
|
+
{ airwayBill: awb.url, trackingNo: deliveryConfirmationNo || tracking_no }
|
|
141
|
+
)
|
|
142
|
+
releaseOrders.push(orderPackage.releaseGood)
|
|
143
|
+
}
|
|
144
|
+
} catch (e) {
|
|
145
|
+
logger.error(e)
|
|
146
|
+
}
|
|
147
|
+
// })
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// trigger RTS
|
|
151
|
+
// try {
|
|
152
|
+
// let uniqueReleaseOrders: ReleaseGood = [...new Map(releaseOrders.map(item => [item['id'], item])).values()]
|
|
153
|
+
|
|
154
|
+
// for (let releaseOrder of uniqueReleaseOrders) {
|
|
155
|
+
// const orderSource: string = releaseOrder.source
|
|
156
|
+
|
|
157
|
+
// if (orderSource == ApplicationType.SELLERCRAFT) {
|
|
158
|
+
// const sellercraft: Sellercraft = await getRepository(Sellercraft).findOne({
|
|
159
|
+
// domain: releaseOrder.bizplace.domain,
|
|
160
|
+
// status: SellercraftStatus.ACTIVE
|
|
161
|
+
// })
|
|
162
|
+
// if (sellercraft) {
|
|
163
|
+
// await getConnection().transaction(async tx => {
|
|
164
|
+
// const sellercraftCtrl: SellercraftController = new SellercraftController(tx, null, null)
|
|
165
|
+
// const rtsTriggerLevel: Setting = await tx.getRepository(Setting).findOne({
|
|
166
|
+
// where: { domain: releaseOrder.domain, category: 'id-rule', name: 'rts-trigger-level' }
|
|
167
|
+
// })
|
|
168
|
+
|
|
169
|
+
// if (rtsTriggerLevel && parseInt(rtsTriggerLevel?.value || 0) == 1) {
|
|
170
|
+
// await sellercraftCtrl.initiateOrderShipment(sellercraft, releaseOrder)
|
|
171
|
+
// }
|
|
172
|
+
// })
|
|
173
|
+
// }
|
|
174
|
+
// }
|
|
175
|
+
// }
|
|
176
|
+
// } catch (e) {
|
|
177
|
+
// logger.error(`[get-lmd-awb-sof-trigger]: ${e}`)
|
|
178
|
+
// }
|
|
179
|
+
//
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function constructAwb(orderPackage, awbRes) {
|
|
183
|
+
const releaseOrder = orderPackage.releaseOrder
|
|
184
|
+
let {
|
|
185
|
+
shipmentID,
|
|
186
|
+
deliveryConfirmationNo,
|
|
187
|
+
deliveryDepotCode,
|
|
188
|
+
primarySortCode,
|
|
189
|
+
secondarySortCode,
|
|
190
|
+
recipient,
|
|
191
|
+
sender,
|
|
192
|
+
tracking_no,
|
|
193
|
+
courier
|
|
194
|
+
} = awbRes
|
|
195
|
+
|
|
196
|
+
let senderFullAddress = `${sender?.address}${sender?.address2 ? ', ' + sender?.address2 : ''}${
|
|
197
|
+
sender?.district ? ', ' + sender?.district : ''
|
|
198
|
+
}${sender?.city ? ', ' + sender?.city : ''}${sender?.postcode ? ', ' + sender?.postcode : ''}${
|
|
199
|
+
sender?.state ? ', ' + sender?.state : ''
|
|
200
|
+
}`
|
|
201
|
+
|
|
202
|
+
let recipientAddress1 = `${recipient?.address}${recipient?.address2 ? ', ' + recipient?.address2 : ''}${
|
|
203
|
+
recipient?.district ? ', ' + recipient?.district : ''
|
|
204
|
+
}`
|
|
205
|
+
|
|
206
|
+
let recipientAddress2 = `${recipient?.state}${recipient?.city ? ', ' + recipient?.city : ''}${
|
|
207
|
+
recipient?.postcode ? ', ' + recipient?.postcode : ''
|
|
208
|
+
}`
|
|
209
|
+
|
|
210
|
+
let data = {
|
|
211
|
+
senderFullAddress,
|
|
212
|
+
senderName: sender?.name,
|
|
213
|
+
recipientAddress1,
|
|
214
|
+
recipientAddress2,
|
|
215
|
+
recipientPhone: recipient?.phone,
|
|
216
|
+
recipientName: recipient?.name,
|
|
217
|
+
refId: shipmentID,
|
|
218
|
+
deliveryConfirmationNo: deliveryConfirmationNo || tracking_no,
|
|
219
|
+
deliveryDepotCode: deliveryDepotCode,
|
|
220
|
+
primarySortCode: primarySortCode,
|
|
221
|
+
secondarySortCode: secondarySortCode,
|
|
222
|
+
orderNo: releaseOrder?.refNo
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
let lmdBoard: Board = await getRepository(Board).findOne({
|
|
226
|
+
where: { name: LMD_BOARDS[courier] },
|
|
227
|
+
relations: ['domain']
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
if (!lmdBoard) throw new Error(`[get-lmd-awb] board is not found (RO: ${releaseOrder.name})`)
|
|
231
|
+
|
|
232
|
+
const { model } = await headlessModel({ domain: lmdBoard.domain, id: lmdBoard.id })
|
|
233
|
+
|
|
234
|
+
const result = await pdf({
|
|
235
|
+
id: lmdBoard.id,
|
|
236
|
+
model,
|
|
237
|
+
data,
|
|
238
|
+
options: {
|
|
239
|
+
format: 'A4'
|
|
240
|
+
},
|
|
241
|
+
context: { state: { domain: lmdBoard.domain } }
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
return result
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
async function uploadAwbToS3(result, orderPackage) {
|
|
248
|
+
const releaseOrder = orderPackage.releaseGood
|
|
249
|
+
const uuid = uuidv4()
|
|
250
|
+
const awb: any = await uploadAwb({
|
|
251
|
+
content: result,
|
|
252
|
+
title: uuid
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
if (!awb?.url) throw new Error(`[get-lmd-awb] awb was not uploaded for (RO: ${releaseOrder.name})`)
|
|
256
|
+
|
|
257
|
+
// create attachment
|
|
258
|
+
|
|
259
|
+
await getRepository(Attachment).insert({
|
|
260
|
+
name: uuid,
|
|
261
|
+
mimetype: 'application/pdf',
|
|
262
|
+
category: 'LMD_AWB',
|
|
263
|
+
refBy: orderPackage.id,
|
|
264
|
+
path: awb.url,
|
|
265
|
+
domain: releaseOrder.domain,
|
|
266
|
+
size: 0,
|
|
267
|
+
encoding: ''
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
return awb
|
|
271
|
+
}
|