@reactionary/source 0.3.18 → 0.6.2
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 +28 -14
- package/core/src/client/client-builder.ts +54 -6
- package/core/src/factories/cart.factory.ts +40 -0
- package/core/src/factories/category.factory.ts +40 -0
- package/core/src/factories/checkout.factory.ts +59 -0
- package/core/src/factories/identity.factory.ts +26 -0
- package/core/src/factories/index.ts +15 -0
- package/core/src/factories/inventory.factory.ts +26 -0
- package/core/src/factories/order-search.factory.ts +33 -0
- package/core/src/factories/order.factory.ts +21 -0
- package/core/src/factories/price.factory.ts +29 -0
- package/core/src/factories/product-associations.factory.ts +30 -0
- package/core/src/factories/product-list.factory.ts +82 -0
- package/core/src/factories/product-reviews.factory.ts +58 -0
- package/core/src/factories/product-search.factory.ts +31 -0
- package/core/src/factories/product.factory.ts +21 -0
- package/core/src/factories/profile.factory.ts +23 -0
- package/core/src/factories/store.factory.ts +21 -0
- package/core/src/index.ts +3 -1
- package/core/src/providers/cart.provider.ts +12 -10
- package/core/src/providers/category.provider.ts +9 -7
- package/core/src/providers/checkout.provider.ts +14 -10
- package/core/src/providers/identity.provider.ts +7 -7
- package/core/src/providers/inventory.provider.ts +4 -4
- package/core/src/providers/order-search.provider.ts +4 -2
- package/core/src/providers/order.provider.ts +4 -4
- package/core/src/providers/price.provider.ts +5 -5
- package/core/src/providers/product-associations.provider.ts +6 -4
- package/core/src/providers/product-list.provider.ts +13 -8
- package/core/src/providers/product-reviews.provider.ts +8 -4
- package/core/src/providers/product-search.provider.ts +15 -28
- package/core/src/providers/product.provider.ts +6 -6
- package/core/src/providers/profile.provider.ts +8 -8
- package/core/src/providers/store.provider.ts +2 -2
- package/core/src/test/client-builder.spec.ts +81 -0
- package/examples/node/package.json +7 -7
- package/examples/node/src/basic/basic-node-provider-model-extension.spec.ts +10 -4
- package/examples/node/src/basic/basic-node-provider-query-extension.spec.ts +8 -2
- package/examples/node/src/basic/basic-node-setup.spec.ts +5 -1
- package/examples/node/src/basic/client-creation.spec.ts +3 -3
- package/examples/node/src/utils.ts +41 -41
- package/examples/node/tsconfig.lib.json +2 -1
- package/package.json +1 -1
- package/providers/algolia/src/core/initialize.ts +76 -21
- package/providers/algolia/src/core/initialize.types.ts +107 -0
- package/providers/algolia/src/factories/index.ts +1 -0
- package/providers/algolia/src/factories/product-search/product-search.factory.ts +182 -0
- package/providers/algolia/src/index.ts +2 -2
- package/providers/algolia/src/providers/analytics.provider.ts +4 -4
- package/providers/algolia/src/providers/product-search.provider.ts +67 -184
- package/providers/algolia/src/schema/capabilities.schema.ts +81 -7
- package/providers/algolia/src/test/analytics.spec.ts +9 -1
- package/providers/algolia/src/test/client-builder-product-search-extension.example.ts +85 -0
- package/providers/commercetools/src/core/capability-descriptors.ts +324 -0
- package/providers/commercetools/src/core/initialize.ts +35 -151
- package/providers/commercetools/src/core/initialize.types.ts +174 -0
- package/providers/commercetools/src/factories/cart/cart.factory.ts +142 -0
- package/providers/commercetools/src/factories/category/category.factory.ts +77 -0
- package/providers/commercetools/src/factories/checkout/checkout-initializer-overrides.example.ts +94 -0
- package/providers/commercetools/src/factories/checkout/checkout.factory.ts +338 -0
- package/providers/commercetools/src/factories/identity/identity.factory.ts +26 -0
- package/providers/commercetools/src/factories/inventory/inventory.factory.ts +49 -0
- package/providers/commercetools/src/factories/order/order.factory.ts +149 -0
- package/providers/commercetools/src/factories/order-search/order-search.factory.ts +108 -0
- package/providers/commercetools/src/factories/price/price.factory.ts +76 -0
- package/providers/commercetools/src/factories/product/product-factory-baseline.example.ts +14 -0
- package/providers/commercetools/src/factories/product/product-factory-schema-and-parse-extension.example.ts +35 -0
- package/providers/commercetools/src/factories/product/product-factory-schema-extension.example.ts +23 -0
- package/providers/commercetools/src/factories/product/product-initializer-factory-extension.example.ts +41 -0
- package/providers/commercetools/src/factories/product/product-provider-custom-method-only.example.ts +47 -0
- package/providers/commercetools/src/factories/product/product-provider-schema-signature-extension.example.ts +61 -0
- package/providers/commercetools/src/factories/product/product.factory.ts +220 -0
- package/providers/commercetools/src/factories/product/utils.example.ts +9 -0
- package/providers/commercetools/src/factories/product-associations/product-associations.factory.ts +103 -0
- package/providers/commercetools/src/factories/product-list/product-list.factory.ts +122 -0
- package/providers/commercetools/src/factories/product-reviews/product-reviews.factory.ts +81 -0
- package/providers/commercetools/src/factories/product-search/product-search.factory.ts +182 -0
- package/providers/commercetools/src/factories/profile/profile.factory.ts +94 -0
- package/providers/commercetools/src/factories/store/store.factory.ts +49 -0
- package/providers/commercetools/src/index.ts +15 -0
- package/providers/commercetools/src/providers/cart.provider.ts +67 -193
- package/providers/commercetools/src/providers/category.provider.ts +24 -64
- package/providers/commercetools/src/providers/checkout.provider.ts +50 -322
- package/providers/commercetools/src/providers/identity.provider.ts +35 -15
- package/providers/commercetools/src/providers/inventory.provider.ts +13 -31
- package/providers/commercetools/src/providers/order-search.provider.ts +16 -110
- package/providers/commercetools/src/providers/order.provider.ts +13 -144
- package/providers/commercetools/src/providers/price.provider.ts +37 -51
- package/providers/commercetools/src/providers/product-associations.provider.ts +39 -104
- package/providers/commercetools/src/providers/product-list.provider.ts +38 -23
- package/providers/commercetools/src/providers/product-reviews.provider.ts +34 -14
- package/providers/commercetools/src/providers/product-search.provider.ts +17 -170
- package/providers/commercetools/src/providers/product.provider.ts +20 -199
- package/providers/commercetools/src/providers/profile.provider.ts +27 -73
- package/providers/commercetools/src/providers/store.provider.ts +13 -31
- package/providers/commercetools/src/schema/capabilities.schema.ts +258 -20
- package/providers/commercetools/src/test/caching.spec.ts +18 -2
- package/providers/commercetools/src/test/client-builder-merge-extensions.example.ts +125 -0
- package/providers/fake/src/core/initialize.ts +213 -44
- package/providers/fake/src/core/initialize.types.ts +164 -0
- package/providers/fake/src/factories/cart/cart.factory.ts +34 -0
- package/providers/fake/src/factories/category/category.factory.ts +40 -0
- package/providers/fake/src/factories/checkout/checkout.factory.ts +53 -0
- package/providers/fake/src/factories/identity/identity.factory.ts +25 -0
- package/providers/fake/src/factories/index.ts +14 -0
- package/providers/fake/src/factories/inventory/inventory.factory.ts +25 -0
- package/providers/fake/src/factories/order/order.factory.ts +22 -0
- package/providers/fake/src/factories/order-search/order-search.factory.ts +27 -0
- package/providers/fake/src/factories/price/price.factory.ts +26 -0
- package/providers/fake/src/factories/product/product.factory.ts +22 -0
- package/providers/fake/src/factories/product-associations/product-associations.factory.ts +25 -0
- package/providers/fake/src/factories/product-reviews/product-reviews.factory.ts +53 -0
- package/providers/fake/src/factories/product-search/product-search.factory.ts +27 -0
- package/providers/fake/src/factories/profile/profile.factory.ts +22 -0
- package/providers/fake/src/factories/store/store.factory.ts +22 -0
- package/providers/fake/src/index.ts +2 -0
- package/providers/fake/src/providers/cart.provider.ts +23 -14
- package/providers/fake/src/providers/category.provider.ts +120 -105
- package/providers/fake/src/providers/checkout.provider.ts +39 -20
- package/providers/fake/src/providers/identity.provider.ts +40 -34
- package/providers/fake/src/providers/inventory.provider.ts +26 -24
- package/providers/fake/src/providers/order-search.provider.ts +38 -30
- package/providers/fake/src/providers/order.provider.ts +21 -37
- package/providers/fake/src/providers/price.provider.ts +42 -34
- package/providers/fake/src/providers/product-associations.provider.ts +23 -10
- package/providers/fake/src/providers/product-reviews.provider.ts +71 -69
- package/providers/fake/src/providers/product-search.provider.ts +43 -70
- package/providers/fake/src/providers/product.provider.ts +34 -32
- package/providers/fake/src/providers/profile.provider.ts +62 -55
- package/providers/fake/src/providers/store.provider.ts +38 -22
- package/providers/fake/src/schema/capabilities.schema.ts +175 -18
- package/providers/fake/src/test/cart.provider.spec.ts +20 -3
- package/providers/fake/src/test/category.provider.spec.ts +4 -1
- package/providers/fake/src/test/checkout.provider.spec.ts +12 -2
- package/providers/fake/src/test/client-builder-product-extension.example.ts +75 -0
- package/providers/fake/src/test/order-search.provider.spec.ts +4 -7
- package/providers/fake/src/test/order.provider.spec.ts +4 -6
- package/providers/fake/src/test/price.provider.spec.ts +3 -1
- package/providers/fake/src/test/product.provider.spec.ts +8 -2
- package/providers/fake/src/test/profile.provider.spec.ts +4 -2
- package/providers/google-analytics/src/core/initialize.ts +37 -12
- package/providers/google-analytics/src/core/initialize.types.ts +47 -0
- package/providers/google-analytics/src/index.ts +1 -0
- package/providers/google-analytics/src/schema/capabilities.schema.ts +31 -5
- package/providers/medusa/src/core/initialize.ts +324 -81
- package/providers/medusa/src/core/initialize.types.ts +184 -0
- package/providers/medusa/src/factories/cart/cart.factory.ts +34 -0
- package/providers/medusa/src/factories/category/category.factory.ts +37 -0
- package/providers/medusa/src/factories/checkout/checkout.factory.ts +50 -0
- package/providers/medusa/src/factories/identity/identity.factory.ts +22 -0
- package/providers/medusa/src/factories/index.ts +12 -0
- package/providers/medusa/src/factories/inventory/inventory.factory.ts +25 -0
- package/providers/medusa/src/factories/order/order.factory.ts +22 -0
- package/providers/medusa/src/factories/order-search/order-search.factory.ts +27 -0
- package/providers/medusa/src/factories/price/price.factory.ts +26 -0
- package/providers/medusa/src/factories/product/product.factory.ts +22 -0
- package/providers/medusa/src/factories/product-associations/product-associations.factory.ts +25 -0
- package/providers/medusa/src/factories/product-search/product-search.factory.ts +27 -0
- package/providers/medusa/src/factories/profile/profile.factory.ts +22 -0
- package/providers/medusa/src/index.ts +2 -0
- package/providers/medusa/src/providers/cart.provider.ts +33 -20
- package/providers/medusa/src/providers/category.provider.ts +30 -12
- package/providers/medusa/src/providers/checkout.provider.ts +42 -17
- package/providers/medusa/src/providers/identity.provider.ts +1 -1
- package/providers/medusa/src/providers/inventory.provider.ts +21 -7
- package/providers/medusa/src/providers/order-search.provider.ts +16 -5
- package/providers/medusa/src/providers/order.provider.ts +17 -5
- package/providers/medusa/src/providers/price.provider.ts +26 -7
- package/providers/medusa/src/providers/product-associations.provider.ts +19 -8
- package/providers/medusa/src/providers/product-search.provider.ts +19 -31
- package/providers/medusa/src/providers/product.provider.ts +47 -11
- package/providers/medusa/src/providers/profile.provider.ts +35 -11
- package/providers/medusa/src/schema/capabilities.schema.ts +229 -18
- package/providers/medusa/src/test/cart.provider.spec.ts +18 -2
- package/providers/medusa/src/test/category.provider.spec.ts +4 -1
- package/providers/medusa/src/test/checkout.spec.ts +9 -9
- package/providers/medusa/src/test/inventory.provider.spec.ts +3 -1
- package/providers/medusa/src/test/large-cart.provider.spec.ts +8 -2
- package/providers/medusa/src/test/price.provider.spec.ts +8 -1
- package/providers/medusa/src/test/product.provider.spec.ts +3 -1
- package/providers/medusa/src/test/search.provider.spec.ts +16 -3
- package/providers/meilisearch/src/core/initialize.ts +88 -21
- package/providers/meilisearch/src/core/initialize.types.ts +119 -0
- package/providers/meilisearch/src/factories/index.ts +2 -0
- package/providers/meilisearch/src/factories/order-search/order-search.factory.ts +27 -0
- package/providers/meilisearch/src/factories/product-search/product-search.factory.ts +27 -0
- package/providers/meilisearch/src/index.ts +2 -0
- package/providers/meilisearch/src/providers/index.ts +1 -0
- package/providers/meilisearch/src/providers/order-search.provider.ts +21 -6
- package/providers/meilisearch/src/providers/product-search.provider.ts +24 -8
- package/providers/meilisearch/src/schema/capabilities.schema.ts +95 -8
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Address as CTAddress,
|
|
3
|
+
Cart as CTCart,
|
|
4
|
+
LineItem,
|
|
5
|
+
Payment as CTPayment,
|
|
6
|
+
ShippingMethod as CTShippingMethod,
|
|
7
|
+
} from '@commercetools/platform-sdk';
|
|
8
|
+
import type {
|
|
9
|
+
CheckoutSchema,
|
|
10
|
+
PaymentMethodSchema,
|
|
11
|
+
ShippingMethodSchema} from '@reactionary/core';
|
|
12
|
+
import {
|
|
13
|
+
CheckoutItemSchema,
|
|
14
|
+
type Address,
|
|
15
|
+
type AnyCheckoutSchema,
|
|
16
|
+
type AnyPaymentMethodSchema,
|
|
17
|
+
type AnyShippingMethodSchema,
|
|
18
|
+
type Checkout,
|
|
19
|
+
type CheckoutFactory,
|
|
20
|
+
type CheckoutIdentifier,
|
|
21
|
+
type CheckoutItem,
|
|
22
|
+
type CostBreakDown,
|
|
23
|
+
type Currency,
|
|
24
|
+
type MonetaryAmount,
|
|
25
|
+
type PaymentInstruction,
|
|
26
|
+
type PaymentInstructionIdentifier,
|
|
27
|
+
type PaymentMethod,
|
|
28
|
+
type PaymentMethodIdentifier,
|
|
29
|
+
type PaymentStatus,
|
|
30
|
+
type RequestContext,
|
|
31
|
+
type ShippingInstruction,
|
|
32
|
+
type ShippingMethod,
|
|
33
|
+
type ShippingMethodIdentifier,
|
|
34
|
+
} from '@reactionary/core';
|
|
35
|
+
import type * as z from 'zod';
|
|
36
|
+
import type {
|
|
37
|
+
CommercetoolsCartIdentifier,
|
|
38
|
+
CommercetoolsCheckoutIdentifier,
|
|
39
|
+
} from '../../schema/commercetools.schema.js';
|
|
40
|
+
|
|
41
|
+
export class CommercetoolsCheckoutFactory<
|
|
42
|
+
TCheckoutSchema extends AnyCheckoutSchema = typeof CheckoutSchema,
|
|
43
|
+
TShippingMethodSchema extends AnyShippingMethodSchema = typeof ShippingMethodSchema,
|
|
44
|
+
TPaymentMethodSchema extends AnyPaymentMethodSchema = typeof PaymentMethodSchema,
|
|
45
|
+
> implements
|
|
46
|
+
CheckoutFactory<TCheckoutSchema, TShippingMethodSchema, TPaymentMethodSchema>
|
|
47
|
+
{
|
|
48
|
+
public readonly checkoutSchema: TCheckoutSchema;
|
|
49
|
+
public readonly shippingMethodSchema: TShippingMethodSchema;
|
|
50
|
+
public readonly paymentMethodSchema: TPaymentMethodSchema;
|
|
51
|
+
|
|
52
|
+
constructor(
|
|
53
|
+
checkoutSchema: TCheckoutSchema,
|
|
54
|
+
shippingMethodSchema: TShippingMethodSchema,
|
|
55
|
+
paymentMethodSchema: TPaymentMethodSchema,
|
|
56
|
+
) {
|
|
57
|
+
this.checkoutSchema = checkoutSchema;
|
|
58
|
+
this.shippingMethodSchema = shippingMethodSchema;
|
|
59
|
+
this.paymentMethodSchema = paymentMethodSchema;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public parseCheckout(
|
|
63
|
+
context: RequestContext,
|
|
64
|
+
data: CTCart,
|
|
65
|
+
): z.output<TCheckoutSchema> {
|
|
66
|
+
const identifier = {
|
|
67
|
+
key: data.id,
|
|
68
|
+
version: data.version || 0,
|
|
69
|
+
} satisfies CommercetoolsCheckoutIdentifier;
|
|
70
|
+
|
|
71
|
+
const originalCartReference = {
|
|
72
|
+
key: data.custom?.fields['commerceToolsCartId'] || '',
|
|
73
|
+
version: 0,
|
|
74
|
+
} satisfies CommercetoolsCartIdentifier;
|
|
75
|
+
|
|
76
|
+
let shippingAddress: Address | undefined;
|
|
77
|
+
if (data.shippingAddress) {
|
|
78
|
+
shippingAddress = this.parseAddress(data.shippingAddress);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
let billingAddress: Address | undefined;
|
|
82
|
+
if (data.billingAddress) {
|
|
83
|
+
billingAddress = this.parseAddress(data.billingAddress);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const paymentInstructions: PaymentInstruction[] = [];
|
|
87
|
+
for (const payment of data.paymentInfo?.payments || []) {
|
|
88
|
+
if (payment.obj) {
|
|
89
|
+
paymentInstructions.push(this.parsePaymentInstruction(context, payment.obj));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const grandTotal = data.totalPrice.centAmount || 0;
|
|
94
|
+
const shippingTotal = data.shippingInfo?.price.centAmount || 0;
|
|
95
|
+
const productTotal = grandTotal - shippingTotal;
|
|
96
|
+
const taxTotal = data.taxedPrice?.totalTax?.centAmount || 0;
|
|
97
|
+
const discountTotal = data.discountOnTotalPrice?.discountedAmount.centAmount || 0;
|
|
98
|
+
const surchargeTotal = 0;
|
|
99
|
+
const currency = data.totalPrice.currencyCode as Currency;
|
|
100
|
+
|
|
101
|
+
const price = {
|
|
102
|
+
totalTax: {
|
|
103
|
+
value: taxTotal / 100,
|
|
104
|
+
currency,
|
|
105
|
+
},
|
|
106
|
+
totalDiscount: {
|
|
107
|
+
value: discountTotal / 100,
|
|
108
|
+
currency,
|
|
109
|
+
},
|
|
110
|
+
totalSurcharge: {
|
|
111
|
+
value: surchargeTotal / 100,
|
|
112
|
+
currency,
|
|
113
|
+
},
|
|
114
|
+
totalShipping: {
|
|
115
|
+
value: shippingTotal / 100,
|
|
116
|
+
currency,
|
|
117
|
+
},
|
|
118
|
+
totalProductPrice: {
|
|
119
|
+
value: productTotal / 100,
|
|
120
|
+
currency,
|
|
121
|
+
},
|
|
122
|
+
grandTotal: {
|
|
123
|
+
value: grandTotal / 100,
|
|
124
|
+
currency,
|
|
125
|
+
},
|
|
126
|
+
} satisfies CostBreakDown;
|
|
127
|
+
|
|
128
|
+
const items: CheckoutItem[] = [];
|
|
129
|
+
for (const lineItem of data.lineItems) {
|
|
130
|
+
items.push(this.parseCheckoutItem(lineItem));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const shippingInstruction = this.parseShippingInstruction(data);
|
|
134
|
+
const readyForFinalization = this.isReadyForFinalization(
|
|
135
|
+
price,
|
|
136
|
+
paymentInstructions,
|
|
137
|
+
billingAddress,
|
|
138
|
+
shippingAddress,
|
|
139
|
+
shippingInstruction,
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const result = {
|
|
143
|
+
identifier,
|
|
144
|
+
originalCartReference,
|
|
145
|
+
name: data.custom?.fields['name'] || '',
|
|
146
|
+
description: data.custom?.fields['description'] || '',
|
|
147
|
+
readyForFinalization,
|
|
148
|
+
billingAddress,
|
|
149
|
+
shippingAddress,
|
|
150
|
+
shippingInstruction,
|
|
151
|
+
paymentInstructions,
|
|
152
|
+
items,
|
|
153
|
+
price,
|
|
154
|
+
} satisfies Checkout;
|
|
155
|
+
|
|
156
|
+
return this.checkoutSchema.parse(result);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
public parseShippingMethod(
|
|
160
|
+
context: RequestContext,
|
|
161
|
+
data: CTShippingMethod,
|
|
162
|
+
): z.output<TShippingMethodSchema> {
|
|
163
|
+
const identifier = {
|
|
164
|
+
key: data.key || '',
|
|
165
|
+
} satisfies ShippingMethodIdentifier;
|
|
166
|
+
|
|
167
|
+
const result = {
|
|
168
|
+
deliveryTime: '',
|
|
169
|
+
description: data.localizedDescription?.[context.languageContext.locale] || '',
|
|
170
|
+
identifier,
|
|
171
|
+
name: data.name,
|
|
172
|
+
price: data.zoneRates[0].shippingRates[0].price
|
|
173
|
+
? {
|
|
174
|
+
value: (data.zoneRates[0].shippingRates[0].price.centAmount || 0) / 100,
|
|
175
|
+
currency:
|
|
176
|
+
(data.zoneRates[0].shippingRates[0].price.currencyCode as Currency) ||
|
|
177
|
+
context.languageContext.currencyCode,
|
|
178
|
+
}
|
|
179
|
+
: { value: 0, currency: context.languageContext.currencyCode },
|
|
180
|
+
} satisfies ShippingMethod;
|
|
181
|
+
|
|
182
|
+
return this.shippingMethodSchema.parse(result);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
public parsePaymentMethod(
|
|
186
|
+
_context: RequestContext,
|
|
187
|
+
data: PaymentMethod,
|
|
188
|
+
): z.output<TPaymentMethodSchema> {
|
|
189
|
+
return this.paymentMethodSchema.parse(data);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
protected parseCheckoutItem(remoteItem: LineItem): CheckoutItem {
|
|
193
|
+
const unitPrice = remoteItem.price.value.centAmount;
|
|
194
|
+
const totalPrice = remoteItem.totalPrice.centAmount || 0;
|
|
195
|
+
const totalDiscount = remoteItem.price.discounted?.value.centAmount || 0;
|
|
196
|
+
const unitDiscount = totalDiscount / remoteItem.quantity;
|
|
197
|
+
const currency = remoteItem.price.value.currencyCode.toUpperCase() as Currency;
|
|
198
|
+
|
|
199
|
+
const item = {
|
|
200
|
+
identifier: {
|
|
201
|
+
key: remoteItem.id,
|
|
202
|
+
},
|
|
203
|
+
variant: {
|
|
204
|
+
sku: remoteItem.variant.sku || '',
|
|
205
|
+
},
|
|
206
|
+
quantity: remoteItem.quantity,
|
|
207
|
+
price: {
|
|
208
|
+
unitPrice: {
|
|
209
|
+
value: unitPrice / 100,
|
|
210
|
+
currency,
|
|
211
|
+
},
|
|
212
|
+
unitDiscount: {
|
|
213
|
+
value: unitDiscount / 100,
|
|
214
|
+
currency,
|
|
215
|
+
},
|
|
216
|
+
totalPrice: {
|
|
217
|
+
value: totalPrice / 100,
|
|
218
|
+
currency,
|
|
219
|
+
},
|
|
220
|
+
totalDiscount: {
|
|
221
|
+
value: totalDiscount / 100,
|
|
222
|
+
currency,
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
} satisfies CheckoutItem;
|
|
226
|
+
|
|
227
|
+
return CheckoutItemSchema.parse(item);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
protected isReadyForFinalization(
|
|
231
|
+
price: CostBreakDown,
|
|
232
|
+
paymentInstructions: PaymentInstruction[],
|
|
233
|
+
billingAddress?: Address,
|
|
234
|
+
shippingAddress?: Address,
|
|
235
|
+
shippingInstruction?: ShippingInstruction,
|
|
236
|
+
): boolean {
|
|
237
|
+
if (!billingAddress) return false;
|
|
238
|
+
if (!shippingInstruction) return false;
|
|
239
|
+
if (!shippingAddress && !shippingInstruction.pickupPoint) return false;
|
|
240
|
+
if (paymentInstructions.length === 0) return false;
|
|
241
|
+
|
|
242
|
+
const authorizedPayments = paymentInstructions
|
|
243
|
+
.filter((paymentInstruction) => paymentInstruction.status === 'authorized')
|
|
244
|
+
.map((paymentInstruction) => paymentInstruction.amount.value)
|
|
245
|
+
.reduce((sum, value) => sum + value, 0);
|
|
246
|
+
|
|
247
|
+
if (price.grandTotal.value !== authorizedPayments) return false;
|
|
248
|
+
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
protected parsePaymentInstruction(
|
|
253
|
+
context: RequestContext,
|
|
254
|
+
data: CTPayment,
|
|
255
|
+
): PaymentInstruction {
|
|
256
|
+
const identifier = {
|
|
257
|
+
key: data.id,
|
|
258
|
+
} satisfies PaymentInstructionIdentifier;
|
|
259
|
+
|
|
260
|
+
const amount = {
|
|
261
|
+
value: data.amountPlanned.centAmount / 100,
|
|
262
|
+
currency: data.amountPlanned.currencyCode as Currency,
|
|
263
|
+
} satisfies MonetaryAmount;
|
|
264
|
+
|
|
265
|
+
const method = data.paymentMethodInfo?.method || 'unknown';
|
|
266
|
+
const paymentProcessor = data.paymentMethodInfo?.paymentInterface || method;
|
|
267
|
+
const paymentName = data.paymentMethodInfo.name?.[context.languageContext.locale];
|
|
268
|
+
|
|
269
|
+
const paymentMethod = {
|
|
270
|
+
method,
|
|
271
|
+
paymentProcessor,
|
|
272
|
+
name: paymentName || method || 'Unknown',
|
|
273
|
+
} satisfies PaymentMethodIdentifier;
|
|
274
|
+
|
|
275
|
+
const customData = data.custom?.fields || {};
|
|
276
|
+
const protocolData = Object.keys(customData).map((key) => ({
|
|
277
|
+
key,
|
|
278
|
+
value: customData[key],
|
|
279
|
+
}));
|
|
280
|
+
|
|
281
|
+
let status: PaymentStatus = 'pending';
|
|
282
|
+
if (data.transactions && data.transactions.length > 0) {
|
|
283
|
+
const lastTransaction = data.transactions[data.transactions.length - 1];
|
|
284
|
+
if (
|
|
285
|
+
lastTransaction.type === 'Authorization' &&
|
|
286
|
+
lastTransaction.state === 'Success'
|
|
287
|
+
) {
|
|
288
|
+
status = 'authorized';
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const result = {
|
|
293
|
+
amount,
|
|
294
|
+
identifier,
|
|
295
|
+
paymentMethod,
|
|
296
|
+
protocolData,
|
|
297
|
+
status,
|
|
298
|
+
} satisfies PaymentInstruction;
|
|
299
|
+
|
|
300
|
+
return result;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
protected parseAddress(data: CTAddress): Address {
|
|
304
|
+
return {
|
|
305
|
+
countryCode: data.country || '',
|
|
306
|
+
firstName: data.firstName || '',
|
|
307
|
+
lastName: data.lastName || '',
|
|
308
|
+
streetAddress: data.streetName || '',
|
|
309
|
+
streetNumber: data.streetNumber || '',
|
|
310
|
+
postalCode: data.postalCode || '',
|
|
311
|
+
city: data.city || '',
|
|
312
|
+
identifier: {
|
|
313
|
+
nickName: '',
|
|
314
|
+
},
|
|
315
|
+
region: '',
|
|
316
|
+
} satisfies Address;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
protected parseShippingInstruction(data: CTCart): ShippingInstruction | undefined {
|
|
320
|
+
if (!data.shippingInfo) return undefined;
|
|
321
|
+
|
|
322
|
+
const instructions = data.custom?.fields['shippingInstruction'] || '';
|
|
323
|
+
const consentForUnattendedDelivery =
|
|
324
|
+
data.custom?.fields['consentForUnattendedDelivery'] === 'true';
|
|
325
|
+
const pickupPoint = data.custom?.fields['pickupPointId'] || '';
|
|
326
|
+
|
|
327
|
+
const result = {
|
|
328
|
+
shippingMethod: {
|
|
329
|
+
key: data.shippingInfo.shippingMethod?.obj?.key || '',
|
|
330
|
+
},
|
|
331
|
+
pickupPoint,
|
|
332
|
+
instructions,
|
|
333
|
+
consentForUnattendedDelivery,
|
|
334
|
+
} satisfies ShippingInstruction;
|
|
335
|
+
|
|
336
|
+
return result;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IdentitySchema} from '@reactionary/core';
|
|
3
|
+
import {
|
|
4
|
+
type AnyIdentitySchema,
|
|
5
|
+
type IdentityFactory,
|
|
6
|
+
type RequestContext,
|
|
7
|
+
} from '@reactionary/core';
|
|
8
|
+
import type * as z from 'zod';
|
|
9
|
+
|
|
10
|
+
export class CommercetoolsIdentityFactory<
|
|
11
|
+
TIdentitySchema extends AnyIdentitySchema = typeof IdentitySchema,
|
|
12
|
+
> implements IdentityFactory<TIdentitySchema>
|
|
13
|
+
{
|
|
14
|
+
public readonly identitySchema: TIdentitySchema;
|
|
15
|
+
|
|
16
|
+
constructor(identitySchema: TIdentitySchema) {
|
|
17
|
+
this.identitySchema = identitySchema;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public parseIdentity(
|
|
21
|
+
_context: RequestContext,
|
|
22
|
+
data: unknown,
|
|
23
|
+
): z.output<TIdentitySchema> {
|
|
24
|
+
return this.identitySchema.parse(data);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { InventoryEntry } from '@commercetools/platform-sdk';
|
|
2
|
+
import type {
|
|
3
|
+
InventorySchema} from '@reactionary/core';
|
|
4
|
+
import {
|
|
5
|
+
type AnyInventorySchema,
|
|
6
|
+
type Inventory,
|
|
7
|
+
type InventoryFactory,
|
|
8
|
+
type InventoryIdentifier,
|
|
9
|
+
type InventoryStatus,
|
|
10
|
+
type RequestContext,
|
|
11
|
+
} from '@reactionary/core';
|
|
12
|
+
import type * as z from 'zod';
|
|
13
|
+
|
|
14
|
+
export class CommercetoolsInventoryFactory<
|
|
15
|
+
TInventorySchema extends AnyInventorySchema = typeof InventorySchema,
|
|
16
|
+
> implements InventoryFactory<TInventorySchema>
|
|
17
|
+
{
|
|
18
|
+
public readonly inventorySchema: TInventorySchema;
|
|
19
|
+
|
|
20
|
+
constructor(inventorySchema: TInventorySchema) {
|
|
21
|
+
this.inventorySchema = inventorySchema;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public parseInventory(
|
|
25
|
+
_context: RequestContext,
|
|
26
|
+
data: InventoryEntry,
|
|
27
|
+
): z.output<TInventorySchema> {
|
|
28
|
+
const identifier = {
|
|
29
|
+
variant: { sku: data.sku || '' },
|
|
30
|
+
fulfillmentCenter: {
|
|
31
|
+
key: data.supplyChannel?.obj?.key || '',
|
|
32
|
+
},
|
|
33
|
+
} satisfies InventoryIdentifier;
|
|
34
|
+
|
|
35
|
+
const quantity = data.availableQuantity || 0;
|
|
36
|
+
let status: InventoryStatus = 'outOfStock';
|
|
37
|
+
if (quantity > 0) {
|
|
38
|
+
status = 'inStock';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const result = {
|
|
42
|
+
identifier,
|
|
43
|
+
quantity,
|
|
44
|
+
status,
|
|
45
|
+
} satisfies Inventory;
|
|
46
|
+
|
|
47
|
+
return this.inventorySchema.parse(result);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { Order as CTOrder } from '@commercetools/platform-sdk';
|
|
2
|
+
import type {
|
|
3
|
+
OrderSchema} from '@reactionary/core';
|
|
4
|
+
import {
|
|
5
|
+
type AnyOrderSchema,
|
|
6
|
+
type CostBreakDown,
|
|
7
|
+
type Currency,
|
|
8
|
+
type ItemCostBreakdown,
|
|
9
|
+
type Order,
|
|
10
|
+
type OrderFactory,
|
|
11
|
+
type OrderIdentifier,
|
|
12
|
+
type OrderItem,
|
|
13
|
+
type OrderStatus,
|
|
14
|
+
type ProductVariantIdentifier,
|
|
15
|
+
type RequestContext,
|
|
16
|
+
} from '@reactionary/core';
|
|
17
|
+
import type * as z from 'zod';
|
|
18
|
+
import type { CommercetoolsOrderIdentifier } from '../../schema/commercetools.schema.js';
|
|
19
|
+
|
|
20
|
+
export class CommercetoolsOrderFactory<
|
|
21
|
+
TOrderSchema extends AnyOrderSchema = typeof OrderSchema,
|
|
22
|
+
> implements OrderFactory<TOrderSchema>
|
|
23
|
+
{
|
|
24
|
+
public readonly orderSchema: TOrderSchema;
|
|
25
|
+
|
|
26
|
+
constructor(orderSchema: TOrderSchema) {
|
|
27
|
+
this.orderSchema = orderSchema;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public parseOrder(
|
|
31
|
+
_context: RequestContext,
|
|
32
|
+
data: CTOrder,
|
|
33
|
+
): z.output<TOrderSchema> {
|
|
34
|
+
const identifier = {
|
|
35
|
+
key: data.id,
|
|
36
|
+
version: data.version || 0,
|
|
37
|
+
} satisfies CommercetoolsOrderIdentifier;
|
|
38
|
+
|
|
39
|
+
const name = data.custom?.fields['name'] || '';
|
|
40
|
+
const description = data.custom?.fields['description'] || '';
|
|
41
|
+
|
|
42
|
+
const grandTotal = data.totalPrice.centAmount || 0;
|
|
43
|
+
const shippingTotal = data.shippingInfo?.price.centAmount || 0;
|
|
44
|
+
const productTotal = grandTotal - shippingTotal;
|
|
45
|
+
const taxTotal = data.taxedPrice?.totalTax?.centAmount || 0;
|
|
46
|
+
const discountTotal = data.discountOnTotalPrice?.discountedAmount.centAmount || 0;
|
|
47
|
+
const surchargeTotal = 0;
|
|
48
|
+
const currency = data.totalPrice.currencyCode as Currency;
|
|
49
|
+
|
|
50
|
+
const price = {
|
|
51
|
+
totalTax: {
|
|
52
|
+
value: taxTotal / 100,
|
|
53
|
+
currency,
|
|
54
|
+
},
|
|
55
|
+
totalDiscount: {
|
|
56
|
+
value: discountTotal / 100,
|
|
57
|
+
currency,
|
|
58
|
+
},
|
|
59
|
+
totalSurcharge: {
|
|
60
|
+
value: surchargeTotal / 100,
|
|
61
|
+
currency,
|
|
62
|
+
},
|
|
63
|
+
totalShipping: {
|
|
64
|
+
value: shippingTotal / 100,
|
|
65
|
+
currency: data.shippingInfo?.price.currencyCode as Currency,
|
|
66
|
+
},
|
|
67
|
+
totalProductPrice: {
|
|
68
|
+
value: productTotal / 100,
|
|
69
|
+
currency,
|
|
70
|
+
},
|
|
71
|
+
grandTotal: {
|
|
72
|
+
value: grandTotal / 100,
|
|
73
|
+
currency,
|
|
74
|
+
},
|
|
75
|
+
} satisfies CostBreakDown;
|
|
76
|
+
|
|
77
|
+
let orderStatus: OrderStatus = 'AwaitingPayment';
|
|
78
|
+
if (data.paymentState === 'Paid' && data.orderState === 'Confirmed') {
|
|
79
|
+
orderStatus = 'ReleasedToFulfillment';
|
|
80
|
+
}
|
|
81
|
+
if (data.shipmentState === 'Ready' && data.orderState === 'Confirmed') {
|
|
82
|
+
orderStatus = 'ReleasedToFulfillment';
|
|
83
|
+
}
|
|
84
|
+
if (
|
|
85
|
+
(data.shipmentState === 'Shipped' || data.shipmentState === 'Delivered') &&
|
|
86
|
+
data.orderState === 'Completed'
|
|
87
|
+
) {
|
|
88
|
+
orderStatus = 'Shipped';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const items: OrderItem[] = [];
|
|
92
|
+
for (const remoteItem of data.lineItems) {
|
|
93
|
+
const lineIdentifier = {
|
|
94
|
+
key: remoteItem.id,
|
|
95
|
+
} satisfies OrderIdentifier;
|
|
96
|
+
const variant = {
|
|
97
|
+
sku: remoteItem.variant.sku || '',
|
|
98
|
+
} satisfies ProductVariantIdentifier;
|
|
99
|
+
|
|
100
|
+
const unitPrice = remoteItem.price.value.centAmount;
|
|
101
|
+
const totalPrice = remoteItem.totalPrice.centAmount || 0;
|
|
102
|
+
const totalDiscount = remoteItem.price.discounted?.value.centAmount || 0;
|
|
103
|
+
const unitDiscount = totalDiscount / remoteItem.quantity;
|
|
104
|
+
|
|
105
|
+
const linePrice = {
|
|
106
|
+
unitPrice: {
|
|
107
|
+
value: unitPrice / 100,
|
|
108
|
+
currency,
|
|
109
|
+
},
|
|
110
|
+
unitDiscount: {
|
|
111
|
+
value: unitDiscount / 100,
|
|
112
|
+
currency,
|
|
113
|
+
},
|
|
114
|
+
totalPrice: {
|
|
115
|
+
value: totalPrice / 100,
|
|
116
|
+
currency,
|
|
117
|
+
},
|
|
118
|
+
totalDiscount: {
|
|
119
|
+
value: totalDiscount / 100,
|
|
120
|
+
currency,
|
|
121
|
+
},
|
|
122
|
+
} satisfies ItemCostBreakdown;
|
|
123
|
+
|
|
124
|
+
items.push({
|
|
125
|
+
identifier: lineIdentifier,
|
|
126
|
+
inventoryStatus: 'NotAllocated',
|
|
127
|
+
price: linePrice,
|
|
128
|
+
quantity: remoteItem.quantity,
|
|
129
|
+
variant,
|
|
130
|
+
} satisfies OrderItem);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const result = {
|
|
134
|
+
identifier,
|
|
135
|
+
name,
|
|
136
|
+
description,
|
|
137
|
+
price,
|
|
138
|
+
items,
|
|
139
|
+
inventoryStatus: 'NotAllocated',
|
|
140
|
+
paymentInstructions: [],
|
|
141
|
+
userId: {
|
|
142
|
+
userId: '',
|
|
143
|
+
},
|
|
144
|
+
orderStatus,
|
|
145
|
+
} satisfies Order;
|
|
146
|
+
|
|
147
|
+
return this.orderSchema.parse(result);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Address as CTAddress,
|
|
3
|
+
Order as CTOrder,
|
|
4
|
+
OrderPagedQueryResponse,
|
|
5
|
+
} from '@commercetools/platform-sdk';
|
|
6
|
+
import type {
|
|
7
|
+
OrderSearchResultSchema} from '@reactionary/core';
|
|
8
|
+
import {
|
|
9
|
+
type Address,
|
|
10
|
+
type AnyOrderSearchResultSchema,
|
|
11
|
+
type Currency,
|
|
12
|
+
type IdentityIdentifier,
|
|
13
|
+
type MonetaryAmount,
|
|
14
|
+
type OrderSearchFactory,
|
|
15
|
+
type OrderSearchQueryByTerm,
|
|
16
|
+
type OrderSearchResult,
|
|
17
|
+
type OrderSearchResultItem,
|
|
18
|
+
type OrderStatus,
|
|
19
|
+
type RequestContext,
|
|
20
|
+
} from '@reactionary/core';
|
|
21
|
+
import type * as z from 'zod';
|
|
22
|
+
|
|
23
|
+
export class CommercetoolsOrderSearchFactory<
|
|
24
|
+
TOrderSearchResultSchema extends AnyOrderSearchResultSchema = typeof OrderSearchResultSchema,
|
|
25
|
+
> implements OrderSearchFactory<TOrderSearchResultSchema>
|
|
26
|
+
{
|
|
27
|
+
public readonly orderSearchResultSchema: TOrderSearchResultSchema;
|
|
28
|
+
|
|
29
|
+
constructor(orderSearchResultSchema: TOrderSearchResultSchema) {
|
|
30
|
+
this.orderSearchResultSchema = orderSearchResultSchema;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public parseOrderSearchResult(
|
|
34
|
+
context: RequestContext,
|
|
35
|
+
data: OrderPagedQueryResponse,
|
|
36
|
+
query: OrderSearchQueryByTerm,
|
|
37
|
+
): z.output<TOrderSearchResultSchema> {
|
|
38
|
+
const result = {
|
|
39
|
+
identifier: {
|
|
40
|
+
...query.search,
|
|
41
|
+
},
|
|
42
|
+
pageNumber: (Math.ceil(data.offset / data.limit) || 0) + 1,
|
|
43
|
+
pageSize: data.limit,
|
|
44
|
+
totalCount: data.total || 0,
|
|
45
|
+
totalPages: Math.ceil((data.total || 0) / data.limit || 0) + 1,
|
|
46
|
+
items: data.results.map((order) => this.parseOrderSearchItem(context, order)),
|
|
47
|
+
} satisfies OrderSearchResult;
|
|
48
|
+
|
|
49
|
+
return this.orderSearchResultSchema.parse(result);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
protected parseAddress(data: CTAddress): Address {
|
|
53
|
+
return {
|
|
54
|
+
countryCode: data.country || '',
|
|
55
|
+
firstName: data.firstName || '',
|
|
56
|
+
lastName: data.lastName || '',
|
|
57
|
+
streetAddress: data.streetName || '',
|
|
58
|
+
streetNumber: data.streetNumber || '',
|
|
59
|
+
postalCode: data.postalCode || '',
|
|
60
|
+
city: data.city || '',
|
|
61
|
+
identifier: {
|
|
62
|
+
nickName: '',
|
|
63
|
+
},
|
|
64
|
+
region: '',
|
|
65
|
+
} satisfies Address;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
protected parseOrderSearchItem(
|
|
69
|
+
context: RequestContext,
|
|
70
|
+
data: CTOrder,
|
|
71
|
+
): OrderSearchResultItem {
|
|
72
|
+
const userId: IdentityIdentifier = {
|
|
73
|
+
userId: data.customerId || data.anonymousId || '',
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
let orderStatus: OrderStatus = 'AwaitingPayment';
|
|
77
|
+
if (data.paymentState === 'Paid' && data.orderState === 'Confirmed') {
|
|
78
|
+
orderStatus = 'ReleasedToFulfillment';
|
|
79
|
+
}
|
|
80
|
+
if (data.shipmentState === 'Ready' && data.orderState === 'Confirmed') {
|
|
81
|
+
orderStatus = 'ReleasedToFulfillment';
|
|
82
|
+
}
|
|
83
|
+
if (
|
|
84
|
+
(data.shipmentState === 'Shipped' || data.shipmentState === 'Delivered') &&
|
|
85
|
+
data.orderState === 'Completed'
|
|
86
|
+
) {
|
|
87
|
+
orderStatus = 'Shipped';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const totalAmount: MonetaryAmount = {
|
|
91
|
+
currency: data.totalPrice
|
|
92
|
+
? (data.totalPrice.currencyCode as Currency)
|
|
93
|
+
: context.languageContext.currencyCode,
|
|
94
|
+
value: data.totalPrice ? data.totalPrice.centAmount / 100 : 0,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
identifier: { key: data.id },
|
|
99
|
+
userId,
|
|
100
|
+
customerName: `${data.billingAddress?.firstName} ${data.billingAddress?.lastName}`,
|
|
101
|
+
shippingAddress: this.parseAddress(data.shippingAddress!),
|
|
102
|
+
orderDate: data.createdAt,
|
|
103
|
+
orderStatus,
|
|
104
|
+
inventoryStatus: orderStatus === 'Shipped' ? 'Allocated' : 'NotAllocated',
|
|
105
|
+
totalAmount,
|
|
106
|
+
} satisfies OrderSearchResultItem;
|
|
107
|
+
}
|
|
108
|
+
}
|