@wtree/payload-ecommerce-coupon 3.78.2 → 3.78.4

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.
Files changed (57) hide show
  1. package/README.md +33 -6
  2. package/dist/client/hooks.d.ts +1 -1
  3. package/dist/client/hooks.d.ts.map +1 -1
  4. package/dist/client/index.d.ts +8 -8
  5. package/dist/client/index.d.ts.map +1 -1
  6. package/dist/collections/createCouponsCollection.d.ts +2 -2
  7. package/dist/collections/createCouponsCollection.d.ts.map +1 -1
  8. package/dist/collections/createReferralCodesCollection.d.ts +2 -2
  9. package/dist/collections/createReferralCodesCollection.d.ts.map +1 -1
  10. package/dist/collections/createReferralProgramsCollection.d.ts +2 -2
  11. package/dist/collections/createReferralProgramsCollection.d.ts.map +1 -1
  12. package/dist/components/PartnerDashboard/CommissionBreakdown.d.ts +2 -2
  13. package/dist/components/PartnerDashboard/CommissionBreakdown.d.ts.map +1 -1
  14. package/dist/components/PartnerDashboard/EarningsSummary.d.ts +2 -2
  15. package/dist/components/PartnerDashboard/EarningsSummary.d.ts.map +1 -1
  16. package/dist/components/PartnerDashboard/ProgramOverview.d.ts +3 -3
  17. package/dist/components/PartnerDashboard/ProgramOverview.d.ts.map +1 -1
  18. package/dist/components/PartnerDashboard/RecentReferrals.d.ts +3 -3
  19. package/dist/components/PartnerDashboard/RecentReferrals.d.ts.map +1 -1
  20. package/dist/components/PartnerDashboard/ReferralCodes.d.ts +3 -3
  21. package/dist/components/PartnerDashboard/ReferralCodes.d.ts.map +1 -1
  22. package/dist/components/PartnerDashboard/ReferralPerformance.d.ts +2 -2
  23. package/dist/components/PartnerDashboard/ReferralPerformance.d.ts.map +1 -1
  24. package/dist/components/PartnerDashboard/index.d.ts +1 -1
  25. package/dist/components/PartnerDashboard/index.d.ts.map +1 -1
  26. package/dist/endpoints/applyCoupon.d.ts +2 -2
  27. package/dist/endpoints/applyCoupon.d.ts.map +1 -1
  28. package/dist/endpoints/partnerStats.d.ts +2 -2
  29. package/dist/endpoints/partnerStats.d.ts.map +1 -1
  30. package/dist/endpoints/validateCoupon.d.ts +2 -2
  31. package/dist/endpoints/validateCoupon.d.ts.map +1 -1
  32. package/dist/hooks/recalculateCart.d.ts +2 -2
  33. package/dist/hooks/recalculateCart.d.ts.map +1 -1
  34. package/dist/index.d.ts +17 -17
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +158 -54
  37. package/dist/index.js.map +1 -1
  38. package/dist/index.mjs +122 -18
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/plugin.d.ts +2 -2
  41. package/dist/plugin.d.ts.map +1 -1
  42. package/dist/types.d.ts +4 -4
  43. package/dist/types.d.ts.map +1 -1
  44. package/dist/utilities/calculateValues.d.ts +2 -2
  45. package/dist/utilities/calculateValues.d.ts.map +1 -1
  46. package/dist/utilities/getCartTotalWithDiscounts.d.ts.map +1 -1
  47. package/dist/utilities/migrateReferralRulesV2.d.ts.map +1 -1
  48. package/dist/utilities/pricing.d.ts.map +1 -1
  49. package/dist/utilities/pushTypeScriptProperties.d.ts +1 -1
  50. package/dist/utilities/pushTypeScriptProperties.d.ts.map +1 -1
  51. package/dist/utilities/recordCouponUsageForOrder.d.ts +2 -2
  52. package/dist/utilities/recordCouponUsageForOrder.d.ts.map +1 -1
  53. package/dist/utilities/sanitizePluginConfig.d.ts +1 -1
  54. package/dist/utilities/sanitizePluginConfig.d.ts.map +1 -1
  55. package/dist/utilities/userRoles.d.ts +3 -3
  56. package/dist/utilities/userRoles.d.ts.map +1 -1
  57. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -454,11 +454,14 @@ const createReferralProgramsCollection = (pluginConfig) => {
454
454
  },
