@reactionary/source 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/README.md +2 -2
- package/core/src/initialization.ts +2 -2
- package/core/src/providers/price.provider.ts +2 -1
- package/core/src/schemas/models/cart.model.ts +7 -2
- package/core/src/schemas/models/identifiers.model.ts +12 -8
- package/core/src/schemas/models/price.model.ts +12 -0
- package/examples/node/package.json +7 -7
- package/examples/node/src/capabilities/cart.spec.ts +97 -15
- package/examples/node/src/capabilities/category.spec.ts +27 -32
- package/examples/node/src/capabilities/checkout.spec.ts +5 -5
- package/examples/node/src/capabilities/identity.spec.ts +6 -2
- package/examples/node/src/capabilities/inventory.spec.ts +1 -1
- package/examples/node/src/capabilities/price.spec.ts +7 -7
- package/examples/node/src/utils.ts +4 -1
- package/package.json +3 -3
- package/providers/algolia/src/providers/product-search.provider.ts +19 -14
- package/providers/commercetools/src/core/client.ts +112 -9
- package/providers/commercetools/src/core/token-cache.ts +4 -5
- package/providers/commercetools/src/providers/cart.provider.ts +76 -11
- package/providers/commercetools/src/providers/inventory.provider.ts +5 -7
- package/providers/commercetools/src/providers/price.provider.ts +17 -30
- package/providers/commercetools/src/schema/configuration.schema.ts +4 -0
- package/providers/commercetools/src/schema/session.schema.ts +3 -1
- package/providers/fake/src/providers/cart.provider.ts +1 -0
- package/providers/fake/src/providers/price.provider.ts +54 -95
- package/providers/medusa/src/providers/cart.provider.ts +159 -70
- package/providers/medusa/src/providers/category.provider.ts +35 -23
- package/providers/medusa/src/providers/checkout.provider.ts +78 -41
- package/providers/medusa/src/providers/order-search.provider.ts +21 -10
- package/providers/medusa/src/providers/price.provider.ts +18 -9
- package/providers/medusa/src/providers/product-recommendations.provider.ts +10 -6
- package/providers/medusa/src/providers/product-search.provider.ts +19 -10
- package/providers/medusa/src/providers/product.provider.ts +20 -12
- package/providers/medusa/src/providers/profile.provider.ts +38 -13
- package/providers/meilisearch/src/providers/order-search.provider.ts +17 -12
- package/providers/meilisearch/src/providers/product-recommendations.provider.ts +10 -11
- package/providers/meilisearch/src/providers/product-search.provider.ts +23 -18
|
@@ -16,10 +16,11 @@ import {
|
|
|
16
16
|
import type * as z from 'zod';
|
|
17
17
|
import type { FakeConfiguration } from '../schema/configuration.schema.js';
|
|
18
18
|
import { base, en, Faker } from '@faker-js/faker';
|
|
19
|
+
import { calcSeed } from '../utilities/seed.js';
|
|
19
20
|
|
|
20
21
|
export class FakePriceProvider extends PriceProvider {
|
|
21
22
|
protected config: FakeConfiguration;
|
|
22
|
-
|
|
23
|
+
protected faker: Faker;
|
|
23
24
|
constructor(
|
|
24
25
|
config: FakeConfiguration,
|
|
25
26
|
cache: Cache,
|
|
@@ -28,66 +29,72 @@ export class FakePriceProvider extends PriceProvider {
|
|
|
28
29
|
super(cache, context);
|
|
29
30
|
|
|
30
31
|
this.config = config;
|
|
32
|
+
this.faker = new Faker({
|
|
33
|
+
locale: [en, base],
|
|
34
|
+
});
|
|
31
35
|
}
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (
|
|
39
|
-
|
|
37
|
+
protected createPrice(variantSku: string, mode: 'list' | 'customer'): Price {
|
|
38
|
+
const seed = calcSeed(variantSku);
|
|
39
|
+
this.faker.seed(seed);
|
|
40
|
+
let price = this.faker.number.int({ min: 300, max: 100000 }) / 100;
|
|
41
|
+
let onSale = false;
|
|
42
|
+
if (mode === 'customer') {
|
|
43
|
+
// For customer price, randomly decide if the product is on sale
|
|
44
|
+
onSale = this.faker.datatype.boolean({ probability: 0.1 }); // 10% chance of being on sale
|
|
45
|
+
|
|
46
|
+
if (onSale) {
|
|
47
|
+
price = price * this.faker.number.float({ min: 0.5, max: 0.9 }); // Apply a random discount between 10% and 50%
|
|
48
|
+
}
|
|
40
49
|
}
|
|
41
50
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
const tiers = [];
|
|
52
|
+
if (variantSku.includes('with-tiers')) {
|
|
53
|
+
// Add tiered pricing for SKUs that include "with-tiers"
|
|
54
|
+
tiers.push({
|
|
55
|
+
minimumQuantity: this.faker.number.int({ min: 2, max: 5 }),
|
|
56
|
+
price: {
|
|
57
|
+
value: price * 0.8, // 20% discount for tier 1
|
|
58
|
+
currency: this.context.languageContext.currencyCode,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
tiers.push({
|
|
62
|
+
minimumQuantity: this.faker.number.int({ min: 6, max: 10 }),
|
|
63
|
+
price: {
|
|
64
|
+
value: price * 0.6, // 40% discount for tier 2
|
|
65
|
+
currency: this.context.languageContext.currencyCode,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
48
68
|
}
|
|
49
69
|
|
|
50
|
-
const generator = new Faker({
|
|
51
|
-
seed: hash || 42,
|
|
52
|
-
locale: [en, base],
|
|
53
|
-
});
|
|
54
70
|
|
|
55
|
-
|
|
71
|
+
return {
|
|
56
72
|
identifier: {
|
|
57
|
-
variant:
|
|
73
|
+
variant: {
|
|
74
|
+
sku: variantSku,
|
|
75
|
+
},
|
|
58
76
|
},
|
|
59
77
|
unitPrice: {
|
|
60
|
-
value:
|
|
78
|
+
value: price,
|
|
61
79
|
currency: this.context.languageContext.currencyCode,
|
|
62
80
|
},
|
|
63
|
-
|
|
81
|
+
onSale,
|
|
82
|
+
tieredPrices: tiers,
|
|
83
|
+
}
|
|
84
|
+
}
|
|
64
85
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
value: tier1Price,
|
|
75
|
-
currency: this.context.languageContext.currencyCode,
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
minimumQuantity: generator.number.int({ min: 6, max: 10 }),
|
|
80
|
-
price: {
|
|
81
|
-
value: tier2Price,
|
|
82
|
-
currency: this.context.languageContext.currencyCode,
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
];
|
|
86
|
-
} else {
|
|
87
|
-
model.tieredPrices = [];
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@Reactionary({
|
|
89
|
+
inputSchema: ListPriceQuerySchema,
|
|
90
|
+
outputSchema: PriceSchema
|
|
91
|
+
})
|
|
92
|
+
public override async getListPrice(payload: ListPriceQuery): Promise<Result<Price>> {
|
|
93
|
+
if (payload.variant.sku === 'unknown-sku') {
|
|
94
|
+
return success(this.createEmptyPriceResult(payload.variant.sku));
|
|
88
95
|
}
|
|
89
96
|
|
|
90
|
-
return success(
|
|
97
|
+
return success(this.createPrice(payload.variant.sku, 'list'));
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
@Reactionary({
|
|
@@ -99,54 +106,6 @@ export class FakePriceProvider extends PriceProvider {
|
|
|
99
106
|
return success(this.createEmptyPriceResult(payload.variant.sku));
|
|
100
107
|
}
|
|
101
108
|
|
|
102
|
-
|
|
103
|
-
let hash = 0;
|
|
104
|
-
const skuString = payload.variant.sku;
|
|
105
|
-
for (let i = 0; i < skuString.length; i++) {
|
|
106
|
-
hash = (hash << 5) - hash + skuString.charCodeAt(i);
|
|
107
|
-
hash = hash & hash; // Convert to 32bit integer
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const generator = new Faker({
|
|
111
|
-
seed: hash || 42,
|
|
112
|
-
locale: [en, base],
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
const model = {
|
|
116
|
-
identifier: {
|
|
117
|
-
variant: payload.variant,
|
|
118
|
-
},
|
|
119
|
-
unitPrice: {
|
|
120
|
-
value: generator.number.int({ min: 300, max: 100000 }) / 100,
|
|
121
|
-
currency: this.context.languageContext.currencyCode,
|
|
122
|
-
},
|
|
123
|
-
} as Price;
|
|
124
|
-
|
|
125
|
-
if (skuString.includes('with-tiers')) {
|
|
126
|
-
const unitPrice = model.unitPrice?.value || 0;
|
|
127
|
-
// Ensure tiered prices are less than the unit price
|
|
128
|
-
const tier1Price = unitPrice * 0.8;
|
|
129
|
-
const tier2Price = tier1Price * 0.8;
|
|
130
|
-
model.tieredPrices = [
|
|
131
|
-
{
|
|
132
|
-
minimumQuantity: generator.number.int({ min: 2, max: 5 }),
|
|
133
|
-
price: {
|
|
134
|
-
value: tier1Price,
|
|
135
|
-
currency: this.context.languageContext.currencyCode,
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
minimumQuantity: generator.number.int({ min: 6, max: 10 }),
|
|
140
|
-
price: {
|
|
141
|
-
value: tier2Price,
|
|
142
|
-
currency: this.context.languageContext.currencyCode,
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
-
];
|
|
146
|
-
} else {
|
|
147
|
-
model.tieredPrices = [];
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return success(model);
|
|
109
|
+
return success(this.createPrice(payload.variant.sku, 'customer'));
|
|
151
110
|
}
|
|
152
111
|
}
|
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
ItemCostBreakdown,
|
|
17
17
|
NotFoundError,
|
|
18
18
|
ProductVariantIdentifier,
|
|
19
|
+
Promotion,
|
|
19
20
|
RequestContext,
|
|
20
21
|
Result,
|
|
21
22
|
} from '@reactionary/core';
|
|
@@ -31,10 +32,10 @@ import {
|
|
|
31
32
|
CartProvider,
|
|
32
33
|
CartQueryByIdSchema,
|
|
33
34
|
CartSchema,
|
|
35
|
+
error,
|
|
34
36
|
ProductVariantIdentifierSchema,
|
|
35
37
|
Reactionary,
|
|
36
38
|
success,
|
|
37
|
-
error,
|
|
38
39
|
} from '@reactionary/core';
|
|
39
40
|
|
|
40
41
|
import createDebug from 'debug';
|
|
@@ -47,8 +48,7 @@ import {
|
|
|
47
48
|
parseMedusaCostBreakdown,
|
|
48
49
|
parseMedusaItemPrice,
|
|
49
50
|
} from '../utils/medusa-helpers.js';
|
|
50
|
-
import type
|
|
51
|
-
import type StoreCartPromotion = require('@medusajs/types');
|
|
51
|
+
import type { StoreAddCartLineItem, StoreCart, StoreCartAddPromotion, StoreCartLineItem, StoreCartRemovePromotion, StoreCartResponse, StoreCreateCart, StoreProduct, StoreUpdateCart, StoreUpdateCartLineItem } from '@medusajs/types';
|
|
52
52
|
|
|
53
53
|
const debug = createDebug('reactionary:medusa:cart');
|
|
54
54
|
|
|
@@ -87,7 +87,7 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
87
87
|
debug('Fetching cart by ID:', medusaId.key);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
const cartResponse = await client.store.cart.retrieve(medusaId.key);
|
|
90
|
+
const cartResponse = await client.store.cart.retrieve(medusaId.key, { fields: this.includedFields });
|
|
91
91
|
|
|
92
92
|
if (debug.enabled) {
|
|
93
93
|
debug('Received cart response:', cartResponse);
|
|
@@ -111,6 +111,21 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Extension point for the `add` operation to control the payload sent to Medusa when adding an item to the cart. By default, it only includes the variant ID and quantity, but you can override it to include more fields as needed.
|
|
117
|
+
*
|
|
118
|
+
* @param payload
|
|
119
|
+
* @param variantId
|
|
120
|
+
* @returns
|
|
121
|
+
*/
|
|
122
|
+
protected addPayload(payload: CartMutationItemAdd, variantId: string): StoreAddCartLineItem {
|
|
123
|
+
return {
|
|
124
|
+
variant_id: variantId,
|
|
125
|
+
quantity: payload.quantity,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
114
129
|
@Reactionary({
|
|
115
130
|
inputSchema: CartMutationItemAddSchema,
|
|
116
131
|
outputSchema: CartSchema,
|
|
@@ -148,13 +163,11 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
148
163
|
|
|
149
164
|
const response = await client.store.cart.createLineItem(
|
|
150
165
|
medusaId.key,
|
|
151
|
-
|
|
152
|
-
variant_id: variantId,
|
|
153
|
-
quantity: payload.quantity,
|
|
154
|
-
},
|
|
166
|
+
this.addPayload(payload, variantId),
|
|
155
167
|
{
|
|
156
168
|
fields: this.includedFields,
|
|
157
169
|
}
|
|
170
|
+
|
|
158
171
|
);
|
|
159
172
|
|
|
160
173
|
if (debug.enabled) {
|
|
@@ -200,6 +213,18 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
200
213
|
}
|
|
201
214
|
}
|
|
202
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Extension point for the `changeQuantity` operation to control the payload sent to Medusa when changing the quantity of an item in the cart. By default, it only includes the new quantity, but you can override it to include more fields as needed.
|
|
218
|
+
* @param payload
|
|
219
|
+
* @returns
|
|
220
|
+
*/
|
|
221
|
+
protected changeQuantityPayload(payload: CartMutationItemQuantityChange): StoreUpdateCartLineItem {
|
|
222
|
+
return {
|
|
223
|
+
quantity: payload.quantity,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
|
|
203
228
|
@Reactionary({
|
|
204
229
|
inputSchema: CartMutationItemQuantityChangeSchema,
|
|
205
230
|
outputSchema: CartSchema,
|
|
@@ -222,9 +247,7 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
222
247
|
const response = await client.store.cart.updateLineItem(
|
|
223
248
|
medusaId.key,
|
|
224
249
|
payload.item.key,
|
|
225
|
-
|
|
226
|
-
quantity: payload.quantity,
|
|
227
|
-
},
|
|
250
|
+
this.changeQuantityPayload(payload),
|
|
228
251
|
{
|
|
229
252
|
fields: this.includedFields,
|
|
230
253
|
}
|
|
@@ -272,7 +295,7 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
272
295
|
identifier: undefined,
|
|
273
296
|
});
|
|
274
297
|
} catch (err) {
|
|
275
|
-
debug('Failed to get active cart ID:',
|
|
298
|
+
debug('Failed to get active cart ID:', err);
|
|
276
299
|
|
|
277
300
|
return error<NotFoundError>({
|
|
278
301
|
type: 'NotFound',
|
|
@@ -282,8 +305,8 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
282
305
|
}
|
|
283
306
|
|
|
284
307
|
@Reactionary({
|
|
308
|
+
cache: false,
|
|
285
309
|
inputSchema: CartMutationDeleteCartSchema,
|
|
286
|
-
outputSchema: CartSchema,
|
|
287
310
|
})
|
|
288
311
|
public override async deleteCart(
|
|
289
312
|
payload: CartMutationDeleteCart
|
|
@@ -319,6 +342,18 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
319
342
|
}
|
|
320
343
|
}
|
|
321
344
|
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Extension point to apply a coupon code to the cart. By default, it only includes the coupon code, but you can override it to include more fields as needed.
|
|
348
|
+
* @param payload
|
|
349
|
+
* @returns
|
|
350
|
+
*/
|
|
351
|
+
protected applyCouponCodePayload(payload: CartMutationApplyCoupon): StoreCartAddPromotion {
|
|
352
|
+
return {
|
|
353
|
+
promo_codes: [payload.couponCode],
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
322
357
|
@Reactionary({
|
|
323
358
|
inputSchema: CartMutationApplyCouponSchema,
|
|
324
359
|
outputSchema: CartSchema,
|
|
@@ -330,16 +365,27 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
330
365
|
const client = await this.getClient();
|
|
331
366
|
const medusaId = payload.cart as MedusaCartIdentifier;
|
|
332
367
|
|
|
333
|
-
|
|
334
|
-
|
|
368
|
+
|
|
369
|
+
const response = await client.client.fetch<StoreCartResponse>(
|
|
370
|
+
`/store/carts/${medusaId.key}/promotions`,
|
|
335
371
|
{
|
|
336
|
-
|
|
337
|
-
|
|
372
|
+
method: "POST",
|
|
373
|
+
body: this.applyCouponCodePayload(payload),
|
|
374
|
+
query: {
|
|
375
|
+
fields: this.includedFields,
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
/** When PR: https://github.com/medusajs/medusa/pull/14850 gets merged, revert to the below
|
|
381
|
+
const response = await client.store.cart.addPromotionCodes(
|
|
382
|
+
medusaId.key,
|
|
383
|
+
this.applyCouponCodePayload(payload),
|
|
338
384
|
{
|
|
339
385
|
fields: this.includedFields,
|
|
340
386
|
}
|
|
341
387
|
);
|
|
342
|
-
|
|
388
|
+
*/
|
|
343
389
|
if (response.cart) {
|
|
344
390
|
return success(this.parseSingle(response.cart));
|
|
345
391
|
}
|
|
@@ -350,6 +396,18 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
350
396
|
}
|
|
351
397
|
}
|
|
352
398
|
|
|
399
|
+
/**
|
|
400
|
+
* Extension point to remove a coupon code from the cart. By default, it only includes the coupon code to be removed, but you can override it to include more fields as needed.
|
|
401
|
+
* @param payload
|
|
402
|
+
* @returns
|
|
403
|
+
*/
|
|
404
|
+
protected removeCouponCodePayload(payload: CartMutationRemoveCoupon): StoreCartRemovePromotion {
|
|
405
|
+
return {
|
|
406
|
+
promo_codes: [payload.couponCode],
|
|
407
|
+
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
353
411
|
@Reactionary({
|
|
354
412
|
inputSchema: CartMutationRemoveCouponSchema,
|
|
355
413
|
outputSchema: CartSchema,
|
|
@@ -361,39 +419,49 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
361
419
|
const client = await this.getClient();
|
|
362
420
|
const medusaId = payload.cart as MedusaCartIdentifier;
|
|
363
421
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
);
|
|
371
|
-
|
|
372
|
-
const remainingCodes = (manualDiscounts
|
|
373
|
-
.filter((x) => x.code !== payload.couponCode)
|
|
374
|
-
.map((promotion: MedusaTypes.StoreCartPromotion) => promotion.code) ||
|
|
375
|
-
[]) as string[];
|
|
376
|
-
const response = await client.store.cart.update(
|
|
377
|
-
medusaId.key,
|
|
378
|
-
{
|
|
379
|
-
promo_codes: remainingCodes || [],
|
|
380
|
-
},
|
|
381
|
-
{
|
|
422
|
+
const response = await client.client.fetch<StoreCartResponse>(
|
|
423
|
+
`/store/carts/${medusaId.key}/promotions`,
|
|
424
|
+
{
|
|
425
|
+
method: "DELETE",
|
|
426
|
+
body: this.removeCouponCodePayload(payload),
|
|
427
|
+
query: {
|
|
382
428
|
fields: this.includedFields,
|
|
383
429
|
}
|
|
384
|
-
|
|
430
|
+
}
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
/*
|
|
385
434
|
|
|
386
|
-
|
|
387
|
-
|
|
435
|
+
const response = await client.store.cart.removePromotionCodes(
|
|
436
|
+
medusaId.key,
|
|
437
|
+
this.removeCouponCodePayload(payload),
|
|
438
|
+
{
|
|
439
|
+
fields: this.includedFields,
|
|
388
440
|
}
|
|
389
|
-
|
|
441
|
+
);
|
|
442
|
+
*/
|
|
390
443
|
|
|
444
|
+
if (response.cart) {
|
|
445
|
+
return success(this.parseSingle(response.cart));
|
|
446
|
+
}
|
|
391
447
|
throw new Error('Failed to remove coupon code');
|
|
392
448
|
} catch (error) {
|
|
393
449
|
handleProviderError('remove coupon code', error);
|
|
394
450
|
}
|
|
395
451
|
}
|
|
396
452
|
|
|
453
|
+
/**
|
|
454
|
+
* Extension point to control the payload sent to Medusa when changing the currency of the cart. By default, it only includes the new region ID, but you can override it to include more fields as needed.
|
|
455
|
+
* @param payload
|
|
456
|
+
* @param newRegionId
|
|
457
|
+
* @returns
|
|
458
|
+
*/
|
|
459
|
+
protected changeCurrencyPayload(payload: CartMutationChangeCurrency, newRegionId: string): StoreUpdateCart {
|
|
460
|
+
return {
|
|
461
|
+
region_id: newRegionId,
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
|
|
397
465
|
@Reactionary({
|
|
398
466
|
inputSchema: CartMutationChangeCurrencySchema,
|
|
399
467
|
outputSchema: CartSchema,
|
|
@@ -404,35 +472,22 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
404
472
|
try {
|
|
405
473
|
const client = await this.getClient();
|
|
406
474
|
|
|
407
|
-
|
|
408
|
-
const
|
|
409
|
-
payload.cart.key
|
|
410
|
-
);
|
|
411
|
-
client.store.cart.update(
|
|
475
|
+
const newRegionId = (await this.medusaApi.getActiveRegion()).id;
|
|
476
|
+
const updatedCartResponse = await client.store.cart.update(
|
|
412
477
|
payload.cart.key,
|
|
413
|
-
|
|
414
|
-
region_id: (await this.medusaApi.getActiveRegion()).id,
|
|
415
|
-
},
|
|
478
|
+
this.changeCurrencyPayload(payload, newRegionId),
|
|
416
479
|
{
|
|
417
480
|
fields: this.includedFields,
|
|
418
481
|
}
|
|
419
482
|
);
|
|
420
|
-
if (!currentCartResponse.cart) {
|
|
421
|
-
throw new Error('Cart not found');
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// Get the new cart
|
|
425
|
-
const newCartResponse = await client.store.cart.retrieve(
|
|
426
|
-
payload.cart.key
|
|
427
|
-
);
|
|
428
483
|
|
|
429
|
-
if (
|
|
484
|
+
if (updatedCartResponse.cart) {
|
|
430
485
|
// Update session to use new cart
|
|
431
486
|
this.medusaApi.setSessionData({
|
|
432
|
-
activeCartId:
|
|
487
|
+
activeCartId: updatedCartResponse.cart.id,
|
|
433
488
|
});
|
|
434
489
|
|
|
435
|
-
return success(this.parseSingle(
|
|
490
|
+
return success(this.parseSingle(updatedCartResponse.cart));
|
|
436
491
|
}
|
|
437
492
|
|
|
438
493
|
throw new Error('Failed to change currency');
|
|
@@ -441,18 +496,28 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
441
496
|
}
|
|
442
497
|
}
|
|
443
498
|
|
|
499
|
+
/**
|
|
500
|
+
* Extension point to control the payload sent to Medusa when creating a cart. By default, it only includes the currency code, but you can override it to include more fields as needed.
|
|
501
|
+
* @param currency
|
|
502
|
+
* @returns
|
|
503
|
+
*/
|
|
504
|
+
protected createCartPayload(currency?: string): StoreCreateCart {
|
|
505
|
+
return {
|
|
506
|
+
currency_code: (
|
|
507
|
+
currency ||
|
|
508
|
+
this.context.languageContext.currencyCode ||
|
|
509
|
+
''
|
|
510
|
+
).toLowerCase(),
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
|
|
444
515
|
protected async createCart(currency?: string): Promise<CartIdentifier> {
|
|
445
516
|
try {
|
|
446
517
|
const client = await this.getClient();
|
|
447
518
|
|
|
448
519
|
const response = await client.store.cart.create(
|
|
449
|
-
|
|
450
|
-
currency_code: (
|
|
451
|
-
currency ||
|
|
452
|
-
this.context.languageContext.currencyCode ||
|
|
453
|
-
''
|
|
454
|
-
).toLowerCase(),
|
|
455
|
-
},
|
|
520
|
+
this.createCartPayload(currency),
|
|
456
521
|
{
|
|
457
522
|
fields: this.includedFields,
|
|
458
523
|
}
|
|
@@ -489,7 +554,7 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
489
554
|
* @returns
|
|
490
555
|
*/
|
|
491
556
|
protected parseItemPrice(
|
|
492
|
-
remoteItem:
|
|
557
|
+
remoteItem: StoreCartLineItem,
|
|
493
558
|
currency: Currency
|
|
494
559
|
): ItemCostBreakdown {
|
|
495
560
|
return parseMedusaItemPrice(remoteItem, currency);
|
|
@@ -500,7 +565,7 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
500
565
|
* @param remote
|
|
501
566
|
* @returns
|
|
502
567
|
*/
|
|
503
|
-
protected parseCostBreakdown(remote:
|
|
568
|
+
protected parseCostBreakdown(remote: StoreCart): CostBreakDown {
|
|
504
569
|
return parseMedusaCostBreakdown(remote);
|
|
505
570
|
}
|
|
506
571
|
|
|
@@ -511,9 +576,10 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
511
576
|
* @returns
|
|
512
577
|
*/
|
|
513
578
|
protected parseCartItem(
|
|
514
|
-
remoteItem:
|
|
579
|
+
remoteItem: StoreCartLineItem,
|
|
515
580
|
currency: Currency
|
|
516
581
|
): CartItem {
|
|
582
|
+
|
|
517
583
|
const item: CartItem = {
|
|
518
584
|
identifier: {
|
|
519
585
|
key: remoteItem.id,
|
|
@@ -535,7 +601,7 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
535
601
|
* @param remote
|
|
536
602
|
* @returns
|
|
537
603
|
*/
|
|
538
|
-
protected parseSingle(remote:
|
|
604
|
+
protected parseSingle(remote: StoreCart): Cart {
|
|
539
605
|
const identifier = MedusaCartIdentifierSchema.parse({
|
|
540
606
|
key: remote.id,
|
|
541
607
|
region_id: remote.region_id,
|
|
@@ -559,12 +625,35 @@ export class MedusaCartProvider extends CartProvider {
|
|
|
559
625
|
items.push(this.parseCartItem(remoteItem, price.grandTotal.currency));
|
|
560
626
|
}
|
|
561
627
|
|
|
628
|
+
|
|
629
|
+
const appliedPromotions = [];
|
|
630
|
+
if (remote.promotions) {
|
|
631
|
+
for (const promo of remote.promotions) {
|
|
632
|
+
|
|
633
|
+
const promotionName = promo.code;
|
|
634
|
+
let promoDescription = '';
|
|
635
|
+
if (promo.application_method?.type === 'percentage') {
|
|
636
|
+
promoDescription = `-${promo.application_method.value}%`;
|
|
637
|
+
}
|
|
638
|
+
if (promo.application_method?.type === 'fixed') {
|
|
639
|
+
promoDescription = `-${promo.application_method.value} ${price.grandTotal.currency}`;
|
|
640
|
+
}
|
|
641
|
+
appliedPromotions.push({
|
|
642
|
+
code: promo.code || '',
|
|
643
|
+
isCouponCode: promo.is_automatic ? false : true,
|
|
644
|
+
name: promotionName || promoDescription,
|
|
645
|
+
description: promoDescription
|
|
646
|
+
} satisfies Promotion);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
562
650
|
const result = {
|
|
563
651
|
identifier,
|
|
564
652
|
name,
|
|
565
653
|
description,
|
|
566
654
|
price,
|
|
567
655
|
items,
|
|
656
|
+
appliedPromotions,
|
|
568
657
|
userId: {
|
|
569
658
|
userId: '???',
|
|
570
659
|
},
|