@timardex/cluemart-server-shared 1.0.281 → 1.0.287

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.cjs CHANGED
@@ -30,6 +30,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ ACTIVE_NOT_DELETED_FILTER: () => ACTIVE_NOT_DELETED_FILTER,
34
+ AFFILIATE_REWARDS: () => AFFILIATE_REWARDS,
33
35
  APP_SETTINGS_ID: () => APP_SETTINGS_ID,
34
36
  AdModel: () => AdModel,
35
37
  AffiliateModel: () => AffiliateModel,
@@ -60,17 +62,25 @@ __export(index_exports, {
60
62
  VendorInfoModel: () => VendorInfoModel,
61
63
  VendorModel: () => VendorModel,
62
64
  VerificationTokenModel: () => VerificationTokenModel,
65
+ activeAffiliateCodeExists: () => activeAffiliateCodeExists,
63
66
  associatesSchema: () => associatesSchema,
67
+ awardAffiliateVendorSubscriptionRewards: () => awardAffiliateVendorSubscriptionRewards,
64
68
  baseResourceFields: () => baseResourceFields,
65
69
  connectToDatabase: () => connectToDatabase,
66
70
  convertObjectIdsToStrings: () => convertObjectIdsToStrings,
71
+ createAffiliateReward: () => createAffiliateReward,
67
72
  dateTimeSchema: () => dateTimeSchema2,
68
73
  didRemoveAnyEventDates: () => didRemoveAnyEventDates,
69
74
  express: () => import_express.default,
75
+ findAffiliateByPromoCode: () => findAffiliateByPromoCode,
70
76
  findEventOrImportedMarketById: () => findEventOrImportedMarketById,
77
+ getSubscriptionRewardPeriodBounds: () => getSubscriptionRewardPeriodBounds,
71
78
  locationGeoSchema: () => locationGeoSchema,
72
79
  locationsSchema: () => locationsSchema,
73
- mongoose: () => import_mongoose34.default,
80
+ mapVendorLicenceToSubscriptionRewardType: () => mapVendorLicenceToSubscriptionRewardType,
81
+ mongoose: () => import_mongoose37.default,
82
+ normalizeAffiliatePromoCodes: () => normalizeAffiliatePromoCodes,
83
+ normalizePromoCode: () => normalizePromoCode,
74
84
  refundPolicySchema: () => refundPolicySchema,
75
85
  relatedPostSchema: () => relatedPostSchema,
76
86
  relationDatesSchema: () => relationDatesSchema,
@@ -3698,14 +3708,14 @@ var EnumGameType = /* @__PURE__ */ ((EnumGameType2) => {
3698
3708
  EnumGameType2["ODD_ONE_OUT"] = "oddOneOut";
3699
3709
  return EnumGameType2;
3700
3710
  })(EnumGameType || {});
3701
- var EnumAffiliateRewardType = /* @__PURE__ */ ((EnumAffiliateRewardType2) => {
3702
- EnumAffiliateRewardType2["ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS"] = "ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS";
3703
- EnumAffiliateRewardType2["ACTIVE_VENDOR_BONUS_REWARD"] = "ACTIVE_VENDOR_BONUS_REWARD";
3704
- EnumAffiliateRewardType2["ACTIVE_VENDOR_PRO_SUBSCRIPTION"] = "ACTIVE_VENDOR_PRO_SUBSCRIPTION";
3705
- EnumAffiliateRewardType2["ACTIVE_VENDOR_STANDARD_SUBSCRIPTION"] = "ACTIVE_VENDOR_STANDARD_SUBSCRIPTION";
3706
- EnumAffiliateRewardType2["NEW_EVENT_REGISTRATION"] = "NEW_EVENT_REGISTRATION";
3707
- EnumAffiliateRewardType2["NEW_VENDOR_REGISTRATION"] = "NEW_VENDOR_REGISTRATION";
3708
- return EnumAffiliateRewardType2;
3711
+ var EnumAffiliateRewardType = /* @__PURE__ */ ((EnumAffiliateRewardType22) => {
3712
+ EnumAffiliateRewardType22["ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS"] = "ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS";
3713
+ EnumAffiliateRewardType22["ACTIVE_VENDOR_BONUS_REWARD"] = "ACTIVE_VENDOR_BONUS_REWARD";
3714
+ EnumAffiliateRewardType22["ACTIVE_VENDOR_PRO_SUBSCRIPTION"] = "ACTIVE_VENDOR_PRO_SUBSCRIPTION";
3715
+ EnumAffiliateRewardType22["ACTIVE_VENDOR_STANDARD_SUBSCRIPTION"] = "ACTIVE_VENDOR_STANDARD_SUBSCRIPTION";
3716
+ EnumAffiliateRewardType22["NEW_EVENT_REGISTRATION"] = "NEW_EVENT_REGISTRATION";
3717
+ EnumAffiliateRewardType22["NEW_VENDOR_REGISTRATION"] = "NEW_VENDOR_REGISTRATION";
3718
+ return EnumAffiliateRewardType22;
3709
3719
  })(EnumAffiliateRewardType || {});
3710
3720
  var statusOptions = [
3711
3721
  ...Object.values(EnumInviteStatus).map((status) => ({
@@ -7510,6 +7520,7 @@ var AFFILIATE_REWARD_FIELDS_FRAGMENT = gql`
7510
7520
  var AFFILIATE_RESOURCE_FIELDS_FRAGMENT = gql`
7511
7521
  fragment AffiliateResourceFields on AffiliateResourceType {
7512
7522
  resourceActive
7523
+ resourceDeletedAt
7513
7524
  resourceId
7514
7525
  resourceName
7515
7526
  resourceType
@@ -9303,6 +9314,7 @@ var affiliateRewardSchema = new MongooseSchema25(
9303
9314
  var affiliateResourceSchema = new MongooseSchema25(
9304
9315
  {
9305
9316
  resourceActive: { default: true, required: true, type: Boolean },
9317
+ resourceDeletedAt: { default: null, required: false, type: Date },
9306
9318
  resourceId: {
9307
9319
  required: true,
9308
9320
  type: import_mongoose25.default.Schema.Types.ObjectId
@@ -9386,31 +9398,27 @@ schema17.index(
9386
9398
  );
9387
9399
  var AffiliateModel = import_mongoose25.default.models.Affiliate || import_mongoose25.default.model("Affiliate", schema17);
9388
9400
 
9389
- // src/service/database.ts
9390
- var import_mongoose26 = __toESM(require("mongoose"));
9391
- var connectToDatabase = async ({
9392
- appName,
9393
- dbName,
9394
- dbPassword,
9395
- dbUser,
9396
- mongodbUri
9397
- }) => {
9398
- try {
9399
- const mongoUri = mongodbUri ? mongodbUri : (
9400
- // Fallback to MongoDB Atlas connection string
9401
- `mongodb+srv://${dbUser}:${dbPassword}@${dbName}.mongodb.net/?retryWrites=true&w=majority&appName=${appName}`
9402
- );
9403
- await import_mongoose26.default.connect(mongoUri);
9404
- const connectionType = mongodbUri ? "Local MongoDB" : "MongoDB Atlas";
9405
- console.log(
9406
- `${connectionType} connected from server/src/service/database.ts`
9407
- );
9408
- } catch (err) {
9409
- console.error("Error connecting to MongoDB:", err);
9410
- throw err;
9411
- }
9401
+ // src/service/promoCode/constants.ts
9402
+ var ACTIVE_NOT_DELETED_FILTER = {
9403
+ active: true,
9404
+ deletedAt: null
9412
9405
  };
9413
9406
 
9407
+ // src/service/affiliate/activeAffiliateCodeExists.ts
9408
+ async function activeAffiliateCodeExists(affiliateCode) {
9409
+ const existing = await AffiliateModel.exists({
9410
+ ...ACTIVE_NOT_DELETED_FILTER,
9411
+ affiliateCode
9412
+ }).exec();
9413
+ return existing !== null;
9414
+ }
9415
+
9416
+ // src/service/promoCode/normalizePromoCode.ts
9417
+ function normalizePromoCode(decoratedPromoCode) {
9418
+ const normalized = decoratedPromoCode?.trim().toUpperCase();
9419
+ return normalized || null;
9420
+ }
9421
+
9414
9422
  // src/service/saveNotificationsInDb.ts
9415
9423
  async function saveNotificationsInDb(payload) {
9416
9424
  const { data, message, title, type, userIds } = payload;
@@ -9544,6 +9552,285 @@ async function sendPushNotifications({
9544
9552
  }
9545
9553
  }
9546
9554
 
9555
+ // src/service/affiliate/createAffiliateReward.ts
9556
+ var AFFILIATE_REWARDS = {
9557
+ [EnumAffiliateRewardType.NEW_EVENT_REGISTRATION]: {
9558
+ description: "10 points for new event registration (one-time reward)",
9559
+ value: 10
9560
+ },
9561
+ [EnumAffiliateRewardType.NEW_VENDOR_REGISTRATION]: {
9562
+ description: "5 points for new vendor registration (one-time reward)",
9563
+ value: 5
9564
+ },
9565
+ [EnumAffiliateRewardType.ACTIVE_VENDOR_PRO_SUBSCRIPTION]: {
9566
+ description: "3 points for active vendor pro subscription (monthly reward)",
9567
+ value: 3
9568
+ },
9569
+ [EnumAffiliateRewardType.ACTIVE_VENDOR_STANDARD_SUBSCRIPTION]: {
9570
+ description: "1 point for active vendor standard subscription (monthly reward)",
9571
+ value: 1
9572
+ },
9573
+ [EnumAffiliateRewardType.ACTIVE_VENDOR_BONUS_REWARD]: {
9574
+ description: "5 bonus points for every 10th active vendor (one-time reward)",
9575
+ value: 5
9576
+ },
9577
+ [EnumAffiliateRewardType.ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS]: {
9578
+ description: "50 points for active event with vendor registrations (one-time reward)",
9579
+ value: 50
9580
+ }
9581
+ };
9582
+ function createAffiliateReward(rewardType, createdAt) {
9583
+ const reward = AFFILIATE_REWARDS[rewardType];
9584
+ return {
9585
+ createdAt,
9586
+ redeemedAt: null,
9587
+ rewardDescription: reward.description,
9588
+ rewardType,
9589
+ rewardValue: reward.value
9590
+ };
9591
+ }
9592
+
9593
+ // src/service/affiliate/vendorSubscriptionRewards.ts
9594
+ function mapVendorLicenceToSubscriptionRewardType(licences, now = /* @__PURE__ */ new Date()) {
9595
+ const validTypes = new Set(
9596
+ (licences ?? []).filter(
9597
+ (licence) => new Date(licence.expiryDate).getTime() > now.getTime()
9598
+ ).map((licence) => licence.licenceType)
9599
+ );
9600
+ if (validTypes.has(EnumUserLicence.PRO_VENDOR) || validTypes.has(EnumUserLicence.PRO_PLUS_VENDOR)) {
9601
+ return EnumAffiliateRewardType.ACTIVE_VENDOR_PRO_SUBSCRIPTION;
9602
+ }
9603
+ if (validTypes.has(EnumUserLicence.STANDARD_VENDOR)) {
9604
+ return EnumAffiliateRewardType.ACTIVE_VENDOR_STANDARD_SUBSCRIPTION;
9605
+ }
9606
+ return null;
9607
+ }
9608
+ function getSubscriptionRewardPeriodBounds(now = /* @__PURE__ */ new Date()) {
9609
+ const periodStart = new Date(
9610
+ Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1)
9611
+ );
9612
+ const periodEnd = new Date(
9613
+ Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1)
9614
+ );
9615
+ return { periodEnd, periodStart };
9616
+ }
9617
+
9618
+ // src/service/affiliate/awardAffiliateVendorSubscriptionRewards.ts
9619
+ function isEligibleVendorResource(resource) {
9620
+ return resource.resourceType === EnumResourceType.VENDOR && resource.resourceActive === true && resource.resourceDeletedAt == null;
9621
+ }
9622
+ async function findAffiliatesWithActiveVendorReferrals() {
9623
+ return await AffiliateModel.find({
9624
+ affiliateResources: {
9625
+ $elemMatch: {
9626
+ resourceActive: true,
9627
+ resourceDeletedAt: null,
9628
+ resourceType: EnumResourceType.VENDOR
9629
+ }
9630
+ },
9631
+ deletedAt: null
9632
+ }).select("_id affiliateCode affiliateResources owner").lean().exec();
9633
+ }
9634
+ async function findEligibleReferredVendor(resourceId, affiliateCode) {
9635
+ return await VendorModel.findOne({
9636
+ _id: resourceId,
9637
+ active: true,
9638
+ deletedAt: null,
9639
+ promoCodes: affiliateCode
9640
+ }).select("_id name owner.userId").lean().exec();
9641
+ }
9642
+ async function resolveSubscriptionRewardTypeForVendorOwner(vendorOwnerUserId, now) {
9643
+ const vendorOwner = await UserModel.findById(vendorOwnerUserId).select("licences").lean().exec();
9644
+ return mapVendorLicenceToSubscriptionRewardType(vendorOwner?.licences, now);
9645
+ }
9646
+ async function notifyAffiliateOwnerOfSubscriptionReward({
9647
+ affiliateId,
9648
+ affiliateOwnerUserId,
9649
+ resourceName,
9650
+ rewardValue
9651
+ }) {
9652
+ const payload = {
9653
+ data: {
9654
+ resourceId: String(affiliateId),
9655
+ resourceName,
9656
+ resourceType: EnumNotificationResourceType.AFFILIATE_REWARD_RECEIVED
9657
+ },
9658
+ message: `You earned ${rewardValue} points! Your referred vendor "${resourceName}" has an active subscription.`,
9659
+ title: "Affiliate points earned",
9660
+ type: EnumNotificationType.SYSTEM,
9661
+ userIds: [affiliateOwnerUserId]
9662
+ };
9663
+ try {
9664
+ await saveNotificationsInDb(payload);
9665
+ await sendPushNotifications(payload);
9666
+ } catch (error) {
9667
+ console.error(
9668
+ `[affiliate] subscription reward notification failed for affiliate ${String(affiliateId)}:`,
9669
+ error instanceof Error ? error.message : error
9670
+ );
9671
+ }
9672
+ }
9673
+ async function tryAwardSubscriptionReward({
9674
+ affiliate,
9675
+ createdAt,
9676
+ period,
9677
+ resource,
9678
+ rewardType,
9679
+ vendor
9680
+ }) {
9681
+ const reward = createAffiliateReward(rewardType, createdAt);
9682
+ const updateResult = await AffiliateModel.updateOne(
9683
+ {
9684
+ _id: affiliate._id,
9685
+ affiliateResources: {
9686
+ $elemMatch: {
9687
+ resourceActive: true,
9688
+ resourceDeletedAt: null,
9689
+ resourceId: vendor._id,
9690
+ resourceType: EnumResourceType.VENDOR,
9691
+ rewards: {
9692
+ $not: {
9693
+ $elemMatch: {
9694
+ createdAt: {
9695
+ $gte: period.periodStart,
9696
+ $lt: period.periodEnd
9697
+ },
9698
+ rewardType
9699
+ }
9700
+ }
9701
+ }
9702
+ }
9703
+ },
9704
+ deletedAt: null
9705
+ },
9706
+ {
9707
+ $inc: { overallPoints: reward.rewardValue },
9708
+ $push: { "affiliateResources.$.rewards": reward }
9709
+ }
9710
+ ).exec();
9711
+ if (updateResult.modifiedCount === 0) {
9712
+ return "skipped";
9713
+ }
9714
+ const affiliateOwnerUserId = affiliate.owner?.userId;
9715
+ if (affiliateOwnerUserId) {
9716
+ await notifyAffiliateOwnerOfSubscriptionReward({
9717
+ affiliateId: affiliate._id,
9718
+ affiliateOwnerUserId,
9719
+ resourceName: resource.resourceName || vendor.name || "vendor",
9720
+ rewardValue: reward.rewardValue
9721
+ });
9722
+ }
9723
+ return "awarded";
9724
+ }
9725
+ async function processAffiliateVendorReferral({
9726
+ affiliate,
9727
+ affiliateCode,
9728
+ createdAt,
9729
+ now,
9730
+ period,
9731
+ resource
9732
+ }) {
9733
+ const vendor = await findEligibleReferredVendor(
9734
+ resource.resourceId,
9735
+ affiliateCode
9736
+ );
9737
+ if (!vendor?.owner?.userId) {
9738
+ return "skipped";
9739
+ }
9740
+ const rewardType = await resolveSubscriptionRewardTypeForVendorOwner(
9741
+ vendor.owner.userId,
9742
+ now
9743
+ );
9744
+ if (!rewardType) {
9745
+ return "skipped";
9746
+ }
9747
+ return tryAwardSubscriptionReward({
9748
+ affiliate,
9749
+ createdAt,
9750
+ period,
9751
+ resource,
9752
+ rewardType,
9753
+ vendor
9754
+ });
9755
+ }
9756
+ async function awardAffiliateVendorSubscriptionRewards(now = /* @__PURE__ */ new Date()) {
9757
+ const period = getSubscriptionRewardPeriodBounds(now);
9758
+ const createdAt = now;
9759
+ const affiliates = await findAffiliatesWithActiveVendorReferrals();
9760
+ let awarded = 0;
9761
+ let skipped = 0;
9762
+ const seenPairs = /* @__PURE__ */ new Set();
9763
+ for (const affiliate of affiliates) {
9764
+ const affiliateCode = normalizePromoCode(affiliate.affiliateCode);
9765
+ if (!affiliateCode) {
9766
+ continue;
9767
+ }
9768
+ for (const resource of affiliate.affiliateResources) {
9769
+ if (!isEligibleVendorResource(resource)) {
9770
+ continue;
9771
+ }
9772
+ const pairKey = `${String(affiliate._id)}:${String(resource.resourceId)}`;
9773
+ if (seenPairs.has(pairKey)) {
9774
+ continue;
9775
+ }
9776
+ seenPairs.add(pairKey);
9777
+ const outcome = await processAffiliateVendorReferral({
9778
+ affiliate,
9779
+ affiliateCode,
9780
+ createdAt,
9781
+ now,
9782
+ period,
9783
+ resource
9784
+ });
9785
+ if (outcome === "awarded") {
9786
+ awarded += 1;
9787
+ } else {
9788
+ skipped += 1;
9789
+ }
9790
+ }
9791
+ }
9792
+ return { awarded, skipped };
9793
+ }
9794
+
9795
+ // src/service/affiliate/findAffiliateByPromoCode.ts
9796
+ async function findAffiliateByPromoCode(promoCode) {
9797
+ return AffiliateModel.findOne({
9798
+ affiliateCode: promoCode,
9799
+ deletedAt: null
9800
+ }).exec();
9801
+ }
9802
+
9803
+ // src/service/affiliate/normalizeAffiliatePromoCodes.ts
9804
+ function normalizeAffiliatePromoCodes(promoCodes) {
9805
+ const normalized = (promoCodes ?? []).map((code) => normalizePromoCode(code)).filter((code) => code !== null);
9806
+ return [...new Set(normalized)];
9807
+ }
9808
+
9809
+ // src/service/database.ts
9810
+ var import_mongoose29 = __toESM(require("mongoose"));
9811
+ var connectToDatabase = async ({
9812
+ appName,
9813
+ dbName,
9814
+ dbPassword,
9815
+ dbUser,
9816
+ mongodbUri
9817
+ }) => {
9818
+ try {
9819
+ const mongoUri = mongodbUri ? mongodbUri : (
9820
+ // Fallback to MongoDB Atlas connection string
9821
+ `mongodb+srv://${dbUser}:${dbPassword}@${dbName}.mongodb.net/?retryWrites=true&w=majority&appName=${appName}`
9822
+ );
9823
+ await import_mongoose29.default.connect(mongoUri);
9824
+ const connectionType = mongodbUri ? "Local MongoDB" : "MongoDB Atlas";
9825
+ console.log(
9826
+ `${connectionType} connected from server/src/service/database.ts`
9827
+ );
9828
+ } catch (err) {
9829
+ console.error("Error connecting to MongoDB:", err);
9830
+ throw err;
9831
+ }
9832
+ };
9833
+
9547
9834
  // src/service/updateAdStatus.ts
9548
9835
  async function updateAdStatuses() {
9549
9836
  const now = /* @__PURE__ */ new Date();
@@ -9580,9 +9867,9 @@ async function updateAdStatuses() {
9580
9867
  }
9581
9868
 
9582
9869
  // src/service/associate.ts
9583
- var import_mongoose28 = __toESM(require("mongoose"));
9870
+ var import_mongoose31 = __toESM(require("mongoose"));
9584
9871
  function normalizeObjectId(id) {
9585
- return typeof id === "string" ? new import_mongoose28.default.Types.ObjectId(id) : id;
9872
+ return typeof id === "string" ? new import_mongoose31.default.Types.ObjectId(id) : id;
9586
9873
  }
9587
9874
  async function getAssociateEmailsForResource({
9588
9875
  normalizedResourceId,
@@ -9734,12 +10021,12 @@ async function updateVendorBasedOnUserLicense(userId, licenceType) {
9734
10021
  }
9735
10022
 
9736
10023
  // src/service/objectIdToString.ts
9737
- var import_mongoose31 = __toESM(require("mongoose"));
10024
+ var import_mongoose34 = __toESM(require("mongoose"));
9738
10025
  function convertObjectIdsToStrings(obj) {
9739
10026
  if (obj === null || obj === void 0) {
9740
10027
  return obj;
9741
10028
  }
9742
- if (obj instanceof import_mongoose31.default.Types.ObjectId) {
10029
+ if (obj instanceof import_mongoose34.default.Types.ObjectId) {
9743
10030
  return obj.toString();
9744
10031
  }
9745
10032
  if (obj instanceof Date) {
@@ -9923,7 +10210,7 @@ function updateRelationDatesToUnavailable(relationDates, eventDateTime) {
9923
10210
 
9924
10211
  // src/types/index.ts
9925
10212
  var import_express = __toESM(require("express"));
9926
- var import_mongoose34 = __toESM(require("mongoose"));
10213
+ var import_mongoose37 = __toESM(require("mongoose"));
9927
10214
  var EnumPubSubEvents = /* @__PURE__ */ ((EnumPubSubEvents2) => {
9928
10215
  EnumPubSubEvents2["GET_CHAT_MESSAGE"] = "GET_CHAT_MESSAGE";
9929
10216
  EnumPubSubEvents2["GET_NOTIFICATIONS"] = "GET_NOTIFICATIONS";
@@ -9933,6 +10220,8 @@ var EnumPubSubEvents = /* @__PURE__ */ ((EnumPubSubEvents2) => {
9933
10220
  })(EnumPubSubEvents || {});
9934
10221
  // Annotate the CommonJS export names for ESM import in node:
9935
10222
  0 && (module.exports = {
10223
+ ACTIVE_NOT_DELETED_FILTER,
10224
+ AFFILIATE_REWARDS,
9936
10225
  APP_SETTINGS_ID,
9937
10226
  AdModel,
9938
10227
  AffiliateModel,
@@ -9963,17 +10252,25 @@ var EnumPubSubEvents = /* @__PURE__ */ ((EnumPubSubEvents2) => {
9963
10252
  VendorInfoModel,
9964
10253
  VendorModel,
9965
10254
  VerificationTokenModel,
10255
+ activeAffiliateCodeExists,
9966
10256
  associatesSchema,
10257
+ awardAffiliateVendorSubscriptionRewards,
9967
10258
  baseResourceFields,
9968
10259
  connectToDatabase,
9969
10260
  convertObjectIdsToStrings,
10261
+ createAffiliateReward,
9970
10262
  dateTimeSchema,
9971
10263
  didRemoveAnyEventDates,
9972
10264
  express,
10265
+ findAffiliateByPromoCode,
9973
10266
  findEventOrImportedMarketById,
10267
+ getSubscriptionRewardPeriodBounds,
9974
10268
  locationGeoSchema,
9975
10269
  locationsSchema,
10270
+ mapVendorLicenceToSubscriptionRewardType,
9976
10271
  mongoose,
10272
+ normalizeAffiliatePromoCodes,
10273
+ normalizePromoCode,
9977
10274
  refundPolicySchema,
9978
10275
  relatedPostSchema,
9979
10276
  relationDatesSchema,