@reactionary/hcl 0.9.7 → 0.9.11
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/capabilities/cart.capability.js +411 -0
- package/capabilities/category.capability.js +111 -35
- package/capabilities/checkout.capability.js +337 -0
- package/capabilities/identity.capability.js +214 -0
- package/capabilities/inventory.capability.js +75 -0
- package/capabilities/price.capability.js +122 -0
- package/capabilities/product-search.capability.js +64 -13
- package/capabilities/product.capability.js +114 -28
- package/core/client.js +80 -89
- package/core/initialize.js +111 -5
- package/core/session-keys.js +14 -0
- package/factories/cart/cart.factory.js +135 -0
- package/factories/checkout/checkout.factory.js +131 -0
- package/factories/identity/identity.factory.js +12 -0
- package/factories/index.js +5 -0
- package/factories/inventory/inventory.factory.js +38 -0
- package/factories/price/price.factory.js +39 -0
- package/index.js +5 -0
- package/package.json +8 -5
- package/schema/capabilities.schema.js +2 -0
- package/schema/configuration.schema.js +12 -1
- package/src/capabilities/cart.capability.d.ts +69 -0
- package/src/capabilities/category.capability.d.ts +20 -1
- package/src/capabilities/checkout.capability.d.ts +41 -0
- package/src/capabilities/identity.capability.d.ts +29 -0
- package/src/capabilities/inventory.capability.d.ts +13 -0
- package/src/capabilities/price.capability.d.ts +16 -0
- package/src/capabilities/product-search.capability.d.ts +7 -2
- package/src/capabilities/product.capability.d.ts +14 -2
- package/src/core/client.d.ts +41 -14
- package/src/core/initialize.types.d.ts +11 -5
- package/src/core/session-keys.d.ts +14 -0
- package/src/factories/cart/cart.factory.d.ts +11 -0
- package/src/factories/checkout/checkout.factory.d.ts +11 -0
- package/src/factories/identity/identity.factory.d.ts +7 -0
- package/src/factories/index.d.ts +5 -0
- package/src/factories/inventory/inventory.factory.d.ts +29 -0
- package/src/factories/price/price.factory.d.ts +26 -0
- package/src/index.d.ts +5 -0
- package/src/schema/capabilities.schema.d.ts +7 -1
- package/src/schema/configuration.schema.d.ts +7 -0
- package/src/schema/hcl.schema.d.ts +321 -0
- package/src/test/test-utils.d.ts +2 -1
- package/test/test-utils.js +6 -1
package/core/initialize.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CategoryPaginatedResultSchema,
|
|
3
|
+
IdentitySchema,
|
|
3
4
|
ProductSchema
|
|
4
5
|
} from "@reactionary/core";
|
|
5
6
|
import { HclCategorySchema } from "../schema/category.schema.js";
|
|
@@ -14,20 +15,40 @@ import {
|
|
|
14
15
|
} from "./initialize.types.js";
|
|
15
16
|
import { HclClient } from "./client.js";
|
|
16
17
|
import {
|
|
18
|
+
HclCartFactory,
|
|
17
19
|
HclCategoryFactory,
|
|
20
|
+
HclCheckoutFactory,
|
|
21
|
+
HclIdentityFactory,
|
|
22
|
+
HclInventoryFactory,
|
|
23
|
+
HclPriceFactory,
|
|
18
24
|
HclProductFactory,
|
|
19
25
|
HclProductSearchFactory
|
|
20
26
|
} from "../factories/index.js";
|
|
27
|
+
import { HclCartCapability } from "../capabilities/cart.capability.js";
|
|
28
|
+
import { HclCheckoutCapability } from "../capabilities/checkout.capability.js";
|
|
21
29
|
import { HclProductCapability } from "../capabilities/product.capability.js";
|
|
22
30
|
import { HclCategoryCapability } from "../capabilities/category.capability.js";
|
|
23
31
|
import { HclProductSearchCapability } from "../capabilities/product-search.capability.js";
|
|
24
|
-
import {
|
|
32
|
+
import { HclPriceCapability } from "../capabilities/price.capability.js";
|
|
33
|
+
import { HclInventoryCapability } from "../capabilities/inventory.capability.js";
|
|
34
|
+
import { HclIdentityCapability } from "../capabilities/identity.capability.js";
|
|
35
|
+
import {
|
|
36
|
+
CartIdentifierSchema,
|
|
37
|
+
CartPaginatedSearchResultSchema,
|
|
38
|
+
CartSchema,
|
|
39
|
+
CheckoutSchema,
|
|
40
|
+
InventorySchema,
|
|
41
|
+
PaymentMethodSchema,
|
|
42
|
+
PriceSchema,
|
|
43
|
+
ProductSearchResultSchema,
|
|
44
|
+
ShippingMethodSchema
|
|
45
|
+
} from "@reactionary/core";
|
|
25
46
|
function withHclCapabilities(configuration, capabilities) {
|
|
26
47
|
return (cache, context) => {
|
|
27
48
|
const client = {};
|
|
28
49
|
const config = HclConfigurationSchema.parse(configuration);
|
|
29
50
|
const caps = HclCapabilitiesSchema.parse(capabilities);
|
|
30
|
-
const hclClient = new HclClient(config);
|
|
51
|
+
const hclClient = new HclClient(config, context);
|
|
31
52
|
const buildCapabilityArgs = (factory) => ({
|
|
32
53
|
cache,
|
|
33
54
|
context,
|
|
@@ -35,9 +56,48 @@ function withHclCapabilities(configuration, capabilities) {
|
|
|
35
56
|
hclClient,
|
|
36
57
|
factory
|
|
37
58
|
});
|
|
59
|
+
if (caps.cart?.enabled) {
|
|
60
|
+
client.cart = resolveCapabilityWithFactory(
|
|
61
|
+
capabilities.cart,
|
|
62
|
+
{
|
|
63
|
+
factory: new HclCartFactory(
|
|
64
|
+
CartSchema,
|
|
65
|
+
CartIdentifierSchema,
|
|
66
|
+
CartPaginatedSearchResultSchema
|
|
67
|
+
),
|
|
68
|
+
capability: (args) => new HclCartCapability(
|
|
69
|
+
args.cache,
|
|
70
|
+
args.context,
|
|
71
|
+
args.config,
|
|
72
|
+
args.hclClient,
|
|
73
|
+
args.factory
|
|
74
|
+
)
|
|
75
|
+
},
|
|
76
|
+
buildCapabilityArgs
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
if (caps.checkout?.enabled) {
|
|
80
|
+
client.checkout = resolveCapabilityWithFactory(
|
|
81
|
+
capabilities.checkout,
|
|
82
|
+
{
|
|
83
|
+
factory: new HclCheckoutFactory(
|
|
84
|
+
CheckoutSchema,
|
|
85
|
+
ShippingMethodSchema,
|
|
86
|
+
PaymentMethodSchema
|
|
87
|
+
),
|
|
88
|
+
capability: (args) => new HclCheckoutCapability(
|
|
89
|
+
args.cache,
|
|
90
|
+
args.context,
|
|
91
|
+
args.config,
|
|
92
|
+
args.hclClient,
|
|
93
|
+
args.factory
|
|
94
|
+
)
|
|
95
|
+
},
|
|
96
|
+
buildCapabilityArgs
|
|
97
|
+
);
|
|
98
|
+
}
|
|
38
99
|
if (caps.product?.enabled) {
|
|
39
100
|
client.product = resolveCapabilityWithFactory(
|
|
40
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
41
101
|
capabilities.product,
|
|
42
102
|
{
|
|
43
103
|
factory: new HclProductFactory(ProductSchema),
|
|
@@ -54,7 +114,6 @@ function withHclCapabilities(configuration, capabilities) {
|
|
|
54
114
|
}
|
|
55
115
|
if (caps.category?.enabled) {
|
|
56
116
|
client.category = resolveCapabilityWithFactory(
|
|
57
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
58
117
|
capabilities.category,
|
|
59
118
|
{
|
|
60
119
|
factory: new HclCategoryFactory(
|
|
@@ -74,7 +133,6 @@ function withHclCapabilities(configuration, capabilities) {
|
|
|
74
133
|
}
|
|
75
134
|
if (caps.productSearch?.enabled) {
|
|
76
135
|
client.productSearch = resolveCapabilityWithFactory(
|
|
77
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
78
136
|
capabilities.productSearch,
|
|
79
137
|
{
|
|
80
138
|
factory: new HclProductSearchFactory(ProductSearchResultSchema),
|
|
@@ -89,6 +147,54 @@ function withHclCapabilities(configuration, capabilities) {
|
|
|
89
147
|
buildCapabilityArgs
|
|
90
148
|
);
|
|
91
149
|
}
|
|
150
|
+
if (caps.price?.enabled) {
|
|
151
|
+
client.price = resolveCapabilityWithFactory(
|
|
152
|
+
capabilities.price,
|
|
153
|
+
{
|
|
154
|
+
factory: new HclPriceFactory(PriceSchema),
|
|
155
|
+
capability: (args) => new HclPriceCapability(
|
|
156
|
+
args.cache,
|
|
157
|
+
args.context,
|
|
158
|
+
args.config,
|
|
159
|
+
args.hclClient,
|
|
160
|
+
args.factory
|
|
161
|
+
)
|
|
162
|
+
},
|
|
163
|
+
buildCapabilityArgs
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
if (caps.inventory?.enabled) {
|
|
167
|
+
client.inventory = resolveCapabilityWithFactory(
|
|
168
|
+
capabilities.inventory,
|
|
169
|
+
{
|
|
170
|
+
factory: new HclInventoryFactory(InventorySchema),
|
|
171
|
+
capability: (args) => new HclInventoryCapability(
|
|
172
|
+
args.cache,
|
|
173
|
+
args.context,
|
|
174
|
+
args.config,
|
|
175
|
+
args.hclClient,
|
|
176
|
+
args.factory
|
|
177
|
+
)
|
|
178
|
+
},
|
|
179
|
+
buildCapabilityArgs
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
if (caps.identity?.enabled) {
|
|
183
|
+
client.identity = resolveCapabilityWithFactory(
|
|
184
|
+
capabilities.identity,
|
|
185
|
+
{
|
|
186
|
+
factory: new HclIdentityFactory(IdentitySchema),
|
|
187
|
+
capability: (args) => new HclIdentityCapability(
|
|
188
|
+
args.cache,
|
|
189
|
+
args.context,
|
|
190
|
+
args.config,
|
|
191
|
+
args.hclClient,
|
|
192
|
+
args.factory
|
|
193
|
+
)
|
|
194
|
+
},
|
|
195
|
+
buildCapabilityArgs
|
|
196
|
+
);
|
|
197
|
+
}
|
|
92
198
|
return client;
|
|
93
199
|
};
|
|
94
200
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const SESSION_KEY_WC_TOKEN = "hcl.WCToken";
|
|
2
|
+
const SESSION_KEY_WC_TRUSTED_TOKEN = "hcl.WCTrustedToken";
|
|
3
|
+
const SESSION_KEY_USER_ID = "hcl.userId";
|
|
4
|
+
const SESSION_KEY_IDENTITY_TYPE = "hcl.identityType";
|
|
5
|
+
const SESSION_KEY_PERSONALIZATION_ID = "hcl.personalizationID";
|
|
6
|
+
const SESSION_KEY_PRICE_RULE_ID = "hcl.priceRuleId";
|
|
7
|
+
export {
|
|
8
|
+
SESSION_KEY_IDENTITY_TYPE,
|
|
9
|
+
SESSION_KEY_PERSONALIZATION_ID,
|
|
10
|
+
SESSION_KEY_PRICE_RULE_ID,
|
|
11
|
+
SESSION_KEY_USER_ID,
|
|
12
|
+
SESSION_KEY_WC_TOKEN,
|
|
13
|
+
SESSION_KEY_WC_TRUSTED_TOKEN
|
|
14
|
+
};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CartIdentifierSchema,
|
|
3
|
+
CartPaginatedSearchResultSchema
|
|
4
|
+
} from "@reactionary/core";
|
|
5
|
+
class HclCartFactory {
|
|
6
|
+
constructor(cartSchema, cartIdentifierSchema = CartIdentifierSchema, cartPaginatedSearchResultSchema = CartPaginatedSearchResultSchema) {
|
|
7
|
+
this.cartSchema = cartSchema;
|
|
8
|
+
this.cartIdentifierSchema = cartIdentifierSchema;
|
|
9
|
+
this.cartPaginatedSearchResultSchema = cartPaginatedSearchResultSchema;
|
|
10
|
+
}
|
|
11
|
+
parseCart(context, data) {
|
|
12
|
+
const cart = data;
|
|
13
|
+
const currency = cart.totalProductPriceCurrency ?? cart.grandTotalCurrency ?? "USD";
|
|
14
|
+
return this.cartSchema.parse({
|
|
15
|
+
identifier: { key: cart.orderId },
|
|
16
|
+
user: { userId: cart.buyerId ?? "" },
|
|
17
|
+
company: cart.orgUniqueID ? { id: cart.orgUniqueID } : void 0,
|
|
18
|
+
name: cart.orderDescription ?? context.session["hcl.cartName"] ?? "",
|
|
19
|
+
description: "",
|
|
20
|
+
items: (cart.orderItem ?? []).map((item) => ({
|
|
21
|
+
identifier: { key: item.orderItemId },
|
|
22
|
+
product: { key: item.productId ?? "" },
|
|
23
|
+
variant: { sku: item.partNumber },
|
|
24
|
+
quantity: Number(item.quantity),
|
|
25
|
+
price: {
|
|
26
|
+
unitPrice: {
|
|
27
|
+
value: Number(item.unitPrice),
|
|
28
|
+
currency: item.currency
|
|
29
|
+
},
|
|
30
|
+
totalPrice: {
|
|
31
|
+
value: Number(item.orderItemPrice),
|
|
32
|
+
currency: item.currency
|
|
33
|
+
},
|
|
34
|
+
unitDiscount: { value: 0, currency: item.currency },
|
|
35
|
+
totalDiscount: { value: 0, currency: item.currency }
|
|
36
|
+
}
|
|
37
|
+
})),
|
|
38
|
+
price: {
|
|
39
|
+
grandTotal: {
|
|
40
|
+
value: Number(cart.grandTotal ?? "0"),
|
|
41
|
+
currency
|
|
42
|
+
},
|
|
43
|
+
totalProductPrice: {
|
|
44
|
+
value: Number(cart.totalProductPrice ?? "0"),
|
|
45
|
+
currency
|
|
46
|
+
},
|
|
47
|
+
totalShipping: {
|
|
48
|
+
value: Number(cart.totalShippingCharge ?? "0"),
|
|
49
|
+
currency
|
|
50
|
+
},
|
|
51
|
+
totalTax: {
|
|
52
|
+
value: Number(cart.totalSalesTax ?? "0"),
|
|
53
|
+
currency
|
|
54
|
+
},
|
|
55
|
+
totalDiscount: {
|
|
56
|
+
value: Math.abs(Number(cart.totalAdjustment ?? "0")),
|
|
57
|
+
currency
|
|
58
|
+
},
|
|
59
|
+
totalSurcharge: { value: 0, currency }
|
|
60
|
+
},
|
|
61
|
+
appliedPromotions: (cart.adjustment ?? []).filter((adj) => adj.usage === "Discount").map((adj) => ({
|
|
62
|
+
code: adj.code,
|
|
63
|
+
isCouponCode: (cart.promotionCode ?? []).some(
|
|
64
|
+
(pc) => pc.code === adj.code
|
|
65
|
+
),
|
|
66
|
+
name: adj.description ?? adj.code,
|
|
67
|
+
description: adj.description ?? "",
|
|
68
|
+
amount: {
|
|
69
|
+
value: Math.abs(Number(adj.amount)),
|
|
70
|
+
currency: adj.currency
|
|
71
|
+
}
|
|
72
|
+
}))
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
parseCartIdentifier(_context, data) {
|
|
76
|
+
const cart = data;
|
|
77
|
+
return this.cartIdentifierSchema.parse({
|
|
78
|
+
key: cart.orderId
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
parseCartPaginatedSearchResult(context, data, _query) {
|
|
82
|
+
const pageSize = _query.search.paginationOptions.pageSize;
|
|
83
|
+
const pageNumber = _query.search.paginationOptions.pageNumber;
|
|
84
|
+
const orderList = data;
|
|
85
|
+
if (Array.isArray(orderList.Order)) {
|
|
86
|
+
const orders = orderList.Order;
|
|
87
|
+
const total = Number(orderList.recordSetTotal ?? orders.length);
|
|
88
|
+
const items = orders.map((order) => {
|
|
89
|
+
const parsed = this.parseCart(context, order);
|
|
90
|
+
return {
|
|
91
|
+
...parsed,
|
|
92
|
+
numItems: (order.orderItem ?? []).length,
|
|
93
|
+
lastModifiedDate: order.lastUpdateDate ?? ""
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
return this.cartPaginatedSearchResultSchema.parse({
|
|
97
|
+
identifier: _query.search,
|
|
98
|
+
items,
|
|
99
|
+
totalCount: total,
|
|
100
|
+
totalPages: Math.ceil(total / Math.max(1, pageSize)),
|
|
101
|
+
pageSize,
|
|
102
|
+
pageNumber
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
const cart = data;
|
|
106
|
+
if (!cart.orderId) {
|
|
107
|
+
return this.cartPaginatedSearchResultSchema.parse({
|
|
108
|
+
identifier: _query.search,
|
|
109
|
+
items: [],
|
|
110
|
+
totalCount: 0,
|
|
111
|
+
totalPages: 0,
|
|
112
|
+
pageSize,
|
|
113
|
+
pageNumber
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const parsedCart = this.parseCart(context, cart);
|
|
117
|
+
return this.cartPaginatedSearchResultSchema.parse({
|
|
118
|
+
identifier: _query.search,
|
|
119
|
+
items: [
|
|
120
|
+
{
|
|
121
|
+
...parsedCart,
|
|
122
|
+
numItems: (cart.orderItem ?? []).length,
|
|
123
|
+
lastModifiedDate: cart.lastUpdateDate ?? ""
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
totalCount: 1,
|
|
127
|
+
totalPages: 1,
|
|
128
|
+
pageSize,
|
|
129
|
+
pageNumber
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export {
|
|
134
|
+
HclCartFactory
|
|
135
|
+
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ShippingMethodSchema,
|
|
3
|
+
PaymentMethodSchema
|
|
4
|
+
} from "@reactionary/core";
|
|
5
|
+
class HclCheckoutFactory {
|
|
6
|
+
constructor(checkoutSchema, shippingMethodSchema = ShippingMethodSchema, paymentMethodSchema = PaymentMethodSchema) {
|
|
7
|
+
this.checkoutSchema = checkoutSchema;
|
|
8
|
+
this.shippingMethodSchema = shippingMethodSchema;
|
|
9
|
+
this.paymentMethodSchema = paymentMethodSchema;
|
|
10
|
+
}
|
|
11
|
+
parseCheckout(context, data) {
|
|
12
|
+
const cart = data;
|
|
13
|
+
const currency = cart.totalProductPriceCurrency ?? cart.grandTotalCurrency ?? "USD";
|
|
14
|
+
const shipModeId = cart.shipModeId ?? (cart.orderItem ?? [])[0]?.shipModeId;
|
|
15
|
+
const shippingInstruction = shipModeId ? {
|
|
16
|
+
shippingMethod: { key: shipModeId },
|
|
17
|
+
pickupPoint: "",
|
|
18
|
+
instructions: "",
|
|
19
|
+
consentForUnattendedDelivery: false
|
|
20
|
+
} : void 0;
|
|
21
|
+
const billingEmail = cart.x_billingAddress?.email1 ?? (cart.paymentInstruction ?? []).flatMap((pi) => pi.protocolData ?? []).find((pd) => pd.name === "email1")?.value ?? context.session["hcl.notificationEmail"] ?? "noreply@checkout.example.com";
|
|
22
|
+
const paymentInstructions = (cart.paymentInstruction ?? []).map((pi) => ({
|
|
23
|
+
identifier: { key: pi.piId },
|
|
24
|
+
paymentMethod: {
|
|
25
|
+
method: pi.payMethodId,
|
|
26
|
+
name: pi.payMethodId,
|
|
27
|
+
paymentProcessor: pi.payMethodId
|
|
28
|
+
},
|
|
29
|
+
amount: {
|
|
30
|
+
value: Number(pi.piAmount ?? "0"),
|
|
31
|
+
currency: pi.currency ?? currency
|
|
32
|
+
},
|
|
33
|
+
protocolData: (pi.protocolData ?? []).map((pd) => ({
|
|
34
|
+
key: pd.name,
|
|
35
|
+
value: pd.value
|
|
36
|
+
})),
|
|
37
|
+
status: "pending"
|
|
38
|
+
}));
|
|
39
|
+
const parseAddress = (addr) => {
|
|
40
|
+
if (!addr)
|
|
41
|
+
return void 0;
|
|
42
|
+
return {
|
|
43
|
+
identifier: { key: addr.addressId ?? "" },
|
|
44
|
+
firstName: addr.firstName ?? "",
|
|
45
|
+
lastName: addr.lastName ?? "",
|
|
46
|
+
streetAddress: (addr.addressLine ?? [])[0] ?? "",
|
|
47
|
+
streetNumber: "",
|
|
48
|
+
city: addr.city ?? "",
|
|
49
|
+
region: addr.state ?? "",
|
|
50
|
+
postalCode: addr.zipCode ?? "",
|
|
51
|
+
countryCode: addr.country ?? ""
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
return this.checkoutSchema.parse({
|
|
55
|
+
identifier: { key: cart.orderId },
|
|
56
|
+
originalCartReference: { key: cart.orderId },
|
|
57
|
+
resultingOrder: cart.resultingOrderKey ? { key: cart.resultingOrderKey } : void 0,
|
|
58
|
+
items: (cart.orderItem ?? []).map((item) => ({
|
|
59
|
+
identifier: { key: item.orderItemId },
|
|
60
|
+
variant: { sku: item.partNumber },
|
|
61
|
+
quantity: Number(item.quantity),
|
|
62
|
+
price: {
|
|
63
|
+
unitPrice: {
|
|
64
|
+
value: Number(item.unitPrice),
|
|
65
|
+
currency: item.currency
|
|
66
|
+
},
|
|
67
|
+
totalPrice: {
|
|
68
|
+
value: Number(item.orderItemPrice),
|
|
69
|
+
currency: item.currency
|
|
70
|
+
},
|
|
71
|
+
unitDiscount: { value: 0, currency: item.currency },
|
|
72
|
+
totalDiscount: { value: 0, currency: item.currency }
|
|
73
|
+
}
|
|
74
|
+
})),
|
|
75
|
+
price: {
|
|
76
|
+
grandTotal: { value: Number(cart.grandTotal ?? "0"), currency },
|
|
77
|
+
totalProductPrice: {
|
|
78
|
+
value: Number(cart.totalProductPrice ?? "0"),
|
|
79
|
+
currency
|
|
80
|
+
},
|
|
81
|
+
totalShipping: {
|
|
82
|
+
value: Number(cart.totalShippingCharge ?? "0"),
|
|
83
|
+
currency
|
|
84
|
+
},
|
|
85
|
+
totalTax: { value: Number(cart.totalSalesTax ?? "0"), currency },
|
|
86
|
+
totalDiscount: {
|
|
87
|
+
value: Math.abs(Number(cart.totalAdjustment ?? "0")),
|
|
88
|
+
currency
|
|
89
|
+
},
|
|
90
|
+
totalSurcharge: { value: 0, currency }
|
|
91
|
+
},
|
|
92
|
+
name: context.session["hcl.cartName"] ?? "",
|
|
93
|
+
description: "",
|
|
94
|
+
shippingAddress: parseAddress(cart.x_shippingAddress),
|
|
95
|
+
billingAddress: parseAddress(cart.x_billingAddress),
|
|
96
|
+
shippingInstruction,
|
|
97
|
+
paymentInstructions,
|
|
98
|
+
pointOfContact: {
|
|
99
|
+
email: billingEmail,
|
|
100
|
+
phone: cart.x_billingAddress?.phone1
|
|
101
|
+
},
|
|
102
|
+
readyForFinalization: paymentInstructions.length > 0 && !!cart.shipModeId
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
parseShippingMethod(_context, data) {
|
|
106
|
+
const mode = data;
|
|
107
|
+
return this.shippingMethodSchema.parse({
|
|
108
|
+
identifier: { key: mode.shipModeId },
|
|
109
|
+
name: mode.shipModeDescription || mode.shipModeCode,
|
|
110
|
+
description: mode.shipModeDescription || mode.shipModeCode,
|
|
111
|
+
price: { value: 0, currency: "USD" },
|
|
112
|
+
deliveryTime: mode.field2 ?? "",
|
|
113
|
+
carrier: mode.carrier
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
parsePaymentMethod(_context, data) {
|
|
117
|
+
const method = data;
|
|
118
|
+
return this.paymentMethodSchema.parse({
|
|
119
|
+
identifier: {
|
|
120
|
+
method: method.paymentMethodName,
|
|
121
|
+
name: method.description ?? method.paymentMethodName,
|
|
122
|
+
paymentProcessor: method.paymentMethodName
|
|
123
|
+
},
|
|
124
|
+
description: method.description ?? method.paymentMethodName,
|
|
125
|
+
isPunchOut: false
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
export {
|
|
130
|
+
HclCheckoutFactory
|
|
131
|
+
};
|
package/factories/index.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
export * from "./cart/cart.factory.js";
|
|
2
|
+
export * from "./checkout/checkout.factory.js";
|
|
1
3
|
export * from "./product/product.factory.js";
|
|
2
4
|
export * from "./category/category.factory.js";
|
|
3
5
|
export * from "./product-search/product-search.factory.js";
|
|
6
|
+
export * from "./price/price.factory.js";
|
|
7
|
+
export * from "./inventory/inventory.factory.js";
|
|
8
|
+
export * from "./identity/identity.factory.js";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const HCL_STATUS_AVAILABLE = "Available";
|
|
2
|
+
class HclInventoryFactory {
|
|
3
|
+
inventorySchema;
|
|
4
|
+
constructor(inventorySchema) {
|
|
5
|
+
this.inventorySchema = inventorySchema;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Map an HclInventoryAvailabilityItem to an Inventory model.
|
|
9
|
+
* The `data.sku` is used for the identifier since WCS items carry only an
|
|
10
|
+
* internal `productId`, not the human-readable part number.
|
|
11
|
+
*/
|
|
12
|
+
parseInventory(_context, data) {
|
|
13
|
+
const { item, sku, fulfilmentCenterKey } = data;
|
|
14
|
+
const identifier = {
|
|
15
|
+
variant: { sku },
|
|
16
|
+
fulfillmentCenter: { key: fulfilmentCenterKey || "online" }
|
|
17
|
+
};
|
|
18
|
+
return this.inventorySchema.parse({
|
|
19
|
+
identifier,
|
|
20
|
+
quantity: Number(item.availableQuantity ?? "0"),
|
|
21
|
+
status: item.inventoryStatus === HCL_STATUS_AVAILABLE ? "inStock" : "outOfStock"
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/** Create an empty (out-of-stock) inventory when no matching record was found. */
|
|
25
|
+
createEmpty(sku, fulfilmentCenterKey) {
|
|
26
|
+
return this.inventorySchema.parse({
|
|
27
|
+
identifier: {
|
|
28
|
+
variant: { sku },
|
|
29
|
+
fulfillmentCenter: { key: fulfilmentCenterKey || "online" }
|
|
30
|
+
},
|
|
31
|
+
quantity: 0,
|
|
32
|
+
status: "outOfStock"
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export {
|
|
37
|
+
HclInventoryFactory
|
|
38
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
class HclPriceFactory {
|
|
2
|
+
priceSchema;
|
|
3
|
+
constructor(priceSchema) {
|
|
4
|
+
this.priceSchema = priceSchema;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Map a price response item to a Price model.
|
|
8
|
+
* Supports both /price (EntitledPrice with capital `UnitPrice`) and
|
|
9
|
+
* /display_price (resultList with lowercase `unitPrice`) response shapes.
|
|
10
|
+
* The `item.partNumber` is used as the variant SKU identifier.
|
|
11
|
+
*/
|
|
12
|
+
parsePrice(_context, data) {
|
|
13
|
+
const { item } = data;
|
|
14
|
+
const entitledItem = item;
|
|
15
|
+
const displayItem = item;
|
|
16
|
+
const priceEntry = entitledItem.UnitPrice?.[0]?.price ?? displayItem.unitPrice?.[0]?.price;
|
|
17
|
+
return this.priceSchema.parse({
|
|
18
|
+
identifier: { variant: { sku: item.partNumber ?? "" } },
|
|
19
|
+
unitPrice: {
|
|
20
|
+
value: priceEntry?.value ?? -1,
|
|
21
|
+
currency: priceEntry?.currency ?? ""
|
|
22
|
+
},
|
|
23
|
+
onSale: false,
|
|
24
|
+
tieredPrices: []
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/** Create an empty (placeholder) price when no result was found for a SKU. */
|
|
28
|
+
createEmpty(sku, currency) {
|
|
29
|
+
return this.priceSchema.parse({
|
|
30
|
+
identifier: { variant: { sku } },
|
|
31
|
+
unitPrice: { value: -1, currency },
|
|
32
|
+
onSale: false,
|
|
33
|
+
tieredPrices: []
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
HclPriceFactory
|
|
39
|
+
};
|
package/index.js
CHANGED
|
@@ -6,6 +6,11 @@ export * from "./core/client.js";
|
|
|
6
6
|
export * from "./core/initialize.js";
|
|
7
7
|
export * from "./core/initialize.types.js";
|
|
8
8
|
export * from "./factories/index.js";
|
|
9
|
+
export * from "./capabilities/cart.capability.js";
|
|
10
|
+
export * from "./capabilities/checkout.capability.js";
|
|
9
11
|
export * from "./capabilities/product.capability.js";
|
|
10
12
|
export * from "./capabilities/category.capability.js";
|
|
11
13
|
export * from "./capabilities/product-search.capability.js";
|
|
14
|
+
export * from "./capabilities/price.capability.js";
|
|
15
|
+
export * from "./capabilities/inventory.capability.js";
|
|
16
|
+
export * from "./capabilities/identity.capability.js";
|
package/package.json
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reactionary/hcl",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"types": "./src/index.d.ts",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@reactionary/core": "0.9.
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
|
|
8
|
+
"@reactionary/core": "0.9.11",
|
|
9
|
+
"debug": "^4.4.3",
|
|
10
|
+
"zod": "4.1.9"
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@nx/vite": "22.4.5",
|
|
14
|
+
"vitest": "^4.0.9"
|
|
12
15
|
},
|
|
13
16
|
"sideEffects": false
|
|
14
17
|
}
|
|
@@ -12,6 +12,7 @@ const HclCapabilitiesSchema = CapabilitiesSchema.pick({
|
|
|
12
12
|
product: true,
|
|
13
13
|
price: true,
|
|
14
14
|
inventory: true,
|
|
15
|
+
identity: true,
|
|
15
16
|
productSearch: true
|
|
16
17
|
}).extend({
|
|
17
18
|
cart: OverridableCapabilitySchema.optional(),
|
|
@@ -20,6 +21,7 @@ const HclCapabilitiesSchema = CapabilitiesSchema.pick({
|
|
|
20
21
|
product: OverridableCapabilitySchema.optional(),
|
|
21
22
|
price: OverridableCapabilitySchema.optional(),
|
|
22
23
|
inventory: OverridableCapabilitySchema.optional(),
|
|
24
|
+
identity: OverridableCapabilitySchema.optional(),
|
|
23
25
|
productSearch: OverridableCapabilitySchema.optional()
|
|
24
26
|
}).partial();
|
|
25
27
|
export {
|
|
@@ -16,6 +16,9 @@ const HclConfigurationSchema = z.looseObject({
|
|
|
16
16
|
apiUrl: z.string().meta({
|
|
17
17
|
description: "The base origin URL for the HCL Commerce server (e.g. https://example.com)."
|
|
18
18
|
}),
|
|
19
|
+
searchApiUrl: z.string().optional().meta({
|
|
20
|
+
description: "The base origin URL for the HCL Commerce Search API server, if different from apiUrl."
|
|
21
|
+
}),
|
|
19
22
|
storeId: z.string().meta({ description: "The HCL Commerce store identifier." }),
|
|
20
23
|
catalogId: z.string().optional().meta({ description: "The HCL Commerce catalog identifier." }),
|
|
21
24
|
/**
|
|
@@ -26,7 +29,15 @@ const HclConfigurationSchema = z.looseObject({
|
|
|
26
29
|
localeMap: z.record(z.string(), z.string()).default({ "en-US": "-1" }).meta({
|
|
27
30
|
description: "Mapping from BCP 47 locale (RequestContext.languageContext.locale) to HCL langId."
|
|
28
31
|
}),
|
|
29
|
-
profiles: HclProfilesSchema
|
|
32
|
+
profiles: HclProfilesSchema,
|
|
33
|
+
/**
|
|
34
|
+
* Optional price rule ID passed to /display_price?q=byPartNumbersAndPriceRuleId.
|
|
35
|
+
* When omitted the server applies its default configured price rule.
|
|
36
|
+
* In Karkkainen this is '10003'.
|
|
37
|
+
*/
|
|
38
|
+
priceRuleId: z.string().optional().meta({
|
|
39
|
+
description: "Price rule ID for /display_price WCS calls. Optional \u2014 the server uses its default rule when absent."
|
|
40
|
+
})
|
|
30
41
|
});
|
|
31
42
|
export {
|
|
32
43
|
HclConfigurationSchema
|