@reactionary/source 0.0.52 → 0.2.16
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/.env-template +19 -0
- package/.github/workflows/pull-request.yml +3 -1
- package/.github/workflows/release.yml +9 -0
- package/.vscode/extensions.json +0 -2
- package/LICENSE +21 -0
- package/README.md +175 -23
- package/core/package.json +6 -3
- package/core/src/cache/cache.interface.ts +1 -0
- package/core/src/cache/index.ts +4 -0
- package/core/src/cache/memory-cache.ts +30 -2
- package/core/src/cache/noop-cache.ts +15 -1
- package/core/src/cache/redis-cache.ts +20 -0
- package/core/src/client/client-builder.ts +71 -54
- package/core/src/client/client.ts +9 -47
- package/core/src/client/index.ts +2 -0
- package/core/src/decorators/index.ts +1 -0
- package/core/src/decorators/reactionary.decorator.ts +203 -34
- package/core/src/index.ts +6 -19
- package/core/src/initialization.ts +1 -18
- package/core/src/metrics/metrics.ts +67 -0
- package/core/src/providers/analytics.provider.ts +1 -6
- package/core/src/providers/base.provider.ts +5 -69
- package/core/src/providers/cart.provider.ts +15 -55
- package/core/src/providers/category.provider.ts +7 -11
- package/core/src/providers/checkout.provider.ts +17 -15
- package/core/src/providers/identity.provider.ts +6 -8
- package/core/src/providers/index.ts +2 -1
- package/core/src/providers/inventory.provider.ts +15 -5
- package/core/src/providers/order-search.provider.ts +29 -0
- package/core/src/providers/order.provider.ts +47 -15
- package/core/src/providers/price.provider.ts +30 -36
- package/core/src/providers/product-search.provider.ts +61 -0
- package/core/src/providers/product.provider.ts +71 -12
- package/core/src/providers/profile.provider.ts +74 -14
- package/core/src/providers/store.provider.ts +3 -5
- package/core/src/schemas/capabilities.schema.ts +10 -3
- package/core/src/schemas/errors/generic.error.ts +9 -0
- package/core/src/schemas/errors/index.ts +4 -0
- package/core/src/schemas/errors/invalid-input.error.ts +9 -0
- package/core/src/schemas/errors/invalid-output.error.ts +9 -0
- package/core/src/schemas/errors/not-found.error.ts +9 -0
- package/core/src/schemas/index.ts +7 -0
- package/core/src/schemas/models/analytics.model.ts +2 -1
- package/core/src/schemas/models/base.model.ts +6 -24
- package/core/src/schemas/models/cart.model.ts +5 -8
- package/core/src/schemas/models/category.model.ts +4 -9
- package/core/src/schemas/models/checkout.model.ts +6 -7
- package/core/src/schemas/models/cost.model.ts +4 -3
- package/core/src/schemas/models/currency.model.ts +2 -1
- package/core/src/schemas/models/identifiers.model.ts +106 -62
- package/core/src/schemas/models/identity.model.ts +10 -19
- package/core/src/schemas/models/index.ts +2 -1
- package/core/src/schemas/models/inventory.model.ts +8 -5
- package/core/src/schemas/models/order-search.model.ts +28 -0
- package/core/src/schemas/models/order.model.ts +20 -26
- package/core/src/schemas/models/payment.model.ts +14 -17
- package/core/src/schemas/models/price.model.ts +11 -11
- package/core/src/schemas/models/product-search.model.ts +42 -0
- package/core/src/schemas/models/product.model.ts +64 -22
- package/core/src/schemas/models/profile.model.ts +19 -22
- package/core/src/schemas/models/shipping-method.model.ts +24 -29
- package/core/src/schemas/models/store.model.ts +9 -5
- package/core/src/schemas/mutations/analytics.mutation.ts +8 -7
- package/core/src/schemas/mutations/base.mutation.ts +2 -1
- package/core/src/schemas/mutations/cart.mutation.ts +33 -33
- package/core/src/schemas/mutations/checkout.mutation.ts +23 -30
- package/core/src/schemas/mutations/identity.mutation.ts +4 -3
- package/core/src/schemas/mutations/profile.mutation.ts +38 -3
- package/core/src/schemas/queries/base.query.ts +2 -1
- package/core/src/schemas/queries/cart.query.ts +3 -3
- package/core/src/schemas/queries/category.query.ts +18 -18
- package/core/src/schemas/queries/checkout.query.ts +7 -9
- package/core/src/schemas/queries/identity.query.ts +2 -1
- package/core/src/schemas/queries/index.ts +2 -1
- package/core/src/schemas/queries/inventory.query.ts +5 -5
- package/core/src/schemas/queries/order-search.query.ts +10 -0
- package/core/src/schemas/queries/order.query.ts +3 -2
- package/core/src/schemas/queries/price.query.ts +10 -4
- package/core/src/schemas/queries/product-search.query.ts +16 -0
- package/core/src/schemas/queries/product.query.ts +13 -6
- package/core/src/schemas/queries/profile.query.ts +5 -2
- package/core/src/schemas/queries/store.query.ts +6 -5
- package/core/src/schemas/result.ts +107 -0
- package/core/src/schemas/session.schema.ts +4 -4
- package/core/src/test/reactionary.decorator.spec.ts +249 -0
- package/core/src/zod-utils.ts +19 -0
- package/core/tsconfig.json +1 -1
- package/core/tsconfig.spec.json +2 -26
- package/core/vitest.config.ts +14 -0
- package/documentation/1-purpose.md +114 -0
- package/documentation/2-getting-started.md +229 -0
- package/documentation/3-querying-and-changing-data.md +74 -0
- package/documentation/4-product-data.md +107 -0
- package/documentation/5-cart-and-checkout.md +211 -0
- package/documentation/6-product-search.md +143 -0
- package/documentation/7-marketing.md +3 -0
- package/eslint.config.mjs +1 -0
- package/examples/node/eslint.config.mjs +1 -4
- package/examples/node/package.json +10 -3
- package/examples/node/project.json +4 -1
- package/examples/node/src/basic/basic-node-provider-model-extension.spec.ts +22 -23
- package/examples/node/src/basic/basic-node-provider-query-extension.spec.ts +15 -11
- package/examples/node/src/basic/basic-node-setup.spec.ts +44 -28
- package/examples/node/src/basic/client-creation.spec.ts +53 -0
- package/examples/node/src/capabilities/cart.spec.ts +255 -0
- package/examples/node/src/capabilities/category.spec.ts +193 -0
- package/examples/node/src/capabilities/checkout.spec.ts +341 -0
- package/examples/node/src/capabilities/identity.spec.ts +93 -0
- package/examples/node/src/capabilities/inventory.spec.ts +66 -0
- package/examples/node/src/capabilities/order-search.spec.ts +265 -0
- package/examples/node/src/capabilities/order.spec.ts +91 -0
- package/examples/node/src/capabilities/price.spec.ts +51 -0
- package/examples/node/src/capabilities/product-search.spec.ts +293 -0
- package/examples/node/src/capabilities/product.spec.ts +122 -0
- package/examples/node/src/capabilities/profile.spec.ts +316 -0
- package/examples/node/src/capabilities/store.spec.ts +26 -0
- package/examples/node/src/utils.ts +147 -0
- package/examples/node/tsconfig.json +9 -12
- package/examples/node/tsconfig.lib.json +1 -2
- package/examples/node/tsconfig.spec.json +2 -14
- package/examples/node/vitest.config.ts +14 -0
- package/migrations.json +22 -5
- package/nx.json +8 -47
- package/package.json +24 -96
- package/providers/algolia/README.md +39 -2
- package/providers/algolia/package.json +2 -1
- package/providers/algolia/src/core/initialize.ts +7 -14
- package/providers/algolia/src/index.ts +2 -4
- package/providers/algolia/src/providers/index.ts +1 -0
- package/providers/algolia/src/providers/product-search.provider.ts +241 -0
- package/providers/algolia/src/schema/capabilities.schema.ts +2 -3
- package/providers/algolia/src/schema/index.ts +3 -0
- package/providers/algolia/src/schema/search.schema.ts +8 -8
- package/providers/algolia/tsconfig.json +1 -1
- package/providers/algolia/tsconfig.lib.json +1 -1
- package/providers/algolia/tsconfig.spec.json +2 -14
- package/providers/algolia/vitest.config.ts +14 -0
- package/providers/commercetools/README.md +30 -3
- package/providers/commercetools/package.json +2 -1
- package/providers/commercetools/src/core/client.ts +178 -99
- package/providers/commercetools/src/core/initialize.ts +130 -74
- package/providers/commercetools/src/core/token-cache.ts +45 -0
- package/providers/commercetools/src/index.ts +3 -2
- package/providers/commercetools/src/providers/cart.provider.ts +281 -341
- package/providers/commercetools/src/providers/category.provider.ts +223 -138
- package/providers/commercetools/src/providers/checkout.provider.ts +631 -449
- package/providers/commercetools/src/providers/identity.provider.ts +50 -29
- package/providers/commercetools/src/providers/index.ts +2 -2
- package/providers/commercetools/src/providers/inventory.provider.ts +76 -74
- package/providers/commercetools/src/providers/order-search.provider.ts +220 -0
- package/providers/commercetools/src/providers/order.provider.ts +96 -61
- package/providers/commercetools/src/providers/price.provider.ts +147 -117
- package/providers/commercetools/src/providers/product-search.provider.ts +528 -0
- package/providers/commercetools/src/providers/product.provider.ts +249 -74
- package/providers/commercetools/src/providers/profile.provider.ts +445 -28
- package/providers/commercetools/src/providers/store.provider.ts +54 -40
- package/providers/commercetools/src/schema/capabilities.schema.ts +3 -1
- package/providers/commercetools/src/schema/commercetools.schema.ts +17 -3
- package/providers/commercetools/src/schema/configuration.schema.ts +1 -0
- package/providers/commercetools/src/schema/session.schema.ts +7 -0
- package/providers/commercetools/src/test/caching.spec.ts +82 -0
- package/providers/commercetools/src/test/identity.spec.ts +109 -0
- package/providers/commercetools/src/test/test-utils.ts +21 -19
- package/providers/commercetools/tsconfig.json +1 -1
- package/providers/commercetools/tsconfig.lib.json +1 -1
- package/providers/commercetools/tsconfig.spec.json +2 -14
- package/providers/commercetools/vitest.config.ts +15 -0
- package/providers/fake/README.md +20 -4
- package/providers/fake/package.json +2 -1
- package/providers/fake/src/core/initialize.ts +47 -49
- package/providers/fake/src/providers/analytics.provider.ts +5 -7
- package/providers/fake/src/providers/cart.provider.ts +163 -92
- package/providers/fake/src/providers/category.provider.ts +78 -50
- package/providers/fake/src/providers/checkout.provider.ts +254 -0
- package/providers/fake/src/providers/identity.provider.ts +57 -65
- package/providers/fake/src/providers/index.ts +6 -2
- package/providers/fake/src/providers/inventory.provider.ts +40 -36
- package/providers/fake/src/providers/order-search.provider.ts +78 -0
- package/providers/fake/src/providers/order.provider.ts +106 -0
- package/providers/fake/src/providers/price.provider.ts +93 -41
- package/providers/fake/src/providers/product-search.provider.ts +206 -0
- package/providers/fake/src/providers/product.provider.ts +56 -41
- package/providers/fake/src/providers/profile.provider.ts +147 -0
- package/providers/fake/src/providers/store.provider.ts +30 -20
- package/providers/fake/src/schema/capabilities.schema.ts +5 -1
- package/providers/fake/src/test/cart.provider.spec.ts +59 -80
- package/providers/fake/src/test/category.provider.spec.ts +145 -87
- package/providers/fake/src/test/checkout.provider.spec.ts +222 -0
- package/providers/fake/src/test/order-search.provider.spec.ts +50 -0
- package/providers/fake/src/test/order.provider.spec.ts +44 -0
- package/providers/fake/src/test/price.provider.spec.ts +50 -45
- package/providers/fake/src/test/product.provider.spec.ts +15 -7
- package/providers/fake/src/test/profile.provider.spec.ts +167 -0
- package/providers/fake/tsconfig.json +1 -1
- package/providers/fake/tsconfig.lib.json +1 -1
- package/providers/fake/tsconfig.spec.json +2 -12
- package/providers/fake/vitest.config.ts +14 -0
- package/providers/medusa/README.md +30 -0
- package/providers/medusa/TESTING.md +98 -0
- package/providers/medusa/eslint.config.mjs +19 -0
- package/providers/medusa/package.json +22 -0
- package/providers/medusa/project.json +34 -0
- package/providers/medusa/src/core/client.ts +370 -0
- package/providers/medusa/src/core/initialize.ts +78 -0
- package/providers/medusa/src/index.ts +13 -0
- package/providers/medusa/src/providers/cart.provider.ts +575 -0
- package/providers/medusa/src/providers/category.provider.ts +247 -0
- package/providers/medusa/src/providers/checkout.provider.ts +636 -0
- package/providers/medusa/src/providers/identity.provider.ts +137 -0
- package/providers/medusa/src/providers/inventory.provider.ts +173 -0
- package/providers/medusa/src/providers/order-search.provider.ts +202 -0
- package/providers/medusa/src/providers/order.provider.ts +226 -0
- package/providers/medusa/src/providers/price.provider.ts +140 -0
- package/providers/medusa/src/providers/product-search.provider.ts +243 -0
- package/providers/medusa/src/providers/product.provider.ts +261 -0
- package/providers/medusa/src/providers/profile.provider.ts +392 -0
- package/providers/medusa/src/schema/capabilities.schema.ts +18 -0
- package/providers/medusa/src/schema/configuration.schema.ts +11 -0
- package/providers/medusa/src/schema/medusa.schema.ts +31 -0
- package/providers/medusa/src/test/cart.provider.spec.ts +240 -0
- package/providers/medusa/src/test/category.provider.spec.ts +231 -0
- package/providers/medusa/src/test/checkout.spec.ts +349 -0
- package/providers/medusa/src/test/identity.provider.spec.ts +122 -0
- package/providers/medusa/src/test/inventory.provider.spec.ts +88 -0
- package/providers/medusa/src/test/large-cart.provider.spec.ts +103 -0
- package/providers/medusa/src/test/price.provider.spec.ts +104 -0
- package/providers/medusa/src/test/product.provider.spec.ts +146 -0
- package/providers/medusa/src/test/search.provider.spec.ts +203 -0
- package/providers/medusa/src/test/test-utils.ts +13 -0
- package/providers/medusa/src/utils/medusa-helpers.ts +89 -0
- package/providers/medusa/tsconfig.json +21 -0
- package/providers/medusa/tsconfig.lib.json +9 -0
- package/providers/medusa/tsconfig.spec.json +4 -0
- package/providers/medusa/vitest.config.ts +15 -0
- package/providers/meilisearch/README.md +48 -0
- package/providers/meilisearch/eslint.config.mjs +22 -0
- package/providers/meilisearch/package.json +13 -0
- package/providers/meilisearch/project.json +34 -0
- package/providers/meilisearch/src/core/initialize.ts +21 -0
- package/providers/meilisearch/src/index.ts +6 -0
- package/providers/meilisearch/src/providers/index.ts +1 -0
- package/providers/meilisearch/src/providers/order-search.provider.ts +222 -0
- package/providers/meilisearch/src/providers/product-search.provider.ts +251 -0
- package/providers/meilisearch/src/schema/capabilities.schema.ts +10 -0
- package/providers/meilisearch/src/schema/configuration.schema.ts +11 -0
- package/providers/meilisearch/src/schema/index.ts +3 -0
- package/providers/meilisearch/src/schema/search.schema.ts +14 -0
- package/providers/meilisearch/tsconfig.json +24 -0
- package/providers/meilisearch/tsconfig.lib.json +10 -0
- package/providers/meilisearch/tsconfig.spec.json +4 -0
- package/providers/meilisearch/vitest.config.ts +14 -0
- package/providers/posthog/package.json +2 -1
- package/providers/posthog/tsconfig.json +1 -1
- package/tsconfig.base.json +5 -0
- package/vitest.config.ts +10 -0
- package/core/src/providers/search.provider.ts +0 -18
- package/core/src/schemas/models/search.model.ts +0 -36
- package/core/src/schemas/queries/search.query.ts +0 -9
- package/examples/next/.swcrc +0 -30
- package/examples/next/eslint.config.mjs +0 -21
- package/examples/next/index.d.ts +0 -6
- package/examples/next/next-env.d.ts +0 -5
- package/examples/next/next.config.js +0 -31
- package/examples/next/project.json +0 -9
- package/examples/next/public/.gitkeep +0 -0
- package/examples/next/public/favicon.ico +0 -0
- package/examples/next/src/app/global.css +0 -0
- package/examples/next/src/app/layout.tsx +0 -18
- package/examples/next/src/app/page.module.scss +0 -2
- package/examples/next/src/app/page.tsx +0 -47
- package/examples/next/src/instrumentation.ts +0 -9
- package/examples/next/tsconfig.json +0 -44
- package/examples/node/jest.config.ts +0 -10
- package/jest.config.ts +0 -6
- package/jest.preset.js +0 -3
- package/providers/algolia/jest.config.ts +0 -10
- package/providers/algolia/src/providers/product.provider.ts +0 -66
- package/providers/algolia/src/providers/search.provider.ts +0 -106
- package/providers/algolia/src/test/search.provider.spec.ts +0 -91
- package/providers/commercetools/jest.config.cjs +0 -10
- package/providers/commercetools/src/providers/search.provider.ts +0 -96
- package/providers/commercetools/src/test/cart.provider.spec.ts +0 -199
- package/providers/commercetools/src/test/category.provider.spec.ts +0 -168
- package/providers/commercetools/src/test/checkout.provider.spec.ts +0 -312
- package/providers/commercetools/src/test/identity.provider.spec.ts +0 -88
- package/providers/commercetools/src/test/inventory.provider.spec.ts +0 -41
- package/providers/commercetools/src/test/price.provider.spec.ts +0 -81
- package/providers/commercetools/src/test/product.provider.spec.ts +0 -80
- package/providers/commercetools/src/test/profile.provider.spec.ts +0 -49
- package/providers/commercetools/src/test/search.provider.spec.ts +0 -61
- package/providers/commercetools/src/test/store.provider.spec.ts +0 -37
- package/providers/fake/jest.config.cjs +0 -10
- package/providers/fake/src/providers/search.provider.ts +0 -132
|
@@ -1,262 +1,401 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Address as CTAddress, Cart as CTCart, Payment as CTPayment, ShippingMethod as CTShippingMethod, LineItem, MyCartUpdateAction } from '@commercetools/platform-sdk';
|
|
2
2
|
import type {
|
|
3
|
+
Address,
|
|
3
4
|
Cache,
|
|
4
5
|
Checkout,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
ShippingMethod,
|
|
8
|
-
CheckoutMutationInitiateCheckout,
|
|
9
|
-
CheckoutMutationSetShippingAddress,
|
|
10
|
-
CheckoutMutationFinalizeCheckout,
|
|
6
|
+
CheckoutIdentifier,
|
|
7
|
+
CheckoutItem,
|
|
11
8
|
CheckoutMutationAddPaymentInstruction,
|
|
9
|
+
CheckoutMutationFinalizeCheckout,
|
|
10
|
+
CheckoutMutationInitiateCheckout,
|
|
12
11
|
CheckoutMutationRemovePaymentInstruction,
|
|
12
|
+
CheckoutMutationSetShippingAddress,
|
|
13
13
|
CheckoutMutationSetShippingInstruction,
|
|
14
14
|
CheckoutQueryById,
|
|
15
15
|
CheckoutQueryForAvailablePaymentMethods,
|
|
16
16
|
CheckoutQueryForAvailableShippingMethods,
|
|
17
|
-
|
|
17
|
+
CostBreakDown,
|
|
18
18
|
Currency,
|
|
19
|
+
MonetaryAmount,
|
|
20
|
+
NotFoundError,
|
|
21
|
+
PaymentInstruction,
|
|
22
|
+
PaymentInstructionIdentifier,
|
|
23
|
+
PaymentMethod,
|
|
24
|
+
PaymentMethodIdentifier,
|
|
25
|
+
PaymentStatus,
|
|
26
|
+
RequestContext,
|
|
27
|
+
Result,
|
|
19
28
|
ShippingInstruction,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
import
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
ShippingMethod,
|
|
30
|
+
ShippingMethodIdentifier,
|
|
31
|
+
} from '@reactionary/core';
|
|
32
|
+
import {
|
|
33
|
+
CheckoutItemSchema,
|
|
34
|
+
CheckoutMutationAddPaymentInstructionSchema,
|
|
35
|
+
CheckoutMutationFinalizeCheckoutSchema,
|
|
36
|
+
CheckoutMutationInitiateCheckoutSchema,
|
|
37
|
+
CheckoutMutationRemovePaymentInstructionSchema,
|
|
38
|
+
CheckoutMutationSetShippingAddressSchema,
|
|
39
|
+
CheckoutMutationSetShippingInstructionSchema,
|
|
40
|
+
CheckoutProvider,
|
|
41
|
+
CheckoutQueryByIdSchema,
|
|
42
|
+
CheckoutQueryForAvailablePaymentMethodsSchema,
|
|
43
|
+
CheckoutQueryForAvailableShippingMethodsSchema,
|
|
44
|
+
CheckoutSchema,
|
|
45
|
+
PaymentMethodSchema,
|
|
46
|
+
Reactionary,
|
|
47
|
+
ShippingMethodSchema,
|
|
48
|
+
success,
|
|
49
|
+
error,
|
|
50
|
+
unwrapValue
|
|
51
|
+
} from '@reactionary/core';
|
|
52
|
+
import z from 'zod';
|
|
53
|
+
import type { CommercetoolsAPI } from '../core/client.js';
|
|
54
|
+
import {
|
|
55
|
+
type CommercetoolsCartIdentifier,
|
|
56
|
+
type CommercetoolsCheckoutIdentifier,
|
|
57
|
+
} from '../schema/commercetools.schema.js';
|
|
58
|
+
import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
|
|
30
59
|
|
|
31
60
|
export class CheckoutNotReadyForFinalizationError extends Error {
|
|
32
61
|
constructor(public checkoutIdentifier: CheckoutIdentifier) {
|
|
33
|
-
super(
|
|
34
|
-
|
|
62
|
+
super(
|
|
63
|
+
'Checkout is not ready for finalization. Ensure all required fields are set and valid. ' +
|
|
64
|
+
(checkoutIdentifier
|
|
65
|
+
? `Checkout ID: ${JSON.stringify(checkoutIdentifier)}`
|
|
66
|
+
: '')
|
|
67
|
+
);
|
|
68
|
+
this.name = 'CheckoutNotReadyForFinalizationError';
|
|
35
69
|
}
|
|
36
70
|
}
|
|
37
71
|
|
|
38
|
-
|
|
39
|
-
export class CommercetoolsCheckoutProvider<
|
|
40
|
-
T extends Checkout = Checkout
|
|
41
|
-
> extends CheckoutProvider<T> {
|
|
72
|
+
export class CommercetoolsCheckoutProvider extends CheckoutProvider {
|
|
42
73
|
protected config: CommercetoolsConfiguration;
|
|
74
|
+
protected commercetools: CommercetoolsAPI;
|
|
43
75
|
|
|
44
|
-
constructor(
|
|
45
|
-
|
|
76
|
+
constructor(
|
|
77
|
+
config: CommercetoolsConfiguration,
|
|
78
|
+
cache: Cache,
|
|
79
|
+
context: RequestContext,
|
|
80
|
+
commercetools: CommercetoolsAPI
|
|
81
|
+
) {
|
|
82
|
+
super(cache, context);
|
|
46
83
|
|
|
47
84
|
this.config = config;
|
|
85
|
+
this.commercetools = commercetools;
|
|
48
86
|
}
|
|
49
87
|
|
|
50
|
-
protected async getClient(
|
|
51
|
-
const client = await
|
|
88
|
+
protected async getClient() {
|
|
89
|
+
const client = await this.commercetools.getClient();
|
|
52
90
|
|
|
53
91
|
return {
|
|
54
|
-
payments: client
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
92
|
+
payments: client
|
|
93
|
+
.withProjectKey({ projectKey: this.config.projectKey })
|
|
94
|
+
.me()
|
|
95
|
+
.payments(),
|
|
96
|
+
carts: client
|
|
97
|
+
.withProjectKey({ projectKey: this.config.projectKey })
|
|
98
|
+
.me()
|
|
99
|
+
.carts(),
|
|
100
|
+
shippingMethods: client
|
|
101
|
+
.withProjectKey({ projectKey: this.config.projectKey })
|
|
102
|
+
.shippingMethods(),
|
|
103
|
+
orders: client
|
|
104
|
+
.withProjectKey({ projectKey: this.config.projectKey })
|
|
105
|
+
.me()
|
|
106
|
+
.orders(),
|
|
58
107
|
};
|
|
59
108
|
}
|
|
60
109
|
|
|
61
|
-
|
|
110
|
+
@Reactionary({
|
|
111
|
+
inputSchema: CheckoutMutationInitiateCheckoutSchema,
|
|
112
|
+
outputSchema: CheckoutSchema,
|
|
113
|
+
})
|
|
114
|
+
public async initiateCheckoutForCart(
|
|
115
|
+
payload: CheckoutMutationInitiateCheckout
|
|
116
|
+
): Promise<Result<Checkout>> {
|
|
62
117
|
// so......we could copy the cart......
|
|
63
118
|
|
|
64
|
-
const client = await this.getClient(
|
|
65
|
-
|
|
66
|
-
const cart = await client.carts
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
119
|
+
const client = await this.getClient();
|
|
120
|
+
|
|
121
|
+
const cart = await client.carts
|
|
122
|
+
.withId({ ID: payload.cart.identifier.key })
|
|
123
|
+
.get()
|
|
124
|
+
.execute();
|
|
125
|
+
const replicationResponse = await client.carts
|
|
126
|
+
.replicate()
|
|
127
|
+
.post({
|
|
128
|
+
body: {
|
|
129
|
+
reference: {
|
|
130
|
+
typeId: 'cart',
|
|
131
|
+
id: cart.body.id,
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
})
|
|
135
|
+
.execute();
|
|
75
136
|
// set the custom type to mark it as a checkout
|
|
76
137
|
|
|
77
138
|
const actions: MyCartUpdateAction[] = [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
139
|
+
{
|
|
140
|
+
action: 'setCustomType',
|
|
141
|
+
type: {
|
|
142
|
+
typeId: 'type',
|
|
143
|
+
key: 'reactionaryCheckout',
|
|
144
|
+
},
|
|
145
|
+
fields: {
|
|
146
|
+
commerceToolsCartId: payload.cart.identifier.key,
|
|
87
147
|
},
|
|
148
|
+
},
|
|
88
149
|
];
|
|
89
150
|
|
|
90
151
|
if (payload.billingAddress) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
152
|
+
actions.push({
|
|
153
|
+
action: 'setBillingAddress',
|
|
154
|
+
address: {
|
|
155
|
+
country: payload.billingAddress.countryCode,
|
|
156
|
+
firstName: payload.billingAddress.firstName || '',
|
|
157
|
+
lastName: payload.billingAddress.lastName || '',
|
|
158
|
+
streetName: payload.billingAddress.streetAddress || '',
|
|
159
|
+
streetNumber: payload.billingAddress.streetNumber || '',
|
|
160
|
+
postalCode: payload.billingAddress.postalCode || '',
|
|
161
|
+
city: payload.billingAddress.city || '',
|
|
162
|
+
email: payload.notificationEmail || '',
|
|
163
|
+
phone: payload.notificationPhone || '',
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
actions.push({
|
|
167
|
+
action: 'setShippingAddress',
|
|
168
|
+
address: {
|
|
169
|
+
country: payload.billingAddress.countryCode,
|
|
170
|
+
firstName: payload.billingAddress.firstName || '',
|
|
171
|
+
lastName: payload.billingAddress.lastName || '',
|
|
172
|
+
streetName: payload.billingAddress.streetAddress || '',
|
|
173
|
+
streetNumber: payload.billingAddress.streetNumber || '',
|
|
174
|
+
postalCode: payload.billingAddress.postalCode || '',
|
|
175
|
+
city: payload.billingAddress.city || '',
|
|
176
|
+
},
|
|
177
|
+
});
|
|
117
178
|
}
|
|
118
179
|
|
|
119
|
-
const checkoutResponse = await client.carts
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return this.parseSingle(checkoutResponse.body, reqCtx);
|
|
180
|
+
const checkoutResponse = await client.carts
|
|
181
|
+
.withId({ ID: replicationResponse.body.id })
|
|
182
|
+
.post({
|
|
183
|
+
body: {
|
|
184
|
+
version: replicationResponse.body.version || 0,
|
|
185
|
+
actions: [...actions],
|
|
186
|
+
},
|
|
187
|
+
})
|
|
188
|
+
.execute();
|
|
129
189
|
|
|
190
|
+
return success(this.parseSingle(checkoutResponse.body));
|
|
130
191
|
}
|
|
131
192
|
|
|
132
|
-
|
|
193
|
+
@Reactionary({
|
|
194
|
+
inputSchema: CheckoutQueryByIdSchema,
|
|
195
|
+
outputSchema: CheckoutSchema.nullable(),
|
|
196
|
+
})
|
|
197
|
+
public async getById(payload: CheckoutQueryById): Promise<Result<Checkout, NotFoundError>> {
|
|
198
|
+
const client = await this.getClient();
|
|
199
|
+
const checkoutResponse = await client.carts
|
|
200
|
+
.withId({ ID: payload.identifier.key })
|
|
201
|
+
.get({
|
|
202
|
+
queryArgs: {
|
|
203
|
+
expand: ['paymentInfo.payments[*]', 'shippingInfo.shippingMethod'],
|
|
204
|
+
},
|
|
205
|
+
})
|
|
206
|
+
.execute();
|
|
133
207
|
|
|
134
|
-
const
|
|
135
|
-
const checkoutResponse = await client.carts.withId({ ID: payload.identifier.key }).get({
|
|
136
|
-
queryArgs: {
|
|
137
|
-
expand: ['paymentInfo.payments[*]', 'shippingInfo.shippingMethod']
|
|
138
|
-
}
|
|
139
|
-
}).execute();
|
|
208
|
+
const checkout = this.parseSingle(checkoutResponse.body);
|
|
140
209
|
|
|
141
|
-
|
|
142
|
-
|
|
210
|
+
if (checkoutResponse.body.cartState === 'Ordered') {
|
|
211
|
+
const order = await client.orders
|
|
212
|
+
.get({
|
|
213
|
+
queryArgs: {
|
|
214
|
+
where: `cart(id="${checkout.identifier.key}")`,
|
|
215
|
+
},
|
|
216
|
+
})
|
|
217
|
+
.execute();
|
|
143
218
|
|
|
144
|
-
|
|
145
|
-
|
|
219
|
+
checkout.resultingOrder = {
|
|
220
|
+
key: order.body.results[0].id,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
146
223
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
224
|
+
return success(checkout);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
@Reactionary({
|
|
228
|
+
inputSchema: CheckoutMutationSetShippingAddressSchema,
|
|
229
|
+
outputSchema: CheckoutSchema,
|
|
230
|
+
})
|
|
231
|
+
public async setShippingAddress(
|
|
232
|
+
payload: CheckoutMutationSetShippingAddress
|
|
233
|
+
): Promise<Result<Checkout>> {
|
|
234
|
+
const client = await this.getClient();
|
|
235
|
+
|
|
236
|
+
const version = (payload.checkout as CommercetoolsCheckoutIdentifier)
|
|
237
|
+
.version;
|
|
238
|
+
const checkoutResponse = await client.carts
|
|
239
|
+
.withId({ ID: payload.checkout.key })
|
|
240
|
+
.post({
|
|
241
|
+
body: {
|
|
242
|
+
version: version,
|
|
243
|
+
actions: [
|
|
244
|
+
{
|
|
245
|
+
action: 'setShippingAddress',
|
|
246
|
+
address: {
|
|
247
|
+
country: payload.shippingAddress.countryCode,
|
|
248
|
+
firstName: payload.shippingAddress.firstName || '',
|
|
249
|
+
lastName: payload.shippingAddress.lastName || '',
|
|
250
|
+
streetName: payload.shippingAddress.streetAddress || '',
|
|
251
|
+
streetNumber: payload.shippingAddress.streetNumber || '',
|
|
252
|
+
postalCode: payload.shippingAddress.postalCode || '',
|
|
253
|
+
city: payload.shippingAddress.city || '',
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
],
|
|
257
|
+
},
|
|
258
|
+
})
|
|
259
|
+
.execute();
|
|
167
260
|
|
|
168
|
-
return this.parseSingle(checkoutResponse.body
|
|
261
|
+
return success(this.parseSingle(checkoutResponse.body));
|
|
169
262
|
}
|
|
170
263
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
264
|
+
@Reactionary({
|
|
265
|
+
inputSchema: CheckoutQueryForAvailableShippingMethodsSchema,
|
|
266
|
+
outputSchema: z.array(ShippingMethodSchema),
|
|
267
|
+
})
|
|
268
|
+
public async getAvailableShippingMethods(
|
|
269
|
+
payload: CheckoutQueryForAvailableShippingMethods
|
|
270
|
+
): Promise<Result<ShippingMethod[]>> {
|
|
271
|
+
const client = await this.getClient();
|
|
272
|
+
const shippingMethodsResponse = await client.shippingMethods
|
|
273
|
+
.matchingCart()
|
|
274
|
+
.get({
|
|
275
|
+
queryArgs: {
|
|
276
|
+
cartId: payload.checkout.key,
|
|
277
|
+
},
|
|
278
|
+
})
|
|
279
|
+
.execute();
|
|
178
280
|
|
|
179
281
|
const result: Array<ShippingMethod> = [];
|
|
180
|
-
const inputShippingMethods: CTShippingMethod[] = shippingMethodsResponse
|
|
282
|
+
const inputShippingMethods: CTShippingMethod[] = shippingMethodsResponse
|
|
283
|
+
.body.results as CTShippingMethod[];
|
|
181
284
|
for (const sm of inputShippingMethods) {
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
285
|
+
const identifier = {
|
|
286
|
+
key: sm.key!,
|
|
287
|
+
} satisfies ShippingMethodIdentifier;
|
|
288
|
+
const name = sm.name;
|
|
289
|
+
const description = sm.localizedDescription?.[this.context.languageContext.locale] || '';
|
|
290
|
+
const shippingMethod = {
|
|
291
|
+
deliveryTime: '',
|
|
292
|
+
description,
|
|
293
|
+
identifier,
|
|
294
|
+
name,
|
|
295
|
+
price: sm.zoneRates[0].shippingRates[0].price
|
|
296
|
+
? {
|
|
297
|
+
value:
|
|
298
|
+
(sm.zoneRates[0].shippingRates[0].price.centAmount || 0) / 100,
|
|
299
|
+
currency:
|
|
300
|
+
sm.zoneRates[0].shippingRates[0].price.currencyCode as Currency ||
|
|
301
|
+
this.context.languageContext.currencyCode,
|
|
302
|
+
}
|
|
303
|
+
: { value: 0, currency: this.context.languageContext.currencyCode },
|
|
304
|
+
} satisfies ShippingMethod;
|
|
305
|
+
|
|
193
306
|
result.push(shippingMethod);
|
|
194
307
|
}
|
|
195
|
-
return result;
|
|
308
|
+
return success(result);
|
|
196
309
|
}
|
|
197
310
|
|
|
198
|
-
|
|
311
|
+
@Reactionary({
|
|
312
|
+
inputSchema: CheckoutQueryForAvailablePaymentMethodsSchema,
|
|
313
|
+
outputSchema: z.array(PaymentMethodSchema),
|
|
314
|
+
})
|
|
315
|
+
public async getAvailablePaymentMethods(
|
|
316
|
+
payload: CheckoutQueryForAvailablePaymentMethods
|
|
317
|
+
): Promise<Result<PaymentMethod[]>> {
|
|
199
318
|
// Commercetools does not have a concept of payment methods, as these are handled by the payment providers.
|
|
200
319
|
// So for now, we will return an empty array.
|
|
201
|
-
const staticMethods = this.getStaticPaymentMethods(payload.checkout
|
|
320
|
+
const staticMethods = this.getStaticPaymentMethods(payload.checkout);
|
|
202
321
|
|
|
203
322
|
const dynamicMethods: PaymentMethod[] = [];
|
|
204
323
|
// later we will also fetch any stored payment methods the user has...
|
|
205
324
|
|
|
206
|
-
return [...staticMethods, ...dynamicMethods];
|
|
325
|
+
return success([...staticMethods, ...dynamicMethods]);
|
|
207
326
|
}
|
|
208
327
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
328
|
+
@Reactionary({
|
|
329
|
+
inputSchema: CheckoutMutationAddPaymentInstructionSchema,
|
|
330
|
+
outputSchema: CheckoutSchema,
|
|
331
|
+
})
|
|
332
|
+
public async addPaymentInstruction(
|
|
333
|
+
payload: CheckoutMutationAddPaymentInstruction
|
|
334
|
+
): Promise<Result<Checkout>> {
|
|
335
|
+
const client = await this.getClient();
|
|
336
|
+
|
|
337
|
+
const response = await client.payments
|
|
338
|
+
.post({
|
|
339
|
+
body: {
|
|
340
|
+
amountPlanned: {
|
|
341
|
+
centAmount: Math.round(
|
|
342
|
+
payload.paymentInstruction.amount.value * 100
|
|
343
|
+
),
|
|
344
|
+
currencyCode: payload.paymentInstruction.amount.currency,
|
|
223
345
|
},
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
346
|
+
paymentMethodInfo: {
|
|
347
|
+
method: payload.paymentInstruction.paymentMethod.method,
|
|
348
|
+
name: {
|
|
349
|
+
[this.context.languageContext.locale]:
|
|
350
|
+
payload.paymentInstruction.paymentMethod.name,
|
|
351
|
+
},
|
|
352
|
+
paymentInterface:
|
|
353
|
+
payload.paymentInstruction.paymentMethod.paymentProcessor,
|
|
230
354
|
},
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
355
|
+
custom: {
|
|
356
|
+
type: {
|
|
357
|
+
typeId: 'type',
|
|
358
|
+
key: 'reactionaryPaymentCustomFields',
|
|
359
|
+
},
|
|
360
|
+
fields: {
|
|
361
|
+
commerceToolsCartId: payload.checkout.key,
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
})
|
|
366
|
+
.execute();
|
|
237
367
|
|
|
238
|
-
const version = (payload.checkout as CommercetoolsCheckoutIdentifier)
|
|
368
|
+
const version = (payload.checkout as CommercetoolsCheckoutIdentifier)
|
|
369
|
+
.version;
|
|
239
370
|
const actions: MyCartUpdateAction[] = [
|
|
240
371
|
{
|
|
241
372
|
action: 'addPayment',
|
|
242
373
|
payment: {
|
|
243
374
|
typeId: 'payment',
|
|
244
|
-
id: response.body.id
|
|
245
|
-
}
|
|
246
|
-
}
|
|
375
|
+
id: response.body.id,
|
|
376
|
+
},
|
|
377
|
+
},
|
|
247
378
|
];
|
|
248
379
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const client = await this.getClient(reqCtx);
|
|
254
|
-
|
|
380
|
+
const result = await this.applyActions(
|
|
381
|
+
payload.checkout as CommercetoolsCheckoutIdentifier,
|
|
382
|
+
actions
|
|
383
|
+
);
|
|
255
384
|
|
|
256
|
-
|
|
257
|
-
|
|
385
|
+
return success(result);
|
|
386
|
+
}
|
|
258
387
|
|
|
388
|
+
@Reactionary({
|
|
389
|
+
inputSchema: CheckoutMutationRemovePaymentInstructionSchema,
|
|
390
|
+
outputSchema: CheckoutSchema,
|
|
391
|
+
})
|
|
392
|
+
public async removePaymentInstruction(
|
|
393
|
+
payload: CheckoutMutationRemovePaymentInstruction
|
|
394
|
+
): Promise<Result<Checkout>> {
|
|
395
|
+
const client = await this.getClient();
|
|
259
396
|
|
|
397
|
+
// FIXME: Need to get full-endpoint rights, if we want to cancel the authorization on the payment. The MyPayment endpoint does not support
|
|
398
|
+
// changing a payment intent after it has transactions.
|
|
260
399
|
|
|
261
400
|
// get newest version
|
|
262
401
|
/*
|
|
@@ -284,8 +423,8 @@ export class CommercetoolsCheckoutProvider<
|
|
|
284
423
|
// The cart can be re-used, and a new payment instruction can be added to it later.
|
|
285
424
|
// The frontend should ignore any payment instructions with status 'canceled' when displaying payment options to the user.
|
|
286
425
|
|
|
287
|
-
|
|
288
|
-
|
|
426
|
+
// Now add the payment to the cart
|
|
427
|
+
/*
|
|
289
428
|
const ctId = payload.checkout as CommercetoolsCheckoutIdentifier
|
|
290
429
|
const updatedCart = await client.carts.withId({ ID: ctId.key }).post({
|
|
291
430
|
body: {
|
|
@@ -309,336 +448,379 @@ export class CommercetoolsCheckoutProvider<
|
|
|
309
448
|
}).execute();
|
|
310
449
|
*/
|
|
311
450
|
|
|
312
|
-
const checkout =
|
|
313
|
-
return checkout
|
|
314
|
-
|
|
451
|
+
const checkout = unwrapValue(await this.getById({ identifier: payload.checkout }));
|
|
452
|
+
return success(checkout);
|
|
315
453
|
}
|
|
316
454
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
455
|
+
@Reactionary({
|
|
456
|
+
inputSchema: CheckoutMutationSetShippingInstructionSchema,
|
|
457
|
+
outputSchema: CheckoutSchema,
|
|
458
|
+
})
|
|
459
|
+
public async setShippingInstruction(
|
|
460
|
+
payload: CheckoutMutationSetShippingInstruction
|
|
461
|
+
): Promise<Result<Checkout>> {
|
|
322
462
|
const actions: MyCartUpdateAction[] = [];
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
463
|
+
actions.push({
|
|
464
|
+
action: 'setShippingMethod',
|
|
465
|
+
shippingMethod: {
|
|
466
|
+
typeId: 'shipping-method',
|
|
467
|
+
key: payload.shippingInstruction.shippingMethod.key,
|
|
468
|
+
},
|
|
469
|
+
});
|
|
470
|
+
actions.push({
|
|
471
|
+
action: 'setCustomField',
|
|
472
|
+
name: 'shippingInstruction',
|
|
473
|
+
value: payload.shippingInstruction.instructions,
|
|
474
|
+
});
|
|
475
|
+
actions.push({
|
|
476
|
+
action: 'setCustomField',
|
|
477
|
+
name: 'consentForUnattendedDelivery',
|
|
478
|
+
value: payload.shippingInstruction.consentForUnattendedDelivery + '',
|
|
479
|
+
});
|
|
480
|
+
actions.push({
|
|
481
|
+
action: 'setCustomField',
|
|
482
|
+
name: 'pickupPointId',
|
|
483
|
+
value: payload.shippingInstruction.pickupPoint,
|
|
484
|
+
});
|
|
346
485
|
|
|
486
|
+
const result = await this.applyActions(
|
|
487
|
+
payload.checkout as CommercetoolsCheckoutIdentifier,
|
|
488
|
+
actions
|
|
489
|
+
);
|
|
347
490
|
|
|
348
|
-
return
|
|
491
|
+
return success(result);
|
|
349
492
|
}
|
|
350
493
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
494
|
+
@Reactionary({
|
|
495
|
+
inputSchema: CheckoutMutationFinalizeCheckoutSchema,
|
|
496
|
+
outputSchema: CheckoutSchema,
|
|
497
|
+
})
|
|
498
|
+
public async finalizeCheckout(
|
|
499
|
+
payload: CheckoutMutationFinalizeCheckout
|
|
500
|
+
): Promise<Result<Checkout>> {
|
|
501
|
+
const checkout = await this.getById({ identifier: payload.checkout });
|
|
502
|
+
if (!checkout.success || !checkout.value.readyForFinalization) {
|
|
354
503
|
throw new CheckoutNotReadyForFinalizationError(payload.checkout);
|
|
355
504
|
}
|
|
356
505
|
|
|
357
|
-
const client = await this.getClient(
|
|
506
|
+
const client = await this.getClient();
|
|
358
507
|
const ctId = payload.checkout as CommercetoolsCheckoutIdentifier;
|
|
359
508
|
|
|
360
509
|
// create the order from the cart
|
|
361
|
-
const orderResponse = await client.orders
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
actions.push({
|
|
370
|
-
action: 'setCustomField',
|
|
371
|
-
name: 'commerceToolsOrderId',
|
|
372
|
-
value: orderResponse.body.id
|
|
373
|
-
});
|
|
510
|
+
const orderResponse = await client.orders
|
|
511
|
+
.post({
|
|
512
|
+
body: {
|
|
513
|
+
id: ctId.key,
|
|
514
|
+
version: ctId.version,
|
|
515
|
+
},
|
|
516
|
+
})
|
|
517
|
+
.execute();
|
|
374
518
|
|
|
375
|
-
return this.
|
|
519
|
+
return this.getById({
|
|
520
|
+
identifier: payload.checkout,
|
|
521
|
+
}) as unknown as Result<Checkout>;
|
|
376
522
|
}
|
|
377
523
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
524
|
protected async applyActions(
|
|
382
525
|
checkout: CheckoutIdentifier,
|
|
383
|
-
actions: MyCartUpdateAction[]
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
const client = await this.getClient(reqCtx);
|
|
526
|
+
actions: MyCartUpdateAction[]
|
|
527
|
+
): Promise<Checkout> {
|
|
528
|
+
const client = await this.getClient();
|
|
387
529
|
const ctId = checkout as CommercetoolsCheckoutIdentifier;
|
|
388
530
|
|
|
531
|
+
try {
|
|
532
|
+
const response = await client.carts
|
|
533
|
+
.withId({ ID: ctId.key })
|
|
534
|
+
.post({
|
|
535
|
+
queryArgs: {
|
|
536
|
+
expand: ['paymentInfo.payments[*]', 'shippingInfo.shippingMethod'],
|
|
537
|
+
},
|
|
538
|
+
body: {
|
|
539
|
+
version: ctId.version,
|
|
540
|
+
actions,
|
|
541
|
+
},
|
|
542
|
+
})
|
|
543
|
+
.execute();
|
|
389
544
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
.post({
|
|
394
|
-
queryArgs: {
|
|
395
|
-
expand: ['paymentInfo.payments[*]', 'shippingInfo.shippingMethod']
|
|
396
|
-
},
|
|
397
|
-
body: {
|
|
398
|
-
version: ctId.version,
|
|
399
|
-
actions,
|
|
400
|
-
},
|
|
401
|
-
})
|
|
402
|
-
.execute();
|
|
545
|
+
if (response.error) {
|
|
546
|
+
console.error(response.error);
|
|
547
|
+
}
|
|
403
548
|
|
|
404
|
-
|
|
405
|
-
console.error(response.error);
|
|
406
|
-
}
|
|
407
|
-
return this.parseSingle(response.body, reqCtx);
|
|
408
|
-
} catch (e: any) {
|
|
409
|
-
console.error('Error applying actions to cart:', e);
|
|
410
|
-
throw e;
|
|
411
|
-
}
|
|
549
|
+
const p = this.parseSingle(response.body);
|
|
412
550
|
|
|
551
|
+
return p;
|
|
552
|
+
} catch (e: any) {
|
|
553
|
+
console.error('Error applying actions to cart:', e);
|
|
554
|
+
throw e;
|
|
555
|
+
}
|
|
413
556
|
}
|
|
414
557
|
|
|
415
558
|
/**
|
|
416
559
|
* Extension point, to allow filtering the options, or adding new ones, like invoicing for b2b.
|
|
417
560
|
*
|
|
418
561
|
* Usecase: Override this, if you need to change the payment options based on the request context.
|
|
419
|
-
* @param reqCtx
|
|
420
562
|
* @returns
|
|
421
563
|
*/
|
|
422
|
-
protected getStaticPaymentMethods(
|
|
564
|
+
protected getStaticPaymentMethods(
|
|
565
|
+
_checkout: CheckoutIdentifier
|
|
566
|
+
): PaymentMethod[] {
|
|
423
567
|
return this.config.paymentMethods || [];
|
|
424
568
|
}
|
|
425
569
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
result.originalCartReference = CommercetoolsCartIdentifierSchema.parse({
|
|
446
|
-
key: remote.custom?.fields['commerceToolsCartId'] || '',
|
|
447
|
-
version: 0,
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
const orderId = remote.custom?.fields['commerceToolsOrderId'];
|
|
451
|
-
if (orderId) {
|
|
452
|
-
result.resultingOrder = CommercetoolsOrderIdentifierSchema.parse({
|
|
453
|
-
key: orderId,
|
|
454
|
-
version: 0,
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
if (remote.shippingAddress) {
|
|
460
|
-
result.shippingAddress = this.parseAddress( remote.shippingAddress, reqCtx) ;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
if (remote.billingAddress ) {
|
|
464
|
-
result.billingAddress = this.parseAddress( remote.billingAddress, reqCtx) ;
|
|
465
|
-
}
|
|
466
|
-
result.shippingInstruction = this.parseShippingInstruction(remote);
|
|
467
|
-
|
|
468
|
-
for(const p of remote.paymentInfo?.payments || []) {
|
|
469
|
-
if (p.obj) {
|
|
470
|
-
result.paymentInstructions.push( this.parsePaymentInstruction(p.obj, reqCtx) );
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
const grandTotal = remote.totalPrice.centAmount || 0;
|
|
475
|
-
const shippingTotal = remote.shippingInfo?.price.centAmount || 0;
|
|
476
|
-
const productTotal = grandTotal - shippingTotal;
|
|
477
|
-
const taxTotal = remote.taxedPrice?.totalTax?.centAmount || 0;
|
|
478
|
-
const discountTotal =
|
|
479
|
-
remote.discountOnTotalPrice?.discountedAmount.centAmount || 0;
|
|
480
|
-
const surchargeTotal = 0;
|
|
481
|
-
const currency = remote.totalPrice.currencyCode as Currency;
|
|
482
|
-
|
|
483
|
-
result.price = {
|
|
484
|
-
totalTax: {
|
|
485
|
-
value: taxTotal / 100,
|
|
486
|
-
currency,
|
|
487
|
-
},
|
|
488
|
-
totalDiscount: {
|
|
489
|
-
value: discountTotal / 100,
|
|
570
|
+
protected parseCheckoutItem(remoteItem: LineItem): CheckoutItem {
|
|
571
|
+
const unitPrice = remoteItem.price.value.centAmount;
|
|
572
|
+
const totalPrice = remoteItem.totalPrice.centAmount || 0;
|
|
573
|
+
const totalDiscount = remoteItem.price.discounted?.value.centAmount || 0;
|
|
574
|
+
const unitDiscount = totalDiscount / remoteItem.quantity;
|
|
575
|
+
const currency =
|
|
576
|
+
remoteItem.price.value.currencyCode.toUpperCase() as Currency;
|
|
577
|
+
|
|
578
|
+
const item = {
|
|
579
|
+
identifier: {
|
|
580
|
+
key: remoteItem.id,
|
|
581
|
+
},
|
|
582
|
+
variant: {
|
|
583
|
+
sku: remoteItem.variant.sku || '',
|
|
584
|
+
},
|
|
585
|
+
quantity: remoteItem.quantity,
|
|
586
|
+
price: {
|
|
587
|
+
unitPrice: {
|
|
588
|
+
value: unitPrice / 100,
|
|
490
589
|
currency,
|
|
491
590
|
},
|
|
492
|
-
|
|
493
|
-
value:
|
|
591
|
+
unitDiscount: {
|
|
592
|
+
value: unitDiscount / 100,
|
|
494
593
|
currency,
|
|
495
594
|
},
|
|
496
|
-
|
|
497
|
-
value:
|
|
498
|
-
currency: remote.shippingInfo?.price.currencyCode as Currency,
|
|
499
|
-
},
|
|
500
|
-
totalProductPrice: {
|
|
501
|
-
value: productTotal / 100,
|
|
595
|
+
totalPrice: {
|
|
596
|
+
value: (totalPrice || 0) / 100,
|
|
502
597
|
currency,
|
|
503
598
|
},
|
|
504
|
-
|
|
505
|
-
value:
|
|
599
|
+
totalDiscount: {
|
|
600
|
+
value: totalDiscount / 100,
|
|
506
601
|
currency,
|
|
507
602
|
},
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
for (const remoteItem of remote.lineItems) {
|
|
511
|
-
const item = CheckoutItemSchema.parse({});
|
|
603
|
+
},
|
|
604
|
+
} satisfies CheckoutItem;
|
|
512
605
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
item.quantity = remoteItem.quantity;
|
|
606
|
+
return CheckoutItemSchema.parse(item);
|
|
607
|
+
}
|
|
516
608
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
609
|
+
protected parseSingle(remote: CTCart): Checkout {
|
|
610
|
+
const identifier = {
|
|
611
|
+
key: remote.id,
|
|
612
|
+
version: remote.version || 0,
|
|
613
|
+
} satisfies CommercetoolsCheckoutIdentifier;
|
|
521
614
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
},
|
|
527
|
-
unitDiscount: {
|
|
528
|
-
value: unitDiscount / 100,
|
|
529
|
-
currency,
|
|
530
|
-
},
|
|
531
|
-
totalPrice: {
|
|
532
|
-
value: (totalPrice || 0) / 100,
|
|
533
|
-
currency,
|
|
534
|
-
},
|
|
535
|
-
totalDiscount: {
|
|
536
|
-
value: totalDiscount / 100,
|
|
537
|
-
currency,
|
|
538
|
-
},
|
|
539
|
-
};
|
|
615
|
+
const originalCartReference = {
|
|
616
|
+
key: remote.custom?.fields['commerceToolsCartId'] || '',
|
|
617
|
+
version: 0,
|
|
618
|
+
} satisfies CommercetoolsCartIdentifier;
|
|
540
619
|
|
|
541
|
-
|
|
542
|
-
|
|
620
|
+
let shippingAddress: Address | undefined;
|
|
621
|
+
if (remote.shippingAddress) {
|
|
622
|
+
shippingAddress = this.parseAddress(remote.shippingAddress);
|
|
623
|
+
}
|
|
543
624
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
key: this.generateCacheKeySingle(result.identifier, reqCtx),
|
|
549
|
-
},
|
|
550
|
-
placeholder: false,
|
|
551
|
-
};
|
|
625
|
+
let billingAddress: Address | undefined;
|
|
626
|
+
if (remote.billingAddress) {
|
|
627
|
+
billingAddress = this.parseAddress(remote.billingAddress);
|
|
628
|
+
}
|
|
552
629
|
|
|
553
|
-
|
|
630
|
+
const paymentInstructions = new Array<PaymentInstruction>();
|
|
631
|
+
for (const p of remote.paymentInfo?.payments || []) {
|
|
632
|
+
if (p.obj) {
|
|
633
|
+
paymentInstructions.push(this.parsePaymentInstruction(p.obj));
|
|
634
|
+
}
|
|
554
635
|
}
|
|
555
636
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
637
|
+
const grandTotal = remote.totalPrice.centAmount || 0;
|
|
638
|
+
const shippingTotal = remote.shippingInfo?.price.centAmount || 0;
|
|
639
|
+
const productTotal = grandTotal - shippingTotal;
|
|
640
|
+
const taxTotal = remote.taxedPrice?.totalTax?.centAmount || 0;
|
|
641
|
+
const discountTotal =
|
|
642
|
+
remote.discountOnTotalPrice?.discountedAmount.centAmount || 0;
|
|
643
|
+
const surchargeTotal = 0;
|
|
644
|
+
const currency = remote.totalPrice.currencyCode as Currency;
|
|
645
|
+
|
|
646
|
+
const price = {
|
|
647
|
+
totalTax: {
|
|
648
|
+
value: taxTotal / 100,
|
|
649
|
+
currency,
|
|
650
|
+
},
|
|
651
|
+
totalDiscount: {
|
|
652
|
+
value: discountTotal / 100,
|
|
653
|
+
currency,
|
|
654
|
+
},
|
|
655
|
+
totalSurcharge: {
|
|
656
|
+
value: surchargeTotal / 100,
|
|
657
|
+
currency,
|
|
658
|
+
},
|
|
659
|
+
totalShipping: {
|
|
660
|
+
value: shippingTotal / 100,
|
|
661
|
+
currency: currency
|
|
662
|
+
},
|
|
663
|
+
totalProductPrice: {
|
|
664
|
+
value: productTotal / 100,
|
|
665
|
+
currency,
|
|
666
|
+
},
|
|
667
|
+
grandTotal: {
|
|
668
|
+
value: grandTotal / 100,
|
|
669
|
+
currency,
|
|
670
|
+
},
|
|
671
|
+
} satisfies CostBreakDown;
|
|
559
672
|
|
|
560
|
-
|
|
561
|
-
|
|
673
|
+
const items = new Array<CheckoutItem>();
|
|
674
|
+
for (const remoteItem of remote.lineItems) {
|
|
675
|
+
const item = this.parseCheckoutItem(remoteItem);
|
|
676
|
+
items.push(item);
|
|
677
|
+
}
|
|
562
678
|
|
|
563
|
-
|
|
564
|
-
|
|
679
|
+
const shippingInstruction = this.parseShippingInstruction(remote);
|
|
680
|
+
const readyForFinalization = this.isReadyForFinalization(
|
|
681
|
+
price,
|
|
682
|
+
paymentInstructions,
|
|
683
|
+
billingAddress,
|
|
684
|
+
shippingAddress,
|
|
685
|
+
shippingInstruction
|
|
686
|
+
);
|
|
687
|
+
|
|
688
|
+
const result = {
|
|
689
|
+
identifier,
|
|
690
|
+
originalCartReference,
|
|
691
|
+
name: remote.custom?.fields['name'] || '',
|
|
692
|
+
description: remote.custom?.fields['description'] || '',
|
|
693
|
+
readyForFinalization,
|
|
694
|
+
billingAddress,
|
|
695
|
+
shippingAddress,
|
|
696
|
+
shippingInstruction,
|
|
697
|
+
paymentInstructions,
|
|
698
|
+
items,
|
|
699
|
+
price,
|
|
700
|
+
} satisfies Checkout;
|
|
565
701
|
|
|
566
|
-
|
|
567
|
-
|
|
702
|
+
return result;
|
|
703
|
+
}
|
|
568
704
|
|
|
569
|
-
|
|
570
|
-
|
|
705
|
+
protected isReadyForFinalization(
|
|
706
|
+
price: CostBreakDown,
|
|
707
|
+
paymentInstructions: Array<PaymentInstruction>,
|
|
708
|
+
billingAddress?: Address,
|
|
709
|
+
shippingAddress?: Address,
|
|
710
|
+
shippingInstruction?: ShippingInstruction
|
|
711
|
+
): boolean {
|
|
712
|
+
// we should have a billing address
|
|
713
|
+
if (!billingAddress) return false;
|
|
571
714
|
|
|
572
|
-
|
|
573
|
-
|
|
715
|
+
// we should know how to ship it
|
|
716
|
+
if (!shippingInstruction) return false;
|
|
574
717
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
newModel.identifier = PaymentInstructionIdentifierSchema.parse({ key: remote.id || '' });
|
|
578
|
-
newModel.amount = {
|
|
579
|
-
value: remote.amountPlanned.centAmount / 100,
|
|
580
|
-
currency: remote.amountPlanned.currencyCode as Currency,
|
|
581
|
-
};
|
|
718
|
+
// and it should ship either to an address or a pickup point
|
|
719
|
+
if (!shippingAddress && !shippingInstruction.pickupPoint) return false;
|
|
582
720
|
|
|
721
|
+
// and it should be paid for
|
|
722
|
+
if (paymentInstructions.length === 0) return false;
|
|
583
723
|
|
|
724
|
+
const authorizedPayments = paymentInstructions
|
|
725
|
+
.filter((pi) => pi.status === 'authorized')
|
|
726
|
+
.map((x) => x.amount.value)
|
|
727
|
+
.reduce((a, b) => a + b, 0);
|
|
728
|
+
if (price.grandTotal.value !== authorizedPayments) return false;
|
|
584
729
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
const paymentName = remote.paymentMethodInfo.name![reqCtx.languageContext.locale];
|
|
588
|
-
newModel.paymentMethod = PaymentMethodIdentifierSchema.parse({
|
|
589
|
-
method,
|
|
590
|
-
paymentProcessor,
|
|
591
|
-
name: paymentName || method || 'Unknown',
|
|
592
|
-
});
|
|
730
|
+
return true;
|
|
731
|
+
}
|
|
593
732
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
733
|
+
protected parsePaymentInstruction(remote: CTPayment): PaymentInstruction {
|
|
734
|
+
const identifier = {
|
|
735
|
+
key: remote.id,
|
|
736
|
+
} satisfies PaymentInstructionIdentifier;
|
|
737
|
+
const amount = {
|
|
738
|
+
value: remote.amountPlanned.centAmount / 100,
|
|
739
|
+
currency: remote.amountPlanned.currencyCode as Currency,
|
|
740
|
+
} satisfies MonetaryAmount;
|
|
741
|
+
|
|
742
|
+
const method = remote.paymentMethodInfo?.method || 'unknown';
|
|
743
|
+
const paymentProcessor =
|
|
744
|
+
remote.paymentMethodInfo?.paymentInterface || method;
|
|
745
|
+
const paymentName =
|
|
746
|
+
remote.paymentMethodInfo.name![this.context.languageContext.locale];
|
|
747
|
+
|
|
748
|
+
const paymentMethod = {
|
|
749
|
+
method,
|
|
750
|
+
paymentProcessor,
|
|
751
|
+
name: paymentName || method || 'Unknown',
|
|
752
|
+
} satisfies PaymentMethodIdentifier;
|
|
753
|
+
|
|
754
|
+
const customData = remote.custom?.fields || {};
|
|
755
|
+
const protocolData =
|
|
756
|
+
Object.keys(customData).map((x) => ({ key: x, value: customData[x] })) ||
|
|
757
|
+
[];
|
|
758
|
+
|
|
759
|
+
let status: PaymentStatus = 'pending';
|
|
760
|
+
if (remote.transactions && remote.transactions.length > 0) {
|
|
761
|
+
const lastTransaction =
|
|
762
|
+
remote.transactions[remote.transactions.length - 1];
|
|
763
|
+
if (
|
|
764
|
+
lastTransaction.type === 'Authorization' &&
|
|
765
|
+
lastTransaction.state === 'Pending'
|
|
766
|
+
) {
|
|
767
|
+
status = 'pending';
|
|
768
|
+
} else if (
|
|
769
|
+
lastTransaction.type === 'Authorization' &&
|
|
770
|
+
lastTransaction.state === 'Success'
|
|
771
|
+
) {
|
|
772
|
+
status = 'authorized';
|
|
605
773
|
}
|
|
606
|
-
|
|
607
|
-
|
|
774
|
+
} else {
|
|
775
|
+
status = 'pending';
|
|
608
776
|
}
|
|
609
777
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
postalCode: remote.postalCode || '',
|
|
618
|
-
city: remote.city || '',
|
|
619
|
-
});
|
|
620
|
-
}
|
|
778
|
+
const result = {
|
|
779
|
+
amount,
|
|
780
|
+
identifier,
|
|
781
|
+
paymentMethod,
|
|
782
|
+
protocolData,
|
|
783
|
+
status
|
|
784
|
+
} satisfies PaymentInstruction;
|
|
621
785
|
|
|
622
|
-
|
|
623
|
-
|
|
786
|
+
return result;
|
|
787
|
+
}
|
|
624
788
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
789
|
+
protected parseAddress(remote: CTAddress) {
|
|
790
|
+
return {
|
|
791
|
+
countryCode: remote.country || '',
|
|
792
|
+
firstName: remote.firstName || '',
|
|
793
|
+
lastName: remote.lastName || '',
|
|
794
|
+
streetAddress: remote.streetName || '',
|
|
795
|
+
streetNumber: remote.streetNumber || '',
|
|
796
|
+
postalCode: remote.postalCode || '',
|
|
797
|
+
city: remote.city || '',
|
|
798
|
+
identifier: {
|
|
799
|
+
nickName: '',
|
|
800
|
+
},
|
|
801
|
+
region: '',
|
|
802
|
+
} satisfies Address;
|
|
803
|
+
}
|
|
628
804
|
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
},
|
|
634
|
-
shippingMethod: {
|
|
635
|
-
key: remote.shippingInfo.shippingMethod?.obj?.key || '',
|
|
636
|
-
},
|
|
637
|
-
pickupPoint: pickupPoint || '',
|
|
638
|
-
instructions: instructions || '',
|
|
639
|
-
consentForUnattendedDelivery: consentForUnattendedDelivery || false,
|
|
640
|
-
});
|
|
805
|
+
protected parseShippingInstruction(
|
|
806
|
+
remote: CTCart
|
|
807
|
+
): ShippingInstruction | undefined {
|
|
808
|
+
if (!remote.shippingInfo) return undefined;
|
|
641
809
|
|
|
642
|
-
|
|
643
|
-
|
|
810
|
+
const instructions = remote.custom?.fields['shippingInstruction'] || '';
|
|
811
|
+
const consentForUnattendedDelivery =
|
|
812
|
+
remote.custom?.fields['consentForUnattendedDelivery'] === 'true' || false;
|
|
813
|
+
const pickupPoint = remote.custom?.fields['pickupPointId'] || '';
|
|
814
|
+
|
|
815
|
+
const shippingInstruction = {
|
|
816
|
+
shippingMethod: {
|
|
817
|
+
key: remote.shippingInfo.shippingMethod?.obj?.key || '',
|
|
818
|
+
},
|
|
819
|
+
pickupPoint: pickupPoint || '',
|
|
820
|
+
instructions: instructions || '',
|
|
821
|
+
consentForUnattendedDelivery: consentForUnattendedDelivery || false,
|
|
822
|
+
} satisfies ShippingInstruction;
|
|
823
|
+
|
|
824
|
+
return shippingInstruction;
|
|
825
|
+
}
|
|
644
826
|
}
|