@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.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { APIError } from "payload";
1
+ import { APIError, addDataAndFileToRequest } from "payload";
2
2
  //#region \0rolldown/runtime.js
3
3
  var __create = Object.create;
4
4
  var __defProp = Object.defineProperty;
@@ -453,11 +453,14 @@ const createReferralProgramsCollection = (pluginConfig) => {
453
453
  },
454
454
  hooks: { beforeChange: [({ data }) => {
455
455
  if (!data.commissionRules || !Array.isArray(data.commissionRules) || data.commissionRules.length === 0) throw new APIError("At least one commission rule is required", 400);
456
- const maxAmount = toNumber(data.maxAmount);
457
- if (maxAmount != null && maxAmount < 0) throw new APIError("Max Amount must be a non-negative number", 400);
456
+ const maxPartnerCommissionPerOrder = toNumber(data.maxPartnerCommissionPerOrder);
457
+ if (maxPartnerCommissionPerOrder != null && maxPartnerCommissionPerOrder < 0) throw new APIError("Maximum commission per order for partner must be a non-negative number", 400);
458
+ const maxCustomerDiscountPerOrder = toNumber(data.maxCustomerDiscountPerOrder);
459
+ if (maxCustomerDiscountPerOrder != null && maxCustomerDiscountPerOrder < 0) throw new APIError("Maximum discount for customer per order must be a non-negative number", 400);
458
460
  const minOrderAmount = toNumber(data.minOrderAmount);
459
461
  if (minOrderAmount != null && minOrderAmount < 0) throw new APIError("Minimum Order Amount must be a non-negative number", 400);
460
- data.maxAmount = maxAmount ?? null;
462
+ data.maxPartnerCommissionPerOrder = maxPartnerCommissionPerOrder != null ? toCents(maxPartnerCommissionPerOrder) : null;
463
+ data.maxCustomerDiscountPerOrder = maxCustomerDiscountPerOrder != null ? toCents(maxCustomerDiscountPerOrder) : null;
461
464
  data.minOrderAmount = minOrderAmount ?? null;
462
465
  data.commissionRules = data.commissionRules.map((rule, index) => {
463
466
  const r = rule;
@@ -540,10 +543,16 @@ const createReferralProgramsCollection = (pluginConfig) => {
540
543
  admin: { description: "Whether this referral program is currently active" }
541
544
  },
542
545
  {
543
- name: "maxAmount",
546
+ name: "maxPartnerCommissionPerOrder",
544
547
  type: "number",
545
548
  min: 0,
546
- admin: { description: "Maximum commission cap per item. Leave empty for no cap." }
549
+ admin: { description: "Maximum commission per order for partner. Leave empty for no cap. Enter value in currency units (will be converted to cents)." }
550
+ },
551
+ {
552
+ name: "maxCustomerDiscountPerOrder",
553
+ type: "number",
554
+ min: 0,
555
+ admin: { description: "Maximum customer discount per order. Leave empty for no cap. Enter value in currency units (will be converted to cents)." }
547
556
  },
548
557
  {
549
558
  name: "minOrderAmount",
@@ -758,11 +767,11 @@ function getRuleSplits(rule) {
758
767
  customerSplit: typeof rule.customerSplit === "number" ? rule.customerSplit : typeof rule.refereeSplit === "number" ? rule.refereeSplit : 100 - partnerRaw
759
768
  };
760
769
  }
761
- function calculateItemRewardByRule({ rule, itemTotal, quantity, maxAmount, allowedTotalCommissionTypes }) {
770
+ function calculateItemRewardByRule({ rule, itemTotal, quantity, allowedTotalCommissionTypes }) {
762
771
  const allowedTypes = allowedCommissionTypesSet(allowedTotalCommissionTypes);
763
772
  if (rule.totalCommission) {
764
773
  if (!allowedTypes.has(rule.totalCommission.type)) return null;
765
- const resolvedMaxAmount = typeof maxAmount === "number" && Number.isFinite(maxAmount) ? maxAmount : typeof rule.totalCommission.maxAmount === "number" && Number.isFinite(rule.totalCommission.maxAmount) ? rule.totalCommission.maxAmount : null;
774
+ const resolvedMaxAmount = typeof rule.totalCommission.maxAmount === "number" && Number.isFinite(rule.totalCommission.maxAmount) ? rule.totalCommission.maxAmount : null;
766
775
  if (rule.totalCommission.type === "fixed" && rule.totalCommission.value == null) {
767
776
  const partnerAmtPerUnit = typeof rule.partnerSplit === "number" ? rule.partnerSplit : null;
768
777
  const customerAmtPerUnit = typeof rule.customerSplit === "number" ? rule.customerSplit : null;
@@ -821,7 +830,7 @@ function getItemCategoryIds(item) {
821
830
  function getItemTagIds(item) {
822
831
  return Array.isArray(item?.product?.tags) ? normalizeIds(item.product.tags) : [];
823
832
  }
824
- function selectBestRuleForItem({ rules, item, itemTotal, quantity, cartTotal, minOrderAmount, maxAmount, allowedTotalCommissionTypes }) {
833
+ function selectBestRuleForItem({ rules, item, itemTotal, quantity, cartTotal, minOrderAmount, allowedTotalCommissionTypes }) {
825
834
  const allowedTypes = allowedCommissionTypesSet(allowedTotalCommissionTypes);
826
835
  const eligibleRules = rules.filter((rule) => {
827
836
  if (!(rule?.totalCommission?.type ? allowedTypes.has(rule.totalCommission.type) : true)) return false;
@@ -851,7 +860,6 @@ function selectBestRuleForItem({ rules, item, itemTotal, quantity, cartTotal, mi
851
860
  rule,
852
861
  itemTotal,
853
862
  quantity,
854
- maxAmount,
855
863
  allowedTotalCommissionTypes
856
864
  });
857
865
  if (!reward) continue;
@@ -916,13 +924,16 @@ function calculateCommissionAndDiscount({ cartItems, program, currencyCode = "AE
916
924
  quantity,
917
925
  cartTotal,
918
926
  minOrderAmount: typeof program?.minOrderAmount === "number" && Number.isFinite(program.minOrderAmount) ? program.minOrderAmount : null,
919
- maxAmount: typeof program?.maxAmount === "number" && Number.isFinite(program.maxAmount) ? program.maxAmount : null,
920
927
  allowedTotalCommissionTypes
921
928
  });
922
929
  if (!bestMatch) continue;
923
930
  totalPartnerCommission += bestMatch.reward.partner;
924
931
  totalCustomerDiscount += bestMatch.reward.customer;
925
932
  }
933
+ const maxPartnerCommissionPerOrder = typeof program?.maxPartnerCommissionPerOrder === "number" && Number.isFinite(program.maxPartnerCommissionPerOrder) ? program.maxPartnerCommissionPerOrder : null;
934
+ const maxCustomerDiscountPerOrder = typeof program?.maxCustomerDiscountPerOrder === "number" && Number.isFinite(program.maxCustomerDiscountPerOrder) ? program.maxCustomerDiscountPerOrder : null;
935
+ if (maxPartnerCommissionPerOrder != null) totalPartnerCommission = Math.min(totalPartnerCommission, maxPartnerCommissionPerOrder);
936
+ if (maxCustomerDiscountPerOrder != null) totalCustomerDiscount = Math.min(totalCustomerDiscount, maxCustomerDiscountPerOrder);
926
937
  return {
927
938
  partnerCommission: totalPartnerCommission,
928
939
  customerDiscount: totalCustomerDiscount
@@ -946,6 +957,22 @@ function writeField$1(doc, field, value) {
946
957
  function normalizeCode$1(value) {
947
958
  return typeof value === "string" ? value.trim().toUpperCase() : "";
948
959
  }
960
+ async function ensureRequestData$1(req) {
961
+ if (req?.data && typeof req.data === "object") return req.data;
962
+ try {
963
+ await addDataAndFileToRequest(req);
964
+ } catch {}
965
+ if (req?.data && typeof req.data === "object") return req.data;
966
+ try {
967
+ const parsed = await req?.json?.();
968
+ if (parsed && typeof parsed === "object") {
969
+ req.data = parsed;
970
+ return parsed;
971
+ }
972
+ } catch {}
973
+ req.data = {};
974
+ return req.data;
975
+ }
949
976
  async function findByNormalizedCode$1({ payload, collection, normalizedCode }) {
950
977
  const exactQuery = await payload.find({
951
978
  collection,
@@ -975,9 +1002,11 @@ const applyCouponHandler = ({ pluginConfig }) => async (req) => {
975
1002
  const { payload } = req;
976
1003
  const fields = pluginConfig.integration.fields;
977
1004
  const collections = pluginConfig.integration.collections;
978
- const rawCode = req?.data?.code;
979
- const cartID = req?.data?.cartID;
980
- const customerEmail = req?.data?.customerEmail;
1005
+ const data = await ensureRequestData$1(req);
1006
+ const rawCode = data?.code;
1007
+ const cartIDRaw = data?.cartID;
1008
+ const cartID = typeof cartIDRaw === "string" || typeof cartIDRaw === "number" ? cartIDRaw : null;
1009
+ const customerEmail = typeof data?.customerEmail === "string" ? data.customerEmail : void 0;
981
1010
  const normalizedCode = normalizeCode$1(rawCode);
982
1011
  if (!normalizedCode || !cartID) return Response.json({
983
1012
  success: false,
@@ -1406,6 +1435,22 @@ function relationId$2(value) {
1406
1435
  function normalizeCode(value) {
1407
1436
  return typeof value === "string" ? value.trim().toUpperCase() : "";
1408
1437
  }
1438
+ async function ensureRequestData(req) {
1439
+ if (req?.data && typeof req.data === "object") return req.data;
1440
+ try {
1441
+ await addDataAndFileToRequest(req);
1442
+ } catch {}
1443
+ if (req?.data && typeof req.data === "object") return req.data;
1444
+ try {
1445
+ const parsed = await req?.json?.();
1446
+ if (parsed && typeof parsed === "object") {
1447
+ req.data = parsed;
1448
+ return parsed;
1449
+ }
1450
+ } catch {}
1451
+ req.data = {};
1452
+ return req.data;
1453
+ }
1409
1454
  async function findByNormalizedCode({ payload, collection, normalizedCode }) {
1410
1455
  const normalizedQuery = await payload.find({
1411
1456
  collection,
@@ -1433,10 +1478,12 @@ async function findByNormalizedCode({ payload, collection, normalizedCode }) {
1433
1478
  }
1434
1479
  const validateCouponHandler = ({ pluginConfig }) => async (req) => {
1435
1480
  const { payload } = req;
1436
- const rawCode = req?.data?.code;
1437
- const cartValue = req?.data?.cartValue;
1438
- const cartID = req?.data?.cartID;
1439
- const customerEmail = req?.data?.customerEmail;
1481
+ const data = await ensureRequestData(req);
1482
+ const rawCode = data?.code;
1483
+ const cartValue = typeof data?.cartValue === "number" ? data.cartValue : void 0;
1484
+ const cartIDRaw = data?.cartID;
1485
+ const cartID = typeof cartIDRaw === "string" || typeof cartIDRaw === "number" ? cartIDRaw : void 0;
1486
+ const customerEmail = typeof data?.customerEmail === "string" ? data.customerEmail : void 0;
1440
1487
  const normalizedCode = normalizeCode(rawCode);
1441
1488
  if (!normalizedCode) return Response.json({
1442
1489
  success: false,
@@ -2131,6 +2178,55 @@ const sanitizePluginConfig = ({ pluginConfig }) => {
2131
2178
  const RECALCULATE_HOOK_KEY = "__payloadEcommerceCouponRecalculateHook__";
2132
2179
  const asArray = (value) => Array.isArray(value) ? value : [];
2133
2180
  const hasNamedField = (collection, fieldName) => asArray(collection.fields).some((f) => f?.name === fieldName);
2181
+ const normalizePath$1 = (path) => {
2182
+ if (!path) return "/";
2183
+ return (path.startsWith("/") ? path : `/${path}`).replace(/\/+$/, "") || "/";
2184
+ };
2185
+ const toCollectionEndpointPath = ({ endpointPath, collectionSlug }) => {
2186
+ const normalizedEndpointPath = normalizePath$1(endpointPath);
2187
+ const normalizedCollectionPath = normalizePath$1(`/${collectionSlug}`);
2188
+ if (!normalizedEndpointPath.startsWith(`${normalizedCollectionPath}/`)) return null;
2189
+ const relative = normalizedEndpointPath.slice(normalizedCollectionPath.length);
2190
+ return relative.startsWith("/") ? relative : `/${relative}`;
2191
+ };
2192
+ const ensureCouponCollectionEndpoints = ({ collection, pluginConfig }) => {
2193
+ const couponsSlug = pluginConfig.collections.couponsSlug;
2194
+ const applyPath = toCollectionEndpointPath({
2195
+ endpointPath: pluginConfig.endpoints.applyCoupon,
2196
+ collectionSlug: couponsSlug
2197
+ });
2198
+ const validatePath = toCollectionEndpointPath({
2199
+ endpointPath: pluginConfig.endpoints.validateCoupon,
2200
+ collectionSlug: couponsSlug
2201
+ });
2202
+ if (!applyPath && !validatePath) return collection;
2203
+ const endpoints = asArray(collection.endpoints);
2204
+ const endpointKeys = new Set(endpoints.map((e) => `${(e?.method || "get").toLowerCase()}:${e?.path || ""}`));
2205
+ if (validatePath) {
2206
+ const validateKey = `post:${validatePath}`;
2207
+ if (!endpointKeys.has(validateKey)) {
2208
+ endpointKeys.add(validateKey);
2209
+ endpoints.push({
2210
+ path: validatePath,
2211
+ method: "post",
2212
+ handler: validateCouponEndpoint({ pluginConfig }).handler
2213
+ });
2214
+ }
2215
+ }
2216
+ if (applyPath) {
2217
+ const applyKey = `post:${applyPath}`;
2218
+ if (!endpointKeys.has(applyKey)) {
2219
+ endpointKeys.add(applyKey);
2220
+ endpoints.push({
2221
+ path: applyPath,
2222
+ method: "post",
2223
+ handler: applyCouponEndpoint({ pluginConfig }).handler
2224
+ });
2225
+ }
2226
+ }
2227
+ collection.endpoints = endpoints;
2228
+ return collection;
2229
+ };
2134
2230
  const addFieldsToCollection = (config, targetSlug, newFields) => {
2135
2231
  const collections = asArray(config.collections);
2136
2232
  const idx = collections.findIndex((c) => c.slug === targetSlug);
@@ -2215,11 +2311,19 @@ const payloadEcommerceCouponPlugin = (pluginOptions = {}) => async (incomingConf
2215
2311
  if (pluginConfig.referralConfig.allowBothSystems) {
2216
2312
  let couponsCollection = createCouponsCollection(pluginConfig);
2217
2313
  if (pluginOptions.collections?.couponsCollectionOverride) couponsCollection = await pluginOptions.collections.couponsCollectionOverride({ defaultCollection: couponsCollection });
2314
+ couponsCollection = ensureCouponCollectionEndpoints({
2315
+ collection: couponsCollection,
2316
+ pluginConfig
2317
+ });
2218
2318
  collectionsToAdd.push(couponsCollection);
2219
2319
  }
2220
2320
  } else {
2221
2321
  let couponsCollection = createCouponsCollection(pluginConfig);
2222
2322
  if (pluginOptions.collections?.couponsCollectionOverride) couponsCollection = await pluginOptions.collections.couponsCollectionOverride({ defaultCollection: couponsCollection });
2323
+ couponsCollection = ensureCouponCollectionEndpoints({
2324
+ collection: couponsCollection,
2325
+ pluginConfig
2326
+ });
2223
2327
  collectionsToAdd.push(couponsCollection);
2224
2328
  }
2225
2329
  const existingSlugs = new Set(asArray(incomingConfig.collections).map((c) => c.slug));