@reactionary/source 0.0.41 → 0.0.48
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/.claude/settings.local.json +28 -0
- package/.env-template +8 -5
- package/.vscode/settings.json +5 -0
- package/README.md +41 -0
- package/core/package.json +3 -1
- package/core/src/cache/cache.interface.ts +14 -18
- package/core/src/cache/memory-cache.ts +56 -0
- package/core/src/cache/noop-cache.ts +5 -23
- package/core/src/cache/redis-cache.ts +28 -38
- package/core/src/client/client-builder.ts +3 -3
- package/core/src/client/client.ts +11 -9
- package/core/src/decorators/reactionary.decorator.ts +80 -8
- package/core/src/index.ts +5 -29
- package/core/src/initialization.ts +43 -0
- package/core/src/providers/analytics.provider.ts +1 -1
- package/core/src/providers/base.provider.ts +61 -25
- package/core/src/providers/cart-payment.provider.ts +57 -0
- package/core/src/providers/cart.provider.ts +131 -8
- package/core/src/providers/category.provider.ts +9 -9
- package/core/src/providers/identity.provider.ts +8 -7
- package/core/src/providers/index.ts +12 -0
- package/core/src/providers/inventory.provider.ts +4 -4
- package/core/src/providers/price.provider.ts +7 -7
- package/core/src/providers/product.provider.ts +17 -5
- package/core/src/providers/profile.provider.ts +22 -0
- package/core/src/providers/search.provider.ts +4 -4
- package/core/src/providers/store.provider.ts +14 -0
- package/core/src/schemas/capabilities.schema.ts +3 -1
- package/core/src/schemas/models/analytics.model.ts +1 -1
- package/core/src/schemas/models/cart.model.ts +16 -3
- package/core/src/schemas/models/identifiers.model.ts +90 -22
- package/core/src/schemas/models/identity.model.ts +23 -7
- package/core/src/schemas/models/index.ts +15 -0
- package/core/src/schemas/models/payment.model.ts +41 -0
- package/core/src/schemas/models/profile.model.ts +35 -0
- package/core/src/schemas/models/shipping-method.model.ts +14 -0
- package/core/src/schemas/models/store.model.ts +11 -0
- package/core/src/schemas/mutations/cart-payment.mutation.ts +21 -0
- package/core/src/schemas/mutations/cart.mutation.ts +62 -3
- package/core/src/schemas/mutations/identity.mutation.ts +8 -1
- package/core/src/schemas/mutations/index.ts +10 -0
- package/core/src/schemas/mutations/profile.mutation.ts +9 -0
- package/core/src/schemas/queries/cart-payment.query.ts +12 -0
- package/core/src/schemas/queries/cart.query.ts +1 -1
- package/core/src/schemas/queries/identity.query.ts +1 -1
- package/core/src/schemas/queries/index.ts +3 -0
- package/core/src/schemas/queries/inventory.query.ts +4 -12
- package/core/src/schemas/queries/price.query.ts +1 -1
- package/core/src/schemas/queries/profile.query.ts +7 -0
- package/core/src/schemas/queries/search.query.ts +1 -1
- package/core/src/schemas/queries/store.query.ts +11 -0
- package/core/src/schemas/session.schema.ts +31 -6
- package/eslint.config.mjs +7 -0
- package/examples/next/src/app/page.tsx +4 -12
- package/examples/node/package.json +1 -3
- package/examples/node/src/basic/basic-node-provider-model-extension.spec.ts +9 -8
- package/examples/node/src/basic/basic-node-provider-query-extension.spec.ts +4 -3
- package/examples/node/src/basic/basic-node-setup.spec.ts +4 -5
- package/nx.json +1 -0
- package/otel/src/metrics.ts +2 -1
- package/otel/src/provider-instrumentation.ts +2 -1
- package/otel/src/tracer.ts +7 -6
- package/otel/src/trpc-middleware.ts +3 -2
- package/package.json +2 -1
- package/providers/algolia/src/core/initialize.ts +4 -3
- package/providers/algolia/src/providers/product.provider.ts +15 -13
- package/providers/algolia/src/providers/search.provider.ts +9 -9
- package/providers/algolia/src/schema/capabilities.schema.ts +1 -1
- package/providers/algolia/src/test/search.provider.spec.ts +10 -10
- package/providers/algolia/src/test/test-utils.ts +9 -4
- package/providers/commercetools/README.md +27 -0
- package/providers/commercetools/src/core/client.ts +164 -117
- package/providers/commercetools/src/core/initialize.ts +24 -14
- package/providers/commercetools/src/providers/cart-payment.provider.ts +193 -0
- package/providers/commercetools/src/providers/cart.provider.ts +402 -125
- package/providers/commercetools/src/providers/category.provider.ts +35 -35
- package/providers/commercetools/src/providers/identity.provider.ts +23 -75
- package/providers/commercetools/src/providers/index.ts +2 -0
- package/providers/commercetools/src/providers/inventory.provider.ts +69 -40
- package/providers/commercetools/src/providers/price.provider.ts +79 -47
- package/providers/commercetools/src/providers/product.provider.ts +36 -30
- package/providers/commercetools/src/providers/profile.provider.ts +61 -0
- package/providers/commercetools/src/providers/search.provider.ts +16 -12
- package/providers/commercetools/src/providers/store.provider.ts +78 -0
- package/providers/commercetools/src/schema/capabilities.schema.ts +3 -1
- package/providers/commercetools/src/schema/commercetools.schema.ts +18 -0
- package/providers/commercetools/src/schema/configuration.schema.ts +2 -1
- package/providers/commercetools/src/test/cart-payment.provider.spec.ts +145 -0
- package/providers/commercetools/src/test/cart.provider.spec.ts +82 -22
- package/providers/commercetools/src/test/category.provider.spec.ts +18 -17
- package/providers/commercetools/src/test/identity.provider.spec.ts +88 -0
- package/providers/commercetools/src/test/inventory.provider.spec.ts +41 -0
- package/providers/commercetools/src/test/price.provider.spec.ts +9 -8
- package/providers/commercetools/src/test/product.provider.spec.ts +33 -5
- package/providers/commercetools/src/test/profile.provider.spec.ts +49 -0
- package/providers/commercetools/src/test/search.provider.spec.ts +8 -7
- package/providers/commercetools/src/test/store.provider.spec.ts +37 -0
- package/providers/commercetools/src/test/test-utils.ts +7 -31
- package/providers/fake/src/core/initialize.ts +96 -38
- package/providers/fake/src/providers/analytics.provider.ts +6 -5
- package/providers/fake/src/providers/cart.provider.ts +66 -19
- package/providers/fake/src/providers/category.provider.ts +12 -12
- package/providers/fake/src/providers/identity.provider.ts +22 -14
- package/providers/fake/src/providers/index.ts +1 -0
- package/providers/fake/src/providers/inventory.provider.ts +13 -13
- package/providers/fake/src/providers/price.provider.ts +13 -13
- package/providers/fake/src/providers/product.provider.ts +13 -10
- package/providers/fake/src/providers/search.provider.ts +7 -5
- package/providers/fake/src/providers/store.provider.ts +47 -0
- package/providers/fake/src/schema/capabilities.schema.ts +4 -1
- package/providers/fake/src/test/cart.provider.spec.ts +18 -18
- package/providers/fake/src/test/category.provider.spec.ts +55 -37
- package/providers/fake/src/test/price.provider.spec.ts +9 -14
- package/providers/fake/src/test/product.provider.spec.ts +27 -0
- package/providers/fake/src/test/test-utils.ts +2 -28
- package/providers/posthog/src/core/initialize.ts +3 -3
- package/providers/posthog/src/schema/capabilities.schema.ts +1 -1
- package/trpc/src/client.ts +42 -41
- package/trpc/src/index.ts +4 -3
- package/trpc/src/integration.spec.ts +11 -11
- package/trpc/src/server.ts +26 -24
- package/trpc/src/test-utils.ts +9 -4
- package/trpc/src/types.ts +24 -22
- package/core/src/cache/cache-evaluation.interface.ts +0 -19
- package/examples/node/src/test-utils.ts +0 -26
|
@@ -1,23 +1,38 @@
|
|
|
1
1
|
import {
|
|
2
|
-
Cart,
|
|
3
2
|
CartItemSchema,
|
|
4
|
-
CartProvider
|
|
5
|
-
Cache,
|
|
6
|
-
Currency,
|
|
3
|
+
CartProvider
|
|
7
4
|
} from '@reactionary/core';
|
|
8
5
|
import type {
|
|
9
6
|
CartMutationItemAdd,
|
|
10
7
|
CartMutationItemQuantityChange,
|
|
11
8
|
CartMutationItemRemove,
|
|
12
9
|
CartQueryById,
|
|
13
|
-
|
|
10
|
+
CartIdentifier, CartMutationApplyCoupon,
|
|
11
|
+
CartMutationCheckout,
|
|
12
|
+
CartMutationDeleteCart,
|
|
13
|
+
CartMutationRemoveCoupon, CartMutationSetBillingAddress,
|
|
14
|
+
CartMutationSetShippingInfo,
|
|
15
|
+
CartMutationChangeCurrency, OrderIdentifier,
|
|
16
|
+
RequestContext,
|
|
17
|
+
Cart,
|
|
18
|
+
Currency
|
|
19
|
+
,
|
|
20
|
+
Cache
|
|
14
21
|
} from '@reactionary/core';
|
|
15
|
-
import { CommercetoolsConfiguration } from '../schema/configuration.schema';
|
|
16
|
-
import { z } from 'zod';
|
|
22
|
+
import type { CommercetoolsConfiguration } from '../schema/configuration.schema';
|
|
23
|
+
import type { z } from 'zod';
|
|
17
24
|
import { CommercetoolsClient } from '../core/client';
|
|
18
|
-
import type {
|
|
25
|
+
import type {
|
|
26
|
+
Cart as CTCart,
|
|
27
|
+
MyCartUpdateAction,
|
|
28
|
+
} from '@commercetools/platform-sdk';
|
|
19
29
|
import { traced } from '@reactionary/otel';
|
|
20
|
-
|
|
30
|
+
import type {
|
|
31
|
+
CommercetoolsCartIdentifier} from '../schema/commercetools.schema';
|
|
32
|
+
import {
|
|
33
|
+
CommercetoolsCartIdentifierSchema,
|
|
34
|
+
CommercetoolsOrderIdentifierSchema,
|
|
35
|
+
} from '../schema/commercetools.schema';
|
|
21
36
|
|
|
22
37
|
export class CommercetoolsCartProvider<
|
|
23
38
|
T extends Cart = Cart
|
|
@@ -30,160 +45,420 @@ export class CommercetoolsCartProvider<
|
|
|
30
45
|
cache: Cache
|
|
31
46
|
) {
|
|
32
47
|
super(schema, cache);
|
|
33
|
-
|
|
34
48
|
this.config = config;
|
|
35
49
|
}
|
|
36
50
|
|
|
37
51
|
@traced()
|
|
38
52
|
public override async getById(
|
|
39
53
|
payload: CartQueryById,
|
|
40
|
-
|
|
54
|
+
reqCtx: RequestContext
|
|
41
55
|
): Promise<T> {
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
result.meta = {
|
|
45
|
-
cache: { hit: false, key: 'empty' },
|
|
46
|
-
placeholder: true
|
|
47
|
-
};
|
|
48
|
-
return this.assert(result);
|
|
49
|
-
}
|
|
56
|
+
try {
|
|
57
|
+
const client = await this.getClient(reqCtx);
|
|
50
58
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
.withId({ ID:
|
|
54
|
-
.get()
|
|
55
|
-
.execute();
|
|
59
|
+
const ctId = payload.cart as CommercetoolsCartIdentifier;
|
|
60
|
+
|
|
61
|
+
const remote = await client.carts.withId({ ID: ctId.key }).get().execute();
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
return this.parseSingle(remote.body, reqCtx);
|
|
64
|
+
} catch (e) {
|
|
65
|
+
return this.createEmptyCart();
|
|
66
|
+
}
|
|
58
67
|
}
|
|
59
68
|
|
|
60
69
|
@traced()
|
|
61
70
|
public override async add(
|
|
62
71
|
payload: CartMutationItemAdd,
|
|
63
|
-
|
|
72
|
+
reqCtx: RequestContext
|
|
73
|
+
): Promise<T> {
|
|
74
|
+
const client = await this.getClient(reqCtx);
|
|
75
|
+
|
|
76
|
+
let cartIdentifier = payload.cart;
|
|
77
|
+
if (!cartIdentifier.key) {
|
|
78
|
+
cartIdentifier = await this.createCart(reqCtx);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return this.applyActions(
|
|
82
|
+
cartIdentifier,
|
|
83
|
+
[
|
|
84
|
+
{
|
|
85
|
+
action: 'addLineItem',
|
|
86
|
+
quantity: payload.quantity,
|
|
87
|
+
sku: payload.sku.key,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
action: 'recalculate',
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
reqCtx
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@traced()
|
|
98
|
+
public override async remove(
|
|
99
|
+
payload: CartMutationItemRemove,
|
|
100
|
+
reqCtx: RequestContext
|
|
101
|
+
): Promise<T> {
|
|
102
|
+
return this.applyActions(
|
|
103
|
+
payload.cart,
|
|
104
|
+
[
|
|
105
|
+
{
|
|
106
|
+
action: 'removeLineItem',
|
|
107
|
+
lineItemId: payload.item.key,
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
action: 'recalculate',
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
reqCtx
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@traced()
|
|
118
|
+
public override async changeQuantity(
|
|
119
|
+
payload: CartMutationItemQuantityChange,
|
|
120
|
+
reqCtx: RequestContext
|
|
64
121
|
): Promise<T> {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
122
|
+
if (payload.quantity === 0) {
|
|
123
|
+
// Changing quantity to 0 is not allowed. Use the remove call instead. This is done to avoid accidental removal of item.
|
|
124
|
+
// Calls with quantity 0 will just be ignored.
|
|
125
|
+
return this.getById({ cart: payload.cart }, reqCtx);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return this.applyActions(
|
|
129
|
+
payload.cart,
|
|
130
|
+
[
|
|
131
|
+
{
|
|
132
|
+
action: 'changeLineItemQuantity',
|
|
133
|
+
lineItemId: payload.item.key,
|
|
134
|
+
quantity: payload.quantity,
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
action: 'recalculate',
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
reqCtx
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
@traced()
|
|
145
|
+
public override async getActiveCartId(
|
|
146
|
+
reqCtx: RequestContext
|
|
147
|
+
): Promise<CartIdentifier> {
|
|
148
|
+
const client = await this.getClient(reqCtx);
|
|
149
|
+
try {
|
|
150
|
+
const carts = await client.activeCart
|
|
151
|
+
.get()
|
|
152
|
+
.execute();
|
|
153
|
+
|
|
154
|
+
return CommercetoolsCartIdentifierSchema.parse({
|
|
155
|
+
key: carts.body.id,
|
|
156
|
+
version: carts.body.version || 0
|
|
157
|
+
});
|
|
158
|
+
} catch (e: any) {
|
|
159
|
+
return CommercetoolsCartIdentifierSchema.parse({
|
|
160
|
+
key: '',
|
|
161
|
+
version: 0
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@traced()
|
|
167
|
+
public override async deleteCart(
|
|
168
|
+
payload: CartMutationDeleteCart,
|
|
169
|
+
reqCtx: RequestContext
|
|
170
|
+
): Promise<T> {
|
|
171
|
+
const client = await this.getClient(reqCtx);
|
|
172
|
+
if (payload.cart.key) {
|
|
173
|
+
const ctId = payload.cart as CommercetoolsCartIdentifier;
|
|
174
|
+
|
|
175
|
+
await client.carts
|
|
176
|
+
.withId({ ID: ctId.key })
|
|
177
|
+
.delete({
|
|
178
|
+
queryArgs: {
|
|
179
|
+
version: ctId.version,
|
|
180
|
+
dataErasure: false,
|
|
77
181
|
},
|
|
78
182
|
})
|
|
79
183
|
.execute();
|
|
184
|
+
}
|
|
80
185
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
186
|
+
const activeCartId = await this.getActiveCartId(reqCtx);
|
|
187
|
+
return this.getById({ cart: activeCartId }, reqCtx);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@traced()
|
|
191
|
+
public override async setShippingInfo(
|
|
192
|
+
payload: CartMutationSetShippingInfo,
|
|
193
|
+
reqCtx: RequestContext
|
|
194
|
+
): Promise<T> {
|
|
195
|
+
const client = await this.getClient(reqCtx);
|
|
196
|
+
const ctId = payload.cart as CommercetoolsCartIdentifier;
|
|
197
|
+
|
|
198
|
+
const actions: MyCartUpdateAction[] = new Array<MyCartUpdateAction>();
|
|
199
|
+
if (payload.shippingMethod) {
|
|
200
|
+
actions.push({
|
|
201
|
+
action: 'setShippingMethod',
|
|
202
|
+
shippingMethod: {
|
|
203
|
+
typeId: 'shipping-method',
|
|
204
|
+
id: payload.shippingMethod.key,
|
|
205
|
+
},
|
|
206
|
+
});
|
|
86
207
|
}
|
|
87
208
|
|
|
88
|
-
|
|
89
|
-
.
|
|
209
|
+
if (payload.shippingAddress) {
|
|
210
|
+
actions.push({
|
|
211
|
+
action: 'setShippingAddress',
|
|
212
|
+
address: {
|
|
213
|
+
country: payload.shippingAddress.countryCode || reqCtx.taxJurisdiction.countryCode || 'US',
|
|
214
|
+
firstName: payload.shippingAddress.firstName,
|
|
215
|
+
lastName: payload.shippingAddress.lastName,
|
|
216
|
+
city: payload.shippingAddress.city,
|
|
217
|
+
postalCode: payload.shippingAddress.postalCode,
|
|
218
|
+
streetName: payload.shippingAddress.streetAddress,
|
|
219
|
+
streetNumber: payload.shippingAddress.streetNumber,
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return this.applyActions(payload.cart, actions, reqCtx);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
@traced()
|
|
228
|
+
public override setBillingAddress(
|
|
229
|
+
payload: CartMutationSetBillingAddress,
|
|
230
|
+
reqCtx: RequestContext
|
|
231
|
+
): Promise<T> {
|
|
232
|
+
return this.applyActions(
|
|
233
|
+
payload.cart,
|
|
234
|
+
[
|
|
235
|
+
{
|
|
236
|
+
action: 'setBillingAddress',
|
|
237
|
+
address: {
|
|
238
|
+
email: payload.notificationEmailAddress,
|
|
239
|
+
mobile: payload.notificationPhoneNumber,
|
|
240
|
+
country: payload.billingAddress.countryCode || reqCtx.taxJurisdiction.countryCode || 'US',
|
|
241
|
+
firstName: payload.billingAddress.firstName,
|
|
242
|
+
lastName: payload.billingAddress.lastName,
|
|
243
|
+
city: payload.billingAddress.city,
|
|
244
|
+
postalCode: payload.billingAddress.postalCode,
|
|
245
|
+
streetName: payload.billingAddress.streetAddress,
|
|
246
|
+
streetNumber: payload.billingAddress.streetNumber,
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
action: 'setCustomerEmail',
|
|
251
|
+
email: payload.notificationEmailAddress,
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
action: 'setCountry',
|
|
255
|
+
country: payload.billingAddress.countryCode || reqCtx.taxJurisdiction.countryCode || 'US',
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
reqCtx
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
@traced()
|
|
263
|
+
public override applyCouponCode(
|
|
264
|
+
payload: CartMutationApplyCoupon,
|
|
265
|
+
reqCtx: RequestContext
|
|
266
|
+
): Promise<T> {
|
|
267
|
+
return this.applyActions(
|
|
268
|
+
payload.cart,
|
|
269
|
+
[
|
|
270
|
+
{
|
|
271
|
+
action: 'addDiscountCode',
|
|
272
|
+
code: payload.couponCode,
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
action: 'recalculate',
|
|
276
|
+
},
|
|
277
|
+
],
|
|
278
|
+
reqCtx
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
@traced()
|
|
283
|
+
public override removeCouponCode(
|
|
284
|
+
payload: CartMutationRemoveCoupon,
|
|
285
|
+
reqCtx: RequestContext
|
|
286
|
+
): Promise<T> {
|
|
287
|
+
return this.applyActions(
|
|
288
|
+
payload.cart,
|
|
289
|
+
[
|
|
290
|
+
{
|
|
291
|
+
action: 'removeDiscountCode',
|
|
292
|
+
discountCode: {
|
|
293
|
+
id: payload.couponCode,
|
|
294
|
+
typeId: 'discount-code',
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
action: 'recalculate',
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
reqCtx
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
@traced()
|
|
306
|
+
public override async checkout(
|
|
307
|
+
payload: CartMutationCheckout,
|
|
308
|
+
reqCtx: RequestContext
|
|
309
|
+
): Promise<OrderIdentifier> {
|
|
310
|
+
// In Commercetools, checkout is done by creating an order from the cart.
|
|
311
|
+
|
|
312
|
+
const client = await this.getClient(reqCtx);
|
|
313
|
+
const ctId = payload.cart as CommercetoolsCartIdentifier;
|
|
314
|
+
|
|
315
|
+
const orderResponse = await client.orders
|
|
90
316
|
.post({
|
|
91
317
|
body: {
|
|
92
|
-
version: version,
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
action: 'addLineItem',
|
|
96
|
-
quantity: payload.quantity,
|
|
97
|
-
productId: payload.product.key,
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
},
|
|
318
|
+
version: ctId.version,
|
|
319
|
+
id: ctId.key,
|
|
320
|
+
}
|
|
101
321
|
})
|
|
102
322
|
.execute();
|
|
103
|
-
|
|
104
|
-
|
|
323
|
+
return CommercetoolsOrderIdentifierSchema.parse({
|
|
324
|
+
key: orderResponse.body.id,
|
|
325
|
+
version: orderResponse.body.version || 0,
|
|
326
|
+
});
|
|
105
327
|
}
|
|
106
328
|
|
|
107
329
|
@traced()
|
|
108
|
-
public override async
|
|
109
|
-
payload:
|
|
110
|
-
|
|
330
|
+
public override async changeCurrency(
|
|
331
|
+
payload: CartMutationChangeCurrency,
|
|
332
|
+
reqCtx: RequestContext
|
|
111
333
|
): Promise<T> {
|
|
112
|
-
|
|
334
|
+
// ok, to do this we have to actually build a new cart, copy over all the items, and then delete the old cart.
|
|
335
|
+
// because Commercetools does not support changing currency of an existing cart.
|
|
336
|
+
|
|
337
|
+
// This is obviously not ideal, but it is what it is.
|
|
113
338
|
|
|
114
|
-
const
|
|
339
|
+
const client = await this.getClient(reqCtx);
|
|
340
|
+
const currentCart = await client.carts
|
|
115
341
|
.withId({ ID: payload.cart.key })
|
|
116
342
|
.get()
|
|
117
343
|
.execute();
|
|
118
|
-
|
|
119
|
-
const remote = await client
|
|
120
|
-
.withId({ ID: payload.cart.key })
|
|
344
|
+
const newCart = await client.carts
|
|
121
345
|
.post({
|
|
122
346
|
body: {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
{
|
|
126
|
-
action: 'removeLineItem',
|
|
127
|
-
lineItemId: payload.item.key,
|
|
128
|
-
},
|
|
129
|
-
],
|
|
347
|
+
currency: payload.newCurrency,
|
|
348
|
+
locale: reqCtx.languageContext.locale,
|
|
130
349
|
},
|
|
131
350
|
})
|
|
132
351
|
.execute();
|
|
133
352
|
|
|
134
|
-
|
|
135
|
-
|
|
353
|
+
const newCartId = CommercetoolsCartIdentifierSchema.parse({
|
|
354
|
+
key: newCart.body.id,
|
|
355
|
+
version: newCart.body.version || 0,
|
|
356
|
+
});
|
|
136
357
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
358
|
+
const cartItemAdds: MyCartUpdateAction[] = currentCart.body.lineItems.map(
|
|
359
|
+
(item) => ({
|
|
360
|
+
action: 'addLineItem',
|
|
361
|
+
sku: item.variant.sku || '',
|
|
362
|
+
quantity: item.quantity,
|
|
363
|
+
})
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
const response = await this.applyActions(
|
|
367
|
+
newCartId,
|
|
368
|
+
[
|
|
369
|
+
...cartItemAdds,
|
|
370
|
+
{
|
|
371
|
+
action: 'recalculate',
|
|
372
|
+
},
|
|
373
|
+
],
|
|
374
|
+
reqCtx
|
|
375
|
+
);
|
|
143
376
|
|
|
144
|
-
|
|
377
|
+
// now delete the old cart.
|
|
378
|
+
await client.carts
|
|
145
379
|
.withId({ ID: payload.cart.key })
|
|
146
|
-
.
|
|
380
|
+
.delete({
|
|
381
|
+
queryArgs: {
|
|
382
|
+
version: currentCart.body.version || 0,
|
|
383
|
+
dataErasure: false,
|
|
384
|
+
},
|
|
385
|
+
})
|
|
147
386
|
.execute();
|
|
148
387
|
|
|
149
|
-
|
|
150
|
-
|
|
388
|
+
return response;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
protected async createCart(reqCtx: RequestContext): Promise<CartIdentifier> {
|
|
392
|
+
const client = await this.getClient(reqCtx);
|
|
393
|
+
const response = await client.carts
|
|
151
394
|
.post({
|
|
152
395
|
body: {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
action: 'changeLineItemQuantity',
|
|
157
|
-
lineItemId: payload.item.key,
|
|
158
|
-
quantity: payload.quantity,
|
|
159
|
-
},
|
|
160
|
-
],
|
|
396
|
+
currency: reqCtx.languageContext.currencyCode || 'USD',
|
|
397
|
+
country: reqCtx.taxJurisdiction.countryCode || 'US',
|
|
398
|
+
locale: reqCtx.languageContext.locale,
|
|
161
399
|
},
|
|
162
400
|
})
|
|
163
401
|
.execute();
|
|
164
402
|
|
|
165
|
-
return
|
|
403
|
+
return CommercetoolsCartIdentifierSchema.parse({
|
|
404
|
+
key: response.body.id,
|
|
405
|
+
version: response.body.version || 0,
|
|
406
|
+
});
|
|
166
407
|
}
|
|
167
408
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
409
|
+
protected async applyActions(
|
|
410
|
+
cart: CartIdentifier,
|
|
411
|
+
actions: MyCartUpdateAction[],
|
|
412
|
+
reqCtx: RequestContext
|
|
413
|
+
): Promise<T> {
|
|
414
|
+
const client = await this.getClient(reqCtx);
|
|
415
|
+
const ctId = cart as CommercetoolsCartIdentifier;
|
|
173
416
|
|
|
174
|
-
const cartClient = client
|
|
175
|
-
.withProjectKey({ projectKey: this.config.projectKey })
|
|
176
|
-
.carts();
|
|
177
417
|
|
|
178
|
-
|
|
418
|
+
|
|
419
|
+
const response = await client.carts
|
|
420
|
+
.withId({ ID: ctId.key })
|
|
421
|
+
.post({
|
|
422
|
+
body: {
|
|
423
|
+
version: ctId.version,
|
|
424
|
+
actions,
|
|
425
|
+
},
|
|
426
|
+
})
|
|
427
|
+
.execute();
|
|
428
|
+
|
|
429
|
+
return this.parseSingle(response.body, reqCtx);
|
|
430
|
+
|
|
179
431
|
}
|
|
180
432
|
|
|
433
|
+
/**
|
|
434
|
+
* Creates a new Commercetools client, optionally upgrading it from Anonymous mode to Guest mode.
|
|
435
|
+
* For now, any Query or Mutation will require an upgrade to Guest mode.
|
|
436
|
+
* In the future, maybe we can delay this upgrade until we actually need it.
|
|
437
|
+
*
|
|
438
|
+
* @param reqCtx
|
|
439
|
+
* @param anonymousCall
|
|
440
|
+
* @returns
|
|
441
|
+
*/
|
|
181
442
|
@traced()
|
|
182
|
-
protected
|
|
183
|
-
const
|
|
443
|
+
protected async getClient(reqCtx: RequestContext) {
|
|
444
|
+
const client = await new CommercetoolsClient(this.config).getClient(reqCtx);
|
|
445
|
+
|
|
446
|
+
const clientWithProject = client.withProjectKey({ projectKey: this.config.projectKey });
|
|
447
|
+
return {
|
|
448
|
+
carts: clientWithProject.me().carts(),
|
|
449
|
+
activeCart: clientWithProject.me().activeCart(),
|
|
450
|
+
orders: clientWithProject.me().orders(),
|
|
184
451
|
|
|
185
|
-
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
protected override parseSingle(remote: CTCart, reqCtx: RequestContext): T {
|
|
456
|
+
const result = this.newModel();
|
|
186
457
|
|
|
458
|
+
result.identifier = CommercetoolsCartIdentifierSchema.parse({
|
|
459
|
+
key: remote.id,
|
|
460
|
+
version: remote.version || 0,
|
|
461
|
+
});
|
|
187
462
|
|
|
188
463
|
result.name = remote.custom?.fields['name'] || '';
|
|
189
464
|
result.description = remote.custom?.fields['description'] || '';
|
|
@@ -192,42 +467,44 @@ export class CommercetoolsCartProvider<
|
|
|
192
467
|
const shippingTotal = remote.shippingInfo?.price.centAmount || 0;
|
|
193
468
|
const productTotal = grandTotal - shippingTotal;
|
|
194
469
|
const taxTotal = remote.taxedPrice?.totalTax?.centAmount || 0;
|
|
195
|
-
const discountTotal =
|
|
470
|
+
const discountTotal =
|
|
471
|
+
remote.discountOnTotalPrice?.discountedAmount.centAmount || 0;
|
|
196
472
|
const surchargeTotal = 0;
|
|
197
473
|
const currency = remote.totalPrice.currencyCode as Currency;
|
|
198
474
|
|
|
199
475
|
result.price = {
|
|
200
476
|
totalTax: {
|
|
201
477
|
value: taxTotal / 100,
|
|
202
|
-
currency
|
|
478
|
+
currency,
|
|
203
479
|
},
|
|
204
480
|
totalDiscount: {
|
|
205
|
-
value: discountTotal/ 100,
|
|
206
|
-
currency
|
|
481
|
+
value: discountTotal / 100,
|
|
482
|
+
currency,
|
|
207
483
|
},
|
|
208
484
|
totalSurcharge: {
|
|
209
485
|
value: surchargeTotal / 100,
|
|
210
|
-
currency
|
|
486
|
+
currency,
|
|
211
487
|
},
|
|
212
488
|
totalShipping: {
|
|
213
489
|
value: shippingTotal / 100,
|
|
214
490
|
currency: remote.shippingInfo?.price.currencyCode as Currency,
|
|
215
491
|
},
|
|
216
492
|
totalProductPrice: {
|
|
217
|
-
value: productTotal
|
|
218
|
-
currency
|
|
493
|
+
value: productTotal / 100,
|
|
494
|
+
currency,
|
|
219
495
|
},
|
|
220
496
|
grandTotal: {
|
|
221
497
|
value: grandTotal / 100,
|
|
222
|
-
currency
|
|
223
|
-
}
|
|
224
|
-
}
|
|
498
|
+
currency,
|
|
499
|
+
},
|
|
500
|
+
};
|
|
225
501
|
|
|
226
502
|
for (const remoteItem of remote.lineItems) {
|
|
227
503
|
const item = CartItemSchema.parse({});
|
|
228
504
|
|
|
229
505
|
item.identifier.key = remoteItem.id;
|
|
230
506
|
item.product.key = remoteItem.productId;
|
|
507
|
+
item.sku.key = remoteItem.variant.sku || '';
|
|
231
508
|
item.quantity = remoteItem.quantity;
|
|
232
509
|
|
|
233
510
|
const unitPrice = remoteItem.price.value.centAmount;
|
|
@@ -235,36 +512,36 @@ export class CommercetoolsCartProvider<
|
|
|
235
512
|
const totalDiscount = remoteItem.price.discounted?.value.centAmount || 0;
|
|
236
513
|
const unitDiscount = totalDiscount / remoteItem.quantity;
|
|
237
514
|
|
|
238
|
-
|
|
239
515
|
item.price = {
|
|
240
516
|
unitPrice: {
|
|
241
517
|
value: unitPrice / 100,
|
|
242
|
-
currency
|
|
518
|
+
currency,
|
|
243
519
|
},
|
|
244
520
|
unitDiscount: {
|
|
245
|
-
value:
|
|
246
|
-
currency
|
|
521
|
+
value: unitDiscount / 100,
|
|
522
|
+
currency,
|
|
247
523
|
},
|
|
248
524
|
totalPrice: {
|
|
249
525
|
value: (totalPrice || 0) / 100,
|
|
250
|
-
currency
|
|
526
|
+
currency,
|
|
251
527
|
},
|
|
252
528
|
totalDiscount: {
|
|
253
529
|
value: totalDiscount / 100,
|
|
254
|
-
currency
|
|
530
|
+
currency,
|
|
255
531
|
},
|
|
256
|
-
}
|
|
532
|
+
};
|
|
257
533
|
|
|
258
534
|
result.items.push(item);
|
|
259
535
|
}
|
|
260
536
|
|
|
261
537
|
result.meta = {
|
|
262
|
-
cache: {
|
|
263
|
-
|
|
538
|
+
cache: {
|
|
539
|
+
hit: false,
|
|
540
|
+
key: this.generateCacheKeySingle(result.identifier, reqCtx),
|
|
541
|
+
},
|
|
542
|
+
placeholder: false,
|
|
264
543
|
};
|
|
265
544
|
|
|
266
545
|
return this.assert(result);
|
|
267
546
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
547
|
}
|