@reactionary/commercetools 0.10.48 → 0.10.50
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.
|
@@ -33,7 +33,11 @@ import { getLanguageCodeFromLocale } from "../core/locale-utils.js";
|
|
|
33
33
|
class CommercetoolsCartCapability extends CartCapability {
|
|
34
34
|
config;
|
|
35
35
|
commercetools;
|
|
36
|
-
expandedCartFields = [
|
|
36
|
+
expandedCartFields = [
|
|
37
|
+
"discountCodes[*].discountCode",
|
|
38
|
+
"lineItems[*].discountedPricePerQuantity[*].discountedPrice.includedDiscounts[*].discount",
|
|
39
|
+
"discountOnTotalPrice.includedDiscounts[*].discount"
|
|
40
|
+
];
|
|
37
41
|
factory;
|
|
38
42
|
constructor(config, cache, context, commercetools, factory) {
|
|
39
43
|
super(cache, context);
|
|
@@ -104,17 +104,38 @@ class CommercetoolsCartFactory {
|
|
|
104
104
|
}
|
|
105
105
|
};
|
|
106
106
|
const localeString = getLanguageCodeFromLocale(context.languageContext.locale) || "en";
|
|
107
|
+
const discountedAmountByCartDiscountId = this.groupDiscountedAmountsByCartDiscountId(data);
|
|
107
108
|
const appliedPromotions = [];
|
|
109
|
+
const codeClaimedCartDiscountIds = /* @__PURE__ */ new Set();
|
|
108
110
|
if (data.discountCodes) {
|
|
109
111
|
for (const promo of data.discountCodes) {
|
|
112
|
+
const cartDiscountIds = promo.discountCode.obj?.cartDiscounts.map((ref) => ref.id) || [];
|
|
113
|
+
cartDiscountIds.forEach((id) => codeClaimedCartDiscountIds.add(id));
|
|
114
|
+
const discountedCentAmount = cartDiscountIds.reduce(
|
|
115
|
+
(sum, id) => sum + (discountedAmountByCartDiscountId.get(id)?.centAmount || 0),
|
|
116
|
+
0
|
|
117
|
+
);
|
|
110
118
|
appliedPromotions.push({
|
|
111
119
|
code: promo.discountCode.obj?.code || "",
|
|
112
120
|
isCouponCode: true,
|
|
113
121
|
name: promo.discountCode.obj?.name?.[localeString] || "",
|
|
114
|
-
description: promo.discountCode.obj?.description?.[localeString] || ""
|
|
122
|
+
description: promo.discountCode.obj?.description?.[localeString] || "",
|
|
123
|
+
...discountedCentAmount > 0 ? { amount: { value: discountedCentAmount / 100, currency } } : {}
|
|
115
124
|
});
|
|
116
125
|
}
|
|
117
126
|
}
|
|
127
|
+
for (const [cartDiscountId, applied] of discountedAmountByCartDiscountId) {
|
|
128
|
+
if (codeClaimedCartDiscountIds.has(cartDiscountId)) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
appliedPromotions.push({
|
|
132
|
+
code: "",
|
|
133
|
+
isCouponCode: false,
|
|
134
|
+
name: applied.cartDiscount?.name?.[localeString] || "",
|
|
135
|
+
description: applied.cartDiscount?.description?.[localeString] || "",
|
|
136
|
+
...applied.centAmount > 0 ? { amount: { value: applied.centAmount / 100, currency } } : {}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
118
139
|
const result = {
|
|
119
140
|
identifier,
|
|
120
141
|
user: {
|
|
@@ -129,6 +150,46 @@ class CommercetoolsCartFactory {
|
|
|
129
150
|
};
|
|
130
151
|
return this.cartSchema.parse(result);
|
|
131
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* commercetools links a discount code to the amount it discounted only
|
|
155
|
+
* indirectly: `discountCode.obj.cartDiscounts` gives the CartDiscount ids a
|
|
156
|
+
* code triggers, while the actual discounted amounts are reported per line
|
|
157
|
+
* item (`discountedPricePerQuantity[].discountedPrice.includedDiscounts`)
|
|
158
|
+
* and on the cart total (`discountOnTotalPrice.includedDiscounts`), each
|
|
159
|
+
* keyed by that same CartDiscount id. Sum both sources by CartDiscount id
|
|
160
|
+
* so a discount code's total can be looked up by joining on its ids, and
|
|
161
|
+
* keep the expanded CartDiscount (when available) so automatically applied
|
|
162
|
+
* discounts — those not claimed by any code — can be surfaced by name.
|
|
163
|
+
*/
|
|
164
|
+
groupDiscountedAmountsByCartDiscountId(data) {
|
|
165
|
+
const totals = /* @__PURE__ */ new Map();
|
|
166
|
+
const add = (cartDiscountId, centAmount, cartDiscount) => {
|
|
167
|
+
const entry = totals.get(cartDiscountId) || { centAmount: 0 };
|
|
168
|
+
entry.centAmount += centAmount;
|
|
169
|
+
entry.cartDiscount = entry.cartDiscount || cartDiscount;
|
|
170
|
+
totals.set(cartDiscountId, entry);
|
|
171
|
+
};
|
|
172
|
+
const expandedCartDiscount = (reference) => reference.typeId === "cart-discount" ? reference.obj : void 0;
|
|
173
|
+
for (const lineItem of data.lineItems) {
|
|
174
|
+
for (const discPrQty of lineItem.discountedPricePerQuantity || []) {
|
|
175
|
+
for (const included of discPrQty.discountedPrice?.includedDiscounts || []) {
|
|
176
|
+
add(
|
|
177
|
+
included.discount.id,
|
|
178
|
+
included.discountedAmount.centAmount * discPrQty.quantity,
|
|
179
|
+
expandedCartDiscount(included.discount)
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
for (const included of data.discountOnTotalPrice?.includedDiscounts || []) {
|
|
185
|
+
add(
|
|
186
|
+
included.discount.id,
|
|
187
|
+
included.discountedAmount.centAmount,
|
|
188
|
+
expandedCartDiscount(included.discount)
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
return totals;
|
|
192
|
+
}
|
|
132
193
|
parseCartItem(lineItem) {
|
|
133
194
|
const unitPrice = lineItem.price.value.centAmount;
|
|
134
195
|
const totalPrice = lineItem.totalPrice.centAmount || 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reactionary/commercetools",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.50",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"types": "./src/index.d.ts",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"url": "git+https://github.com/Solteq/reactionary.git"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@reactionary/core": "0.10.
|
|
12
|
+
"@reactionary/core": "0.10.50",
|
|
13
13
|
"zod": "4.1.9",
|
|
14
14
|
"@commercetools/ts-client": "^4.9.1",
|
|
15
15
|
"@commercetools/platform-sdk": "^8.25.0",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CartPagedQueryResponse, Cart as CTCart, LineItem } from '@commercetools/platform-sdk';
|
|
1
|
+
import type { CartDiscount, CartPagedQueryResponse, Cart as CTCart, LineItem } from '@commercetools/platform-sdk';
|
|
2
2
|
import type { AnyCartPaginatedSearchResult, CartPaginatedSearchResultSchema, CartQueryList, CartSchema, CartSearchResultItem } from '@reactionary/core';
|
|
3
3
|
import { type AnyCartIdentifierSchema, type AnyCartSchema, type CartFactory, type CartItem, type RequestContext } from '@reactionary/core';
|
|
4
4
|
import type * as z from 'zod';
|
|
@@ -12,5 +12,20 @@ export declare class CommercetoolsCartFactory<TCartSchema extends AnyCartSchema
|
|
|
12
12
|
parseCartIdentifier(_context: RequestContext, data: CTCart): z.output<TCartIdentifierSchema>;
|
|
13
13
|
parseCartSearchResultItem(context: RequestContext, data: CTCart): CartSearchResultItem;
|
|
14
14
|
parseCart(context: RequestContext, data: CTCart): z.output<TCartSchema>;
|
|
15
|
+
/**
|
|
16
|
+
* commercetools links a discount code to the amount it discounted only
|
|
17
|
+
* indirectly: `discountCode.obj.cartDiscounts` gives the CartDiscount ids a
|
|
18
|
+
* code triggers, while the actual discounted amounts are reported per line
|
|
19
|
+
* item (`discountedPricePerQuantity[].discountedPrice.includedDiscounts`)
|
|
20
|
+
* and on the cart total (`discountOnTotalPrice.includedDiscounts`), each
|
|
21
|
+
* keyed by that same CartDiscount id. Sum both sources by CartDiscount id
|
|
22
|
+
* so a discount code's total can be looked up by joining on its ids, and
|
|
23
|
+
* keep the expanded CartDiscount (when available) so automatically applied
|
|
24
|
+
* discounts — those not claimed by any code — can be surfaced by name.
|
|
25
|
+
*/
|
|
26
|
+
protected groupDiscountedAmountsByCartDiscountId(data: CTCart): Map<string, {
|
|
27
|
+
centAmount: number;
|
|
28
|
+
cartDiscount?: CartDiscount;
|
|
29
|
+
}>;
|
|
15
30
|
protected parseCartItem(lineItem: LineItem): CartItem;
|
|
16
31
|
}
|