@wtree/payload-ecommerce-coupon 3.72.2 → 3.76.1

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/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1
2
 
2
3
  //#region src/collections/createCouponsCollection.ts
3
4
  const createCouponsCollection = (pluginConfig) => {
@@ -566,9 +567,119 @@ function roundTo2(value) {
566
567
  return Math.round(value * 100) / 100;
567
568
  }
568
569
 
570
+ //#endregion
571
+ //#region src/utilities/pricing.ts
572
+ const DEFAULT_PRICE_CURRENCY = "AED";
573
+ function normalizeCurrencyCode(currencyCode) {
574
+ if (!currencyCode) return DEFAULT_PRICE_CURRENCY;
575
+ return currencyCode.toUpperCase();
576
+ }
577
+ function readNumberField(entity, key) {
578
+ if (!entity || typeof entity !== "object") return void 0;
579
+ const value = entity[key];
580
+ return typeof value === "number" ? value : void 0;
581
+ }
582
+ function getPriceFieldKey(currencyCode) {
583
+ return `priceIn${normalizeCurrencyCode(currencyCode)}`;
584
+ }
585
+ function readMoneyField(entity, currencyCode, defaultCurrencyCode = DEFAULT_PRICE_CURRENCY) {
586
+ if (!entity) return void 0;
587
+ const primaryField = getPriceFieldKey(currencyCode);
588
+ const primary = readNumberField(entity, primaryField);
589
+ if (typeof primary === "number") return primary;
590
+ const fallbackField = getPriceFieldKey(defaultCurrencyCode);
591
+ if (fallbackField !== primaryField) {
592
+ const fallback = readNumberField(entity, fallbackField);
593
+ if (typeof fallback === "number") return fallback;
594
+ }
595
+ return typeof entity.price === "number" ? entity.price : void 0;
596
+ }
597
+ function resolveMoneyField(entity, currencyCode, defaultCurrencyCode = DEFAULT_PRICE_CURRENCY) {
598
+ return readMoneyField(entity, currencyCode, defaultCurrencyCode) ?? 0;
599
+ }
600
+ function getCartItemUnitPrice({ item, product, variant, currencyCode, defaultCurrencyCode = DEFAULT_PRICE_CURRENCY }) {
601
+ if (typeof item?.price === "number") return item.price;
602
+ if (typeof item?.unitPrice === "number") return item.unitPrice;
603
+ if (variant) return resolveMoneyField(variant, currencyCode, defaultCurrencyCode);
604
+ return resolveMoneyField(product, currencyCode, defaultCurrencyCode);
605
+ }
606
+
607
+ //#endregion
608
+ //#region src/utilities/calculateValues.ts
609
+ function calculateCouponDiscount({ coupon, cartTotal }) {
610
+ let discount = 0;
611
+ if (coupon.type === "percentage") {
612
+ discount = roundTo2(cartTotal * coupon.value / 100);
613
+ if (coupon.maxDiscountAmount != null && discount > coupon.maxDiscountAmount) discount = roundTo2(coupon.maxDiscountAmount);
614
+ } else if (coupon.type === "fixed") {
615
+ discount = roundTo2(coupon.value);
616
+ if (discount > cartTotal) discount = roundTo2(cartTotal);
617
+ }
618
+ return roundTo2(discount);
619
+ }
620
+ function calculateCommissionAndDiscount({ cartItems, program, currencyCode = "AED" }) {
621
+ const rules = program.commissionRules || [];
622
+ if (rules.length === 0) return {
623
+ partnerCommission: 0,
624
+ customerDiscount: 0
625
+ };
626
+ let totalPartnerCommission = 0;
627
+ let totalCustomerDiscount = 0;
628
+ for (const item of cartItems) {
629
+ const rule = findApplicableCommissionRule(rules, item);
630
+ if (!rule) continue;
631
+ const itemPrice = getCartItemUnitPrice({
632
+ item,
633
+ product: typeof item.product === "object" ? item.product : {},
634
+ variant: typeof item.variant === "object" ? item.variant : {},
635
+ currencyCode
636
+ });
637
+ const quantity = item.quantity ?? 1;
638
+ const itemTotal = itemPrice * quantity;
639
+ let itemPartner;
640
+ let itemCustomer;
641
+ if (rule.basis === "shared") {
642
+ if (!rule.totalCommission || rule.referrerSplit == null || rule.refereeSplit == null) continue;
643
+ let totalPot;
644
+ if (rule.totalCommission.type === "percentage") totalPot = itemTotal * rule.totalCommission.value / 100;
645
+ else totalPot = rule.totalCommission.value * quantity;
646
+ if (rule.totalCommission.maxAmount != null && totalPot > rule.totalCommission.maxAmount) totalPot = rule.totalCommission.maxAmount;
647
+ itemPartner = Math.floor(totalPot * (rule.referrerSplit || 0) / 100);
648
+ itemCustomer = Math.floor(totalPot * (rule.refereeSplit || 0) / 100);
649
+ } else {
650
+ if (!rule.referrerReward || !rule.refereeReward) continue;
651
+ if (rule.referrerReward.type === "percentage") itemPartner = itemTotal * rule.referrerReward.value / 100;
652
+ else itemPartner = rule.referrerReward.value * quantity;
653
+ if (rule.referrerReward.maxReward != null && itemPartner > rule.referrerReward.maxReward) itemPartner = rule.referrerReward.maxReward;
654
+ if (rule.refereeReward.type === "percentage") itemCustomer = itemTotal * rule.refereeReward.value / 100;
655
+ else itemCustomer = rule.refereeReward.value * quantity;
656
+ if (rule.refereeReward.maxReward != null && itemCustomer > rule.refereeReward.maxReward) itemCustomer = rule.refereeReward.maxReward;
657
+ }
658
+ totalPartnerCommission += itemPartner;
659
+ totalCustomerDiscount += itemCustomer;
660
+ }
661
+ return {
662
+ partnerCommission: totalPartnerCommission,
663
+ customerDiscount: totalCustomerDiscount
664
+ };
665
+ }
666
+ function findApplicableCommissionRule(rules, item) {
667
+ const productId = typeof item.product === "string" ? item.product : item.product?.id;
668
+ const categoryId = item.category ?? item.product?.category;
669
+ const productRule = rules.find((r) => r.appliesTo === "products" && r.products?.some((p) => (typeof p === "string" ? p : p?.id) === productId));
670
+ if (productRule) return productRule;
671
+ if (categoryId) {
672
+ const categoryRule = rules.find((r) => r.appliesTo === "categories" && r.categories?.some((c) => (typeof c === "string" ? c : c?.id) === categoryId));
673
+ if (categoryRule) return categoryRule;
674
+ }
675
+ return rules.find((r) => r.appliesTo === "all") ?? null;
676
+ }
677
+
569
678
  //#endregion
570
679
  //#region src/endpoints/applyCoupon.ts
680
+ const globalDebugLogs = [];
571
681
  const applyCouponHandler = ({ pluginConfig }) => async (req) => {
682
+ globalDebugLogs.length = 0;
572
683
  const { payload } = req;
573
684
  const { code, cartID, customerEmail } = req.data || {};
574
685
  if (!code || !cartID) return Response.json({
@@ -578,7 +689,8 @@ const applyCouponHandler = ({ pluginConfig }) => async (req) => {
578
689
  try {
579
690
  const cartQuery = await payload.findByID({
580
691
  collection: "carts",
581
- id: cartID
692
+ id: cartID,
693
+ depth: 2
582
694
  });
583
695
  if (!cartQuery) return Response.json({
584
696
  success: false,
@@ -627,11 +739,21 @@ const applyCouponHandler = ({ pluginConfig }) => async (req) => {
627
739
  }
628
740
  };
629
741
  async function handleCouponCode({ payload, code, cartID, cart, customerEmail, pluginConfig }) {
630
- const couponQuery = await payload.find({
742
+ let couponQuery = await payload.find({
631
743
  collection: pluginConfig.collections.couponsSlug,
632
744
  where: { code: { equals: code } },
633
745
  limit: 1
634
746
  });
747
+ if (!couponQuery.docs.length) couponQuery = await payload.find({
748
+ collection: pluginConfig.collections.couponsSlug,
749
+ where: { code: { equals: code.toLowerCase() } },
750
+ limit: 1
751
+ });
752
+ if (!couponQuery.docs.length) couponQuery = await payload.find({
753
+ collection: pluginConfig.collections.couponsSlug,
754
+ where: { code: { equals: code.toUpperCase() } },
755
+ limit: 1
756
+ });
635
757
  if (!couponQuery.docs.length) return Response.json({
636
758
  success: false,
637
759
  error: "Invalid coupon code"
@@ -685,15 +807,10 @@ async function handleCouponCode({ payload, code, cartID, cart, customerEmail, pl
685
807
  success: false,
686
808
  error: `Maximum order value of ${coupon.maxOrderValue} ${pluginConfig.defaultCurrency} exceeded`
687
809
  }, { status: 400 });
688
- let discount = 0;
689
- if (coupon.type === "percentage") {
690
- discount = roundTo2(cartTotal * coupon.value / 100);
691
- if (coupon.maxDiscountAmount != null && discount > coupon.maxDiscountAmount) discount = roundTo2(coupon.maxDiscountAmount);
692
- } else if (coupon.type === "fixed") {
693
- discount = roundTo2(coupon.value);
694
- if (discount > cartTotal) discount = roundTo2(cartTotal);
695
- }
696
- const discountAmount = roundTo2(discount);
810
+ const discountAmount = calculateCouponDiscount({
811
+ coupon,
812
+ cartTotal
813
+ });
697
814
  const total = roundTo2(Math.max(0, cartTotal - discountAmount));
698
815
  await payload.update({
699
816
  collection: "carts",
@@ -713,16 +830,29 @@ async function handleCouponCode({ payload, code, cartID, cart, customerEmail, pl
713
830
  value: coupon.value
714
831
  },
715
832
  discount: discountAmount,
716
- currency: pluginConfig.defaultCurrency
833
+ currency: pluginConfig.defaultCurrency,
834
+ debug: globalDebugLogs
717
835
  });
718
836
  }
719
837
  async function handleReferralCode({ payload, code, cartID, cart, customerEmail: _customerEmail, pluginConfig }) {
720
- const referralQuery = await payload.find({
838
+ let referralQuery = await payload.find({
721
839
  collection: pluginConfig.collections.referralCodesSlug,
722
840
  where: { code: { equals: code } },
723
841
  limit: 1,
724
842
  depth: 1
725
843
  });
844
+ if (!referralQuery.docs.length) referralQuery = await payload.find({
845
+ collection: pluginConfig.collections.referralCodesSlug,
846
+ where: { code: { equals: code.toLowerCase() } },
847
+ limit: 1,
848
+ depth: 1
849
+ });
850
+ if (!referralQuery.docs.length) referralQuery = await payload.find({
851
+ collection: pluginConfig.collections.referralCodesSlug,
852
+ where: { code: { equals: code.toUpperCase() } },
853
+ limit: 1,
854
+ depth: 1
855
+ });
726
856
  if (!referralQuery.docs.length) return Response.json({
727
857
  success: false,
728
858
  error: "Invalid referral code"
@@ -768,10 +898,8 @@ async function handleReferralCode({ payload, code, cartID, cart, customerEmail:
768
898
  error: `Minimum order value of ${program.minOrderValue} ${pluginConfig.defaultCurrency} required`
769
899
  }, { status: 400 });
770
900
  const { partnerCommission, customerDiscount } = calculateCommissionAndDiscount({
771
- cart,
772
- program,
773
- pluginConfig,
774
- payload
901
+ cartItems: cart.items || [],
902
+ program
775
903
  });
776
904
  const roundedPartnerCommission = roundTo2(partnerCommission);
777
905
  const roundedCustomerDiscount = roundTo2(customerDiscount);
@@ -792,88 +920,10 @@ async function handleReferralCode({ payload, code, cartID, cart, customerEmail:
792
920
  referralCode: { code: referralCode.code },
793
921
  partnerCommission: roundedPartnerCommission,
794
922
  customerDiscount: roundedCustomerDiscount,
795
- currency: pluginConfig.defaultCurrency
923
+ currency: pluginConfig.defaultCurrency,
924
+ debug: globalDebugLogs
796
925
  });
797
926
  }
798
- function calculateCommissionAndDiscount({ cart, program, pluginConfig: _pluginConfig, payload: _payload }) {
799
- const cartTotal = cart.subtotal || cart.total || 0;
800
- const cartItems = cart.items || [];
801
- const rules = program.commissionRules || [];
802
- if (rules.length === 0) return {
803
- partnerCommission: 0,
804
- customerDiscount: 0
805
- };
806
- let totalPartnerCommission = 0;
807
- let totalCustomerDiscount = 0;
808
- for (const item of cartItems) {
809
- const rule = findApplicableCommissionRule(rules, item);
810
- if (!rule) continue;
811
- const itemPrice = item.price ?? item.unitPrice ?? 0;
812
- const quantity = item.quantity ?? 1;
813
- const itemTotal = itemPrice * quantity;
814
- console.log("Calculating Item:", {
815
- id: item.id,
816
- itemPrice,
817
- quantity,
818
- itemTotal,
819
- ruleBasis: rule.basis
820
- });
821
- let itemPartner = 0;
822
- let itemCustomer = 0;
823
- if (rule.basis === "shared") {
824
- if (!rule.totalCommission || rule.referrerSplit == null || rule.refereeSplit == null) {
825
- console.error("Missing shared commission fields", rule);
826
- continue;
827
- }
828
- let totalPot = 0;
829
- if (rule.totalCommission.type === "percentage") totalPot = itemTotal * rule.totalCommission.value / 100;
830
- else totalPot = rule.totalCommission.value * quantity;
831
- console.log("Shared Commission Pot:", {
832
- type: rule.totalCommission.type,
833
- value: rule.totalCommission.value,
834
- totalPot
835
- });
836
- if (rule.totalCommission.maxAmount != null && totalPot > rule.totalCommission.maxAmount) {
837
- totalPot = rule.totalCommission.maxAmount;
838
- console.log("Total pot capped at:", totalPot);
839
- }
840
- itemPartner = totalPot * rule.referrerSplit / 100;
841
- itemCustomer = totalPot * rule.refereeSplit / 100;
842
- console.log("Shared Splits:", {
843
- referrerSplit: rule.referrerSplit,
844
- refereeSplit: rule.refereeSplit,
845
- itemPartner,
846
- itemCustomer
847
- });
848
- } else {
849
- if (!rule.referrerReward || !rule.refereeReward) continue;
850
- if (rule.referrerReward.type === "percentage") itemPartner = itemTotal * rule.referrerReward.value / 100;
851
- else itemPartner = rule.referrerReward.value * quantity;
852
- if (rule.referrerReward.maxReward != null && itemPartner > rule.referrerReward.maxReward) itemPartner = rule.referrerReward.maxReward;
853
- if (rule.refereeReward.type === "percentage") itemCustomer = itemTotal * rule.refereeReward.value / 100;
854
- else itemCustomer = rule.refereeReward.value * quantity;
855
- if (rule.refereeReward.maxReward != null && itemCustomer > rule.refereeReward.maxReward) itemCustomer = rule.refereeReward.maxReward;
856
- }
857
- totalPartnerCommission += itemPartner;
858
- totalCustomerDiscount += itemCustomer;
859
- }
860
- if (totalCustomerDiscount > cartTotal) totalCustomerDiscount = cartTotal;
861
- return {
862
- partnerCommission: totalPartnerCommission,
863
- customerDiscount: totalCustomerDiscount
864
- };
865
- }
866
- function findApplicableCommissionRule(rules, item) {
867
- const productId = typeof item.product === "string" ? item.product : item.product?.id;
868
- const categoryId = item.category ?? item.product?.category;
869
- const productRule = rules.find((r) => r.appliesTo === "products" && r.products?.some((p) => (typeof p === "string" ? p : p?.id) === productId));
870
- if (productRule) return productRule;
871
- if (categoryId) {
872
- const categoryRule = rules.find((r) => r.appliesTo === "categories" && r.categories?.some((c) => (typeof c === "string" ? c : c?.id) === categoryId));
873
- if (categoryRule) return categoryRule;
874
- }
875
- return rules.find((r) => r.appliesTo === "all") ?? null;
876
- }
877
927
  const applyCouponEndpoint = ({ pluginConfig }) => ({
878
928
  path: pluginConfig.endpoints.applyCoupon,
879
929
  method: "post",
@@ -1036,11 +1086,21 @@ const validateCouponHandler = ({ pluginConfig }) => async (req) => {
1036
1086
  }
1037
1087
  };
1038
1088
  async function validateCouponCode$1({ payload, code, cartValue, customerEmail, pluginConfig }) {
1039
- const coupon = await payload.find({
1089
+ let coupon = await payload.find({
1040
1090
  collection: pluginConfig.collections.couponsSlug,
1041
1091
  where: { code: { equals: code } },
1042
1092
  limit: 1
1043
1093
  });
1094
+ if (!coupon.docs.length) coupon = await payload.find({
1095
+ collection: pluginConfig.collections.couponsSlug,
1096
+ where: { code: { equals: code.toLowerCase() } },
1097
+ limit: 1
1098
+ });
1099
+ if (!coupon.docs.length) coupon = await payload.find({
1100
+ collection: pluginConfig.collections.couponsSlug,
1101
+ where: { code: { equals: code.toUpperCase() } },
1102
+ limit: 1
1103
+ });
1044
1104
  if (!coupon.docs.length) return Response.json({
1045
1105
  success: false,
1046
1106
  error: "Invalid coupon code"
@@ -1112,11 +1172,21 @@ async function validateCouponCode$1({ payload, code, cartValue, customerEmail, p
1112
1172
  });
1113
1173
  }
1114
1174
  async function validateReferralCode({ payload, code, cartID, pluginConfig }) {
1115
- const referral = await payload.find({
1175
+ let referral = await payload.find({
1116
1176
  collection: pluginConfig.collections.referralCodesSlug,
1117
1177
  where: { code: { equals: code } },
1118
1178
  limit: 1
1119
1179
  });
1180
+ if (!referral.docs.length) referral = await payload.find({
1181
+ collection: pluginConfig.collections.referralCodesSlug,
1182
+ where: { code: { equals: code.toLowerCase() } },
1183
+ limit: 1
1184
+ });
1185
+ if (!referral.docs.length) referral = await payload.find({
1186
+ collection: pluginConfig.collections.referralCodesSlug,
1187
+ where: { code: { equals: code.toUpperCase() } },
1188
+ limit: 1
1189
+ });
1120
1190
  if (!referral.docs.length) return Response.json({
1121
1191
  success: false,
1122
1192
  error: "Referral code not found"
@@ -1158,12 +1228,12 @@ async function validateReferralCode({ payload, code, cartID, pluginConfig }) {
1158
1228
  const itemPrice = item.price ?? item.unitPrice ?? 0;
1159
1229
  const quantity = item.quantity ?? 1;
1160
1230
  const itemTotal = itemPrice * quantity;
1161
- let itemPartner = 0;
1231
+ let itemPartner;
1162
1232
  if (rule.referrerReward.type === "percentage") itemPartner = itemTotal * rule.referrerReward.value / 100;
1163
1233
  else itemPartner = rule.referrerReward.value * quantity;
1164
1234
  if (rule.referrerReward.maxReward != null && itemPartner > rule.referrerReward.maxReward) itemPartner = rule.referrerReward.maxReward;
1165
1235
  totalPartnerCommission += itemPartner;
1166
- let itemCustomer = 0;
1236
+ let itemCustomer;
1167
1237
  if (rule.refereeReward.type === "percentage") itemCustomer = itemTotal * rule.refereeReward.value / 100;
1168
1238
  else itemCustomer = rule.refereeReward.value * quantity;
1169
1239
  if (rule.refereeReward.maxReward != null && itemCustomer > rule.refereeReward.maxReward) itemCustomer = rule.refereeReward.maxReward;
@@ -1201,6 +1271,115 @@ const validateCouponEndpoint = ({ pluginConfig }) => ({
1201
1271
  handler: validateCouponHandler({ pluginConfig })
1202
1272
  });
1203
1273
 
1274
+ //#endregion
1275
+ //#region src/hooks/recalculateCart.ts
1276
+ const recalculateCartHook = (pluginConfig) => async ({ data, req, originalDoc }) => {
1277
+ if (!req.payload) return data;
1278
+ const effectiveItems = data.items || originalDoc?.items || [];
1279
+ console.log("[RecalculateCart] Hook triggered", {
1280
+ hasDataItems: !!data.items,
1281
+ dataItemsCount: data.items?.length,
1282
+ originalItemsCount: originalDoc?.items?.length,
1283
+ effectiveItemsCount: effectiveItems.length
1284
+ });
1285
+ if (!effectiveItems.length) return {
1286
+ ...data,
1287
+ partnerCommission: 0,
1288
+ customerDiscount: 0,
1289
+ discountAmount: 0,
1290
+ total: 0
1291
+ };
1292
+ const appliedReferralCode = data.appliedReferralCode ?? originalDoc?.appliedReferralCode;
1293
+ const appliedCoupon = data.appliedCoupon ?? originalDoc?.appliedCoupon;
1294
+ if (!appliedReferralCode && !appliedCoupon) {
1295
+ if (data.appliedReferralCode === null || data.appliedCoupon === null) return {
1296
+ ...data,
1297
+ partnerCommission: 0,
1298
+ customerDiscount: 0,
1299
+ discountAmount: 0
1300
+ };
1301
+ return data;
1302
+ }
1303
+ const productIds = effectiveItems.map((item) => typeof item.product === "string" ? item.product : item.product?.id).filter(Boolean);
1304
+ if (!productIds.length) return data;
1305
+ const productsQuery = await req.payload.find({
1306
+ collection: "products",
1307
+ where: { id: { in: productIds } },
1308
+ limit: productIds.length
1309
+ });
1310
+ const productsMap = new Map(productsQuery.docs.map((p) => [p.id, p]));
1311
+ let calculatedSubtotal = 0;
1312
+ const enrichedItems = effectiveItems.map((item) => {
1313
+ const productId = typeof item.product === "string" ? item.product : item.product?.id;
1314
+ const product = productsMap.get(productId) || {};
1315
+ const itemPrice = getCartItemUnitPrice({
1316
+ item,
1317
+ product,
1318
+ variant: typeof item.variant === "object" ? item.variant : void 0,
1319
+ currencyCode: pluginConfig.defaultCurrency
1320
+ });
1321
+ calculatedSubtotal += itemPrice * (item.quantity ?? 1);
1322
+ console.log("[RecalculateCart] Item processed", {
1323
+ productId,
1324
+ quantity: item.quantity,
1325
+ priceUsed: itemPrice,
1326
+ currentSubtotal: calculatedSubtotal
1327
+ });
1328
+ return {
1329
+ ...item,
1330
+ product,
1331
+ price: itemPrice
1332
+ };
1333
+ });
1334
+ if (appliedReferralCode && pluginConfig.enableReferrals) {
1335
+ const referralQuery = await req.payload.find({
1336
+ collection: pluginConfig.collections.referralCodesSlug,
1337
+ where: { id: { equals: typeof appliedReferralCode === "string" ? appliedReferralCode : appliedReferralCode.id } },
1338
+ limit: 1,
1339
+ depth: 1
1340
+ });
1341
+ if (referralQuery.docs.length) {
1342
+ const referralCode = referralQuery.docs[0];
1343
+ const program = typeof referralCode.program === "object" ? referralCode.program : null;
1344
+ if (program) {
1345
+ const { partnerCommission, customerDiscount } = calculateCommissionAndDiscount({
1346
+ cartItems: enrichedItems,
1347
+ program,
1348
+ currencyCode: pluginConfig.defaultCurrency
1349
+ });
1350
+ const roundedCustomerDiscount = roundTo2(customerDiscount);
1351
+ data.partnerCommission = roundTo2(partnerCommission);
1352
+ data.customerDiscount = roundedCustomerDiscount;
1353
+ data.total = Math.max(0, calculatedSubtotal - roundedCustomerDiscount);
1354
+ }
1355
+ }
1356
+ }
1357
+ if (appliedCoupon && (!appliedReferralCode || pluginConfig.referralConfig.allowBothSystems)) {
1358
+ const couponQuery = await req.payload.find({
1359
+ collection: pluginConfig.collections.couponsSlug,
1360
+ where: { id: { equals: typeof appliedCoupon === "string" ? appliedCoupon : appliedCoupon.id } },
1361
+ limit: 1
1362
+ });
1363
+ if (couponQuery.docs.length) {
1364
+ const coupon = couponQuery.docs[0];
1365
+ const discountAmount = calculateCouponDiscount({
1366
+ coupon,
1367
+ cartTotal: calculatedSubtotal
1368
+ });
1369
+ console.log("[RecalculateCart] Coupon Logic", {
1370
+ appliedCoupon,
1371
+ couponId: coupon.id,
1372
+ cartTotal: calculatedSubtotal,
1373
+ discountAmount
1374
+ });
1375
+ data.discountAmount = discountAmount;
1376
+ const currentDiscount = data.customerDiscount || 0;
1377
+ data.total = Math.max(0, calculatedSubtotal - currentDiscount - discountAmount);
1378
+ }
1379
+ }
1380
+ return data;
1381
+ };
1382
+
1204
1383
  //#endregion
1205
1384
  //#region src/utilities/sanitizePluginConfig.ts
1206
1385
  const sanitizePluginConfig = ({ pluginConfig }) => {
@@ -1418,6 +1597,15 @@ const payloadEcommerceCouponPlugin = (pluginOptions = {}) => async (incomingConf
1418
1597
  }]);
1419
1598
  }
1420
1599
  }
1600
+ const cartIndex = incomingConfig.collections.findIndex((c) => c.slug === "carts");
1601
+ if (cartIndex > -1) {
1602
+ const collection = incomingConfig.collections[cartIndex];
1603
+ collection.hooks = {
1604
+ ...collection.hooks,
1605
+ beforeChange: [...collection.hooks?.beforeChange || [], recalculateCartHook(pluginConfig)]
1606
+ };
1607
+ incomingConfig.collections[cartIndex] = collection;
1608
+ }
1421
1609
  return incomingConfig;
1422
1610
  };
1423
1611