455
455
  hooks: { beforeChange: [({ data }) => {
456
456
  if (!data.commissionRules || !Array.isArray(data.commissionRules) || data.commissionRules.length === 0) throw new payload.APIError("At least one commission rule is required", 400);
457
- const maxAmount = toNumber(data.maxAmount);
458
- if (maxAmount != null && maxAmount < 0) throw new payload.APIError("Max Amount must be a non-negative number", 400);
457
+ const maxPartnerCommissionPerOrder = toNumber(data.maxPartnerCommissionPerOrder);
458
+ if (maxPartnerCommissionPerOrder != null && maxPartnerCommissionPerOrder < 0) throw new payload.APIError("Maximum commission per order for partner must be a non-negative number", 400);
459
+ const maxCustomerDiscountPerOrder = toNumber(data.maxCustomerDiscountPerOrder);
460
+ if (maxCustomerDiscountPerOrder != null && maxCustomerDiscountPerOrder < 0) throw new payload.APIError("Maximum discount for customer per order must be a non-negative number", 400);
459
461
  const minOrderAmount = toNumber(data.minOrderAmount);
460
462
  if (minOrderAmount != null && minOrderAmount < 0) throw new payload.APIError("Minimum Order Amount must be a non-negative number", 400);
461
- data.maxAmount = maxAmount ?? null;
463
+ data.maxPartnerCommissionPerOrder = maxPartnerCommissionPerOrder != null ? toCents(maxPartnerCommissionPerOrder) : null;
464
+ data.maxCustomerDiscountPerOrder = maxCustomerDiscountPerOrder != null ? toCents(maxCustomerDiscountPerOrder) : null;
462
465
  data.minOrderAmount = minOrderAmount ?? null;
463
466
  data.commissionRules = data.commissionRules.map((rule, index) => {
464
467
  const r = rule;
@@ -541,10 +544,16 @@ const createReferralProgramsCollection = (pluginConfig) => {
541
544
  admin: { description: "Whether this referral program is currently active" }
542
545
  },
543
546
  {
544
- name: "maxAmount",
547
+ name: "maxPartnerCommissionPerOrder",
545
548
  type: "number",
546
549
  min: 0,
547
- admin: { description: "Maximum commission cap per item. Leave empty for no cap." }
550
+ admin: { description: "Maximum commission per order for partner. Leave empty for no cap. Enter value in currency units (will be converted to cents)." }
551
+ },
552
+ {
553
+ name: "maxCustomerDiscountPerOrder",
554
+ type: "number",
555
+ min: 0,
556
+ admin: { description: "Maximum customer discount per order. Leave empty for no cap. Enter value in currency units (will be converted to cents)." }
548
557
  },
549
558
  {
550
559
  name: "minOrderAmount",
@@ -759,11 +768,11 @@ function getRuleSplits(rule) {
759
768
  customerSplit: typeof rule.customerSplit === "number" ? rule.customerSplit : typeof rule.refereeSplit === "number" ? rule.refereeSplit : 100 - partnerRaw
760
769
  };
761
770
  }
762
- function calculateItemRewardByRule({ rule, itemTotal, quantity, maxAmount, allowedTotalCommissionTypes }) {
771
+ function calculateItemRewardByRule({ rule, itemTotal, quantity, allowedTotalCommissionTypes }) {
763
772
  const allowedTypes = allowedCommissionTypesSet(allowedTotalCommissionTypes);
764
773
  if (rule.totalCommission) {
765
774
  if (!allowedTypes.has(rule.totalCommission.type)) return null;
766
- const resolvedMaxAmount = typeof maxAmount === "number" && Number.isFinite(maxAmount) ? maxAmount : typeof rule.totalCommission.maxAmount === "number" && Number.isFinite(rule.totalCommission.maxAmount) ? rule.totalCommission.maxAmount : null;
775
+ const resolvedMaxAmount = typeof rule.totalCommission.maxAmount === "number" && Number.isFinite(rule.totalCommission.maxAmount) ? rule.totalCommission.maxAmount : null;
767
776
  if (rule.totalCommission.type === "fixed" && rule.totalCommission.value == null) {
768
777
  const partnerAmtPerUnit = typeof rule.partnerSplit === "number" ? rule.partnerSplit : null;
769
778
  const customerAmtPerUnit = typeof rule.customerSplit === "number" ? rule.customerSplit : null;
@@ -822,7 +831,7 @@ function getItemCategoryIds(item) {
822
831
  function getItemTagIds(item) {
823
832
  return Array.isArray(item?.product?.tags) ? normalizeIds(item.product.tags) : [];
824
833
  }
825
- function selectBestRuleForItem({ rules, item, itemTotal, quantity, cartTotal, minOrderAmount, maxAmount, allowedTotalCommissionTypes }) {
834
+ function selectBestRuleForItem({ rules, item, itemTotal, quantity, cartTotal, minOrderAmount, allowedTotalCommissionTypes }) {
826
835
  const allowedTypes = allowedCommissionTypesSet(allowedTotalCommissionTypes);
827
836
  const eligibleRules = rules.filter((rule) => {
828
837
  if (!(rule?.totalCommission?.type ? allowedTypes.has(rule.totalCommission.type) : true)) return false;
@@ -852,7 +861,6 @@ function selectBestRuleForItem({ rules, item, itemTotal, quantity, cartTotal, mi
852
861
  rule,
853
862
  itemTotal,
854
863
  quantity,
855
- maxAmount,
856
864
  allowedTotalCommissionTypes
857
865
  });
858
866
  if (!reward) continue;
@@ -917,13 +925,16 @@ function calculateCommissionAndDiscount({ cartItems, program, currencyCode = "AE
917
925
  quantity,
918
926
  cartTotal,
919
927
  minOrderAmount: typeof program?.minOrderAmount === "number" && Number.isFinite(program.minOrderAmount) ? program.minOrderAmount : null,
920
- maxAmount: typeof program?.maxAmount === "number" && Number.isFinite(program.maxAmount) ? program.maxAmount : null,
921
928
  allowedTotalCommissionTypes
922
929
  });
923
930
  if (!bestMatch) continue;
924
931
  totalPartnerCommission += bestMatch.reward.partner;
925
932
  totalCustomerDiscount += bestMatch.reward.customer;
926
933
  }
934
+ const maxPartnerCommissionPerOrder = typeof program?.maxPartnerCommissionPerOrder === "number" && Number.isFinite(program.maxPartnerCommissionPerOrder) ? program.maxPartnerCommissionPerOrder : null;
935
+ const maxCustomerDiscountPerOrder = typeof program?.maxCustomerDiscountPerOrder === "number" && Number.isFinite(program.maxCustomerDiscountPerOrder) ? program.maxCustomerDiscountPerOrder : null;
936
+ if (maxPartnerCommissionPerOrder != null) totalPartnerCommission = Math.min(totalPartnerCommission, maxPartnerCommissionPerOrder);
937
+ if (maxCustomerDiscountPerOrder != null) totalCustomerDiscount = Math.min(totalCustomerDiscount, maxCustomerDiscountPerOrder);
927
938
  return {
928
939
  partnerCommission: totalPartnerCommission,
929
940
  customerDiscount: totalCustomerDiscount
@@ -947,38 +958,56 @@ function writeField$1(doc, field, value) {
947
958
  function normalizeCode$1(value) {
948
959
  return typeof value === "string" ? value.trim().toUpperCase() : "";
949
960
  }
950
- async function findByNormalizedCode$1({ payload, collection, normalizedCode }) {
951
- const exactQuery = await payload.find({
961
+ async function ensureRequestData$1(req) {
962
+ if (req?.data && typeof req.data === "object") return req.data;
963
+ try {
964
+ await (0, payload.addDataAndFileToRequest)(req);
965
+ } catch {}
966
+ if (req?.data && typeof req.data === "object") return req.data;
967
+ try {
968
+ const parsed = await req?.json?.();
969
+ if (parsed && typeof parsed === "object") {
970
+ req.data = parsed;
971
+ return parsed;
972
+ }
973
+ } catch {}
974
+ req.data = {};
975
+ return req.data;
976
+ }
977
+ async function findByNormalizedCode$1({ payload: payload$5, collection, normalizedCode }) {
978
+ const exactQuery = await payload$5.find({
952
979
  collection,
953
980
  where: { normalizedCode: { equals: normalizedCode } },
954
981
  limit: 1
955
982
  });
956
983
  if (exactQuery?.docs?.[0]) return exactQuery.docs[0];
957
- const lowerQuery = await payload.find({
984
+ const lowerQuery = await payload$5.find({
958
985
  collection,
959
986
  where: { code: { equals: normalizedCode.toLowerCase() } },
960
987
  limit: 1
961
988
  });
962
989
  if (lowerQuery?.docs?.[0]) return lowerQuery.docs[0];
963
- const upperQuery = await payload.find({
990
+ const upperQuery = await payload$5.find({
964
991
  collection,
965
992
  where: { code: { equals: normalizedCode.toUpperCase() } },
966
993
  limit: 1
967
994
  });
968
995
  if (upperQuery?.docs?.[0]) return upperQuery.docs[0];
969
- return (await payload.find({
996
+ return (await payload$5.find({
970
997
  collection,
971
998
  where: { code: { equals: normalizedCode } },
972
999
  limit: 1
973
1000
  }))?.docs?.[0] ?? null;
974
1001
  }
975
1002
  const applyCouponHandler = ({ pluginConfig }) => async (req) => {
976
- const { payload } = req;
1003
+ const { payload: payload$6 } = req;
977
1004
  const fields = pluginConfig.integration.fields;
978
1005
  const collections = pluginConfig.integration.collections;
979
- const rawCode = req?.data?.code;
980
- const cartID = req?.data?.cartID;
981
- const customerEmail = req?.data?.customerEmail;
1006
+ const data = await ensureRequestData$1(req);
1007
+ const rawCode = data?.code;
1008
+ const cartIDRaw = data?.cartID;
1009
+ const cartID = typeof cartIDRaw === "string" || typeof cartIDRaw === "number" ? cartIDRaw : null;
1010
+ const customerEmail = typeof data?.customerEmail === "string" ? data.customerEmail : void 0;
982
1011
  const normalizedCode = normalizeCode$1(rawCode);
983
1012
  if (!normalizedCode || !cartID) return Response.json({
984
1013
  success: false,
@@ -987,19 +1016,19 @@ const applyCouponHandler = ({ pluginConfig }) => async (req) => {
987
1016
  const allowCoupon = await Promise.resolve(pluginConfig.policies.canApplyCoupon({
988
1017
  req,
989
1018
  user: req?.user,
990
- payload
1019
+ payload: payload$6
991
1020
  }));
992
1021
  const allowReferral = await Promise.resolve(pluginConfig.policies.canApplyReferral({
993
1022
  req,
994
1023
  user: req?.user,
995
- payload
1024
+ payload: payload$6
996
1025
  }));
997
1026
  if (!allowCoupon && !(pluginConfig.enableReferrals && allowReferral)) return Response.json({
998
1027
  success: false,
999
1028
  error: "Forbidden"
1000
1029
  }, { status: 403 });
1001
1030
  try {
1002
- const cart = await payload.findByID({
1031
+ const cart = await payload$6.findByID({
1003
1032
  collection: collections.cartsSlug,
1004
1033
  id: cartID,
1005
1034
  depth: 2
@@ -1016,14 +1045,14 @@ const applyCouponHandler = ({ pluginConfig }) => async (req) => {
1016
1045
  }, { status: 400 });
1017
1046
  if (pluginConfig.enableReferrals && allowReferral) {
1018
1047
  const referralResult = await handleReferralCode({
1019
- payload,
1048
+ payload: payload$6,
1020
1049
  cart,
1021
1050
  cartID,
1022
1051
  normalizedCode,
1023
1052
  pluginConfig
1024
1053
  });
1025
1054
  if (!referralResult.ok && referralResult.status === 404 && pluginConfig.referralConfig.allowBothSystems && allowCoupon) return await handleCouponCode({
1026
- payload,
1055
+ payload: payload$6,
1027
1056
  cart,
1028
1057
  cartID,
1029
1058
  normalizedCode,
@@ -1037,7 +1066,7 @@ const applyCouponHandler = ({ pluginConfig }) => async (req) => {
1037
1066
  error: "Forbidden"
1038
1067
  }, { status: 403 });
1039
1068
  return await handleCouponCode({
1040
- payload,
1069
+ payload: payload$6,
1041
1070
  cart,
1042
1071
  cartID,
1043
1072
  normalizedCode,
@@ -1052,11 +1081,11 @@ const applyCouponHandler = ({ pluginConfig }) => async (req) => {
1052
1081
  }, { status: 500 });
1053
1082
  }
1054
1083
  };
1055
- async function handleCouponCode({ payload, cart, cartID, normalizedCode, customerEmail, pluginConfig }) {
1084
+ async function handleCouponCode({ payload: payload$7, cart, cartID, normalizedCode, customerEmail, pluginConfig }) {
1056
1085
  const fields = pluginConfig.integration.fields;
1057
1086
  const resolvers = pluginConfig.integration.resolvers;
1058
1087
  const coupon = await findByNormalizedCode$1({
1059
- payload,
1088
+ payload: payload$7,
1060
1089
  collection: pluginConfig.collections.couponsSlug,
1061
1090
  normalizedCode
1062
1091
  });
@@ -1085,7 +1114,7 @@ async function handleCouponCode({ payload, cart, cartID, normalizedCode, custome
1085
1114
  success: false,
1086
1115
  error: "Customer email is required for this coupon."
1087
1116
  }, { status: 400 });
1088
- if ((await payload.find({
1117
+ if ((await payload$7.find({
1089
1118
  collection: pluginConfig.orderIntegration.ordersSlug,
1090
1119
  where: { and: [
1091
1120
  { [fields.orderAppliedCouponField]: { equals: coupon.id } },
@@ -1121,7 +1150,7 @@ async function handleCouponCode({ payload, cart, cartID, normalizedCode, custome
1121
1150
  writeField$1(data, fields.cartAppliedCouponField, coupon.id);
1122
1151
  writeField$1(data, fields.cartDiscountAmountField, discountAmount);
1123
1152
  writeField$1(data, fields.cartTotalField, nextTotal);
1124
- await payload.update({
1153
+ await payload$7.update({
1125
1154
  collection: pluginConfig.integration.collections.cartsSlug,
1126
1155
  id: cartID,
1127
1156
  data
@@ -1138,11 +1167,11 @@ async function handleCouponCode({ payload, cart, cartID, normalizedCode, custome
1138
1167
  currency: pluginConfig.defaultCurrency
1139
1168
  });
1140
1169
  }
1141
- async function handleReferralCode({ payload, cart, cartID, normalizedCode, pluginConfig }) {
1170
+ async function handleReferralCode({ payload: payload$8, cart, cartID, normalizedCode, pluginConfig }) {
1142
1171
  const fields = pluginConfig.integration.fields;
1143
1172
  const resolvers = pluginConfig.integration.resolvers;
1144
1173
  const referralCode = await findByNormalizedCode$1({
1145
- payload,
1174
+ payload: payload$8,
1146
1175
  collection: pluginConfig.collections.referralCodesSlug,
1147
1176
  normalizedCode
1148
1177
  });
@@ -1163,7 +1192,7 @@ async function handleReferralCode({ payload, cart, cartID, normalizedCode, plugi
1163
1192
  error: "Referral code usage limit exceeded"
1164
1193
  }, { status: 400 });
1165
1194
  const programId = typeof referralCode.program === "string" || typeof referralCode.program === "number" ? referralCode.program : referralCode.program?.id;
1166
- const program = await payload.findByID({
1195
+ const program = await payload$8.findByID({
1167
1196
  collection: pluginConfig.collections.referralProgramsSlug,
1168
1197
  id: programId
1169
1198
  });
@@ -1200,7 +1229,7 @@ async function handleReferralCode({ payload, cart, cartID, normalizedCode, plugi
1200
1229
  writeField$1(data, fields.cartPartnerCommissionField, roundedPartnerCommission);
1201
1230
  writeField$1(data, fields.cartCustomerDiscountField, roundedCustomerDiscount);
1202
1231
  writeField$1(data, fields.cartTotalField, nextTotal);
1203
- await payload.update({
1232
+ await payload$8.update({
1204
1233
  collection: pluginConfig.integration.collections.cartsSlug,
1205
1234
  id: cartID,
1206
1235
  data
@@ -1407,37 +1436,55 @@ function relationId$2(value) {
1407
1436
  function normalizeCode(value) {
1408
1437
  return typeof value === "string" ? value.trim().toUpperCase() : "";
1409
1438
  }
1410
- async function findByNormalizedCode({ payload, collection, normalizedCode }) {
1411
- const normalizedQuery = await payload.find({
1439
+ async function ensureRequestData(req) {
1440
+ if (req?.data && typeof req.data === "object") return req.data;
1441
+ try {
1442
+ await (0, payload.addDataAndFileToRequest)(req);
1443
+ } catch {}
1444
+ if (req?.data && typeof req.data === "object") return req.data;
1445
+ try {
1446
+ const parsed = await req?.json?.();
1447
+ if (parsed && typeof parsed === "object") {
1448
+ req.data = parsed;
1449
+ return parsed;
1450
+ }
1451
+ } catch {}
1452
+ req.data = {};
1453
+ return req.data;
1454
+ }
1455
+ async function findByNormalizedCode({ payload: payload$1, collection, normalizedCode }) {
1456
+ const normalizedQuery = await payload$1.find({
1412
1457
  collection,
1413
1458
  where: { normalizedCode: { equals: normalizedCode } },
1414
1459
  limit: 1
1415
1460
  });
1416
1461
  if (normalizedQuery?.docs?.length) return normalizedQuery.docs[0];
1417
- const lowerQuery = await payload.find({
1462
+ const lowerQuery = await payload$1.find({
1418
1463
  collection,
1419
1464
  where: { code: { equals: normalizedCode.toLowerCase() } },
1420
1465
  limit: 1
1421
1466
  });
1422
1467
  if (lowerQuery?.docs?.length) return lowerQuery.docs[0];
1423
- const upperQuery = await payload.find({
1468
+ const upperQuery = await payload$1.find({
1424
1469
  collection,
1425
1470
  where: { code: { equals: normalizedCode.toUpperCase() } },
1426
1471
  limit: 1
1427
1472
  });
1428
1473
  if (upperQuery?.docs?.length) return upperQuery.docs[0];
1429
- return (await payload.find({
1474
+ return (await payload$1.find({
1430
1475
  collection,
1431
1476
  where: { code: { equals: normalizedCode } },
1432
1477
  limit: 1
1433
1478
  }))?.docs?.[0] ?? null;
1434
1479
  }
1435
1480
  const validateCouponHandler = ({ pluginConfig }) => async (req) => {
1436
- const { payload } = req;
1437
- const rawCode = req?.data?.code;
1438
- const cartValue = req?.data?.cartValue;
1439
- const cartID = req?.data?.cartID;
1440
- const customerEmail = req?.data?.customerEmail;
1481
+ const { payload: payload$2 } = req;
1482
+ const data = await ensureRequestData(req);
1483
+ const rawCode = data?.code;
1484
+ const cartValue = typeof data?.cartValue === "number" ? data.cartValue : void 0;
1485
+ const cartIDRaw = data?.cartID;
1486
+ const cartID = typeof cartIDRaw === "string" || typeof cartIDRaw === "number" ? cartIDRaw : void 0;
1487
+ const customerEmail = typeof data?.customerEmail === "string" ? data.customerEmail : void 0;
1441
1488
  const normalizedCode = normalizeCode(rawCode);
1442
1489
  if (!normalizedCode) return Response.json({
1443
1490
  success: false,
@@ -1448,13 +1495,13 @@ const validateCouponHandler = ({ pluginConfig }) => async (req) => {
1448
1495
  if (!await Promise.resolve(pluginConfig.policies.canApplyReferral({
1449
1496
  req,
1450
1497
  user: req?.user,
1451
- payload
1498
+ payload: payload$2
1452
1499
  }))) return Response.json({
1453
1500
  success: false,
1454
1501
  error: "Forbidden"
1455
1502
  }, { status: 403 });
1456
1503
  return await validateReferralCode({
1457
- payload,
1504
+ payload: payload$2,
1458
1505
  normalizedCode,
1459
1506
  cartID,
1460
1507
  pluginConfig
@@ -1463,13 +1510,13 @@ const validateCouponHandler = ({ pluginConfig }) => async (req) => {
1463
1510
  if (!await Promise.resolve(pluginConfig.policies.canApplyCoupon({
1464
1511
  req,
1465
1512
  user: req?.user,
1466
- payload
1513
+ payload: payload$2
1467
1514
  }))) return Response.json({
1468
1515
  success: false,
1469
1516
  error: "Forbidden"
1470
1517
  }, { status: 403 });
1471
1518
  return await validateCouponCode$1({
1472
- payload,
1519
+ payload: payload$2,
1473
1520
  normalizedCode,
1474
1521
  cartValue,
1475
1522
  customerEmail,
@@ -1483,10 +1530,10 @@ const validateCouponHandler = ({ pluginConfig }) => async (req) => {
1483
1530
  }, { status: 500 });
1484
1531
  }
1485
1532
  };
1486
- async function validateCouponCode$1({ payload, normalizedCode, cartValue, customerEmail, pluginConfig }) {
1533
+ async function validateCouponCode$1({ payload: payload$3, normalizedCode, cartValue, customerEmail, pluginConfig }) {
1487
1534
  const fields = pluginConfig.integration.fields;
1488
1535
  const couponData = await findByNormalizedCode({
1489
- payload,
1536
+ payload: payload$3,
1490
1537
  collection: pluginConfig.collections.couponsSlug,
1491
1538
  normalizedCode
1492
1539
  });
@@ -1511,7 +1558,7 @@ async function validateCouponCode$1({ payload, normalizedCode, cartValue, custom
1511
1558
  }, { status: 400 });
1512
1559
  if (couponData.perCustomerLimit != null && couponData.perCustomerLimit > 0 && typeof customerEmail === "string" && customerEmail.trim().length > 0) {
1513
1560
  const email = customerEmail.trim();
1514
- if ((await payload.find({
1561
+ if ((await payload$3.find({
1515
1562
  collection: pluginConfig.orderIntegration.ordersSlug,
1516
1563
  where: { and: [
1517
1564
  { [fields.orderAppliedCouponField]: { equals: couponData.id } },
@@ -1558,11 +1605,11 @@ async function validateCouponCode$1({ payload, normalizedCode, cartValue, custom
1558
1605
  currency: pluginConfig.defaultCurrency
1559
1606
  });
1560
1607
  }
1561
- async function validateReferralCode({ payload, normalizedCode, cartID, pluginConfig }) {
1608
+ async function validateReferralCode({ payload: payload$4, normalizedCode, cartID, pluginConfig }) {
1562
1609
  const collections = pluginConfig.integration.collections;
1563
1610
  const resolvers = pluginConfig.integration.resolvers;
1564
1611
  const referralData = await findByNormalizedCode({
1565
- payload,
1612
+ payload: payload$4,
1566
1613
  collection: pluginConfig.collections.referralCodesSlug,
1567
1614
  normalizedCode
1568
1615
  });
@@ -1587,7 +1634,7 @@ async function validateReferralCode({ payload, normalizedCode, cartID, pluginCon
1587
1634
  success: false,
1588
1635
  error: "Referral program not found"
1589
1636
  }, { status: 404 });
1590
- const program = await payload.findByID({
1637
+ const program = await payload$4.findByID({
1591
1638
  collection: pluginConfig.collections.referralProgramsSlug,
1592
1639
  id: programId
1593
1640
  });
@@ -1595,7 +1642,7 @@ async function validateReferralCode({ payload, normalizedCode, cartID, pluginCon
1595
1642
  success: false,
1596
1643
  error: "Referral program is not active"
1597
1644
  }, { status: 400 });
1598
- const cart = cartID ? await payload.findByID({
1645
+ const cart = cartID ? await payload$4.findByID({
1599
1646
  collection: collections.cartsSlug,
1600
1647
  id: cartID,
1601
1648
  depth: 2
@@ -2132,6 +2179,55 @@ const sanitizePluginConfig = ({ pluginConfig }) => {
2132
2179
  const RECALCULATE_HOOK_KEY = "__payloadEcommerceCouponRecalculateHook__";
2133
2180
  const asArray = (value) => Array.isArray(value) ? value : [];
2134
2181
  const hasNamedField = (collection, fieldName) => asArray(collection.fields).some((f) => f?.name === fieldName);
2182
+ const normalizePath$1 = (path) => {
2183
+ if (!path) return "/";
2184
+ return (path.startsWith("/") ? path : `/${path}`).replace(/\/+$/, "") || "/";
2185
+ };
2186
+ const toCollectionEndpointPath = ({ endpointPath, collectionSlug }) => {
2187
+ const normalizedEndpointPath = normalizePath$1(endpointPath);
2188
+ const normalizedCollectionPath = normalizePath$1(`/${collectionSlug}`);
2189
+ if (!normalizedEndpointPath.startsWith(`${normalizedCollectionPath}/`)) return null;
2190
+ const relative = normalizedEndpointPath.slice(normalizedCollectionPath.length);
2191
+ return relative.startsWith("/") ? relative : `/${relative}`;
2192
+ };
2193
+ const ensureCouponCollectionEndpoints = ({ collection, pluginConfig }) => {
2194
+ const couponsSlug = pluginConfig.collections.couponsSlug;
2195
+ const applyPath = toCollectionEndpointPath({
2196
+ endpointPath: pluginConfig.endpoints.applyCoupon,
2197
+ collectionSlug: couponsSlug
2198
+ });
2199
+ const validatePath = toCollectionEndpointPath({
2200
+ endpointPath: pluginConfig.endpoints.validateCoupon,
2201
+ collectionSlug: couponsSlug
2202
+ });
2203
+ if (!applyPath && !validatePath) return collection;
2204
+ const endpoints = asArray(collection.endpoints);
2205
+ const endpointKeys = new Set(endpoints.map((e) => `${(e?.method || "get").toLowerCase()}:${e?.path || ""}`));
2206
+ if (validatePath) {
2207
+ const validateKey = `post:${validatePath}`;
2208
+ if (!endpointKeys.has(validateKey)) {
2209
+ endpointKeys.add(validateKey);
2210
+ endpoints.push({
2211
+ path: validatePath,
2212
+ method: "post",
2213
+ handler: validateCouponEndpoint({ pluginConfig }).handler
2214
+ });
2215
+ }
2216
+ }
2217
+ if (applyPath) {
2218
+ const applyKey = `post:${applyPath}`;
2219
+ if (!endpointKeys.has(applyKey)) {
2220
+ endpointKeys.add(applyKey);
2221
+ endpoints.push({
2222
+ path: applyPath,
2223
+ method: "post",
2224
+ handler: applyCouponEndpoint({ pluginConfig }).handler
2225
+ });
2226
+ }
2227
+ }
2228
+ collection.endpoints = endpoints;
2229
+ return collection;
2230
+ };
2135
2231
  const addFieldsToCollection = (config, targetSlug, newFields) => {
2136
2232
  const collections = asArray(config.collections);
2137
2233
  const idx = collections.findIndex((c) => c.slug === targetSlug);
@@ -2216,11 +2312,19 @@ const payloadEcommerceCouponPlugin = (pluginOptions = {}) => async (incomingConf
2216
2312
  if (pluginConfig.referralConfig.allowBothSystems) {
2217
2313
  let couponsCollection = createCouponsCollection(pluginConfig);
2218
2314
  if (pluginOptions.collections?.couponsCollectionOverride) couponsCollection = await pluginOptions.collections.couponsCollectionOverride({ defaultCollection: couponsCollection });
2315
+ couponsCollection = ensureCouponCollectionEndpoints({
2316
+ collection: couponsCollection,
2317
+ pluginConfig
2318
+ });
2219
2319
  collectionsToAdd.push(couponsCollection);
2220
2320
  }
2221
2321
  } else {
2222
2322
  let couponsCollection = createCouponsCollection(pluginConfig);
2223
2323
  if (pluginOptions.collections?.couponsCollectionOverride) couponsCollection = await pluginOptions.collections.couponsCollectionOverride({ defaultCollection: couponsCollection });
2324
+ couponsCollection = ensureCouponCollectionEndpoints({
2325
+ collection: couponsCollection,
2326
+ pluginConfig
2327
+ });
2224
2328
  collectionsToAdd.push(couponsCollection);
2225
2329
  }
2226
2330
  const existingSlugs = new Set(asArray(incomingConfig.collections).map((c) => c.slug));