@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.mjs CHANGED
@@ -3608,14 +3608,14 @@ var EnumGameType = /* @__PURE__ */ ((EnumGameType2) => {
3608
3608
  EnumGameType2["ODD_ONE_OUT"] = "oddOneOut";
3609
3609
  return EnumGameType2;
3610
3610
  })(EnumGameType || {});
3611
- var EnumAffiliateRewardType = /* @__PURE__ */ ((EnumAffiliateRewardType2) => {
3612
- EnumAffiliateRewardType2["ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS"] = "ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS";
3613
- EnumAffiliateRewardType2["ACTIVE_VENDOR_BONUS_REWARD"] = "ACTIVE_VENDOR_BONUS_REWARD";
3614
- EnumAffiliateRewardType2["ACTIVE_VENDOR_PRO_SUBSCRIPTION"] = "ACTIVE_VENDOR_PRO_SUBSCRIPTION";
3615
- EnumAffiliateRewardType2["ACTIVE_VENDOR_STANDARD_SUBSCRIPTION"] = "ACTIVE_VENDOR_STANDARD_SUBSCRIPTION";
3616
- EnumAffiliateRewardType2["NEW_EVENT_REGISTRATION"] = "NEW_EVENT_REGISTRATION";
3617
- EnumAffiliateRewardType2["NEW_VENDOR_REGISTRATION"] = "NEW_VENDOR_REGISTRATION";
3618
- return EnumAffiliateRewardType2;
3611
+ var EnumAffiliateRewardType = /* @__PURE__ */ ((EnumAffiliateRewardType22) => {
3612
+ EnumAffiliateRewardType22["ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS"] = "ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS";
3613
+ EnumAffiliateRewardType22["ACTIVE_VENDOR_BONUS_REWARD"] = "ACTIVE_VENDOR_BONUS_REWARD";
3614
+ EnumAffiliateRewardType22["ACTIVE_VENDOR_PRO_SUBSCRIPTION"] = "ACTIVE_VENDOR_PRO_SUBSCRIPTION";
3615
+ EnumAffiliateRewardType22["ACTIVE_VENDOR_STANDARD_SUBSCRIPTION"] = "ACTIVE_VENDOR_STANDARD_SUBSCRIPTION";
3616
+ EnumAffiliateRewardType22["NEW_EVENT_REGISTRATION"] = "NEW_EVENT_REGISTRATION";
3617
+ EnumAffiliateRewardType22["NEW_VENDOR_REGISTRATION"] = "NEW_VENDOR_REGISTRATION";
3618
+ return EnumAffiliateRewardType22;
3619
3619
  })(EnumAffiliateRewardType || {});
3620
3620
  var statusOptions = [
3621
3621
  ...Object.values(EnumInviteStatus).map((status) => ({
@@ -7420,6 +7420,7 @@ var AFFILIATE_REWARD_FIELDS_FRAGMENT = gql`
7420
7420
  var AFFILIATE_RESOURCE_FIELDS_FRAGMENT = gql`
7421
7421
  fragment AffiliateResourceFields on AffiliateResourceType {
7422
7422
  resourceActive
7423
+ resourceDeletedAt
7423
7424
  resourceId
7424
7425
  resourceName
7425
7426
  resourceType
@@ -9213,6 +9214,7 @@ var affiliateRewardSchema = new MongooseSchema25(
9213
9214
  var affiliateResourceSchema = new MongooseSchema25(
9214
9215
  {
9215
9216
  resourceActive: { default: true, required: true, type: Boolean },
9217
+ resourceDeletedAt: { default: null, required: false, type: Date },
9216
9218
  resourceId: {
9217
9219
  required: true,
9218
9220
  type: mongoose25.Schema.Types.ObjectId
@@ -9296,31 +9298,27 @@ schema17.index(
9296
9298
  );
9297
9299
  var AffiliateModel = mongoose25.models.Affiliate || mongoose25.model("Affiliate", schema17);
9298
9300
 
9299
- // src/service/database.ts
9300
- import mongoose26 from "mongoose";
9301
- var connectToDatabase = async ({
9302
- appName,
9303
- dbName,
9304
- dbPassword,
9305
- dbUser,
9306
- mongodbUri
9307
- }) => {
9308
- try {
9309
- const mongoUri = mongodbUri ? mongodbUri : (
9310
- // Fallback to MongoDB Atlas connection string
9311
- `mongodb+srv://${dbUser}:${dbPassword}@${dbName}.mongodb.net/?retryWrites=true&w=majority&appName=${appName}`
9312
- );
9313
- await mongoose26.connect(mongoUri);
9314
- const connectionType = mongodbUri ? "Local MongoDB" : "MongoDB Atlas";
9315
- console.log(
9316
- `${connectionType} connected from server/src/service/database.ts`
9317
- );
9318
- } catch (err) {
9319
- console.error("Error connecting to MongoDB:", err);
9320
- throw err;
9321
- }
9301
+ // src/service/promoCode/constants.ts
9302
+ var ACTIVE_NOT_DELETED_FILTER = {
9303
+ active: true,
9304
+ deletedAt: null
9322
9305
  };
9323
9306
 
9307
+ // src/service/affiliate/activeAffiliateCodeExists.ts
9308
+ async function activeAffiliateCodeExists(affiliateCode) {
9309
+ const existing = await AffiliateModel.exists({
9310
+ ...ACTIVE_NOT_DELETED_FILTER,
9311
+ affiliateCode
9312
+ }).exec();
9313
+ return existing !== null;
9314
+ }
9315
+
9316
+ // src/service/promoCode/normalizePromoCode.ts
9317
+ function normalizePromoCode(decoratedPromoCode) {
9318
+ const normalized = decoratedPromoCode?.trim().toUpperCase();
9319
+ return normalized || null;
9320
+ }
9321
+
9324
9322
  // src/service/saveNotificationsInDb.ts
9325
9323
  async function saveNotificationsInDb(payload) {
9326
9324
  const { data, message, title, type, userIds } = payload;
@@ -9454,6 +9452,285 @@ async function sendPushNotifications({
9454
9452
  }
9455
9453
  }
9456
9454
 
9455
+ // src/service/affiliate/createAffiliateReward.ts
9456
+ var AFFILIATE_REWARDS = {
9457
+ [EnumAffiliateRewardType.NEW_EVENT_REGISTRATION]: {
9458
+ description: "10 points for new event registration (one-time reward)",
9459
+ value: 10
9460
+ },
9461
+ [EnumAffiliateRewardType.NEW_VENDOR_REGISTRATION]: {
9462
+ description: "5 points for new vendor registration (one-time reward)",
9463
+ value: 5
9464
+ },
9465
+ [EnumAffiliateRewardType.ACTIVE_VENDOR_PRO_SUBSCRIPTION]: {
9466
+ description: "3 points for active vendor pro subscription (monthly reward)",
9467
+ value: 3
9468
+ },
9469
+ [EnumAffiliateRewardType.ACTIVE_VENDOR_STANDARD_SUBSCRIPTION]: {
9470
+ description: "1 point for active vendor standard subscription (monthly reward)",
9471
+ value: 1
9472
+ },
9473
+ [EnumAffiliateRewardType.ACTIVE_VENDOR_BONUS_REWARD]: {
9474
+ description: "5 bonus points for every 10th active vendor (one-time reward)",
9475
+ value: 5
9476
+ },
9477
+ [EnumAffiliateRewardType.ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS]: {
9478
+ description: "50 points for active event with vendor registrations (one-time reward)",
9479
+ value: 50
9480
+ }
9481
+ };
9482
+ function createAffiliateReward(rewardType, createdAt) {
9483
+ const reward = AFFILIATE_REWARDS[rewardType];
9484
+ return {
9485
+ createdAt,
9486
+ redeemedAt: null,
9487
+ rewardDescription: reward.description,
9488
+ rewardType,
9489
+ rewardValue: reward.value
9490
+ };
9491
+ }
9492
+
9493
+ // src/service/affiliate/vendorSubscriptionRewards.ts
9494
+ function mapVendorLicenceToSubscriptionRewardType(licences, now = /* @__PURE__ */ new Date()) {
9495
+ const validTypes = new Set(
9496
+ (licences ?? []).filter(
9497
+ (licence) => new Date(licence.expiryDate).getTime() > now.getTime()
9498
+ ).map((licence) => licence.licenceType)
9499
+ );
9500
+ if (validTypes.has(EnumUserLicence.PRO_VENDOR) || validTypes.has(EnumUserLicence.PRO_PLUS_VENDOR)) {
9501
+ return EnumAffiliateRewardType.ACTIVE_VENDOR_PRO_SUBSCRIPTION;
9502
+ }
9503
+ if (validTypes.has(EnumUserLicence.STANDARD_VENDOR)) {
9504
+ return EnumAffiliateRewardType.ACTIVE_VENDOR_STANDARD_SUBSCRIPTION;
9505
+ }
9506
+ return null;
9507
+ }
9508
+ function getSubscriptionRewardPeriodBounds(now = /* @__PURE__ */ new Date()) {
9509
+ const periodStart = new Date(
9510
+ Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1)
9511
+ );
9512
+ const periodEnd = new Date(
9513
+ Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1)
9514
+ );
9515
+ return { periodEnd, periodStart };
9516
+ }
9517
+
9518
+ // src/service/affiliate/awardAffiliateVendorSubscriptionRewards.ts
9519
+ function isEligibleVendorResource(resource) {
9520
+ return resource.resourceType === EnumResourceType.VENDOR && resource.resourceActive === true && resource.resourceDeletedAt == null;
9521
+ }
9522
+ async function findAffiliatesWithActiveVendorReferrals() {
9523
+ return await AffiliateModel.find({
9524
+ affiliateResources: {
9525
+ $elemMatch: {
9526
+ resourceActive: true,
9527
+ resourceDeletedAt: null,
9528
+ resourceType: EnumResourceType.VENDOR
9529
+ }
9530
+ },
9531
+ deletedAt: null
9532
+ }).select("_id affiliateCode affiliateResources owner").lean().exec();
9533
+ }
9534
+ async function findEligibleReferredVendor(resourceId, affiliateCode) {
9535
+ return await VendorModel.findOne({
9536
+ _id: resourceId,
9537
+ active: true,
9538
+ deletedAt: null,
9539
+ promoCodes: affiliateCode
9540
+ }).select("_id name owner.userId").lean().exec();
9541
+ }
9542
+ async function resolveSubscriptionRewardTypeForVendorOwner(vendorOwnerUserId, now) {
9543
+ const vendorOwner = await UserModel.findById(vendorOwnerUserId).select("licences").lean().exec();
9544
+ return mapVendorLicenceToSubscriptionRewardType(vendorOwner?.licences, now);
9545
+ }
9546
+ async function notifyAffiliateOwnerOfSubscriptionReward({
9547
+ affiliateId,
9548
+ affiliateOwnerUserId,
9549
+ resourceName,
9550
+ rewardValue
9551
+ }) {
9552
+ const payload = {
9553
+ data: {
9554
+ resourceId: String(affiliateId),
9555
+ resourceName,
9556
+ resourceType: EnumNotificationResourceType.AFFILIATE_REWARD_RECEIVED
9557
+ },
9558
+ message: `You earned ${rewardValue} points! Your referred vendor "${resourceName}" has an active subscription.`,
9559
+ title: "Affiliate points earned",
9560
+ type: EnumNotificationType.SYSTEM,
9561
+ userIds: [affiliateOwnerUserId]
9562
+ };
9563
+ try {
9564
+ await saveNotificationsInDb(payload);
9565
+ await sendPushNotifications(payload);
9566
+ } catch (error) {
9567
+ console.error(
9568
+ `[affiliate] subscription reward notification failed for affiliate ${String(affiliateId)}:`,
9569
+ error instanceof Error ? error.message : error
9570
+ );
9571
+ }
9572
+ }
9573
+ async function tryAwardSubscriptionReward({
9574
+ affiliate,
9575
+ createdAt,
9576
+ period,
9577
+ resource,
9578
+ rewardType,
9579
+ vendor
9580
+ }) {
9581
+ const reward = createAffiliateReward(rewardType, createdAt);
9582
+ const updateResult = await AffiliateModel.updateOne(
9583
+ {
9584
+ _id: affiliate._id,
9585
+ affiliateResources: {
9586
+ $elemMatch: {
9587
+ resourceActive: true,
9588
+ resourceDeletedAt: null,
9589
+ resourceId: vendor._id,
9590
+ resourceType: EnumResourceType.VENDOR,
9591
+ rewards: {
9592
+ $not: {
9593
+ $elemMatch: {
9594
+ createdAt: {
9595
+ $gte: period.periodStart,
9596
+ $lt: period.periodEnd
9597
+ },
9598
+ rewardType
9599
+ }
9600
+ }
9601
+ }
9602
+ }
9603
+ },
9604
+ deletedAt: null
9605
+ },
9606
+ {
9607
+ $inc: { overallPoints: reward.rewardValue },
9608
+ $push: { "affiliateResources.$.rewards": reward }
9609
+ }
9610
+ ).exec();
9611
+ if (updateResult.modifiedCount === 0) {
9612
+ return "skipped";
9613
+ }
9614
+ const affiliateOwnerUserId = affiliate.owner?.userId;
9615
+ if (affiliateOwnerUserId) {
9616
+ await notifyAffiliateOwnerOfSubscriptionReward({
9617
+ affiliateId: affiliate._id,
9618
+ affiliateOwnerUserId,
9619
+ resourceName: resource.resourceName || vendor.name || "vendor",
9620
+ rewardValue: reward.rewardValue
9621
+ });
9622
+ }
9623
+ return "awarded";
9624
+ }
9625
+ async function processAffiliateVendorReferral({
9626
+ affiliate,
9627
+ affiliateCode,
9628
+ createdAt,
9629
+ now,
9630
+ period,
9631
+ resource
9632
+ }) {
9633
+ const vendor = await findEligibleReferredVendor(
9634
+ resource.resourceId,
9635
+ affiliateCode
9636
+ );
9637
+ if (!vendor?.owner?.userId) {
9638
+ return "skipped";
9639
+ }
9640
+ const rewardType = await resolveSubscriptionRewardTypeForVendorOwner(
9641
+ vendor.owner.userId,
9642
+ now
9643
+ );
9644
+ if (!rewardType) {
9645
+ return "skipped";
9646
+ }
9647
+ return tryAwardSubscriptionReward({
9648
+ affiliate,
9649
+ createdAt,
9650
+ period,
9651
+ resource,
9652
+ rewardType,
9653
+ vendor
9654
+ });
9655
+ }
9656
+ async function awardAffiliateVendorSubscriptionRewards(now = /* @__PURE__ */ new Date()) {
9657
+ const period = getSubscriptionRewardPeriodBounds(now);
9658
+ const createdAt = now;
9659
+ const affiliates = await findAffiliatesWithActiveVendorReferrals();
9660
+ let awarded = 0;
9661
+ let skipped = 0;
9662
+ const seenPairs = /* @__PURE__ */ new Set();
9663
+ for (const affiliate of affiliates) {
9664
+ const affiliateCode = normalizePromoCode(affiliate.affiliateCode);
9665
+ if (!affiliateCode) {
9666
+ continue;
9667
+ }
9668
+ for (const resource of affiliate.affiliateResources) {
9669
+ if (!isEligibleVendorResource(resource)) {
9670
+ continue;
9671
+ }
9672
+ const pairKey = `${String(affiliate._id)}:${String(resource.resourceId)}`;
9673
+ if (seenPairs.has(pairKey)) {
9674
+ continue;
9675
+ }
9676
+ seenPairs.add(pairKey);
9677
+ const outcome = await processAffiliateVendorReferral({
9678
+ affiliate,
9679
+ affiliateCode,
9680
+ createdAt,
9681
+ now,
9682
+ period,
9683
+ resource
9684
+ });
9685
+ if (outcome === "awarded") {
9686
+ awarded += 1;
9687
+ } else {
9688
+ skipped += 1;
9689
+ }
9690
+ }
9691
+ }
9692
+ return { awarded, skipped };
9693
+ }
9694
+
9695
+ // src/service/affiliate/findAffiliateByPromoCode.ts
9696
+ async function findAffiliateByPromoCode(promoCode) {
9697
+ return AffiliateModel.findOne({
9698
+ affiliateCode: promoCode,
9699
+ deletedAt: null
9700
+ }).exec();
9701
+ }
9702
+
9703
+ // src/service/affiliate/normalizeAffiliatePromoCodes.ts
9704
+ function normalizeAffiliatePromoCodes(promoCodes) {
9705
+ const normalized = (promoCodes ?? []).map((code) => normalizePromoCode(code)).filter((code) => code !== null);
9706
+ return [...new Set(normalized)];
9707
+ }
9708
+
9709
+ // src/service/database.ts
9710
+ import mongoose26 from "mongoose";
9711
+ var connectToDatabase = async ({
9712
+ appName,
9713
+ dbName,
9714
+ dbPassword,
9715
+ dbUser,
9716
+ mongodbUri
9717
+ }) => {
9718
+ try {
9719
+ const mongoUri = mongodbUri ? mongodbUri : (
9720
+ // Fallback to MongoDB Atlas connection string
9721
+ `mongodb+srv://${dbUser}:${dbPassword}@${dbName}.mongodb.net/?retryWrites=true&w=majority&appName=${appName}`
9722
+ );
9723
+ await mongoose26.connect(mongoUri);
9724
+ const connectionType = mongodbUri ? "Local MongoDB" : "MongoDB Atlas";
9725
+ console.log(
9726
+ `${connectionType} connected from server/src/service/database.ts`
9727
+ );
9728
+ } catch (err) {
9729
+ console.error("Error connecting to MongoDB:", err);
9730
+ throw err;
9731
+ }
9732
+ };
9733
+
9457
9734
  // src/service/updateAdStatus.ts
9458
9735
  async function updateAdStatuses() {
9459
9736
  const now = /* @__PURE__ */ new Date();
@@ -9842,6 +10119,8 @@ var EnumPubSubEvents = /* @__PURE__ */ ((EnumPubSubEvents2) => {
9842
10119
  return EnumPubSubEvents2;
9843
10120
  })(EnumPubSubEvents || {});
9844
10121
  export {
10122
+ ACTIVE_NOT_DELETED_FILTER,
10123
+ AFFILIATE_REWARDS,
9845
10124
  APP_SETTINGS_ID,
9846
10125
  AdModel,
9847
10126
  AffiliateModel,
@@ -9872,17 +10151,25 @@ export {
9872
10151
  VendorInfoModel,
9873
10152
  VendorModel,
9874
10153
  VerificationTokenModel,
10154
+ activeAffiliateCodeExists,
9875
10155
  associatesSchema,
10156
+ awardAffiliateVendorSubscriptionRewards,
9876
10157
  baseResourceFields,
9877
10158
  connectToDatabase,
9878
10159
  convertObjectIdsToStrings,
10160
+ createAffiliateReward,
9879
10161
  dateTimeSchema2 as dateTimeSchema,
9880
10162
  didRemoveAnyEventDates,
9881
10163
  express,
10164
+ findAffiliateByPromoCode,
9882
10165
  findEventOrImportedMarketById,
10166
+ getSubscriptionRewardPeriodBounds,
9883
10167
  locationGeoSchema,
9884
10168
  locationsSchema,
10169
+ mapVendorLicenceToSubscriptionRewardType,
9885
10170
  mongoose29 as mongoose,
10171
+ normalizeAffiliatePromoCodes,
10172
+ normalizePromoCode,
9886
10173
  refundPolicySchema,
9887
10174
  relatedPostSchema,
9888
10175
  relationDatesSchema,