@things-factory/integration-sellercraft 8.0.0-beta.9 → 8.0.0

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 (51) hide show
  1. package/dist-server/tsconfig.tsbuildinfo +1 -1
  2. package/package.json +14 -14
  3. package/server/constants/index.ts +2 -0
  4. package/server/constants/order-status-mapping.ts +28 -0
  5. package/server/constants/platform.ts +6 -0
  6. package/server/controllers/index.ts +5 -0
  7. package/server/controllers/sellercraft/apis/add-inbound-order.ts +50 -0
  8. package/server/controllers/sellercraft/apis/echo.ts +14 -0
  9. package/server/controllers/sellercraft/apis/fetch-order-document.ts +18 -0
  10. package/server/controllers/sellercraft/apis/index.ts +8 -0
  11. package/server/controllers/sellercraft/apis/initiate-order-document.ts +17 -0
  12. package/server/controllers/sellercraft/apis/initiate-order-shipment.ts +29 -0
  13. package/server/controllers/sellercraft/apis/pack-marketplace-order.ts +35 -0
  14. package/server/controllers/sellercraft/apis/update-marketplace-order.ts +14 -0
  15. package/server/controllers/sellercraft/apis/update-product.ts +21 -0
  16. package/server/controllers/sellercraft/index.ts +7 -0
  17. package/server/controllers/sellercraft/platform-action.ts +39 -0
  18. package/server/controllers/sellercraft/sellercraft.ts +109 -0
  19. package/server/controllers/sellercraft-api/decorators.ts +52 -0
  20. package/server/controllers/sellercraft-api/index.ts +51 -0
  21. package/server/controllers/sellercraft-api/types.ts +0 -0
  22. package/server/controllers/sellercraft-channel-integration/apis/echo.ts +14 -0
  23. package/server/controllers/sellercraft-channel-integration/apis/index.ts +6 -0
  24. package/server/controllers/sellercraft-channel-integration/apis/ingest-channel-categories.ts +37 -0
  25. package/server/controllers/sellercraft-channel-integration/apis/ingest-channel-category-attributes.ts +65 -0
  26. package/server/controllers/sellercraft-channel-integration/apis/ingest-channel-order-package.ts +62 -0
  27. package/server/controllers/sellercraft-channel-integration/apis/ingest-channel-order.ts +92 -0
  28. package/server/controllers/sellercraft-channel-integration/apis/ingest-channel-product.ts +97 -0
  29. package/server/controllers/sellercraft-channel-integration/index.ts +7 -0
  30. package/server/controllers/sellercraft-channel-integration/platform-action.ts +39 -0
  31. package/server/controllers/sellercraft-channel-integration/sellercraft-channel-integration.ts +115 -0
  32. package/server/controllers/sellercraft-channel-integration-api/decorators.ts +45 -0
  33. package/server/controllers/sellercraft-channel-integration-api/index.ts +45 -0
  34. package/server/controllers/sellercraft-channel-integration-api/types.ts +0 -0
  35. package/server/index.ts +7 -0
  36. package/server/middlewares/index.ts +3 -0
  37. package/server/migrations/index.ts +9 -0
  38. package/server/routers/sellercraft-router.ts +326 -0
  39. package/server/routes.ts +32 -0
  40. package/server/service/index.ts +23 -0
  41. package/server/service/marketplace-channel/index.ts +6 -0
  42. package/server/service/marketplace-channel/marketplace-channel-order-mutation.ts +456 -0
  43. package/server/service/marketplace-channel/marketplace-channel-product-mutation.ts +282 -0
  44. package/server/service/marketplace-channel/marketplace-channel.ts +76 -0
  45. package/server/service/sellercraft/index.ts +6 -0
  46. package/server/service/sellercraft/sellercraft-mutation.ts +126 -0
  47. package/server/service/sellercraft/sellercraft-query.ts +43 -0
  48. package/server/service/sellercraft/sellercraft-type.ts +54 -0
  49. package/server/service/sellercraft/sellercraft.ts +96 -0
  50. package/server/utils/tokencraft-util.ts +60 -0
  51. package/tsconfig.json +9 -0
