@things-factory/integration-sellercraft 4.3.24 → 4.3.25
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/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@things-factory/integration-sellercraft",
|
3
|
-
"version": "4.3.
|
3
|
+
"version": "4.3.25",
|
4
4
|
"main": "dist-server/index.js",
|
5
5
|
"browser": "client/index.js",
|
6
6
|
"things-factory": true,
|
@@ -31,7 +31,7 @@
|
|
31
31
|
"@things-factory/context-ui": "^4.3.23",
|
32
32
|
"@things-factory/grist-ui": "^4.3.23",
|
33
33
|
"@things-factory/i18n-base": "^4.3.23",
|
34
|
-
"@things-factory/integration-marketplace": "^4.3.
|
34
|
+
"@things-factory/integration-marketplace": "^4.3.25",
|
35
35
|
"@things-factory/integration-ui": "^4.3.24",
|
36
36
|
"@things-factory/more-ui": "^4.3.23",
|
37
37
|
"@things-factory/resource-ui": "^4.3.24",
|
@@ -51,5 +51,5 @@
|
|
51
51
|
"nock": "^13.0.2",
|
52
52
|
"should": "^13.2.3"
|
53
53
|
},
|
54
|
-
"gitHead": "
|
54
|
+
"gitHead": "bdcecd8454d7a76df3c5676a39440d57bc21d5cb"
|
55
55
|
}
|
@@ -132,7 +132,7 @@ sellercraftRouter.post('/sellercraft/store/update-product-stock', async (context
|
|
132
132
|
}
|
133
133
|
if (req.locationId) {
|
134
134
|
let location = JSON.parse(req.locationId)
|
135
|
-
req.qty -=
|
135
|
+
req.qty -= await StoreAPI.getStoreProductVariationStock(mappedStore, { variantId: req.variationId })
|
136
136
|
req.locationId = location[0].location_id
|
137
137
|
}
|
138
138
|
result = await StoreAPI.updateStoreProductVariationStock(mappedStore, req)
|
@@ -142,15 +142,8 @@ sellercraftRouter.post('/sellercraft/store/update-product-stock', async (context
|
|
142
142
|
itemId: requestBody[i].native_product_id,
|
143
143
|
distributors: requestBody[i].distributors || [], // for Magento
|
144
144
|
variationSku: requestBody[i].variant.sku,
|
145
|
-
locationId: requestBody[i]?.variant?.extra_metadata?.locationId, // for Shopify
|
146
|
-
inventoryItemId: requestBody[i]?.variant?.extra_metadata?.inventoryItemId, // for Shopify
|
147
145
|
context: { state: { domain: null } }
|
148
146
|
}
|
149
|
-
if (req.locationId) {
|
150
|
-
let location = JSON.parse(req.locationId)
|
151
|
-
req.qty -= location[0].available
|
152
|
-
req.locationId = location[0].location_id
|
153
|
-
}
|
154
147
|
result = await StoreAPI.updateStoreProductStock(mappedStore, req)
|
155
148
|
}
|
156
149
|
|
@@ -1,4 +1,4 @@
|
|
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
4
|
import { config } from '@things-factory/env'
|
@@ -10,215 +10,224 @@ import { MarketplaceChannel } from './marketplace-channel'
|
|
10
10
|
@Resolver()
|
11
11
|
export class MarketplaceChannelProductMutation {
|
12
12
|
@Mutation(returns => Boolean)
|
13
|
-
async syncAllMarketplaceChannelProducts(
|
13
|
+
async syncAllMarketplaceChannelProducts(
|
14
|
+
@Ctx() context: any,
|
15
|
+
@Arg('fromUpdatedDate', { nullable: true }) fromUpdatedDate?: string,
|
16
|
+
@Arg('toUpdatedDate', { nullable: true }) toUpdatedDate?: string
|
17
|
+
): Promise<boolean> {
|
14
18
|
const sellercraftChannelIntegrationConfig = config.get('sellercraftChannelIntegrationConfig', {})
|
15
19
|
const { tokenCraftApiKey: apiKey, getShopsTokenCraftUrl } = sellercraftChannelIntegrationConfig
|
16
20
|
|
17
21
|
const channels: MarketplaceChannel[] = await getRepository(MarketplaceChannel).find({ where: { isActive: true } })
|
18
22
|
|
19
23
|
for (var i = 0; i < channels.length; i++) {
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
})
|
28
|
-
|
29
|
-
if (!channelResponse.ok) {
|
30
|
-
throw new Error(channelResponse)
|
31
|
-
}
|
32
|
-
var shopsResponse = await channelResponse.json()
|
33
|
-
var shops = shopsResponse.shops
|
34
|
-
|
35
|
-
for (var j = 0; j < shops.length; j++) {
|
36
|
-
var store = {
|
37
|
-
accessKey: shops[j]?.credential?.consumer_key || '',
|
38
|
-
accessSecret: shops[j]?.credential?.consumer_secret || '',
|
39
|
-
storeURL: shops[j]?.credential?.store_url || '',
|
40
|
-
platform: channels[i].name,
|
41
|
-
accessToken: shops[j]?.credential?.access_token, // Magento+, Tiktok
|
42
|
-
channelShopId: shops[j]?.channel_shop_id,
|
43
|
-
storeId: shops[j]?.credential?.store_url || ''
|
44
|
-
}
|
45
|
-
|
46
|
-
let countryCode = shops[j].country_code
|
47
|
-
let channelCode = shops[j].org_prefix
|
48
|
-
let organisationId = shops[j].account_id
|
49
|
-
let channelShopId = shops[j].channel_shop_id
|
50
|
-
|
51
|
-
var sellercraftStore = { ...store, platform: 'sellercraftChannelIntegration' }
|
52
|
-
|
53
|
-
const productResult = []
|
54
|
-
let totalPages: number = 1
|
55
|
-
let limit: number = 50
|
56
|
-
let parentLinks = []
|
57
|
-
|
58
|
-
for (let page = 0; page < totalPages; page++) {
|
59
|
-
const { results, total, parentLinkList } = await StoreAPI.getStoreProducts(store, {
|
60
|
-
pagination: { page, limit }
|
61
|
-
})
|
62
|
-
totalPages = Math.ceil(total / limit)
|
63
|
-
productResult.push(...results)
|
64
|
-
if (store.platform == 'magento') parentLinks.push(...parentLinkList)
|
65
|
-
}
|
66
|
-
|
67
|
-
const categoryResult = []
|
68
|
-
let totalPagesCategory: number = 1
|
69
|
-
let limitCategory: number = 100
|
70
|
-
|
71
|
-
if (store.platform != 'shopify') {
|
72
|
-
for (let page = 0; page < totalPagesCategory; page++) {
|
73
|
-
const { results, total } = await StoreAPI.getStoreProductCategories(store, {
|
74
|
-
pagination: { page, limitCategory }
|
75
|
-
})
|
76
|
-
totalPagesCategory = Math.ceil(total / limitCategory)
|
77
|
-
categoryResult.push(...results)
|
24
|
+
try {
|
25
|
+
var channelsFullPath = getShopsTokenCraftUrl + '?channel_id=' + channels[i].channelId
|
26
|
+
const channelResponse: any = await fetch(channelsFullPath, {
|
27
|
+
method: 'get',
|
28
|
+
headers: {
|
29
|
+
'Content-Type': 'application/json',
|
30
|
+
'x-api-key': apiKey
|
78
31
|
}
|
79
|
-
}
|
80
|
-
categoryResult.push({ id: 1, name: 'default', isActive: true })
|
81
|
-
}
|
32
|
+
})
|
82
33
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
width,
|
100
|
-
height,
|
101
|
-
weight,
|
102
|
-
extraMetadata
|
103
|
-
} = variation
|
104
|
-
|
105
|
-
return {
|
106
|
-
variationSku,
|
107
|
-
variationId,
|
108
|
-
name,
|
109
|
-
isEnabled,
|
110
|
-
isSellable,
|
111
|
-
attributes: store.platform != 'shopify' ? attributes : null,
|
112
|
-
stockLocked,
|
113
|
-
stockReported,
|
114
|
-
fullPrice: parseFloat(fullPrice) || 0,
|
115
|
-
priceDiscounted: parseFloat(priceDiscounted) || 0,
|
116
|
-
inventoryProducts: [
|
117
|
-
{
|
118
|
-
qty: 1,
|
119
|
-
name: `${name} - ${variationSku}`,
|
120
|
-
sku: variationSku,
|
121
|
-
productVersions: [
|
122
|
-
{
|
123
|
-
label: 'Default',
|
124
|
-
packageLengthMM: length,
|
125
|
-
packageWidthMM: width,
|
126
|
-
packageHeightMM: height,
|
127
|
-
packageWeightGram: weight,
|
128
|
-
qty: stockReported
|
129
|
-
}
|
130
|
-
]
|
131
|
-
}
|
132
|
-
],
|
133
|
-
extraMetadata
|
34
|
+
if (!channelResponse.ok) {
|
35
|
+
throw new Error(channelResponse)
|
36
|
+
}
|
37
|
+
var shopsResponse = await channelResponse.json()
|
38
|
+
var shops = shopsResponse.shops
|
39
|
+
|
40
|
+
for (var j = 0; j < shops.length; j++) {
|
41
|
+
try {
|
42
|
+
var store = {
|
43
|
+
accessKey: shops[j]?.credential?.consumer_key || '',
|
44
|
+
accessSecret: shops[j]?.credential?.consumer_secret || '',
|
45
|
+
storeURL: shops[j]?.credential?.store_url || '',
|
46
|
+
platform: channels[i].name,
|
47
|
+
accessToken: shops[j]?.credential?.access_token, // Magento+, Tiktok
|
48
|
+
channelShopId: shops[j]?.channel_shop_id,
|
49
|
+
storeId: shops[j]?.credential?.store_url || ''
|
134
50
|
}
|
135
|
-
})
|
136
51
|
|
137
|
-
|
138
|
-
|
139
|
-
|
52
|
+
let countryCode = shops[j].country_code
|
53
|
+
let channelCode = shops[j].org_prefix
|
54
|
+
let organisationId = shops[j].account_id
|
55
|
+
let channelShopId = shops[j].channel_shop_id
|
56
|
+
|
57
|
+
var sellercraftStore = { ...store, platform: 'sellercraftChannelIntegration' }
|
58
|
+
|
59
|
+
const productResult = []
|
60
|
+
let totalPages: number = 1
|
61
|
+
let limit: number = 50
|
62
|
+
let parentLinks = []
|
63
|
+
|
64
|
+
for (let page = 0; page < totalPages; page++) {
|
65
|
+
const { results, total, parentLinkList } = await StoreAPI.getStoreProducts(store, {
|
66
|
+
pagination: { page, limit }
|
67
|
+
})
|
68
|
+
totalPages = Math.ceil(total / limit)
|
69
|
+
productResult.push(...results)
|
70
|
+
if (store.platform == 'magento') parentLinks.push(...parentLinkList)
|
140
71
|
}
|
141
|
-
})
|
142
|
-
|
143
|
-
return {
|
144
|
-
organisationId,
|
145
|
-
channelShopId: channelShopId,
|
146
|
-
channelCode: channels[i].channelCode,
|
147
|
-
channelCountry: shops[j].country_code,
|
148
|
-
categoryId: store.platform == 'shopify' ? 1 : categoryId,
|
149
|
-
productId: parentLinks.find(e => e.children.includes(productId))?.id || productId,
|
150
|
-
name,
|
151
|
-
brand,
|
152
|
-
isVerified,
|
153
|
-
images,
|
154
|
-
attributes,
|
155
|
-
variations
|
156
|
-
}
|
157
|
-
})
|
158
72
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
return {
|
163
|
-
categoryId,
|
164
|
-
categoryName,
|
165
|
-
parent,
|
166
|
-
isActive: isActive || true,
|
167
|
-
channelCode,
|
168
|
-
countryCode,
|
169
|
-
childrenCategories: []
|
170
|
-
}
|
171
|
-
})
|
73
|
+
const categoryResult = []
|
74
|
+
let totalPagesCategory: number = 1
|
75
|
+
let limitCategory: number = 100
|
172
76
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
let vars = mappedProducts
|
178
|
-
.filter(e => e.productId == np.productId)
|
179
|
-
.map(e => {
|
180
|
-
return e.variations[0]
|
77
|
+
if (store.platform != 'shopify') {
|
78
|
+
for (let page = 0; page < totalPagesCategory; page++) {
|
79
|
+
const { results, total } = await StoreAPI.getStoreProductCategories(store, {
|
80
|
+
pagination: { page, limitCategory }
|
181
81
|
})
|
182
|
-
|
183
|
-
|
184
|
-
np.variations = np.variations.filter(v => v.variationId != np.productId)
|
82
|
+
totalPagesCategory = Math.ceil(total / limitCategory)
|
83
|
+
categoryResult.push(...results)
|
185
84
|
}
|
186
|
-
|
85
|
+
} else {
|
86
|
+
categoryResult.push({ id: 1, name: 'default', isActive: true })
|
187
87
|
}
|
188
|
-
}
|
189
|
-
mappedProducts = newList
|
190
|
-
}
|
191
88
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
89
|
+
let mappedProducts = productResult.map(item => {
|
90
|
+
let { categoryId, itemId: productId, name, brand, isVerified, images, attributes, variations } = item
|
91
|
+
|
92
|
+
variations = variations.map(variation => {
|
93
|
+
let {
|
94
|
+
variationSku,
|
95
|
+
variationId,
|
96
|
+
name,
|
97
|
+
isEnabled: isEnabled,
|
98
|
+
isSellable: isSellable,
|
99
|
+
attributes,
|
100
|
+
stockLocked,
|
101
|
+
qty: stockReported,
|
102
|
+
costPrice: fullPrice,
|
103
|
+
sellPrice: priceDiscounted,
|
104
|
+
length,
|
105
|
+
width,
|
106
|
+
height,
|
107
|
+
weight,
|
108
|
+
extraMetadata
|
109
|
+
} = variation
|
110
|
+
|
111
|
+
return {
|
112
|
+
variationSku,
|
113
|
+
variationId,
|
114
|
+
name,
|
115
|
+
isEnabled,
|
116
|
+
isSellable,
|
117
|
+
attributes: store.platform != 'shopify' ? attributes : null,
|
118
|
+
stockLocked,
|
119
|
+
stockReported,
|
120
|
+
fullPrice: parseFloat(fullPrice) || 0,
|
121
|
+
priceDiscounted: parseFloat(priceDiscounted) || 0,
|
122
|
+
inventoryProducts: [
|
123
|
+
{
|
124
|
+
qty: 1,
|
125
|
+
name: `${name} - ${variationSku}`,
|
126
|
+
sku: variationSku,
|
127
|
+
productVersions: [
|
128
|
+
{
|
129
|
+
label: 'Default',
|
130
|
+
packageLengthMM: length,
|
131
|
+
packageWidthMM: width,
|
132
|
+
packageHeightMM: height,
|
133
|
+
packageWeightGram: weight,
|
134
|
+
qty: stockReported
|
135
|
+
}
|
136
|
+
]
|
137
|
+
}
|
138
|
+
],
|
139
|
+
extraMetadata
|
140
|
+
}
|
141
|
+
})
|
142
|
+
|
143
|
+
images = images?.map(image => {
|
144
|
+
return {
|
145
|
+
url: image
|
146
|
+
}
|
147
|
+
})
|
148
|
+
|
149
|
+
return {
|
150
|
+
organisationId,
|
151
|
+
channelShopId: channelShopId,
|
152
|
+
channelCode: channels[i].channelCode,
|
153
|
+
channelCountry: shops[j].country_code,
|
154
|
+
categoryId: store.platform == 'shopify' ? 1 : categoryId,
|
155
|
+
productId: parentLinks.find(e => e.children.includes(productId))?.id || productId,
|
156
|
+
name,
|
157
|
+
brand,
|
158
|
+
isVerified,
|
159
|
+
images,
|
160
|
+
attributes,
|
161
|
+
variations
|
162
|
+
}
|
163
|
+
})
|
164
|
+
|
165
|
+
let mappedCategories = categoryResult.map(category => {
|
166
|
+
let { id: categoryId, name: categoryName, parent, isActive } = category
|
167
|
+
|
168
|
+
return {
|
169
|
+
categoryId,
|
170
|
+
categoryName,
|
171
|
+
parent,
|
172
|
+
isActive: isActive || true,
|
173
|
+
channelCode,
|
174
|
+
countryCode,
|
175
|
+
childrenCategories: []
|
176
|
+
}
|
177
|
+
})
|
201
178
|
|
202
|
-
|
203
|
-
|
204
|
-
|
179
|
+
if (store.platform == 'magento') {
|
180
|
+
let newList = []
|
181
|
+
for (let np of mappedProducts) {
|
182
|
+
if (np.productId == np.variations[0].variationId) {
|
183
|
+
let vars = mappedProducts
|
184
|
+
.filter(e => e.productId == np.productId)
|
185
|
+
.map(e => {
|
186
|
+
return e.variations[0]
|
187
|
+
})
|
188
|
+
np.variations = vars
|
189
|
+
if (np.variations.length > 1) {
|
190
|
+
np.variations = np.variations.filter(v => v.variationId != np.productId)
|
191
|
+
}
|
192
|
+
newList.push(np)
|
193
|
+
}
|
194
|
+
}
|
195
|
+
mappedProducts = newList
|
205
196
|
}
|
206
|
-
}).filter(e => e)
|
207
197
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
198
|
+
try {
|
199
|
+
let filterList = []
|
200
|
+
mappedCategories = mappedCategories.map(category => {
|
201
|
+
if (mappedCategories.filter(e => e.parent == category.categoryId).length > 0) {
|
202
|
+
category.childrenCategories = mappedCategories.filter(e => e.parent == category.categoryId)
|
203
|
+
filterList.push(...mappedCategories.filter(e => e.parent == category.categoryId))
|
204
|
+
}
|
205
|
+
return category
|
206
|
+
})
|
207
|
+
|
208
|
+
mappedCategories = mappedCategories
|
209
|
+
.map(mc => {
|
210
|
+
if (filterList.indexOf(mc) == -1) {
|
211
|
+
return mc
|
212
|
+
}
|
213
|
+
})
|
214
|
+
.filter(e => e)
|
212
215
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
})
|
218
|
-
}
|
219
|
-
} catch (e) {}
|
220
|
-
}
|
216
|
+
await SellercraftChannelIntegrationAPI.ingestChannelCategories(sellercraftStore, {
|
217
|
+
categories: mappedCategories
|
218
|
+
})
|
219
|
+
} catch (e) {}
|
221
220
|
|
221
|
+
try {
|
222
|
+
for (let k = 0, l = mappedProducts.length; k < l; k++) {
|
223
|
+
await SellercraftChannelIntegrationAPI.ingestChannelProduct(sellercraftStore, {
|
224
|
+
products: [mappedProducts[k]]
|
225
|
+
})
|
226
|
+
}
|
227
|
+
} catch (e) {}
|
228
|
+
} catch (e) {}
|
229
|
+
}
|
230
|
+
} catch (e) {}
|
222
231
|
}
|
223
232
|
return true
|
224
233
|
}
|