@things-factory/integration-sellercraft 5.0.0-alpha.9 → 5.0.0-zeta.1

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 (49) hide show
  1. package/dist-server/constants/order-status-mapping.js +24 -3
  2. package/dist-server/constants/order-status-mapping.js.map +1 -1
  3. package/dist-server/constants/platform.js +4 -1
  4. package/dist-server/constants/platform.js.map +1 -1
  5. package/dist-server/controllers/sellercraft/sellercraft.js +2 -2
  6. package/dist-server/controllers/sellercraft/sellercraft.js.map +1 -1
  7. package/dist-server/controllers/sellercraft-api/decorators.js +2 -0
  8. package/dist-server/controllers/sellercraft-api/decorators.js.map +1 -1
  9. package/dist-server/controllers/sellercraft-channel-integration/apis/ingest-channel-categories.js +18 -21
  10. package/dist-server/controllers/sellercraft-channel-integration/apis/ingest-channel-categories.js.map +1 -1
  11. package/dist-server/controllers/sellercraft-channel-integration/apis/ingest-channel-order-package.js +5 -2
  12. package/dist-server/controllers/sellercraft-channel-integration/apis/ingest-channel-order-package.js.map +1 -1
  13. package/dist-server/controllers/sellercraft-channel-integration/apis/ingest-channel-order.js +21 -14
  14. package/dist-server/controllers/sellercraft-channel-integration/apis/ingest-channel-order.js.map +1 -1
  15. package/dist-server/controllers/sellercraft-channel-integration/apis/ingest-channel-product.js +23 -23
  16. package/dist-server/controllers/sellercraft-channel-integration/apis/ingest-channel-product.js.map +1 -1
  17. package/dist-server/controllers/sellercraft-channel-integration/sellercraft-channel-integration.js +17 -6
  18. package/dist-server/controllers/sellercraft-channel-integration/sellercraft-channel-integration.js.map +1 -1
  19. package/dist-server/routers/sellercraft-router.js +204 -134
  20. package/dist-server/routers/sellercraft-router.js.map +1 -1
  21. package/dist-server/service/marketplace-channel/marketplace-channel-order-mutation.js +327 -103
  22. package/dist-server/service/marketplace-channel/marketplace-channel-order-mutation.js.map +1 -1
  23. package/dist-server/service/marketplace-channel/marketplace-channel-product-mutation.js +173 -99
  24. package/dist-server/service/marketplace-channel/marketplace-channel-product-mutation.js.map +1 -1
  25. package/dist-server/service/marketplace-channel/marketplace-channel.js +5 -0
  26. package/dist-server/service/marketplace-channel/marketplace-channel.js.map +1 -1
  27. package/dist-server/service/sellercraft/sellercraft-mutation.js +3 -6
  28. package/dist-server/service/sellercraft/sellercraft-mutation.js.map +1 -1
  29. package/dist-server/service/sellercraft/sellercraft-query.js +1 -1
  30. package/dist-server/service/sellercraft/sellercraft-query.js.map +1 -1
  31. package/dist-server/utils/tokencraft-util.js +63 -0
  32. package/dist-server/utils/tokencraft-util.js.map +1 -0
  33. package/package.json +15 -15
  34. package/server/constants/order-status-mapping.ts +24 -2
  35. package/server/constants/platform.ts +4 -1
  36. package/server/controllers/sellercraft/sellercraft.ts +2 -2
  37. package/server/controllers/sellercraft-api/decorators.ts +3 -0
  38. package/server/controllers/sellercraft-channel-integration/apis/ingest-channel-categories.ts +19 -22
  39. package/server/controllers/sellercraft-channel-integration/apis/ingest-channel-order-package.ts +6 -2
  40. package/server/controllers/sellercraft-channel-integration/apis/ingest-channel-order.ts +22 -15
  41. package/server/controllers/sellercraft-channel-integration/apis/ingest-channel-product.ts +32 -26
  42. package/server/controllers/sellercraft-channel-integration/sellercraft-channel-integration.ts +15 -6
  43. package/server/routers/sellercraft-router.ts +218 -164
  44. package/server/service/marketplace-channel/marketplace-channel-order-mutation.ts +392 -156
  45. package/server/service/marketplace-channel/marketplace-channel-product-mutation.ts +199 -145
  46. package/server/service/marketplace-channel/marketplace-channel.ts +4 -0
  47. package/server/service/sellercraft/sellercraft-mutation.ts +3 -3
  48. package/server/service/sellercraft/sellercraft-query.ts +1 -1
  49. package/server/utils/tokencraft-util.ts +60 -0
