@things-factory/integration-sellercraft 5.0.0-alpha.3 → 5.0.0-alpha.32
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/dist-server/constants/index.js +1 -0
- package/dist-server/constants/index.js.map +1 -1
- package/dist-server/constants/order-status-mapping.js +10 -0
- package/dist-server/constants/order-status-mapping.js.map +1 -0
- package/dist-server/controllers/index.js +2 -0
- package/dist-server/controllers/index.js.map +1 -1
- package/dist-server/controllers/sellercraft-channel-integration/apis/ingest-channel-categories.js +18 -20
- package/dist-server/controllers/sellercraft-channel-integration/apis/ingest-channel-categories.js.map +1 -1
- package/dist-server/controllers/sellercraft-channel-integration/apis/ingest-channel-order.js +17 -14
- package/dist-server/controllers/sellercraft-channel-integration/apis/ingest-channel-order.js.map +1 -1
- package/dist-server/controllers/sellercraft-channel-integration/apis/ingest-channel-product.js +23 -43
- package/dist-server/controllers/sellercraft-channel-integration/apis/ingest-channel-product.js.map +1 -1
- package/dist-server/controllers/sellercraft-channel-integration/sellercraft-channel-integration.js +1 -1
- package/dist-server/routers/sellercraft-router.js +29 -13
- package/dist-server/routers/sellercraft-router.js.map +1 -1
- package/dist-server/service/index.js +5 -1
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/marketplace-channel/index.js +9 -0
- package/dist-server/service/marketplace-channel/index.js.map +1 -0
- package/dist-server/service/marketplace-channel/marketplace-channel-order-mutation.js +150 -0
- package/dist-server/service/marketplace-channel/marketplace-channel-order-mutation.js.map +1 -0
- package/dist-server/service/marketplace-channel/marketplace-channel-product-mutation.js +149 -0
- package/dist-server/service/marketplace-channel/marketplace-channel-product-mutation.js.map +1 -0
- package/dist-server/service/marketplace-channel/marketplace-channel.js +83 -0
- package/dist-server/service/marketplace-channel/marketplace-channel.js.map +1 -0
- package/dist-server/service/sellercraft/sellercraft.js +1 -1
- package/package.json +15 -15
- package/server/constants/index.ts +2 -1
- package/server/constants/order-status-mapping.ts +6 -0
- package/server/controllers/index.ts +2 -0
- package/server/controllers/sellercraft-channel-integration/apis/ingest-channel-categories.ts +18 -20
- package/server/controllers/sellercraft-channel-integration/apis/ingest-channel-order.ts +18 -14
- package/server/controllers/sellercraft-channel-integration/apis/ingest-channel-product.ts +27 -47
- package/server/controllers/sellercraft-channel-integration/sellercraft-channel-integration.ts +1 -1
- package/server/routers/sellercraft-router.ts +32 -14
- package/server/service/index.ts +6 -1
- package/server/service/marketplace-channel/index.ts +6 -0
- package/server/service/marketplace-channel/marketplace-channel-order-mutation.ts +182 -0
- package/server/service/marketplace-channel/marketplace-channel-product-mutation.ts +161 -0
- package/server/service/marketplace-channel/marketplace-channel.ts +64 -0
- package/server/service/sellercraft/sellercraft.ts +1 -1
@@ -11,35 +11,25 @@ export function ingestChannelProduct() {
|
|
11
11
|
let productVariations: any[] = product.variations.map(variant => {
|
12
12
|
return {
|
13
13
|
seller_sku: variant.variationSku,
|
14
|
-
native_variant_id: variant.variationId,
|
14
|
+
native_variant_id: variant.variationId.toString(),
|
15
15
|
label: variant.name,
|
16
|
-
is_enabled: variant.isEnabled,
|
17
|
-
is_sellable: variant.isSellable,
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
: [],
|
16
|
+
is_enabled: variant.isEnabled || true,
|
17
|
+
is_sellable: variant.isSellable || true,
|
18
|
+
is_deleted: false, // default
|
19
|
+
variant_attributes: variant?.attributes.map(attribute => {
|
20
|
+
return {
|
21
|
+
...attribute,
|
22
|
+
native_attribute_id: attribute.native_attribute_id.toString()
|
23
|
+
}
|
24
|
+
}) || [],
|
26
25
|
stock_locked: variant?.stockLocked ? variant.stockLocked : 0,
|
27
26
|
native_stock_reported: variant?.stockReported ? variant.stockReported : 0,
|
28
|
-
price_full: variant.fullPrice,
|
29
|
-
price_discounted: variant.priceDiscounted,
|
30
|
-
price_discounts: variant?.product_discounts
|
31
|
-
? variant.product_discounts.map(discount => {
|
32
|
-
return {
|
33
|
-
price_discounted: discount.priceDiscounted,
|
34
|
-
native_discount_id: discount.id,
|
35
|
-
name: discount.name
|
36
|
-
}
|
37
|
-
})
|
38
|
-
: [],
|
27
|
+
price_full: variant.fullPrice || 0,
|
28
|
+
price_discounted: variant.priceDiscounted || variant.fullPrice || 0,
|
39
29
|
inventory_products: variant?.inventoryProducts
|
40
30
|
? variant.inventoryProducts.map(inventoryProduct => {
|
41
31
|
return {
|
42
|
-
quantity: inventoryProduct.qty,
|
32
|
+
quantity: inventoryProduct.qty || 1,
|
43
33
|
name: inventoryProduct.name,
|
44
34
|
inventory_sku: inventoryProduct.sku,
|
45
35
|
product_versions: inventoryProduct?.productVersions
|
@@ -53,7 +43,7 @@ export function ingestChannelProduct() {
|
|
53
43
|
package_weight_gram: productVersion?.packageWeightGram
|
54
44
|
? productVersion.packageWeightGram
|
55
45
|
: 0,
|
56
|
-
stock_available: productVersion.qty
|
46
|
+
stock_available: productVersion.qty || 0
|
57
47
|
}
|
58
48
|
})
|
59
49
|
: []
|
@@ -68,43 +58,33 @@ export function ingestChannelProduct() {
|
|
68
58
|
channel_shop_id: product.channelShopId,
|
69
59
|
channel_code: product.channelCode,
|
70
60
|
channel_country: product.channelCountry,
|
71
|
-
native_category_id: product.categoryId,
|
72
|
-
native_product_id: product.productId,
|
61
|
+
native_category_id: product.categoryId.toString(),
|
62
|
+
native_product_id: product.productId.toString(),
|
73
63
|
label: product.name,
|
74
|
-
brand: product.brand,
|
75
|
-
is_verified: product.isVerified,
|
76
|
-
|
64
|
+
brand: product.brand || '',
|
65
|
+
is_verified: product.isVerified || true,
|
66
|
+
flexible_attributes: product.channelCode == 'WCM' ? true : false, // add channels that do not support category_attributes ingestion
|
67
|
+
images: product?.images.map(image => {
|
77
68
|
return {
|
78
69
|
file_url: image.url
|
79
70
|
}
|
80
71
|
}),
|
81
|
-
product_attributes: product
|
72
|
+
product_attributes: product?.attributes.map(attribute => {
|
82
73
|
return {
|
83
|
-
|
84
|
-
|
74
|
+
...attribute,
|
75
|
+
native_attribute_id: attribute.native_attribute_id.toString()
|
85
76
|
}
|
86
|
-
})
|
77
|
+
}),
|
78
|
+
variants: productVariations
|
87
79
|
}
|
88
80
|
})
|
89
81
|
|
90
82
|
return {
|
91
|
-
payload:
|
83
|
+
payload: [...newProducts]
|
92
84
|
}
|
93
85
|
},
|
94
86
|
normalize(res) {
|
95
|
-
|
96
|
-
handover_type: handOverType,
|
97
|
-
pickup_time: pickupTime,
|
98
|
-
pickup_address: pickupAddress,
|
99
|
-
dropoff_address: dropoffAddress
|
100
|
-
} = res.data
|
101
|
-
|
102
|
-
return {
|
103
|
-
handOverType,
|
104
|
-
pickupTime,
|
105
|
-
pickupAddress,
|
106
|
-
dropoffAddress
|
107
|
-
}
|
87
|
+
return res
|
108
88
|
}
|
109
89
|
}
|
110
90
|
}
|
@@ -10,7 +10,7 @@ export const sellercraftRouter = new Router()
|
|
10
10
|
|
11
11
|
sellercraftRouter.post('/sellercraft/store/update-product-price', async (context, next) => {
|
12
12
|
const sellercraftChannelIntegrationConfig = config.get('sellercraftChannelIntegrationConfig', {})
|
13
|
-
const { apiKey, tokenCraftUrl } = sellercraftChannelIntegrationConfig
|
13
|
+
const { tokenCraftApiKey: apiKey, tokenCraftUrl } = sellercraftChannelIntegrationConfig
|
14
14
|
|
15
15
|
const xApiKey = context.headers['x-api-key']
|
16
16
|
|
@@ -23,7 +23,7 @@ sellercraftRouter.post('/sellercraft/store/update-product-price', async (context
|
|
23
23
|
var result
|
24
24
|
|
25
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
|
26
|
+
var fullPath = `${tokenCraftUrl}?channel_id=${requestBody[i].channel_id}&shop_id=${requestBody[i].shop_id}`
|
27
27
|
const response: any = await fetch(fullPath, {
|
28
28
|
method: 'get',
|
29
29
|
headers: {
|
@@ -67,7 +67,7 @@ sellercraftRouter.post('/sellercraft/store/update-product-price', async (context
|
|
67
67
|
|
68
68
|
sellercraftRouter.post('/sellercraft/store/update-product-stock', async (context, next) => {
|
69
69
|
const sellercraftChannelIntegrationConfig = config.get('sellercraftChannelIntegrationConfig', {})
|
70
|
-
const { apiKey, tokenCraftUrl } = sellercraftChannelIntegrationConfig
|
70
|
+
const { tokenCraftApiKey: apiKey, tokenCraftUrl } = sellercraftChannelIntegrationConfig
|
71
71
|
|
72
72
|
const xApiKey = context.headers['x-api-key']
|
73
73
|
|
@@ -79,7 +79,7 @@ sellercraftRouter.post('/sellercraft/store/update-product-stock', async (context
|
|
79
79
|
var result
|
80
80
|
|
81
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
|
82
|
+
var fullPath = `${tokenCraftUrl}?channel_id=${requestBody[i].channel_id}&shop_id=${requestBody[i].shop_id}`
|
83
83
|
const response: any = await fetch(fullPath, {
|
84
84
|
method: 'get',
|
85
85
|
headers: {
|
@@ -120,7 +120,7 @@ sellercraftRouter.post('/sellercraft/store/update-product-stock', async (context
|
|
120
120
|
|
121
121
|
sellercraftRouter.post('/sellercraft/store/update-order-status', async (context, next) => {
|
122
122
|
const sellercraftChannelIntegrationConfig = config.get('sellercraftChannelIntegrationConfig', {})
|
123
|
-
const { apiKey, tokenCraftUrl } = sellercraftChannelIntegrationConfig
|
123
|
+
const { tokenCraftApiKey: apiKey, tokenCraftUrl } = sellercraftChannelIntegrationConfig
|
124
124
|
|
125
125
|
const xApiKey = context.headers['x-api-key']
|
126
126
|
|
@@ -131,7 +131,7 @@ sellercraftRouter.post('/sellercraft/store/update-order-status', async (context,
|
|
131
131
|
var store: any = {}
|
132
132
|
|
133
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
|
134
|
+
var fullPath = `${tokenCraftUrl}?channel_id=${requestBody.channel_id}&shop_id=${requestBody.shop_id}`
|
135
135
|
const response: any = await fetch(fullPath, {
|
136
136
|
method: 'get',
|
137
137
|
headers: {
|
@@ -160,7 +160,7 @@ sellercraftRouter.post('/sellercraft/store/update-order-status', async (context,
|
|
160
160
|
|
161
161
|
sellercraftRouter.post('/sellercraft/store/update-product-attribute', async (context, next) => {
|
162
162
|
const sellercraftChannelIntegrationConfig = config.get('sellercraftChannelIntegrationConfig', {})
|
163
|
-
const { apiKey, tokenCraftUrl } = sellercraftChannelIntegrationConfig
|
163
|
+
const { tokenCraftApiKey: apiKey, tokenCraftUrl } = sellercraftChannelIntegrationConfig
|
164
164
|
|
165
165
|
const xApiKey = context.headers['x-api-key']
|
166
166
|
|
@@ -168,10 +168,9 @@ sellercraftRouter.post('/sellercraft/store/update-product-attribute', async (con
|
|
168
168
|
|
169
169
|
const requestBody = context.request.body
|
170
170
|
var store: any = {}
|
171
|
-
const attributes: any[] = requestBody.attributes
|
172
171
|
|
173
172
|
// https://staging-tokencraft.sellercraft.co/v1/get-shop?channel_id=4bfb3362-d57c-47f8-8781-007316d179bf&shop_id=dd9cf3b7-114f-4d74-a7e2-7b524ae086f2
|
174
|
-
var fullPath = tokenCraftUrl
|
173
|
+
var fullPath = `${tokenCraftUrl}?channel_id=${requestBody.channel_id}&shop_id=${requestBody.shop_id}`
|
175
174
|
const response: any = await fetch(fullPath, {
|
176
175
|
method: 'get',
|
177
176
|
headers: {
|
@@ -189,14 +188,33 @@ sellercraftRouter.post('/sellercraft/store/update-product-attribute', async (con
|
|
189
188
|
storeURL: store.shop.credential.store_url,
|
190
189
|
platform: PLATFORM[`${store.shop.org_prefix}`]
|
191
190
|
}
|
191
|
+
|
192
|
+
let { product_sku: productSku, native_product_id: itemId, variants } = requestBody
|
192
193
|
|
193
|
-
|
194
|
-
attributes
|
195
|
-
const attributeReqBody = { attributeId: attribute.native_attribute_id, name: attribute.attribute_key }
|
194
|
+
variants.map(variant => {
|
195
|
+
let { variant_sku: variantSku, native_variant_id: variantId, attributes } = variant
|
196
196
|
|
197
|
-
|
197
|
+
attributes.map(attribute => {
|
198
|
+
let { native_attribute_id: id, attribute_key: name, attribute_value: value } = attribute
|
199
|
+
|
200
|
+
return {
|
201
|
+
id,
|
202
|
+
name,
|
203
|
+
value
|
204
|
+
}
|
198
205
|
})
|
199
|
-
|
206
|
+
|
207
|
+
return {
|
208
|
+
variantSku,
|
209
|
+
variantId,
|
210
|
+
attributes
|
211
|
+
}
|
212
|
+
})
|
213
|
+
|
214
|
+
for (var i = 0; i < variants.length; i++) {
|
215
|
+
let variant = variants[i]
|
216
|
+
await StoreAPI.updateProductAttribute(mappedStore, { productSku, itemId, variant })
|
217
|
+
}
|
200
218
|
|
201
219
|
context.status = 200
|
202
220
|
})
|
package/server/service/index.ts
CHANGED
@@ -3,10 +3,12 @@ export * from './sellercraft/sellercraft'
|
|
3
3
|
|
4
4
|
/* IMPORT ENTITIES AND RESOLVERS */
|
5
5
|
import { entities as SellercraftEntities, resolvers as SellercraftResolvers } from './sellercraft'
|
6
|
+
import { entities as MarketplaceChannelEntities, resolvers as MarketplaceSellercraftResolvers } from './marketplace-channel'
|
6
7
|
|
7
8
|
export const entities = [
|
8
9
|
/* ENTITIES */
|
9
10
|
...SellercraftEntities,
|
11
|
+
...MarketplaceChannelEntities
|
10
12
|
]
|
11
13
|
|
12
14
|
|
@@ -14,5 +16,8 @@ export const schema = {
|
|
14
16
|
resolverClasses: [
|
15
17
|
/* RESOLVER CLASSES */
|
16
18
|
...SellercraftResolvers,
|
17
|
-
|
19
|
+
...MarketplaceSellercraftResolvers
|
20
|
+
]
|
18
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]
|
@@ -0,0 +1,182 @@
|
|
1
|
+
import { Arg, Ctx, Mutation, Resolver } from 'type-graphql'
|
2
|
+
import { getRepository } from 'typeorm'
|
3
|
+
|
4
|
+
import { MarketplaceChannel } from './marketplace-channel'
|
5
|
+
|
6
|
+
import { config } from '@things-factory/env'
|
7
|
+
import { StoreAPI } from '@things-factory/integration-marketplace'
|
8
|
+
import { SellercraftChannelIntegrationAPI } from '../../controllers/sellercraft-channel-integration-api'
|
9
|
+
|
10
|
+
@Resolver()
|
11
|
+
export class MarketplaceChannelOrderMutation {
|
12
|
+
@Mutation(returns => Boolean)
|
13
|
+
async syncAllMarketplaceChannelOrders(
|
14
|
+
@Arg('fromDate') fromDate: string,
|
15
|
+
@Arg('toDate') toDate: string,
|
16
|
+
@Ctx() context: any
|
17
|
+
): Promise<boolean> {
|
18
|
+
const sellercraftChannelIntegrationConfig = config.get('sellercraftChannelIntegrationConfig', {})
|
19
|
+
const { tokenCraftApiKey: apiKey, getShopsTokenCraftUrl } = sellercraftChannelIntegrationConfig
|
20
|
+
|
21
|
+
const channels: MarketplaceChannel[] = await getRepository(MarketplaceChannel).find()
|
22
|
+
|
23
|
+
for (var i = 0; i < channels.length; i++) {
|
24
|
+
var channelsFullPath = getShopsTokenCraftUrl + '?channel_id=' + channels[i].channelId
|
25
|
+
const channelResponse: any = await fetch(channelsFullPath, {
|
26
|
+
method: 'get',
|
27
|
+
headers: {
|
28
|
+
'Content-Type': 'application/json',
|
29
|
+
'x-api-key': apiKey
|
30
|
+
}
|
31
|
+
})
|
32
|
+
|
33
|
+
if (!channelResponse.ok) {
|
34
|
+
throw new Error(channelResponse)
|
35
|
+
}
|
36
|
+
var shopsResponse = await channelResponse.json()
|
37
|
+
var shops = shopsResponse.shops
|
38
|
+
|
39
|
+
for (var j = 0; j < shops.length; j++) {
|
40
|
+
var store = {
|
41
|
+
accessKey: shops[j].credential.consumer_key,
|
42
|
+
accessSecret: shops[j].credential.consumer_secret,
|
43
|
+
storeURL: shops[j].credential.store_url,
|
44
|
+
platform: channels[i].name,
|
45
|
+
accessToken: shops[j].credential.access_token // Magento+
|
46
|
+
}
|
47
|
+
|
48
|
+
// let countryCode = shops[j].country_code
|
49
|
+
// let channelCode = shops[j].org_prefix
|
50
|
+
let organisationId = shops[j].account_id
|
51
|
+
let channelShopId = shops[j].channel_shop_id
|
52
|
+
|
53
|
+
const orderReq = {
|
54
|
+
fromDate: fromDate,
|
55
|
+
toDate: toDate
|
56
|
+
}
|
57
|
+
const orderResult = await StoreAPI.getStoreOrders(store, orderReq)
|
58
|
+
|
59
|
+
var sellercraftStore = { ...store, platform: 'sellercraftChannelIntegration' }
|
60
|
+
|
61
|
+
let mappedOrderResult = orderResult.results.map(order => {
|
62
|
+
let {
|
63
|
+
firstName: custFirstName,
|
64
|
+
lastName: custLastName,
|
65
|
+
orderCreatedAt: createdAt,
|
66
|
+
orderUpdatedAt: updatedAt,
|
67
|
+
orderNo: id,
|
68
|
+
status
|
69
|
+
} = order
|
70
|
+
|
71
|
+
let {
|
72
|
+
first_name: billFirstName,
|
73
|
+
last_name: billLastName,
|
74
|
+
address_1: billAddress1,
|
75
|
+
address_2: billAddress2,
|
76
|
+
address_3: billAddress3,
|
77
|
+
address_4: billAddress4,
|
78
|
+
address_5: billAddress5,
|
79
|
+
city: billCity,
|
80
|
+
postcode: billPostalCode,
|
81
|
+
country: billCountry,
|
82
|
+
phone: billPhone1,
|
83
|
+
phone_2: billPhone2
|
84
|
+
} = order?.billing
|
85
|
+
|
86
|
+
let {
|
87
|
+
first_name: shipFirstName,
|
88
|
+
last_name: shipLastName,
|
89
|
+
address_1: shipAddress1,
|
90
|
+
address_2: shipAddress2,
|
91
|
+
address_3: shipAddress3,
|
92
|
+
address_4: shipAddress4,
|
93
|
+
address_5: shipAddress5,
|
94
|
+
city: shipCity,
|
95
|
+
postcode: shipPostalCode,
|
96
|
+
country: shipCountry,
|
97
|
+
phone: shipPhone1,
|
98
|
+
phone_2: shipPhone2
|
99
|
+
} = order.shipping
|
100
|
+
|
101
|
+
let orderItems = order.orderItems.map(item => {
|
102
|
+
let { name: id, variationId: variationId, slaExpiresAt, total, totalTax, subtotal, subtotalTax, qty } = item
|
103
|
+
|
104
|
+
return {
|
105
|
+
id,
|
106
|
+
variationId,
|
107
|
+
currency: order.orderShipping.collectionCurrency,
|
108
|
+
createdAt: order.orderCreatedAt,
|
109
|
+
updatedAt: order.orderUpdatedAt,
|
110
|
+
charges: [
|
111
|
+
{
|
112
|
+
name: 'PRICE_NORMAL_SELLING',
|
113
|
+
grossAmount: total,
|
114
|
+
nettAmount: subtotal
|
115
|
+
},
|
116
|
+
{
|
117
|
+
name: 'TAXES',
|
118
|
+
grossAmount: totalTax,
|
119
|
+
nettAmount: subtotalTax
|
120
|
+
}
|
121
|
+
],
|
122
|
+
slaExpiresAt,
|
123
|
+
qty
|
124
|
+
}
|
125
|
+
})
|
126
|
+
|
127
|
+
let mappedOrderItems = []
|
128
|
+
orderItems.map(oi => {
|
129
|
+
for (let i = 0; i < oi.qty; i++) {
|
130
|
+
mappedOrderItems.push({
|
131
|
+
...oi,
|
132
|
+
id: `${oi.id}-${i+1}`
|
133
|
+
})
|
134
|
+
}
|
135
|
+
})
|
136
|
+
|
137
|
+
return {
|
138
|
+
custFirstName,
|
139
|
+
custLastName,
|
140
|
+
createdAt,
|
141
|
+
updatedAt,
|
142
|
+
id,
|
143
|
+
billFirstName,
|
144
|
+
billLastName,
|
145
|
+
billAddress1: billAddress1.toString() || shipAddress1.toString(),
|
146
|
+
billAddress2: billAddress2 || shipAddress2,
|
147
|
+
billAddress3: billAddress3 || shipAddress3,
|
148
|
+
billAddress4: billAddress4 || shipAddress4,
|
149
|
+
billAddress5: billAddress5 || shipAddress5,
|
150
|
+
billCity: billCity || shipCity,
|
151
|
+
billPostalCode: billPostalCode || shipPostalCode,
|
152
|
+
billCountry: billCountry || shipCountry,
|
153
|
+
billPhone1: billPhone1 || shipPhone1,
|
154
|
+
billPhone2: billPhone2 || shipPhone2,
|
155
|
+
shipFirstName,
|
156
|
+
shipLastName,
|
157
|
+
shipAddress1: shipAddress1.toString(),
|
158
|
+
shipAddress2,
|
159
|
+
shipAddress3,
|
160
|
+
shipAddress4,
|
161
|
+
shipAddress5,
|
162
|
+
shipCity,
|
163
|
+
shipPostalCode,
|
164
|
+
shipCountry,
|
165
|
+
shipPhone1,
|
166
|
+
shipPhone2,
|
167
|
+
mappedOrderItems,
|
168
|
+
channelShopId,
|
169
|
+
organisationId,
|
170
|
+
status
|
171
|
+
}
|
172
|
+
})
|
173
|
+
|
174
|
+
if (mappedOrderResult.length > 0) {
|
175
|
+
await SellercraftChannelIntegrationAPI.ingestChannelOrder(sellercraftStore, { orders: mappedOrderResult })
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
return true
|
180
|
+
}
|
181
|
+
}
|
182
|
+
}
|
@@ -0,0 +1,161 @@
|
|
1
|
+
import { Ctx, Mutation, Resolver } from 'type-graphql'
|
2
|
+
import { getRepository } from 'typeorm'
|
3
|
+
|
4
|
+
import { MarketplaceChannel } from './marketplace-channel'
|
5
|
+
|
6
|
+
import { config } from '@things-factory/env'
|
7
|
+
import { StoreAPI } from '@things-factory/integration-marketplace'
|
8
|
+
import { SellercraftChannelIntegrationAPI } from '../../controllers/sellercraft-channel-integration-api'
|
9
|
+
|
10
|
+
@Resolver()
|
11
|
+
export class MarketplaceChannelProductMutation {
|
12
|
+
@Mutation(returns => Boolean)
|
13
|
+
async syncAllMarketplaceChannelProducts(@Ctx() context: any): Promise<boolean> {
|
14
|
+
const sellercraftChannelIntegrationConfig = config.get('sellercraftChannelIntegrationConfig', {})
|
15
|
+
const { tokenCraftApiKey: apiKey, getShopsTokenCraftUrl } = sellercraftChannelIntegrationConfig
|
16
|
+
|
17
|
+
const channels: MarketplaceChannel[] = await getRepository(MarketplaceChannel).find()
|
18
|
+
|
19
|
+
for (var i = 0; i < channels.length; i++) {
|
20
|
+
var channelsFullPath = getShopsTokenCraftUrl + '?channel_id=' + channels[i].channelId
|
21
|
+
const channelResponse: any = await fetch(channelsFullPath, {
|
22
|
+
method: 'get',
|
23
|
+
headers: {
|
24
|
+
'Content-Type': 'application/json',
|
25
|
+
'x-api-key': apiKey
|
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+
|
42
|
+
}
|
43
|
+
|
44
|
+
let countryCode = shops[j].country_code
|
45
|
+
let channelCode = shops[j].org_prefix
|
46
|
+
let organisationId = shops[j].account_id
|
47
|
+
let channelShopId = shops[j].channel_shop_id
|
48
|
+
|
49
|
+
var sellercraftStore = { ...store, platform: 'sellercraftChannelIntegration' }
|
50
|
+
|
51
|
+
const productResult = await StoreAPI.getStoreProducts(store, {})
|
52
|
+
|
53
|
+
const categoryResult = await StoreAPI.getStoreProductCategories(store, {})
|
54
|
+
|
55
|
+
let mappedProducts = productResult.results.map(item => {
|
56
|
+
let { categoryId, itemId: productId, name, brand, isVerified, images, attributes, variations } = item
|
57
|
+
|
58
|
+
variations = variations.map(variation => {
|
59
|
+
let {
|
60
|
+
variationSku,
|
61
|
+
variationId,
|
62
|
+
name,
|
63
|
+
isEnabled: isEnabled,
|
64
|
+
isEnabled: isSellable,
|
65
|
+
attributes,
|
66
|
+
stockLocked,
|
67
|
+
qty: stockReported,
|
68
|
+
costPrice: fullPrice,
|
69
|
+
sellPrice: priceDiscounted,
|
70
|
+
length,
|
71
|
+
width,
|
72
|
+
height,
|
73
|
+
weight
|
74
|
+
} = variation
|
75
|
+
|
76
|
+
return {
|
77
|
+
variationSku,
|
78
|
+
variationId,
|
79
|
+
name,
|
80
|
+
isEnabled,
|
81
|
+
isSellable,
|
82
|
+
attributes,
|
83
|
+
stockLocked,
|
84
|
+
stockReported,
|
85
|
+
fullPrice,
|
86
|
+
priceDiscounted,
|
87
|
+
inventoryProducts: [
|
88
|
+
{
|
89
|
+
qty: stockReported,
|
90
|
+
name: `${name} - ${variationSku}`,
|
91
|
+
sku: variationSku,
|
92
|
+
productVersions: [
|
93
|
+
{
|
94
|
+
label: 'Default',
|
95
|
+
packageLengthMM: length,
|
96
|
+
packageWidthMM: width,
|
97
|
+
packageHeightMM: height,
|
98
|
+
packageWeightGram: weight,
|
99
|
+
qty: 1
|
100
|
+
}
|
101
|
+
]
|
102
|
+
}
|
103
|
+
]
|
104
|
+
}
|
105
|
+
})
|
106
|
+
|
107
|
+
images = images?.map(image => {
|
108
|
+
return {
|
109
|
+
url: image
|
110
|
+
}
|
111
|
+
})
|
112
|
+
|
113
|
+
return {
|
114
|
+
organisationId,
|
115
|
+
channelShopId: channelShopId,
|
116
|
+
channelCode: channels[i].channelCode,
|
117
|
+
channelCountry: shops[j].country_code,
|
118
|
+
categoryId,
|
119
|
+
productId,
|
120
|
+
name,
|
121
|
+
brand,
|
122
|
+
isVerified,
|
123
|
+
images,
|
124
|
+
attributes,
|
125
|
+
variations
|
126
|
+
}
|
127
|
+
})
|
128
|
+
|
129
|
+
let mappedCategories = categoryResult.results.map(category => {
|
130
|
+
let { id: categoryId, name: categoryName, parent, isActive } = category
|
131
|
+
|
132
|
+
return {
|
133
|
+
categoryId,
|
134
|
+
categoryName,
|
135
|
+
parent,
|
136
|
+
isLeaf: parent == 0 ? false : true,
|
137
|
+
isActive: isActive || true,
|
138
|
+
channelCode,
|
139
|
+
countryCode,
|
140
|
+
childrenCategories: []
|
141
|
+
}
|
142
|
+
})
|
143
|
+
|
144
|
+
mappedCategories = mappedCategories.map(category => {
|
145
|
+
if (mappedCategories.filter(e => e.parent == category.categoryId).length > 0) {
|
146
|
+
category.childrenCategories = mappedCategories.filter(e => e.parent == category.categoryId)
|
147
|
+
}
|
148
|
+
return category
|
149
|
+
})
|
150
|
+
|
151
|
+
await SellercraftChannelIntegrationAPI.ingestChannelCategories(sellercraftStore, {
|
152
|
+
categories: mappedCategories
|
153
|
+
})
|
154
|
+
|
155
|
+
await SellercraftChannelIntegrationAPI.ingestChannelProduct(sellercraftStore, { products: mappedProducts })
|
156
|
+
}
|
157
|
+
|
158
|
+
return true
|
159
|
+
}
|
160
|
+
}
|
161
|
+
}
|
@@ -0,0 +1,64 @@
|
|
1
|
+
import { Field, ID, ObjectType } from 'type-graphql'
|
2
|
+
import {
|
3
|
+
Column,
|
4
|
+
CreateDateColumn,
|
5
|
+
Entity,
|
6
|
+
Index,
|
7
|
+
ManyToOne,
|
8
|
+
PrimaryGeneratedColumn,
|
9
|
+
RelationId,
|
10
|
+
UpdateDateColumn
|
11
|
+
} from 'typeorm'
|
12
|
+
|
13
|
+
import { User } from '@things-factory/auth-base'
|
14
|
+
import { Domain } from '@things-factory/shell'
|
15
|
+
|
16
|
+
@Entity()
|
17
|
+
@Index('ix_marketplace_channel_0 ', (marketplaceChannel: MarketplaceChannel) => [marketplaceChannel.domain, marketplaceChannel.name], { unique: true })
|
18
|
+
@ObjectType({ description: 'Entity for Marketplace Channel' })
|
19
|
+
export class MarketplaceChannel {
|
20
|
+
@PrimaryGeneratedColumn('uuid')
|
21
|
+
@Field(type => ID)
|
22
|
+
readonly id: string
|
23
|
+
|
24
|
+
@ManyToOne(type => Domain)
|
25
|
+
@Field({ nullable: true })
|
26
|
+
domain?: Domain
|
27
|
+
|
28
|
+
@RelationId((marketplaceChannel: MarketplaceChannel) => marketplaceChannel.domain)
|
29
|
+
domainId?: string
|
30
|
+
|
31
|
+
@Column()
|
32
|
+
@Field()
|
33
|
+
name: string
|
34
|
+
|
35
|
+
@Column()
|
36
|
+
@Field()
|
37
|
+
channelCode: string
|
38
|
+
|
39
|
+
@Column()
|
40
|
+
@Field()
|
41
|
+
channelId: string
|
42
|
+
|
43
|
+
@CreateDateColumn()
|
44
|
+
@Field({ nullable: true })
|
45
|
+
createdAt?: Date
|
46
|
+
|
47
|
+
@UpdateDateColumn()
|
48
|
+
@Field({ nullable: true })
|
49
|
+
updatedAt?: Date
|
50
|
+
|
51
|
+
@ManyToOne(type => User, { nullable: true })
|
52
|
+
@Field({ nullable: true })
|
53
|
+
creator?: User
|
54
|
+
|
55
|
+
@RelationId((marketplaceChannel: MarketplaceChannel) => marketplaceChannel.creator)
|
56
|
+
creatorId?: string
|
57
|
+
|
58
|
+
@ManyToOne(type => User, { nullable: true })
|
59
|
+
@Field({ nullable: true })
|
60
|
+
updater?: User
|
61
|
+
|
62
|
+
@RelationId((marketplaceChannel: MarketplaceChannel) => marketplaceChannel.updater)
|
63
|
+
updaterId?: string
|
64
|
+
}
|