@reactionary/provider-commercetools 0.3.16 → 0.3.18
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/core/client.js +83 -9
- package/core/token-cache.js +5 -6
- package/package.json +2 -2
- package/providers/cart.provider.js +53 -11
- package/providers/inventory.provider.js +5 -2
- package/providers/price.provider.js +18 -16
- package/schema/configuration.schema.js +5 -1
- package/src/core/client.d.ts +17 -1
- package/src/core/token-cache.d.ts +2 -2
- package/src/providers/cart.provider.d.ts +1 -0
- package/src/providers/price.provider.d.ts +0 -4
- package/src/schema/configuration.schema.d.ts +4 -0
- package/src/schema/session.schema.d.ts +1 -0
package/core/client.js
CHANGED
|
@@ -10,12 +10,14 @@ import {
|
|
|
10
10
|
import * as crypto from "crypto";
|
|
11
11
|
import createDebug from "debug";
|
|
12
12
|
import { RequestContextTokenCache } from "./token-cache.js";
|
|
13
|
+
import { CommercetoolsSessionSchema } from "../schema/session.schema.js";
|
|
13
14
|
const debug = createDebug("reactionary:commercetools");
|
|
15
|
+
const PROVIDER_SESSION_KEY = "COMMERCETOOLS_PROVIDER";
|
|
14
16
|
class CommercetoolsAPI {
|
|
15
17
|
constructor(config, context) {
|
|
16
18
|
this.config = config;
|
|
17
19
|
this.context = context;
|
|
18
|
-
this.
|
|
20
|
+
this.tokenCache = new RequestContextTokenCache(this.context, PROVIDER_SESSION_KEY);
|
|
19
21
|
}
|
|
20
22
|
async getClient() {
|
|
21
23
|
if (!this.client) {
|
|
@@ -29,6 +31,77 @@ class CommercetoolsAPI {
|
|
|
29
31
|
}
|
|
30
32
|
return this.adminClient;
|
|
31
33
|
}
|
|
34
|
+
getSessionData() {
|
|
35
|
+
return this.context.session[PROVIDER_SESSION_KEY] ? this.context.session[PROVIDER_SESSION_KEY] : CommercetoolsSessionSchema.parse({});
|
|
36
|
+
}
|
|
37
|
+
setSessionData(sessionData) {
|
|
38
|
+
const existingData = this.context.session[PROVIDER_SESSION_KEY];
|
|
39
|
+
this.context.session[PROVIDER_SESSION_KEY] = {
|
|
40
|
+
...existingData,
|
|
41
|
+
...sessionData
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Only caches it pr session for now...... but still better than every call
|
|
46
|
+
* @param key
|
|
47
|
+
* @returns
|
|
48
|
+
*/
|
|
49
|
+
async resolveChannelIdByKey(key) {
|
|
50
|
+
const sessionData = this.getSessionData();
|
|
51
|
+
const cacheKey = `___channel_${key}`;
|
|
52
|
+
const cachedValue = sessionData[cacheKey];
|
|
53
|
+
if (cachedValue) {
|
|
54
|
+
if (debug.enabled) {
|
|
55
|
+
debug(`Resolved channel ${key} from cache`);
|
|
56
|
+
}
|
|
57
|
+
return cachedValue + "";
|
|
58
|
+
}
|
|
59
|
+
const client = await this.getAdminClient();
|
|
60
|
+
const response = await client.withProjectKey({ projectKey: this.config.projectKey }).channels().withKey({ key }).get().execute();
|
|
61
|
+
const channel = response.body;
|
|
62
|
+
this.setSessionData({
|
|
63
|
+
cacheKey: channel.id
|
|
64
|
+
});
|
|
65
|
+
if (debug.enabled) {
|
|
66
|
+
debug(`Resolved channel ${key} from API and cached it`);
|
|
67
|
+
}
|
|
68
|
+
return channel.id;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Only caches it pr session for now...... but still better than every call
|
|
72
|
+
* @param key
|
|
73
|
+
* @returns
|
|
74
|
+
*/
|
|
75
|
+
async resolveChannelIdByRole(role) {
|
|
76
|
+
const sessionData = this.getSessionData();
|
|
77
|
+
const cacheKey = `___channel_role_${role}`;
|
|
78
|
+
const cachedValue = sessionData[cacheKey];
|
|
79
|
+
if (cachedValue) {
|
|
80
|
+
if (debug.enabled) {
|
|
81
|
+
debug(`Resolved channel ${role} from cache`);
|
|
82
|
+
}
|
|
83
|
+
return cachedValue + "";
|
|
84
|
+
}
|
|
85
|
+
const client = await this.getAdminClient();
|
|
86
|
+
const response = await client.withProjectKey({ projectKey: this.config.projectKey }).channels().get({
|
|
87
|
+
queryArgs: {
|
|
88
|
+
where: `roles contains any (:role)`,
|
|
89
|
+
"var.role": role
|
|
90
|
+
}
|
|
91
|
+
}).execute();
|
|
92
|
+
const channels = response.body;
|
|
93
|
+
if (channels.results.length === 0) {
|
|
94
|
+
throw new Error(`No channel found with role ${role}`);
|
|
95
|
+
}
|
|
96
|
+
const channel = channels.results[0];
|
|
97
|
+
this.setSessionData({
|
|
98
|
+
[cacheKey]: channel.id
|
|
99
|
+
});
|
|
100
|
+
if (debug.enabled) {
|
|
101
|
+
debug(`Resolved channel ${role} from API and cached it`);
|
|
102
|
+
}
|
|
103
|
+
return channel.id;
|
|
104
|
+
}
|
|
32
105
|
async createAdminClient() {
|
|
33
106
|
let builder = this.createBaseClientBuilder();
|
|
34
107
|
builder = builder.withAnonymousSessionFlow({
|
|
@@ -42,11 +115,11 @@ class CommercetoolsAPI {
|
|
|
42
115
|
return createApiBuilderFromCtpClient(builder.build());
|
|
43
116
|
}
|
|
44
117
|
async createClient() {
|
|
45
|
-
let session = await this.
|
|
118
|
+
let session = await this.tokenCache.get();
|
|
46
119
|
const isNewSession = !session || !session.refreshToken;
|
|
47
120
|
if (isNewSession) {
|
|
48
121
|
await this.becomeGuest();
|
|
49
|
-
session = await this.
|
|
122
|
+
session = await this.tokenCache.get();
|
|
50
123
|
}
|
|
51
124
|
let builder = this.createBaseClientBuilder();
|
|
52
125
|
builder = builder.withRefreshTokenFlow({
|
|
@@ -57,7 +130,7 @@ class CommercetoolsAPI {
|
|
|
57
130
|
host: this.config.authUrl,
|
|
58
131
|
projectKey: this.config.projectKey,
|
|
59
132
|
refreshToken: session?.refreshToken || "",
|
|
60
|
-
tokenCache: this.
|
|
133
|
+
tokenCache: this.tokenCache
|
|
61
134
|
});
|
|
62
135
|
return createApiBuilderFromCtpClient(builder.build());
|
|
63
136
|
}
|
|
@@ -92,7 +165,7 @@ class CommercetoolsAPI {
|
|
|
92
165
|
clientSecret: this.config.clientSecret,
|
|
93
166
|
user: { username, password }
|
|
94
167
|
},
|
|
95
|
-
tokenCache: this.
|
|
168
|
+
tokenCache: this.tokenCache,
|
|
96
169
|
scopes: this.config.scopes
|
|
97
170
|
});
|
|
98
171
|
const loginClient = createApiBuilderFromCtpClient(loginBuilder.build());
|
|
@@ -111,7 +184,7 @@ class CommercetoolsAPI {
|
|
|
111
184
|
});
|
|
112
185
|
}
|
|
113
186
|
async logout() {
|
|
114
|
-
await this.
|
|
187
|
+
await this.tokenCache.set({ token: "", refreshToken: "", expirationTime: 0 });
|
|
115
188
|
const identity = {
|
|
116
189
|
type: "Anonymous"
|
|
117
190
|
};
|
|
@@ -119,7 +192,7 @@ class CommercetoolsAPI {
|
|
|
119
192
|
}
|
|
120
193
|
// FIXME: This can fail if the short-lived access token has expired. In other words, probably missing a token refresh.
|
|
121
194
|
async introspect() {
|
|
122
|
-
const session = await this.
|
|
195
|
+
const session = await this.tokenCache.get();
|
|
123
196
|
if (!session || !session.token) {
|
|
124
197
|
const identity = {
|
|
125
198
|
type: "Anonymous"
|
|
@@ -191,7 +264,7 @@ class CommercetoolsAPI {
|
|
|
191
264
|
}
|
|
192
265
|
);
|
|
193
266
|
const result = await response.json();
|
|
194
|
-
this.
|
|
267
|
+
this.tokenCache.set({
|
|
195
268
|
expirationTime: Date.now() + Number(result.expires_in) * 1e3 - 5 * 60 * 1e3,
|
|
196
269
|
token: result.access_token,
|
|
197
270
|
refreshToken: result.refresh_token
|
|
@@ -235,5 +308,6 @@ class CommercetoolsAPI {
|
|
|
235
308
|
}
|
|
236
309
|
}
|
|
237
310
|
export {
|
|
238
|
-
CommercetoolsAPI
|
|
311
|
+
CommercetoolsAPI,
|
|
312
|
+
PROVIDER_SESSION_KEY
|
|
239
313
|
};
|
package/core/token-cache.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { CommercetoolsSessionSchema } from "../schema/session.schema.js";
|
|
2
|
-
const PROVIDER_COMMERCETOOLS_SESSION_KEY = "PROVIDER_COMMERCETOOLS";
|
|
3
2
|
class RequestContextTokenCache {
|
|
4
|
-
constructor(context) {
|
|
3
|
+
constructor(context, sessionProviderKey) {
|
|
5
4
|
this.context = context;
|
|
5
|
+
this.sessionProviderKey = sessionProviderKey;
|
|
6
6
|
}
|
|
7
7
|
async get(tokenCacheOptions) {
|
|
8
8
|
const session = CommercetoolsSessionSchema.parse(
|
|
9
|
-
this.context.session[
|
|
9
|
+
this.context.session[this.sessionProviderKey] || {}
|
|
10
10
|
);
|
|
11
11
|
if (!session) {
|
|
12
12
|
return {
|
|
@@ -23,15 +23,14 @@ class RequestContextTokenCache {
|
|
|
23
23
|
}
|
|
24
24
|
async set(cache, tokenCacheOptions) {
|
|
25
25
|
const session = CommercetoolsSessionSchema.parse(
|
|
26
|
-
this.context.session[
|
|
26
|
+
this.context.session[this.sessionProviderKey] || {}
|
|
27
27
|
);
|
|
28
|
-
this.context.session[
|
|
28
|
+
this.context.session[this.sessionProviderKey] = session;
|
|
29
29
|
session.refreshToken = cache.refreshToken;
|
|
30
30
|
session.token = cache.token;
|
|
31
31
|
session.expirationTime = cache.expirationTime;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
export {
|
|
35
|
-
PROVIDER_COMMERCETOOLS_SESSION_KEY,
|
|
36
35
|
RequestContextTokenCache
|
|
37
36
|
};
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reactionary/provider-commercetools",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.18",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"types": "src/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@reactionary/core": "0.3.
|
|
7
|
+
"@reactionary/core": "0.3.18",
|
|
8
8
|
"debug": "^4.4.3",
|
|
9
9
|
"zod": "4.1.9",
|
|
10
10
|
"@commercetools/ts-client": "^4.2.1",
|
|
@@ -32,6 +32,7 @@ import { CommercetoolsCartIdentifierSchema } from "../schema/commercetools.schem
|
|
|
32
32
|
class CommercetoolsCartProvider extends CartProvider {
|
|
33
33
|
constructor(config, cache, context, commercetools) {
|
|
34
34
|
super(cache, context);
|
|
35
|
+
this.expandedCartFields = ["discountCodes[*].discountCode"];
|
|
35
36
|
this.config = config;
|
|
36
37
|
this.commercetools = commercetools;
|
|
37
38
|
}
|
|
@@ -39,7 +40,13 @@ class CommercetoolsCartProvider extends CartProvider {
|
|
|
39
40
|
const client = await this.getClient();
|
|
40
41
|
const ctId = payload.cart;
|
|
41
42
|
try {
|
|
42
|
-
const remote = await client.carts.withId({ ID: ctId.key }).get(
|
|
43
|
+
const remote = await client.carts.withId({ ID: ctId.key }).get(
|
|
44
|
+
{
|
|
45
|
+
queryArgs: {
|
|
46
|
+
expand: this.expandedCartFields
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
).execute();
|
|
43
50
|
return success(this.parseSingle(remote.body));
|
|
44
51
|
} catch (err) {
|
|
45
52
|
return error({
|
|
@@ -53,6 +60,7 @@ class CommercetoolsCartProvider extends CartProvider {
|
|
|
53
60
|
if (!cartIdentifier) {
|
|
54
61
|
cartIdentifier = await this.createCart();
|
|
55
62
|
}
|
|
63
|
+
const channelId = await this.commercetools.resolveChannelIdByRole("Primary");
|
|
56
64
|
const result = await this.applyActions(cartIdentifier, [
|
|
57
65
|
{
|
|
58
66
|
action: "addLineItem",
|
|
@@ -61,7 +69,7 @@ class CommercetoolsCartProvider extends CartProvider {
|
|
|
61
69
|
// FIXME: This should be dynamic, probably as part of the context...
|
|
62
70
|
distributionChannel: {
|
|
63
71
|
typeId: "channel",
|
|
64
|
-
|
|
72
|
+
id: channelId
|
|
65
73
|
}
|
|
66
74
|
},
|
|
67
75
|
{
|
|
@@ -142,11 +150,21 @@ class CommercetoolsCartProvider extends CartProvider {
|
|
|
142
150
|
return success(result);
|
|
143
151
|
}
|
|
144
152
|
async removeCouponCode(payload) {
|
|
153
|
+
const client = await this.getClient();
|
|
154
|
+
const currentCart = await client.carts.withId({ ID: payload.cart.key }).get({
|
|
155
|
+
queryArgs: {
|
|
156
|
+
expand: this.expandedCartFields
|
|
157
|
+
}
|
|
158
|
+
}).execute();
|
|
159
|
+
const discountCodeReference = currentCart.body.discountCodes?.find((dc) => dc.discountCode.obj?.code === payload.couponCode)?.discountCode;
|
|
160
|
+
if (!discountCodeReference) {
|
|
161
|
+
return success(this.parseSingle(currentCart.body));
|
|
162
|
+
}
|
|
145
163
|
const result = await this.applyActions(payload.cart, [
|
|
146
164
|
{
|
|
147
165
|
action: "removeDiscountCode",
|
|
148
166
|
discountCode: {
|
|
149
|
-
id:
|
|
167
|
+
id: discountCodeReference.id,
|
|
150
168
|
typeId: "discount-code"
|
|
151
169
|
}
|
|
152
170
|
},
|
|
@@ -197,6 +215,9 @@ class CommercetoolsCartProvider extends CartProvider {
|
|
|
197
215
|
currency: this.context.languageContext.currencyCode || "USD",
|
|
198
216
|
country: this.context.taxJurisdiction.countryCode || "US",
|
|
199
217
|
locale: this.context.languageContext.locale
|
|
218
|
+
},
|
|
219
|
+
queryArgs: {
|
|
220
|
+
expand: this.expandedCartFields
|
|
200
221
|
}
|
|
201
222
|
}).execute();
|
|
202
223
|
return CommercetoolsCartIdentifierSchema.parse({
|
|
@@ -212,6 +233,9 @@ class CommercetoolsCartProvider extends CartProvider {
|
|
|
212
233
|
body: {
|
|
213
234
|
version: ctId.version,
|
|
214
235
|
actions
|
|
236
|
+
},
|
|
237
|
+
queryArgs: {
|
|
238
|
+
expand: this.expandedCartFields
|
|
215
239
|
}
|
|
216
240
|
}).execute();
|
|
217
241
|
if (response.error) {
|
|
@@ -242,7 +266,13 @@ class CommercetoolsCartProvider extends CartProvider {
|
|
|
242
266
|
parseCartItem(remoteItem) {
|
|
243
267
|
const unitPrice = remoteItem.price.value.centAmount;
|
|
244
268
|
const totalPrice = remoteItem.totalPrice.centAmount || 0;
|
|
245
|
-
|
|
269
|
+
let itemDiscount = 0;
|
|
270
|
+
if (remoteItem.discountedPricePerQuantity && remoteItem.discountedPricePerQuantity.length > 0) {
|
|
271
|
+
itemDiscount = remoteItem.discountedPricePerQuantity.reduce((sum, discPrQty) => {
|
|
272
|
+
return sum + discPrQty.quantity * discPrQty.discountedPrice?.includedDiscounts?.reduce((sum2, discount) => sum2 + discount.discountedAmount.centAmount, 0) || 0;
|
|
273
|
+
}, 0);
|
|
274
|
+
}
|
|
275
|
+
const totalDiscount = (remoteItem.price.discounted?.value.centAmount || 0) + itemDiscount;
|
|
246
276
|
const unitDiscount = totalDiscount / remoteItem.quantity;
|
|
247
277
|
const currency = remoteItem.price.value.currencyCode.toUpperCase();
|
|
248
278
|
const item = {
|
|
@@ -282,11 +312,16 @@ class CommercetoolsCartProvider extends CartProvider {
|
|
|
282
312
|
key: remote.id,
|
|
283
313
|
version: remote.version || 0
|
|
284
314
|
};
|
|
315
|
+
const items = new Array();
|
|
316
|
+
for (const remoteItem of remote.lineItems) {
|
|
317
|
+
const item = this.parseCartItem(remoteItem);
|
|
318
|
+
items.push(item);
|
|
319
|
+
}
|
|
285
320
|
const grandTotal = remote.totalPrice.centAmount || 0;
|
|
286
321
|
const shippingTotal = remote.shippingInfo?.price.centAmount || 0;
|
|
287
322
|
const productTotal = grandTotal - shippingTotal;
|
|
288
323
|
const taxTotal = remote.taxedPrice?.totalTax?.centAmount || 0;
|
|
289
|
-
const discountTotal = remote.discountOnTotalPrice?.discountedAmount.centAmount || 0;
|
|
324
|
+
const discountTotal = (remote.discountOnTotalPrice?.discountedAmount.centAmount || 0) + items.reduce((sum, item) => sum + (item.price.totalDiscount.value * 100 || 0), 0);
|
|
290
325
|
const surchargeTotal = 0;
|
|
291
326
|
const currency = remote.totalPrice.currencyCode;
|
|
292
327
|
const price = {
|
|
@@ -315,10 +350,17 @@ class CommercetoolsCartProvider extends CartProvider {
|
|
|
315
350
|
currency
|
|
316
351
|
}
|
|
317
352
|
};
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
353
|
+
const localeString = this.context.languageContext.locale || "en";
|
|
354
|
+
const appliedPromotions = [];
|
|
355
|
+
if (remote.discountCodes) {
|
|
356
|
+
for (const promo of remote.discountCodes) {
|
|
357
|
+
appliedPromotions.push({
|
|
358
|
+
code: promo.discountCode.obj?.code || "",
|
|
359
|
+
isCouponCode: true,
|
|
360
|
+
name: promo.discountCode.obj?.name?.[localeString] || "",
|
|
361
|
+
description: promo.discountCode.obj?.description?.[localeString] || ""
|
|
362
|
+
});
|
|
363
|
+
}
|
|
322
364
|
}
|
|
323
365
|
const cart = {
|
|
324
366
|
identifier,
|
|
@@ -328,6 +370,7 @@ class CommercetoolsCartProvider extends CartProvider {
|
|
|
328
370
|
name: remote.custom?.fields["name"] || "",
|
|
329
371
|
description: remote.custom?.fields["description"] || "",
|
|
330
372
|
price,
|
|
373
|
+
appliedPromotions,
|
|
331
374
|
items
|
|
332
375
|
};
|
|
333
376
|
return cart;
|
|
@@ -364,8 +407,7 @@ __decorateClass([
|
|
|
364
407
|
], CommercetoolsCartProvider.prototype, "getActiveCartId", 1);
|
|
365
408
|
__decorateClass([
|
|
366
409
|
Reactionary({
|
|
367
|
-
inputSchema: CartMutationDeleteCartSchema
|
|
368
|
-
outputSchema: CartSchema
|
|
410
|
+
inputSchema: CartMutationDeleteCartSchema
|
|
369
411
|
})
|
|
370
412
|
], CommercetoolsCartProvider.prototype, "deleteCart", 1);
|
|
371
413
|
__decorateClass([
|
|
@@ -23,8 +23,7 @@ class CommercetoolsInventoryProvider extends InventoryProvider {
|
|
|
23
23
|
async getBySKU(payload) {
|
|
24
24
|
const client = await this.getClient();
|
|
25
25
|
try {
|
|
26
|
-
const
|
|
27
|
-
const channelId = channel.body.id;
|
|
26
|
+
const channelId = await this.commercetools.resolveChannelIdByKey(payload.fulfilmentCenter.key);
|
|
28
27
|
const remote = await client.inventory().get({
|
|
29
28
|
queryArgs: {
|
|
30
29
|
where: "sku=:sku AND supplyChannel(id=:channel)",
|
|
@@ -66,6 +65,10 @@ class CommercetoolsInventoryProvider extends InventoryProvider {
|
|
|
66
65
|
}
|
|
67
66
|
__decorateClass([
|
|
68
67
|
Reactionary({
|
|
68
|
+
cache: true,
|
|
69
|
+
cacheTimeToLiveInSeconds: 300,
|
|
70
|
+
currencyDependentCaching: false,
|
|
71
|
+
localeDependentCaching: false,
|
|
69
72
|
inputSchema: InventoryQueryBySKUSchema,
|
|
70
73
|
outputSchema: InventorySchema
|
|
71
74
|
})
|
|
@@ -25,7 +25,12 @@ class CommercetoolsPriceProvider extends PriceProvider {
|
|
|
25
25
|
}
|
|
26
26
|
async getCustomerPrice(payload) {
|
|
27
27
|
const client = await this.getClient();
|
|
28
|
-
|
|
28
|
+
let priceChannelId;
|
|
29
|
+
if (this.config.customerPriceChannelKey) {
|
|
30
|
+
priceChannelId = await this.commercetools.resolveChannelIdByKey(this.config.customerPriceChannelKey);
|
|
31
|
+
} else {
|
|
32
|
+
priceChannelId = await this.commercetools.resolveChannelIdByRole("Primary");
|
|
33
|
+
}
|
|
29
34
|
const response = await client.productProjections().get({
|
|
30
35
|
queryArgs: {
|
|
31
36
|
staged: false,
|
|
@@ -46,7 +51,12 @@ class CommercetoolsPriceProvider extends PriceProvider {
|
|
|
46
51
|
}
|
|
47
52
|
async getListPrice(payload) {
|
|
48
53
|
const client = await this.getClient();
|
|
49
|
-
|
|
54
|
+
let priceChannelId;
|
|
55
|
+
if (this.config.listPriceChannelKey) {
|
|
56
|
+
priceChannelId = await this.commercetools.resolveChannelIdByKey(this.config.listPriceChannelKey);
|
|
57
|
+
} else {
|
|
58
|
+
priceChannelId = await this.commercetools.resolveChannelIdByRole("Primary");
|
|
59
|
+
}
|
|
50
60
|
const response = await client.productProjections().get({
|
|
51
61
|
queryArgs: {
|
|
52
62
|
staged: false,
|
|
@@ -79,8 +89,12 @@ class CommercetoolsPriceProvider extends PriceProvider {
|
|
|
79
89
|
value: price.value.centAmount / 100,
|
|
80
90
|
currency: price.value.currencyCode
|
|
81
91
|
};
|
|
92
|
+
let isOnSale = false;
|
|
82
93
|
if (options.includeDiscounts) {
|
|
83
94
|
const discountedPrice = price.discounted?.value || price.value;
|
|
95
|
+
if (price.discounted) {
|
|
96
|
+
isOnSale = true;
|
|
97
|
+
}
|
|
84
98
|
unitPrice = {
|
|
85
99
|
value: discountedPrice.centAmount / 100,
|
|
86
100
|
currency: price.value.currencyCode
|
|
@@ -94,23 +108,11 @@ class CommercetoolsPriceProvider extends PriceProvider {
|
|
|
94
108
|
const result = {
|
|
95
109
|
identifier,
|
|
96
110
|
tieredPrices: [],
|
|
97
|
-
unitPrice
|
|
111
|
+
unitPrice,
|
|
112
|
+
onSale: isOnSale
|
|
98
113
|
};
|
|
99
114
|
return result;
|
|
100
115
|
}
|
|
101
|
-
async getChannels() {
|
|
102
|
-
const adminClient = await this.commercetools.getAdminClient();
|
|
103
|
-
const offerPriceChannelPromise = adminClient.withProjectKey({ projectKey: this.config.projectKey }).channels().withKey({ key: "Offer Price" }).get().execute();
|
|
104
|
-
const listPriceChannelPromise = adminClient.withProjectKey({ projectKey: this.config.projectKey }).channels().withKey({ key: "List Price" }).get().execute();
|
|
105
|
-
const [offerChannel, listChannel] = await Promise.all([
|
|
106
|
-
offerPriceChannelPromise,
|
|
107
|
-
listPriceChannelPromise
|
|
108
|
-
]);
|
|
109
|
-
return {
|
|
110
|
-
offer: offerChannel.body.id,
|
|
111
|
-
list: listChannel.body.id
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
116
|
}
|
|
115
117
|
__decorateClass([
|
|
116
118
|
Reactionary({
|
|
@@ -7,8 +7,12 @@ const CommercetoolsConfigurationSchema = z.looseObject({
|
|
|
7
7
|
clientId: z.string(),
|
|
8
8
|
clientSecret: z.string(),
|
|
9
9
|
scopes: z.array(z.string()).default(() => []),
|
|
10
|
+
adminClientId: z.string().optional(),
|
|
11
|
+
adminClientSecret: z.string().optional(),
|
|
10
12
|
paymentMethods: PaymentMethodSchema.array().optional().default(() => []),
|
|
11
|
-
facetFieldsForSearch: z.array(z.string()).default(() => [])
|
|
13
|
+
facetFieldsForSearch: z.array(z.string()).default(() => []),
|
|
14
|
+
listPriceChannelKey: z.string().optional(),
|
|
15
|
+
customerPriceChannelKey: z.string().optional()
|
|
12
16
|
});
|
|
13
17
|
export {
|
|
14
18
|
CommercetoolsConfigurationSchema
|
package/src/core/client.d.ts
CHANGED
|
@@ -3,15 +3,31 @@ import { type ApiRoot } from '@commercetools/platform-sdk';
|
|
|
3
3
|
import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
|
|
4
4
|
import { type AnonymousIdentity, type GuestIdentity, type RegisteredIdentity, type RequestContext } from '@reactionary/core';
|
|
5
5
|
import { RequestContextTokenCache } from './token-cache.js';
|
|
6
|
+
import { type CommercetoolsSession } from '../schema/session.schema.js';
|
|
7
|
+
export declare const PROVIDER_SESSION_KEY = "COMMERCETOOLS_PROVIDER";
|
|
6
8
|
export declare class CommercetoolsAPI {
|
|
7
9
|
protected config: CommercetoolsConfiguration;
|
|
8
10
|
protected context: RequestContext;
|
|
9
|
-
protected
|
|
11
|
+
protected tokenCache: RequestContextTokenCache;
|
|
10
12
|
protected client: Promise<ApiRoot> | undefined;
|
|
11
13
|
protected adminClient: Promise<ApiRoot> | undefined;
|
|
12
14
|
constructor(config: CommercetoolsConfiguration, context: RequestContext);
|
|
13
15
|
getClient(): Promise<ApiRoot>;
|
|
14
16
|
getAdminClient(): Promise<ApiRoot>;
|
|
17
|
+
getSessionData(): CommercetoolsSession;
|
|
18
|
+
setSessionData(sessionData: Partial<CommercetoolsSession>): void;
|
|
19
|
+
/**
|
|
20
|
+
* Only caches it pr session for now...... but still better than every call
|
|
21
|
+
* @param key
|
|
22
|
+
* @returns
|
|
23
|
+
*/
|
|
24
|
+
resolveChannelIdByKey(key: string): Promise<string>;
|
|
25
|
+
/**
|
|
26
|
+
* Only caches it pr session for now...... but still better than every call
|
|
27
|
+
* @param key
|
|
28
|
+
* @returns
|
|
29
|
+
*/
|
|
30
|
+
resolveChannelIdByRole(role: string): Promise<string>;
|
|
15
31
|
protected createAdminClient(): Promise<ApiRoot>;
|
|
16
32
|
protected createClient(): Promise<ApiRoot>;
|
|
17
33
|
register(username: string, password: string): Promise<{
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { TokenCache, TokenCacheOptions, TokenStore } from "@commercetools/ts-client";
|
|
2
2
|
import type { RequestContext } from "@reactionary/core";
|
|
3
|
-
export declare const PROVIDER_COMMERCETOOLS_SESSION_KEY = "PROVIDER_COMMERCETOOLS";
|
|
4
3
|
export declare class RequestContextTokenCache implements TokenCache {
|
|
5
4
|
protected context: RequestContext;
|
|
6
|
-
|
|
5
|
+
protected sessionProviderKey: string;
|
|
6
|
+
constructor(context: RequestContext, sessionProviderKey: string);
|
|
7
7
|
get(tokenCacheOptions?: TokenCacheOptions): Promise<TokenStore | undefined>;
|
|
8
8
|
set(cache: TokenStore, tokenCacheOptions?: TokenCacheOptions): Promise<void>;
|
|
9
9
|
}
|
|
@@ -6,6 +6,7 @@ import type { CommercetoolsAPI } from '../core/client.js';
|
|
|
6
6
|
export declare class CommercetoolsCartProvider extends CartProvider {
|
|
7
7
|
protected config: CommercetoolsConfiguration;
|
|
8
8
|
protected commercetools: CommercetoolsAPI;
|
|
9
|
+
protected expandedCartFields: string[];
|
|
9
10
|
constructor(config: CommercetoolsConfiguration, cache: Cache, context: RequestContext, commercetools: CommercetoolsAPI);
|
|
10
11
|
getById(payload: CartQueryById): Promise<Result<Cart, NotFoundError>>;
|
|
11
12
|
add(payload: CartMutationItemAdd): Promise<Result<Cart>>;
|
|
@@ -6,6 +6,8 @@ export declare const CommercetoolsConfigurationSchema: z.ZodObject<{
|
|
|
6
6
|
clientId: z.ZodString;
|
|
7
7
|
clientSecret: z.ZodString;
|
|
8
8
|
scopes: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
9
|
+
adminClientId: z.ZodOptional<z.ZodString>;
|
|
10
|
+
adminClientSecret: z.ZodOptional<z.ZodString>;
|
|
9
11
|
paymentMethods: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
10
12
|
identifier: z.ZodObject<{
|
|
11
13
|
method: z.ZodString;
|
|
@@ -22,5 +24,7 @@ export declare const CommercetoolsConfigurationSchema: z.ZodObject<{
|
|
|
22
24
|
isPunchOut: z.ZodBoolean;
|
|
23
25
|
}, z.core.$loose>>>>;
|
|
24
26
|
facetFieldsForSearch: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
27
|
+
listPriceChannelKey: z.ZodOptional<z.ZodString>;
|
|
28
|
+
customerPriceChannelKey: z.ZodOptional<z.ZodString>;
|
|
25
29
|
}, z.core.$loose>;
|
|
26
30
|
export type CommercetoolsConfiguration = z.infer<typeof CommercetoolsConfigurationSchema>;
|