@@ -1,213 +1,228 @@
1
1
  import Router from 'koa-router'
2
+ import { v4 as uuidv4 } from 'uuid'
2
3
 
3
4
  import { config } from '@things-factory/env'
4
5
  import { StoreAPI } from '@things-factory/integration-marketplace'
5
- import { PLATFORM } from '../constants'
6
+ import { getShop } from '../utils/tokencraft-util'
7
+
8
+ import { SHIPPING_TYPE } from '../constants'
6
9
 
7
10
  const debug = require('debug')('things-factory:integration-sellercraft:sellercraft-router')
8
11
 
9
12
  export const sellercraftRouter = new Router()
10
13
 
11
14
  sellercraftRouter.post('/sellercraft/store/update-product-price', async (context, next) => {
12
- const sellercraftChannelIntegrationConfig = config.get('sellercraftChannelIntegrationConfig', {})
13
- const { tokenCraftApiKey: apiKey, tokenCraftUrl } = sellercraftChannelIntegrationConfig
14
-
15
- const xApiKey = context.headers['x-api-key']
16
-
17
- if (apiKey !== xApiKey) context.throw(400, 'api key validation failed')
18
-
19
15
  const requestBody = context.request.body
20
16
 
21
17
  for (var i = 0; i < requestBody.length; i++) {
22
- var store: any = {} // get from tokencraft
18
+ let mappedStore: any = await getShop(context, requestBody[i].channel_id, requestBody[i].shop_id)
23
19
  var result
24
20
 
25
- // https://staging-tokencraft.sellercraft.co/v1/get-shop?channel_id=4bfb3362-d57c-47f8-8781-007316d179bf&shop_id=dd9cf3b7-114f-4d74-a7e2-7b524ae086f2
26
- var fullPath = tokenCraftUrl + '?channel_id=4bfb3362-d57c-47f8-8781-007316d179bf&shop_id=' + requestBody[i].shop_id
27
- const response: any = await fetch(fullPath, {
28
- method: 'get',
29
- headers: {
30
- 'Content-Type': 'application/json',
31
- 'x-api-key': apiKey
21
+ try {
22
+ if (requestBody[i].variant.native_variant_id != requestBody[i].native_product_id) {
23
+ const req = {
24
+ costPrice: requestBody[i].variant.full_price,
25
+ sellPrice: requestBody[i].variant.sale_price,
26
+ productId: requestBody[i].native_product_id,
27
+ variationId: requestBody[i].variant.native_variant_id,
28
+ variationSku: requestBody[i].variant.sku,
29
+ context: { state: { domain: null } }
30
+ }
31
+ result = await StoreAPI.updateStoreProductVariationPrice(mappedStore, req)
32
+ } else {
33
+ const req = {
34
+ costPrice: requestBody[i].variant.full_price,
35
+ sellPrice: requestBody[i].variant.sale_price,
36
+ productId: requestBody[i].native_product_id,
37
+ variationSku: requestBody[i].variant.sku,
38
+ context: { state: { domain: null } }
39
+ }
40
+ result = await StoreAPI.updateStoreProductPrice(mappedStore, req)
32
41
  }
33
- })
34
- if (response.ok) {
35
- store = await response.json()
36
- }
37
42
 
38
- let mappedStore: any = {
39
- accessKey: store.shop.credential.consumer_key,
40
- accessSecret: store.shop.credential.consumer_secret,
41
- storeURL: store.shop.credential.store_url,
42
- platform: PLATFORM[`${store.shop.org_prefix}`]
43
- }
43
+ debug(result)
44
44
 
45
- if (requestBody[i].native_variant_id) {
46
- const req = {
47
- costPrice: requestBody[i].full_price,
48
- sellPrice: requestBody[i].sale_price,
49
- productId: requestBody[i].native_product_id,
50
- variationId: requestBody[i].native_variant_id
51
- }
52
- result = await StoreAPI.updateStoreProductVariationPrice(mappedStore, req)
53
- } else {
54
- const req = {
55
- costPrice: requestBody[i].full_price,
56
- sellPrice: requestBody[i].sale_price,
57
- productId: requestBody[i].native_product_id
58
- }
59
- result = await StoreAPI.updateStoreProductPrice(mappedStore, req)
45
+ context.type = 'application/json'
46
+ context.status = 200
47
+ context.body = 'Succeeded'
48
+ } catch (e) {
49
+ context.type = 'application/json'
50
+ context.status = 500
51
+ context.body = e.message
60
52
  }
61
-
62
- debug(result)
63
53
  }
64
-
65
- context.status = 200
66
54
  })
67
55
 
68
56
  sellercraftRouter.post('/sellercraft/store/update-product-stock', async (context, next) => {
69
- const sellercraftChannelIntegrationConfig = config.get('sellercraftChannelIntegrationConfig', {})
70
- const { tokenCraftApiKey: apiKey, tokenCraftUrl } = sellercraftChannelIntegrationConfig
71
-
72
- const xApiKey = context.headers['x-api-key']
73
-
74
- if (apiKey !== xApiKey) context.throw(400, 'api key validation failed')
75
-
76
57
  const requestBody = context.request.body
77
58
  for (var i = 0; i < requestBody.length; i++) {
78
- var store: any = {} // get from tokencraft
59
+ let mappedStore: any = await getShop(context, requestBody[i].channel_id, requestBody[i].shop_id)
79
60
  var result
80
61
 
81
- // https://staging-tokencraft.sellercraft.co/v1/get-shop?channel_id=4bfb3362-d57c-47f8-8781-007316d179bf&shop_id=dd9cf3b7-114f-4d74-a7e2-7b524ae086f2
82
- var fullPath = tokenCraftUrl + '?channel_id=4bfb3362-d57c-47f8-8781-007316d179bf&shop_id=' + requestBody[i].shop_id
83
- const response: any = await fetch(fullPath, {
84
- method: 'get',
85
- headers: {
86
- 'Content-Type': 'application/json',
87
- 'x-api-key': apiKey
62
+ try {
63
+ if (requestBody[i].variant.native_variant_id != requestBody[i].native_product_id) {
64
+ const req = {
65
+ qty: requestBody[i].variant.stock,
66
+ itemId: requestBody[i].native_product_id,
67
+ variationId: requestBody[i].variant.native_variant_id,
68
+ distributors: requestBody[i].distributors || [], // for Magento
69
+ variationSku: requestBody[i].variant.sku,
70
+ locationId: requestBody[i]?.variant?.extra_metadata?.locationId, // for Shopify
71
+ inventoryItemId: requestBody[i]?.variant?.extra_metadata?.inventoryItemId, // for Shopify
72
+ context: { state: { domain: null } }
73
+ }
74
+ if (req.locationId) {
75
+ let location = JSON.parse(req.locationId)
76
+ req.qty -= await StoreAPI.getStoreProductVariationStock(mappedStore, { variantId: req.variationId })
77
+ req.locationId = location[0].location_id
78
+ }
79
+ result = await StoreAPI.updateStoreProductVariationStock(mappedStore, req)
80
+ } else {
81
+ const req = {
82
+ qty: requestBody[i].variant.stock,
83
+ itemId: requestBody[i].native_product_id,
84
+ distributors: requestBody[i].distributors || [], // for Magento
85
+ variationSku: requestBody[i].variant.sku,
86
+ context: { state: { domain: null } }
87
+ }
88
+ result = await StoreAPI.updateStoreProductStock(mappedStore, req)
88
89
  }
89
- })
90
- if (response.ok) {
91
- store = await response.json()
92
- }
93
90
 
94
- let mappedStore: any = {
95
- accessKey: store.shop.credential.consumer_key,
96
- accessSecret: store.shop.credential.consumer_secret,
97
- storeURL: store.shop.credential.store_url,
98
- platform: PLATFORM[`${store.shop.org_prefix}`]
99
- }
91
+ debug(result)
100
92
 
101
- if (requestBody[i].native_variant_id) {
102
- const req = {
103
- qty: requestBody[i].stock,
104
- itemId: requestBody[i].native_product_id,
105
- variationId: requestBody[i].native_variant_id
106
- }
107
- result = await StoreAPI.updateStoreProductVariationStock(mappedStore, req)
108
- } else {
109
- const req = {
110
- qty: requestBody[i].stock,
111
- itemId: requestBody[i].native_product_id
112
- }
113
- result = await StoreAPI.updateStoreProductStock(mappedStore, req)
93
+ context.type = 'application/json'
94
+ context.status = 200
95
+ context.body = 'Succeeded'
96
+ } catch (e) {
97
+ context.type = 'application/json'
98
+ context.status = 500
99
+ context.body = e.message
114
100
  }
115
-
116
- debug(result)
117
101
  }
118
- context.status = 200
119
102
  })
120
103
 
121
104
  sellercraftRouter.post('/sellercraft/store/update-order-status', async (context, next) => {
122
- const sellercraftChannelIntegrationConfig = config.get('sellercraftChannelIntegrationConfig', {})
123
- const { tokenCraftApiKey: apiKey, tokenCraftUrl } = sellercraftChannelIntegrationConfig
124
-
125
- const xApiKey = context.headers['x-api-key']
105
+ try {
106
+ const requestBody = context.request.body
107
+ var result: any = {}
108
+ let mappedStore: any = await getShop(context, requestBody.channel_id, requestBody.shop_id)
109
+
110
+ const reqBody = {
111
+ orderId: requestBody.native_order_id,
112
+ status: requestBody.order_status,
113
+ carrier: requestBody?.shipper_last_mile,
114
+ trackingNo: requestBody?.tracking_number,
115
+ orderItems: unmapOrderItems(
116
+ requestBody?.order_items.map(oi => {
117
+ return oi.native_order_item_id
118
+ }) || []
119
+ ),
120
+ isSOF: requestBody?.seller_logistics,
121
+ locations:
122
+ mappedStore.platform == 'shopify'
123
+ ? requestBody?.order_items.map(oi => {
124
+ let jsonLocation = oi.extra_metadata.locationId
125
+ return JSON.parse(jsonLocation)[0].location_id
126
+ })
127
+ : null,
128
+ context: { state: { domain: null } }
129
+ }
126
130
 
127
- if (apiKey !== xApiKey) context.throw(400, 'api key validation failed')
131
+ let responseBody: any = { operation_id: uuidv4() }
132
+ try {
133
+ try {
134
+ result = (await StoreAPI.updateOrderStatus(mappedStore, reqBody)) || {}
135
+ debug(result)
136
+ } catch (e) {
137
+ if (e?.requiredDocument) result.requiredDocument = e.requiredDocument
138
+ }
128
139
 
129
- const requestBody = context.request.body
130
- var result
131
- var store: any = {}
132
-
133
- // https://staging-tokencraft.sellercraft.co/v1/get-shop?channel_id=4bfb3362-d57c-47f8-8781-007316d179bf&shop_id=dd9cf3b7-114f-4d74-a7e2-7b524ae086f2
134
- var fullPath = tokenCraftUrl + '?channel_id=4bfb3362-d57c-47f8-8781-007316d179bf&shop_id=' + requestBody.shop_id
135
- const response: any = await fetch(fullPath, {
136
- method: 'get',
137
- headers: {
138
- 'Content-Type': 'application/json',
139
- 'x-api-key': apiKey
140
- }
141
- })
142
- if (response.ok) {
143
- store = await response.json()
144
- }
140
+ if (result?.requiredDocument) {
141
+ // call document api and ingest channel order package
142
+ const order: any = await StoreAPI.getStoreOrder(mappedStore, { orderId: reqBody.orderId })
143
+ let orderPackage: any = order ? (order[0]?.orderPackage ? order[0].orderPackage : {}) : {}
144
+ if (orderPackage) {
145
+ const packageId: string = orderPackage.packageId
146
+
147
+ let orderDocument: any = orderPackage.orderDocument
148
+ if (orderDocument?.length == 0) {
149
+ let hasDocument: boolean = false
150
+ while (!hasDocument) {
151
+ orderDocument = await StoreAPI.getStoreOrderDocument(mappedStore, { packageId, documentType: 1 })
152
+ if (orderDocument?.length > 0) {
153
+ hasDocument = true
154
+ break
155
+ }
156
+ }
157
+ }
158
+
159
+ // Order Package Payload
160
+ let newOrderPackage: any =
161
+ {
162
+ channel_shop_id: mappedStore.channelShopId,
163
+ native_order_id: reqBody.orderId,
164
+ native_package_id: orderPackage.packageId.toString(),
165
+ shipping_tracking_code: orderPackage.trackingNumber,
166
+ shipping_type_value: orderPackage?.shippingType ? orderPackage.shippingType : SHIPPING_TYPE.DROP_SHIPPING,
167
+ warehouse_code: SHIPPING_TYPE.DROP_SHIPPING,
168
+ shipper: {
169
+ name: orderPackage.shippingProvider,
170
+ is_cod_supported: orderPackage?.isCodSupport ? orderPackage.isCodSupport : false
171
+ },
172
+ documents:
173
+ orderDocument?.map(doc => {
174
+ return {
175
+ file: doc.file,
176
+ file_type_value: doc.fileTypeValue,
177
+ mime_type: doc.mimeType
178
+ }
179
+ }) || [],
180
+ shipper_last_mile: {
181
+ name: orderPackage.shippingProvider,
182
+ is_cod_supported: orderPackage?.isCodSupport ? orderPackage.isCodSupport : false
183
+ },
184
+ order_item_ids: orderPackage?.orderListIdList
185
+ ? orderPackage.orderListIdList
186
+ : reqBody.orderItems.map(oi => {
187
+ return oi.order_item_id
188
+ })
189
+ } || {}
190
+
191
+ responseBody.package = newOrderPackage
192
+ }
193
+ responseBody.response_code = 'E0'
194
+ responseBody.message = 'Success'
195
+ }
145
196
 
146
- let mappedStore: any = {
147
- accessKey: store.shop.credential.consumer_key,
148
- accessSecret: store.shop.credential.consumer_secret,
149
- storeURL: store.shop.credential.store_url,
150
- platform: PLATFORM[`${store.shop.org_prefix}`]
151
- }
197
+ responseBody.time = Math.floor(new Date(new Date().toUTCString()).getTime() / 1000)
152
198
 
153
- const reqBody = { orderId: requestBody.native_order_id, status: requestBody.order_status }
199
+ context.type = 'application/json'
200
+ context.status = 200
201
+ context.body = responseBody
154
202
 
155
- result = await StoreAPI.updateOrderStatus(mappedStore, reqBody)
156
- debug(result)
203
+ await next()
204
+ } catch (e) {
205
+ responseBody.response_code = 'E1'
206
+ responseBody.message = e.message
157
207
 
158
- context.status = 200
208
+ context.type = 'application/json'
209
+ context.status = 500
210
+ context.body = responseBody
211
+ }
212
+ } catch (e) {}
159
213
  })
160
214
 
161
215
  sellercraftRouter.post('/sellercraft/store/update-product-attribute', async (context, next) => {
162
- const sellercraftChannelIntegrationConfig = config.get('sellercraftChannelIntegrationConfig', {})
163
- const { tokenCraftApiKey: apiKey, tokenCraftUrl } = sellercraftChannelIntegrationConfig
164
-
165
- const xApiKey = context.headers['x-api-key']
166
-
167
- if (apiKey !== xApiKey) context.throw(400, 'api key validation failed')
168
-
169
216
  const requestBody = context.request.body
170
- var store: any = {}
171
-
172
- // https://staging-tokencraft.sellercraft.co/v1/get-shop?channel_id=4bfb3362-d57c-47f8-8781-007316d179bf&shop_id=dd9cf3b7-114f-4d74-a7e2-7b524ae086f2
173
- var fullPath = tokenCraftUrl + '?channel_id=4bfb3362-d57c-47f8-8781-007316d179bf&shop_id=' + requestBody.shop_id
174
- const response: any = await fetch(fullPath, {
175
- method: 'get',
176
- headers: {
177
- 'Content-Type': 'application/json',
178
- 'x-api-key': apiKey
179
- }
180
- })
181
- if (response.ok) {
182
- store = await response.json()
183
- }
217
+ let mappedStore: any = await getShop(context, requestBody.channel_id, requestBody.shop_id)
184
218
 
185
- let mappedStore: any = {
186
- accessKey: store.shop.credential.consumer_key,
187
- accessSecret: store.shop.credential.consumer_secret,
188
- storeURL: store.shop.credential.store_url,
189
- platform: PLATFORM[`${store.shop.org_prefix}`]
190
- }
191
-
192
- let {
193
- product_sku: productSku,
194
- native_product_id: itemId,
195
- variants
196
- } = requestBody
219
+ let { product_sku: productSku, native_product_id: itemId, variants } = requestBody
197
220
 
198
221
  variants.map(variant => {
199
- let {
200
- variant_sku: variantSku,
201
- native_variant_id: variantId,
202
- attributes
203
- } = variant
222
+ let { variant_sku: variantSku, native_variant_id: variantId, attributes } = variant
204
223
 
205
224
  attributes.map(attribute => {
206
- let {
207
- native_attribute_id: id,
208
- attribute_key: name,
209
- attribute_value: value
210
- } = attribute
225
+ let { native_attribute_id: id, attribute_key: name, attribute_value: value } = attribute
211
226
 
212
227
  return {
213
228
  id,
@@ -224,9 +239,48 @@ sellercraftRouter.post('/sellercraft/store/update-product-attribute', async (con
224
239
  })
225
240
 
226
241
  for (var i = 0; i < variants.length; i++) {
227
- let variant = variants[i]
228
- await StoreAPI.updateProductAttribute(mappedStore, { productSku, itemId, variant })
242
+ try {
243
+ let variant = variants[i]
244
+ await StoreAPI.updateProductAttribute(mappedStore, {
245
+ productSku,
246
+ itemId,
247
+ variant,
248
+ context: { state: { domain: null } }
249
+ })
250
+ context.type = 'application/json'
251
+ context.status = 200
252
+ context.body = 'Succeeded'
253
+ } catch (e) {
254
+ context.type = 'application/json'
255
+ context.status = 500
256
+ context.body = e.message
257
+ }
229
258
  }
230
-
231
- context.status = 200
232
259
  })
260
+
261
+ function unmapOrderItems(orderItems) {
262
+ let itemsList = []
263
+ let res = orderItems.map(e => {
264
+ return e.split('-')[0]
265
+ })
266
+
267
+ for (let item of res) {
268
+ let count = 0
269
+
270
+ res.forEach(element => {
271
+ if (element === item) {
272
+ count += 1
273
+ }
274
+ })
275
+
276
+ itemsList.push({
277
+ order_item_id: item,
278
+ qty: count
279
+ })
280
+ }
281
+
282
+ itemsList = itemsList.filter(
283
+ (value, index, self) => index === self.findIndex(t => t.order_item_id === value.order_item_id)
284
+ )
285
+ return itemsList
286
+ }