@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,167 +1,221 @@
1
- import { Ctx, Mutation, Resolver } from 'type-graphql'
1
+ import { Arg, Ctx, Mutation, Resolver } from 'type-graphql'
2
2
  import { getRepository } from 'typeorm'
3
3
 
4
- import { MarketplaceChannel } from './marketplace-channel'
5
-
6
4
  import { config } from '@things-factory/env'
7
5
  import { StoreAPI } from '@things-factory/integration-marketplace'
6
+
8
7
  import { SellercraftChannelIntegrationAPI } from '../../controllers/sellercraft-channel-integration-api'
8
+ import { MarketplaceChannel } from './marketplace-channel'
9
+ import { getShops } from '../../utils/tokencraft-util'
9
10
 
10
11
  @Resolver()
11
12
  export class MarketplaceChannelProductMutation {
12
13
  @Mutation(returns => Boolean)
13
14
  async syncAllMarketplaceChannelProducts(
14
- @Ctx() context: any
15
+ @Ctx() context: any,
16
+ @Arg('fromUpdatedDate', { nullable: true }) fromUpdatedDate?: string,
17
+ @Arg('toUpdatedDate', { nullable: true }) toUpdatedDate?: string
15
18
  ): Promise<boolean> {
16
19
  const sellercraftChannelIntegrationConfig = config.get('sellercraftChannelIntegrationConfig', {})
17
- const { tokenCraftApiKey: apiKey, getShopsTokenCraftUrl } = sellercraftChannelIntegrationConfig
18
20
 
19
- const channels: MarketplaceChannel[] = await getRepository(MarketplaceChannel).find()
21
+ const channels: MarketplaceChannel[] = await getRepository(MarketplaceChannel).find({ where: { isActive: true } })
20
22
 
21
23
  for (var i = 0; i < channels.length; i++) {
22
- var channelsFullPath = getShopsTokenCraftUrl + '?channel_id=' + channels[i].channelId
23
- const channelResponse: any = await fetch(channelsFullPath, {
24
- method: 'get',
25
- headers: {
26
- 'Content-Type': 'application/json',
27
- 'x-api-key': apiKey
28
- }
29
- })
30
-
31
- if (!channelResponse.ok) {
32
- throw new Error(channelResponse)
33
- }
34
- var shopsResponse = await channelResponse.json()
35
- var shops = shopsResponse.shops
36
-
37
- for (var j = 0; j < shops.length; j++) {
38
- var store = {
39
- accessKey: shops[j].credential.consumer_key,
40
- accessSecret: shops[j].credential.consumer_secret,
41
- storeURL: shops[j].credential.store_url,
42
- platform: channels[i].name
43
- }
24
+ try {
25
+ let shops: any = await getShops(channels[i].channelId)
26
+
27
+ for (var j = 0; j < shops.length; j++) {
28
+ try {
29
+ var store = {
30
+ accessKey: shops[j]?.credential?.consumer_key || '',
31
+ accessSecret: shops[j]?.credential?.consumer_secret || '',
32
+ storeURL: shops[j]?.credential?.store_url || '',
33
+ platform: channels[i].name,
34
+ accessToken: shops[j]?.credential?.access_token, // Magento+, Tiktok
35
+ channelShopId: shops[j]?.channel_shop_id,
36
+ storeId: shops[j]?.credential?.store_url || ''
37
+ }
38
+
39
+ let countryCode = shops[j].country_code
40
+ let channelCode = shops[j].org_prefix
41
+ let organisationId = shops[j].account_id
42
+ let channelShopId = shops[j].channel_shop_id
43
+
44
+ var sellercraftStore = { ...store, platform: 'sellercraftChannelIntegration' }
45
+
46
+ const productResult = []
47
+ let totalPages: number = 1
48
+ let limit: number = 50
49
+ let parentLinks = []
50
+
51
+ for (let page = 0; page < totalPages; page++) {
52
+ const { results, total, parentLinkList } = await StoreAPI.getStoreProducts(store, {
53
+ pagination: { page, limit }
54
+ })
55
+ totalPages = Math.ceil(total / limit)
56
+ productResult.push(...results)
57
+ if (store.platform == 'magento') parentLinks.push(...parentLinkList)
58
+ }
44
59
 
45
- let countryCode = shops[j].country_code
46
- let channelCode = shops[j].org_prefix
47
- let organisationId = shops[j].credential.account_id
48
- let channelShopId = shops[j].credential.channel_shop_id
49
-
50
- var sellercraftStore = { ...store, platform: 'sellercraftChannelIntegration' }
51
-
52
- const productResult = await StoreAPI.getStoreProducts(store, {})
53
-
54
- const categoryResult = await StoreAPI.getStoreProductCategories(store, {})
55
-
56
- let mappedProducts = productResult.results.map((item) => {
57
- let {
58
- categoryId,
59
- itemId: productId,
60
- name,
61
- brand,
62
- isVerified,
63
- images,
64
- attributes,
65
- variations
66
- } = item
67
-
68
- variations = variations.map(variation => {
69
- let {
70
- variationSku,
71
- variationId,
72
- name,
73
- isEnabled: isEnabled,
74
- isEnabled: isSellable,
75
- attributes,
76
- stockLocked,
77
- qty: stockReported,
78
- costPrice: fullPrice,
79
- sellPrice: priceDiscounted,
80
- length,
81
- width,
82
- height,
83
- weight
84
- } = variation
85
-
86
- return {
87
- variationSku,
88
- variationId,
89
- name,
90
- isEnabled,
91
- isSellable,
92
- attributes,
93
- stockLocked,
94
- stockReported,
95
- fullPrice,
96
- priceDiscounted,
97
- inventoryProducts: [{
98
- qty: stockReported,
99
- name: `${name} - ${variationSku}`,
100
- sku: variationSku,
101
- productVersions: [{
102
- label: 'Default',
103
- packageLengthMM: length,
104
- packageWidthMM: width,
105
- packageHeightMM: height,
106
- packageWeightGram: weight,
107
- qty: 1
108
- }]
109
- }]
60
+ const categoryResult = []
61
+ let totalPagesCategory: number = 1
62
+ let limitCategory: number = 100
63
+
64
+ if (store.platform != 'shopify') {
65
+ for (let page = 0; page < totalPagesCategory; page++) {
66
+ const { results, total } = await StoreAPI.getStoreProductCategories(store, {
67
+ pagination: { page, limitCategory }
68
+ })
69
+ totalPagesCategory = Math.ceil(total / limitCategory)
70
+ categoryResult.push(...results)
71
+ }
72
+ } else {
73
+ categoryResult.push({ id: 1, name: 'default', isActive: true })
110
74
  }
111
- })
112
75
 
113
- images = images.map(image => {
114
- return {
115
- url: image
76
+ let mappedProducts = productResult.map(item => {
77
+ let { categoryId, itemId: productId, name, brand, isVerified, images, sellercraftAttributes, variations } = item
78
+
79
+ variations = variations.map(variation => {
80
+ let {
81
+ variationSku,
82
+ variationId,
83
+ name,
84
+ isEnabled: isEnabled,
85
+ isSellable: isSellable,
86
+ sellercraftAttributes,
87
+ stockLocked,
88
+ qty: stockReported,
89
+ costPrice: fullPrice,
90
+ sellPrice: priceDiscounted,
91
+ length,
92
+ width,
93
+ height,
94
+ weight,
95
+ extraMetadata
96
+ } = variation
97
+
98
+ return {
99
+ variationSku,
100
+ variationId,
101
+ name,
102
+ isEnabled,
103
+ isSellable,
104
+ attributes: sellercraftAttributes || [],
105
+ stockLocked,
106
+ stockReported,
107
+ fullPrice: parseFloat(fullPrice) || 0,
108
+ priceDiscounted: parseFloat(priceDiscounted) || 0,
109
+ inventoryProducts: [
110
+ {
111
+ qty: 1,
112
+ name: `${name} - ${variationSku}`,
113
+ sku: variationSku,
114
+ productVersions: [
115
+ {
116
+ label: 'Default',
117
+ packageLengthMM: length,
118
+ packageWidthMM: width,
119
+ packageHeightMM: height,
120
+ packageWeightGram: weight,
121
+ qty: stockReported
122
+ }
123
+ ]
124
+ }
125
+ ],
126
+ extraMetadata
127
+ }
128
+ })
129
+
130
+ images = images?.map(image => {
131
+ return {
132
+ url: image
133
+ }
134
+ })
135
+
136
+ return {
137
+ organisationId,
138
+ channelShopId: channelShopId,
139
+ channelCode: channels[i].channelCode,
140
+ channelCountry: shops[j].country_code,
141
+ categoryId: store.platform == 'shopify' ? 1 : categoryId,
142
+ productId: parentLinks.find(e => e.children.includes(productId))?.id || productId,
143
+ name,
144
+ brand,
145
+ isVerified,
146
+ images,
147
+ attributes: sellercraftAttributes || [],
148
+ variations
149
+ }
150
+ })
151
+
152
+ let mappedCategories = categoryResult.map(category => {
153
+ let { id: categoryId, name: categoryName, parent, isActive } = category
154
+
155
+ return {
156
+ categoryId,
157
+ categoryName,
158
+ parent,
159
+ isActive: isActive || true,
160
+ channelCode,
161
+ countryCode,
162
+ childrenCategories: []
163
+ }
164
+ })
165
+
166
+ if (store.platform == 'magento') {
167
+ let newList = []
168
+ for (let np of mappedProducts) {
169
+ if (np.productId == np.variations[0].variationId) {
170
+ let vars = mappedProducts
171
+ .filter(e => e.productId == np.productId)
172
+ .map(e => {
173
+ return e.variations[0]
174
+ })
175
+ np.variations = vars
176
+ if (np.variations.length > 1) {
177
+ np.variations = np.variations.filter(v => v.variationId != np.productId)
178
+ }
179
+ newList.push(np)
180
+ }
181
+ }
182
+ mappedProducts = newList
116
183
  }
117
- })
118
-
119
- return {
120
- organisationId,
121
- channelShopId: channelShopId,
122
- channelCode: channels[i].channelCode,
123
- channelCountry: shops[j].country_code,
124
- categoryId,
125
- productId,
126
- name,
127
- brand,
128
- isVerified,
129
- images,
130
- attributes,
131
- variations
132
- }
133
- })
134
-
135
- let mappedCategories = categoryResult.results.map((category) => {
136
- let {
137
- id: categoryId,
138
- name: categoryName,
139
- parent,
140
- isActive
141
- } = category
142
-
143
- return {
144
- categoryId,
145
- categoryName,
146
- parent,
147
- isLeaf: parent == 0 ? false : true,
148
- isActive: isActive || true,
149
- channelCode,
150
- countryCode
151
- }
152
- })
153
-
154
- mappedCategories.map((category) => {
155
- category.childrenCategories = mappedCategories.filter(e => e.parent == category.categoryId )
156
- })
157
-
158
- const ingestCategory = await SellercraftChannelIntegrationAPI.ingestChannelCategories(sellercraftStore, { categories: mappedCategories})
159
-
160
- const ingestProduct = await SellercraftChannelIntegrationAPI.ingestChannelProduct(sellercraftStore, { products: mappedProducts })
161
-
162
- }
163
-
164
- return true
184
+
185
+ try {
186
+ let filterList = []
187
+ mappedCategories = mappedCategories.map(category => {
188
+ if (mappedCategories.filter(e => e.parent == category.categoryId).length > 0) {
189
+ category.childrenCategories = mappedCategories.filter(e => e.parent == category.categoryId)
190
+ filterList.push(...mappedCategories.filter(e => e.parent == category.categoryId))
191
+ }
192
+ return category
193
+ })
194
+
195
+ mappedCategories = mappedCategories
196
+ .map(mc => {
197
+ if (filterList.indexOf(mc) == -1) {
198
+ return mc
199
+ }
200
+ })
201
+ .filter(e => e)
202
+
203
+ await SellercraftChannelIntegrationAPI.ingestChannelCategories(sellercraftStore, {
204
+ categories: mappedCategories
205
+ })
206
+ } catch (e) {}
207
+
208
+ try {
209
+ for (let k = 0, l = mappedProducts.length; k < l; k++) {
210
+ await SellercraftChannelIntegrationAPI.ingestChannelProduct(sellercraftStore, {
211
+ products: [mappedProducts[k]]
212
+ })
213
+ }
214
+ } catch (e) {}
215
+ } catch (e) {}
216
+ }
217
+ } catch (e) {}
165
218
  }
219
+ return true
166
220
  }
167
221
  }
@@ -40,6 +40,10 @@ export class MarketplaceChannel {
40
40
  @Field()
41
41
  channelId: string
42
42
 
43
+ @Column({ default: true })
44
+ @Field()
45
+ isActive: boolean
46
+
43
47
  @CreateDateColumn()
44
48
  @Field({ nullable: true })
45
49
  createdAt?: Date
@@ -1,6 +1,6 @@
1
1
  import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
2
2
  import { In } from 'typeorm'
3
- import uuid from 'uuid/v4'
3
+ import { v4 as uuidv4 } from 'uuid'
4
4
 
5
5
  import { Sellercraft, SellercraftPlatform, SellercraftStatus } from './sellercraft'
6
6
  import { NewSellercraft, SellercraftPatch } from './sellercraft-type'
@@ -14,7 +14,7 @@ export class SellercraftMutation {
14
14
 
15
15
  return await tx.getRepository(Sellercraft).save({
16
16
  ...sellercraft,
17
- name: uuid(),
17
+ name: uuidv4(),
18
18
  domain,
19
19
  creator: user,
20
20
  updater: user
@@ -60,7 +60,7 @@ export class SellercraftMutation {
60
60
  const result = await sellercraftRepo.save({
61
61
  ...newRecord,
62
62
  domain,
63
- name: uuid(),
63
+ name: uuidv4(),
64
64
  status: SellercraftStatus.ACTIVE,
65
65
  platform: SellercraftPlatform.SELLERCRAFT,
66
66
  creator: user,
@@ -18,7 +18,7 @@ export class SellercraftQuery {
18
18
  async sellercrafts(@Args() params: ListParam, @Ctx() context: any): Promise<SellercraftList> {
19
19
  const { domain } = context.state
20
20
 
21
- const convertedParams = convertListParams(params, domain.id)
21
+ const convertedParams = convertListParams(params, { domain })
22
22
  const [items, total] = await getRepository(Sellercraft).findAndCount(convertedParams)
23
23
 
24
24
  return { items, total }
@@ -0,0 +1,60 @@
1
+ import { config } from '@things-factory/env'
2
+ import { PLATFORM } from '../constants'
3
+ import { createPayloadLog } from '@things-factory/integration-base'
4
+
5
+ export async function getShop(context: any, channelId: string, shopId: string) {
6
+ const sellercraftChannelIntegrationConfig = config.get('sellercraftChannelIntegrationConfig', {})
7
+ const { tokenCraftApiKey: apiKey, tokenCraftUrl } = sellercraftChannelIntegrationConfig
8
+ const xApiKey = context.headers['x-api-key']
9
+
10
+ if (apiKey !== xApiKey) context.throw(400, 'api key validation failed')
11
+
12
+ var fullPath = `${tokenCraftUrl}?channel_id=${channelId}&shop_id=${shopId}`
13
+ const response: any = await fetch(fullPath, {
14
+ method: 'get',
15
+ headers: {
16
+ 'Content-Type': 'application/json',
17
+ 'x-api-key': apiKey
18
+ }
19
+ })
20
+ if (response.ok) {
21
+ let store = await response.json()
22
+ let mappedStore: any = {
23
+ accessKey: store.shop?.credential?.consumer_key || '',
24
+ accessSecret: store.shop?.credential?.consumer_secret || '',
25
+ storeURL: store.shop?.credential?.store_url,
26
+ platform: PLATFORM[`${store.shop.org_prefix}`],
27
+ accessToken: store.shop?.credential?.access_token,
28
+ channelShopId: store.shop?.channel_shop_id,
29
+ storeId: store.shop?.credential?.store_url
30
+ }
31
+ return mappedStore
32
+ } else {
33
+ createPayloadLog(shopId, tokenCraftUrl, `channel_id=${channelId}&shop_id=${shopId}`, response?.statusText || 500, {
34
+ state: { domain: null }
35
+ })
36
+ }
37
+ }
38
+
39
+ export async function getShops(channelId: string) {
40
+ const sellercraftChannelIntegrationConfig = config.get('sellercraftChannelIntegrationConfig', {})
41
+ const { tokenCraftApiKey: apiKey, getShopsTokenCraftUrl } = sellercraftChannelIntegrationConfig
42
+
43
+ var channelsFullPath = getShopsTokenCraftUrl + '?channel_id=' + channelId
44
+ const channelResponse: any = await fetch(channelsFullPath, {
45
+ method: 'get',
46
+ headers: {
47
+ 'Content-Type': 'application/json',
48
+ 'x-api-key': apiKey
49
+ }
50
+ })
51
+
52
+ if (!channelResponse.ok) {
53
+ createPayloadLog(channelId, getShopsTokenCraftUrl, `channel_id=${channelId}`, channelResponse?.statusText || 500, {
54
+ state: { domain: null }
55
+ })
56
+ throw new Error(channelResponse)
57
+ }
58
+ var shopsResponse = await channelResponse.json()
59
+ return shopsResponse.shops
60
+ }