@reactionary/commercetools 0.10.48 → 0.10.49

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 = ["discountCodes[*].discountCode"];
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.48",
3
+ "version": "0.10.49",
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.48",
12
+ "@reactionary/core": "0.10.49",
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
  }