@things-factory/worksheet-base 4.3.191 → 4.3.194

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 (22) hide show
  1. package/dist-server/controllers/ecommerce/sellercraft-controller.js +1 -1
  2. package/dist-server/controllers/ecommerce/sellercraft-controller.js.map +1 -1
  3. package/dist-server/controllers/outbound/picking-worksheet-controller.js +1 -1
  4. package/dist-server/controllers/outbound/picking-worksheet-controller.js.map +1 -1
  5. package/dist-server/controllers/worksheet-controller.js +1 -1
  6. package/dist-server/controllers/worksheet-controller.js.map +1 -1
  7. package/dist-server/graphql/resolvers/worksheet/confirm-cancellation-release-order.js +3 -2
  8. package/dist-server/graphql/resolvers/worksheet/confirm-cancellation-release-order.js.map +1 -1
  9. package/dist-server/graphql/resolvers/worksheet/picking/complete-batch-picking.js +30 -1
  10. package/dist-server/graphql/resolvers/worksheet/picking/complete-batch-picking.js.map +1 -1
  11. package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js +25 -0
  12. package/dist-server/graphql/resolvers/worksheet/picking/complete-picking.js.map +1 -1
  13. package/dist-server/utils/lmd-util.js +138 -1
  14. package/dist-server/utils/lmd-util.js.map +1 -1
  15. package/package.json +9 -8
  16. package/server/controllers/ecommerce/sellercraft-controller.ts +1 -1
  17. package/server/controllers/outbound/picking-worksheet-controller.ts +34 -9
  18. package/server/controllers/worksheet-controller.ts +34 -12
  19. package/server/graphql/resolvers/worksheet/confirm-cancellation-release-order.ts +2 -1
  20. package/server/graphql/resolvers/worksheet/picking/complete-batch-picking.ts +34 -2
  21. package/server/graphql/resolvers/worksheet/picking/complete-picking.ts +27 -1
  22. package/server/utils/lmd-util.ts +186 -1
@@ -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 (foundReleaseGood?.orderPackages?.length && foundReleaseGood.lmdOption && foundReleaseGood.lastMileDelivery && foundReleaseGood?.orderPackages?.some(op => op.parcelId == null)){
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 {
@@ -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
+ }