@@ -0,0 +1,326 @@
1
+ import Router from 'koa-router'
2
+ import { v4 as uuidv4 } from 'uuid'
3
+
4
+ import { StoreAPI } from '@things-factory/integration-marketplace'
5
+ import { createPayloadLog, PayloadType } from '@things-factory/integration-base'
6
+ import { sleep } from '@things-factory/utils'
7
+
8
+ import { SHIPPING_TYPE } from '../constants'
9
+ import { getShop } from '../utils/tokencraft-util'
10
+
11
+ const debug = require('debug')('things-factory:integration-sellercraft:sellercraft-router')
12
+
13
+ export const sellercraftRouter = new Router()
14
+
15
+ sellercraftRouter.post('/sellercraft/store/update-product-price', async (context, next) => {
16
+ const requestBody = context.request.body
17
+
18
+ for (var i = 0; i < requestBody.length; i++) {
19
+ let mappedStore: any = await getShop(context, requestBody[i].channel_id, requestBody[i].shop_id)
20
+ var result
21
+
22
+ try {
23
+ if (requestBody[i].variant.native_variant_id != requestBody[i].native_product_id) {
24
+ const req = {
25
+ costPrice: requestBody[i].variant.full_price,
26
+ sellPrice: requestBody[i].variant.sale_price,
27
+ productId: requestBody[i].native_product_id,
28
+ variationId: requestBody[i].variant.native_variant_id,
29
+ variationSku: requestBody[i].variant.sku,
30
+ context: { state: { domain: null } }
31
+ }
32
+ result = await StoreAPI.updateStoreProductVariationPrice(mappedStore, req)
33
+ } else {
34
+ const req = {
35
+ costPrice: requestBody[i].variant.full_price,
36
+ sellPrice: requestBody[i].variant.sale_price,
37
+ productId: requestBody[i].native_product_id,
38
+ variationSku: requestBody[i].variant.sku,
39
+ context: { state: { domain: null } }
40
+ }
41
+ result = await StoreAPI.updateStoreProductPrice(mappedStore, req)
42
+ }
43
+
44
+ debug(result)
45
+
46
+ context.type = 'application/json'
47
+ context.status = 200
48
+ context.body = 'Succeeded'
49
+ } catch (e) {
50
+ context.type = 'application/json'
51
+ context.status = 500
52
+ context.body = e.message
53
+ }
54
+ }
55
+ })
56
+
57
+ sellercraftRouter.post('/sellercraft/store/update-product-stock', async (context, next) => {
58
+ const requestBody = context.request.body
59
+ for (var i = 0; i < requestBody.length; i++) {
60
+ let mappedStore: any = await getShop(context, requestBody[i].channel_id, requestBody[i].shop_id)
61
+ var result
62
+
63
+ try {
64
+ if (requestBody[i].variant.native_variant_id != requestBody[i].native_product_id) {
65
+ const req = {
66
+ qty: requestBody[i].variant.stock,
67
+ itemId: requestBody[i].native_product_id,
68
+ variationId: requestBody[i].variant.native_variant_id,
69
+ distributors: requestBody[i].distributors || [], // for Magento
70
+ variationSku: requestBody[i].variant.sku,
71
+ locationId: requestBody[i]?.variant?.extra_metadata?.locationId, // for Shopify
72
+ inventoryItemId: requestBody[i]?.variant?.extra_metadata?.inventoryItemId, // for Shopify
73
+ context: { state: { domain: null } }
74
+ }
75
+ if (req.locationId) {
76
+ let location = JSON.parse(req.locationId)
77
+ req.qty -= await StoreAPI.getStoreProductVariationStock(mappedStore, { variantId: req.variationId })
78
+ req.locationId = location[0].location_id
79
+ }
80
+ result = await StoreAPI.updateStoreProductVariationStock(mappedStore, req)
81
+ } else {
82
+ const req = {
83
+ qty: requestBody[i].variant.stock,
84
+ itemId: requestBody[i].native_product_id,
85
+ distributors: requestBody[i].distributors || [], // for Magento
86
+ variationSku: requestBody[i].variant.sku,
87
+ context: { state: { domain: null } }
88
+ }
89
+ result = await StoreAPI.updateStoreProductStock(mappedStore, req)
90
+ }
91
+
92
+ debug(result)
93
+
94
+ context.type = 'application/json'
95
+ context.status = 200
96
+ context.body = 'Succeeded'
97
+ } catch (e) {
98
+ context.type = 'application/json'
99
+ context.status = 500
100
+ context.body = e.message
101
+ }
102
+ }
103
+ })
104
+
105
+ sellercraftRouter.post('/sellercraft/store/update-order-status', async (context, next) => {
106
+ try {
107
+ const requestBody = context.request.body
108
+ var result: any = {}
109
+ let mappedStore: any = await getShop(context, requestBody.channel_id, requestBody.shop_id)
110
+ let packageIds: any =
111
+ mappedStore.platform == 'tiktok'
112
+ ? requestBody?.order_items.map(oi => {
113
+ return oi.package_id
114
+ })
115
+ : []
116
+
117
+ const reqBody = {
118
+ orderId: requestBody.native_order_id,
119
+ status: requestBody.order_status,
120
+ carrier: requestBody?.shipper_last_mile,
121
+ trackingNo: requestBody?.tracking_number,
122
+ orderItems: unmapOrderItems(
123
+ requestBody?.order_items.map(oi => {
124
+ return oi.native_order_item_id
125
+ }) || []
126
+ ),
127
+ isSOF: requestBody?.seller_logistics,
128
+ packageIds: [...new Set(packageIds)],
129
+ locations:
130
+ mappedStore.platform == 'shopify'
131
+ ? requestBody?.order_items.map(oi => {
132
+ let jsonLocation = oi.extra_metadata.locationId
133
+ return JSON.parse(jsonLocation)[0].location_id
134
+ })
135
+ : null,
136
+ context: { state: { domain: null } }
137
+ }
138
+
139
+ let responseBody: any = { operation_id: uuidv4() }
140
+ try {
141
+ try {
142
+ if (mappedStore.platform == 'tiktok') {
143
+ for (let packageId of reqBody.packageIds) {
144
+ result = (await StoreAPI.updateOrderStatus(mappedStore, { packageId, status: reqBody.status })) || {}
145
+ }
146
+ } else {
147
+ result = (await StoreAPI.updateOrderStatus(mappedStore, reqBody)) || {}
148
+ }
149
+
150
+ debug(result)
151
+ } catch (e) {
152
+ if (e?.requiredDocument) result.requiredDocument = e.requiredDocument
153
+ }
154
+
155
+ if (result?.requiredDocument) {
156
+ // call document api and ingest channel order package
157
+ const order: any = await StoreAPI.getStoreOrder(mappedStore, { orderId: reqBody.orderId })
158
+ let orderPackage: any = order ? (order[0]?.orderPackage ? order[0].orderPackage : {}) : {}
159
+ if (orderPackage) {
160
+ const packageId: string = orderPackage.packageId
161
+
162
+ let orderDocument: any = orderPackage.orderDocument
163
+ if (orderDocument?.length == 0) {
164
+ let hasDocument: boolean = false
165
+ let retries = 0
166
+ while (!hasDocument && retries < 10) {
167
+ orderDocument = await StoreAPI.getStoreOrderDocument(mappedStore, { packageId, documentType: 1 })
168
+ if (orderDocument?.length > 0) {
169
+ hasDocument = true
170
+ break
171
+ }
172
+ await sleep(1000)
173
+ retries++
174
+ }
175
+ }
176
+
177
+ // Order Package Payload
178
+ let newOrderPackage: any = {
179
+ channel_shop_id: mappedStore.channelShopId,
180
+ native_order_id: reqBody.orderId,
181
+ native_package_id: orderPackage.packageId.toString(),
182
+ shipping_tracking_code: orderPackage.trackingNumber,
183
+ shipping_type_value: orderPackage?.shippingType ? orderPackage.shippingType : SHIPPING_TYPE.DROP_SHIPPING,
184
+ warehouse_code: SHIPPING_TYPE.DROP_SHIPPING,
185
+ shipper: {
186
+ name: orderPackage.shippingProvider,
187
+ is_cod_supported: orderPackage?.isCodSupport ? orderPackage.isCodSupport : false
188
+ },
189
+ documents:
190
+ orderDocument?.map(doc => {
191
+ return {
192
+ file: doc.file,
193
+ file_type_value: doc.fileTypeValue,
194
+ mime_type: doc.mimeType
195
+ }
196
+ }) || [],
197
+ shipper_last_mile: {
198
+ name: orderPackage.shippingProvider,
199
+ is_cod_supported: orderPackage?.isCodSupport ? orderPackage.isCodSupport : false
200
+ },
201
+ order_item_ids: orderPackage?.orderListIdList
202
+ ? orderPackage.orderListIdList
203
+ : reqBody.orderItems.map(oi => {
204
+ return oi.order_item_id
205
+ })
206
+ }
207
+
208
+ responseBody.package = newOrderPackage
209
+ }
210
+ responseBody.response_code = 'E0'
211
+ responseBody.message = 'Success'
212
+ }
213
+
214
+ responseBody.time = Math.floor(new Date(new Date().toUTCString()).getTime() / 1000)
215
+
216
+ try {
217
+ createPayloadLog(
218
+ mappedStore.channelShopId,
219
+ '/sellercraft/store/update-order-status',
220
+ requestBody,
221
+ responseBody,
222
+ null,
223
+ PayloadType.INGESTION,
224
+ 'hub-api'
225
+ )
226
+ } catch (e) {}
227
+
228
+ context.type = 'application/json'
229
+ context.status = 200
230
+ context.body = responseBody
231
+
232
+ await next()
233
+ } catch (e) {
234
+ responseBody.response_code = 'E1'
235
+ responseBody.message = e.message
236
+
237
+ context.type = 'application/json'
238
+ context.status = 500
239
+ context.body = responseBody
240
+ try {
241
+ createPayloadLog(
242
+ mappedStore?.channelShopId,
243
+ '/sellercraft/store/update-order-status',
244
+ requestBody,
245
+ responseBody,
246
+ null,
247
+ PayloadType.INGESTION,
248
+ 'hub-api'
249
+ )
250
+ } catch (e) {}
251
+ }
252
+ } catch (e) {}
253
+ })
254
+
255
+ sellercraftRouter.post('/sellercraft/store/update-product-attribute', async (context, next) => {
256
+ const requestBody = context.request.body
257
+ let mappedStore: any = await getShop(context, requestBody.channel_id, requestBody.shop_id)
258
+
259
+ let { product_sku: productSku, native_product_id: itemId, variants } = requestBody
260
+
261
+ variants.map(variant => {
262
+ let { variant_sku: variantSku, native_variant_id: variantId, attributes } = variant
263
+
264
+ attributes.map(attribute => {
265
+ let { native_attribute_id: id, attribute_key: name, attribute_value: value } = attribute
266
+
267
+ return {
268
+ id,
269
+ name,
270
+ value
271
+ }
272
+ })
273
+
274
+ return {
275
+ variantSku,
276
+ variantId,
277
+ attributes
278
+ }
279
+ })
280
+
281
+ for (var i = 0; i < variants.length; i++) {
282
+ try {
283
+ let variant = variants[i]
284
+ await StoreAPI.updateProductAttribute(mappedStore, {
285
+ productSku,
286
+ itemId,
287
+ variant,
288
+ context: { state: { domain: null } }
289
+ })
290
+ context.type = 'application/json'
291
+ context.status = 200
292
+ context.body = 'Succeeded'
293
+ } catch (e) {
294
+ context.type = 'application/json'
295
+ context.status = 500
296
+ context.body = e.message
297
+ }
298
+ }
299
+ })
300
+
301
+ function unmapOrderItems(orderItems) {
302
+ let itemsList = []
303
+ let res = orderItems.map(e => {
304
+ return e.split('-')[0]
305
+ })
306
+
307
+ for (let item of res) {
308
+ let count = 0
309
+
310
+ res.forEach(element => {
311
+ if (element === item) {
312
+ count += 1
313
+ }
314
+ })
315
+
316
+ itemsList.push({
317
+ order_item_id: item,
318
+ qty: count
319
+ })
320
+ }
321
+
322
+ itemsList = itemsList.filter(
323
+ (value, index, self) => index === self.findIndex(t => t.order_item_id === value.order_item_id)
324
+ )
325
+ return itemsList
326
+ }
@@ -0,0 +1,32 @@
1
+ import { sellercraftRouter } from './routers/sellercraft-router'
2
+
3
+ const debug = require('debug')('things-factory:integration-sellercraft:routes')
4
+
5
+ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRouter) => {
6
+ /*
7
+ * can add global public routes to application (auth not required, tenancy not required)
8
+ *
9
+ * ex) routes.get('/path', async(context, next) => {})
10
+ * ex) routes.post('/path', async(context, next) => {})
11
+ */
12
+
13
+ globalPublicRouter.use(sellercraftRouter.routes(), sellercraftRouter.allowedMethods())
14
+ })
15
+
16
+ process.on('bootstrap-module-global-private-route' as any, (app, globalPrivateRouter) => {
17
+ /*
18
+ * can add global private routes to application (auth required, tenancy not required)
19
+ */
20
+ })
21
+
22
+ process.on('bootstrap-module-domain-public-route' as any, (app, domainPublicRouter) => {
23
+ /*
24
+ * can add domain public routes to application (auth not required, tenancy required)
25
+ */
26
+ })
27
+
28
+ process.on('bootstrap-module-domain-private-route' as any, (app, domainPrivateRouter) => {
29
+ /*
30
+ * can add domain private routes to application (auth required, tenancy required)
31
+ */
32
+ })
@@ -0,0 +1,23 @@
1
+ /* EXPORT ENTITY TYPES */
2
+ export * from './sellercraft/sellercraft'
3
+
4
+ /* IMPORT ENTITIES AND RESOLVERS */
5
+ import { entities as SellercraftEntities, resolvers as SellercraftResolvers } from './sellercraft'
6
+ import { entities as MarketplaceChannelEntities, resolvers as MarketplaceSellercraftResolvers } from './marketplace-channel'
7
+
8
+ export const entities = [
9
+ /* ENTITIES */
10
+ ...SellercraftEntities,
11
+ ...MarketplaceChannelEntities
12
+ ]
13
+
14
+
15
+ export const schema = {
16
+ resolverClasses: [
17
+ /* RESOLVER CLASSES */
18
+ ...SellercraftResolvers,
19
+ ...MarketplaceSellercraftResolvers
20
+ ]
21
+ }
22
+
23
+ export { MarketplaceSellercraftResolvers }
@@ -0,0 +1,6 @@
1
+ import { MarketplaceChannel } from './marketplace-channel'
2
+ import { MarketplaceChannelOrderMutation } from './marketplace-channel-order-mutation'
3
+ import { MarketplaceChannelProductMutation } from './marketplace-channel-product-mutation'
4
+
5
+ export const entities = [MarketplaceChannel]
6
+ export const resolvers = [MarketplaceChannelOrderMutation, MarketplaceChannelProductMutation]