@timardex/cluemart-server-shared 1.0.284 → 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.
@@ -40,7 +40,7 @@ import {
40
40
  socialShareResourceSchema,
41
41
  termsAgreementSchema,
42
42
  userLicenseSchema
43
- } from "../chunk-4FWW5CDC.mjs";
43
+ } from "../chunk-6EDO734D.mjs";
44
44
  export {
45
45
  APP_SETTINGS_ID,
46
46
  AdModel,
@@ -33,12 +33,15 @@ __export(service_exports, {
33
33
  ACTIVE_NOT_DELETED_FILTER: () => ACTIVE_NOT_DELETED_FILTER,
34
34
  AFFILIATE_REWARDS: () => AFFILIATE_REWARDS,
35
35
  activeAffiliateCodeExists: () => activeAffiliateCodeExists,
36
+ awardAffiliateVendorSubscriptionRewards: () => awardAffiliateVendorSubscriptionRewards,
36
37
  connectToDatabase: () => connectToDatabase,
37
38
  convertObjectIdsToStrings: () => convertObjectIdsToStrings,
38
39
  createAffiliateReward: () => createAffiliateReward,
39
40
  didRemoveAnyEventDates: () => didRemoveAnyEventDates,
40
41
  findAffiliateByPromoCode: () => findAffiliateByPromoCode,
41
42
  findEventOrImportedMarketById: () => findEventOrImportedMarketById,
43
+ getSubscriptionRewardPeriodBounds: () => getSubscriptionRewardPeriodBounds,
44
+ mapVendorLicenceToSubscriptionRewardType: () => mapVendorLicenceToSubscriptionRewardType,
42
45
  normalizeAffiliatePromoCodes: () => normalizeAffiliatePromoCodes,
43
46
  normalizePromoCode: () => normalizePromoCode,
44
47
  saveNotificationsInDb: () => saveNotificationsInDb,
@@ -3661,14 +3664,14 @@ var EnumGameType = /* @__PURE__ */ ((EnumGameType2) => {
3661
3664
  EnumGameType2["ODD_ONE_OUT"] = "oddOneOut";
3662
3665
  return EnumGameType2;
3663
3666
  })(EnumGameType || {});
3664
- var EnumAffiliateRewardType = /* @__PURE__ */ ((EnumAffiliateRewardType2) => {
3665
- EnumAffiliateRewardType2["ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS"] = "ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS";
3666
- EnumAffiliateRewardType2["ACTIVE_VENDOR_BONUS_REWARD"] = "ACTIVE_VENDOR_BONUS_REWARD";
3667
- EnumAffiliateRewardType2["ACTIVE_VENDOR_PRO_SUBSCRIPTION"] = "ACTIVE_VENDOR_PRO_SUBSCRIPTION";
3668
- EnumAffiliateRewardType2["ACTIVE_VENDOR_STANDARD_SUBSCRIPTION"] = "ACTIVE_VENDOR_STANDARD_SUBSCRIPTION";
3669
- EnumAffiliateRewardType2["NEW_EVENT_REGISTRATION"] = "NEW_EVENT_REGISTRATION";
3670
- EnumAffiliateRewardType2["NEW_VENDOR_REGISTRATION"] = "NEW_VENDOR_REGISTRATION";
3671
- return EnumAffiliateRewardType2;
3667
+ var EnumAffiliateRewardType = /* @__PURE__ */ ((EnumAffiliateRewardType22) => {
3668
+ EnumAffiliateRewardType22["ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS"] = "ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS";
3669
+ EnumAffiliateRewardType22["ACTIVE_VENDOR_BONUS_REWARD"] = "ACTIVE_VENDOR_BONUS_REWARD";
3670
+ EnumAffiliateRewardType22["ACTIVE_VENDOR_PRO_SUBSCRIPTION"] = "ACTIVE_VENDOR_PRO_SUBSCRIPTION";
3671
+ EnumAffiliateRewardType22["ACTIVE_VENDOR_STANDARD_SUBSCRIPTION"] = "ACTIVE_VENDOR_STANDARD_SUBSCRIPTION";
3672
+ EnumAffiliateRewardType22["NEW_EVENT_REGISTRATION"] = "NEW_EVENT_REGISTRATION";
3673
+ EnumAffiliateRewardType22["NEW_VENDOR_REGISTRATION"] = "NEW_VENDOR_REGISTRATION";
3674
+ return EnumAffiliateRewardType22;
3672
3675
  })(EnumAffiliateRewardType || {});
3673
3676
  var statusOptions = [
3674
3677
  ...Object.values(EnumInviteStatus).map((status) => ({
@@ -9366,89 +9369,12 @@ async function activeAffiliateCodeExists(affiliateCode) {
9366
9369
  return existing !== null;
9367
9370
  }
9368
9371
 
9369
- // src/service/affiliate/createAffiliateReward.ts
9370
- var AFFILIATE_REWARDS = {
9371
- [EnumAffiliateRewardType.NEW_EVENT_REGISTRATION]: {
9372
- description: "10 points for new event registration (one-time reward)",
9373
- value: 10
9374
- },
9375
- [EnumAffiliateRewardType.NEW_VENDOR_REGISTRATION]: {
9376
- description: "5 points for new vendor registration (one-time reward)",
9377
- value: 5
9378
- },
9379
- [EnumAffiliateRewardType.ACTIVE_VENDOR_PRO_SUBSCRIPTION]: {
9380
- description: "3 points for active vendor pro subscription (monthly reward)",
9381
- value: 3
9382
- },
9383
- [EnumAffiliateRewardType.ACTIVE_VENDOR_STANDARD_SUBSCRIPTION]: {
9384
- description: "1 point for active vendor standard subscription (monthly reward)",
9385
- value: 1
9386
- },
9387
- [EnumAffiliateRewardType.ACTIVE_VENDOR_BONUS_REWARD]: {
9388
- description: "5 bonus points for every 10th active vendor (one-time reward)",
9389
- value: 5
9390
- },
9391
- [EnumAffiliateRewardType.ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS]: {
9392
- description: "50 points for active event with vendor registrations (one-time reward)",
9393
- value: 50
9394
- }
9395
- };
9396
- function createAffiliateReward(rewardType, createdAt) {
9397
- const reward = AFFILIATE_REWARDS[rewardType];
9398
- return {
9399
- createdAt,
9400
- redeemedAt: null,
9401
- rewardDescription: reward.description,
9402
- rewardType,
9403
- rewardValue: reward.value
9404
- };
9405
- }
9406
-
9407
- // src/service/affiliate/findAffiliateByPromoCode.ts
9408
- async function findAffiliateByPromoCode(promoCode) {
9409
- return AffiliateModel.findOne({
9410
- affiliateCode: promoCode,
9411
- deletedAt: null
9412
- }).exec();
9413
- }
9414
-
9415
9372
  // src/service/promoCode/normalizePromoCode.ts
9416
9373
  function normalizePromoCode(decoratedPromoCode) {
9417
9374
  const normalized = decoratedPromoCode?.trim().toUpperCase();
9418
9375
  return normalized || null;
9419
9376
  }
9420
9377
 
9421
- // src/service/affiliate/normalizeAffiliatePromoCodes.ts
9422
- function normalizeAffiliatePromoCodes(promoCodes) {
9423
- const normalized = (promoCodes ?? []).map((code) => normalizePromoCode(code)).filter((code) => code !== null);
9424
- return [...new Set(normalized)];
9425
- }
9426
-
9427
- // src/service/database.ts
9428
- var import_mongoose28 = __toESM(require("mongoose"));
9429
- var connectToDatabase = async ({
9430
- appName,
9431
- dbName,
9432
- dbPassword,
9433
- dbUser,
9434
- mongodbUri
9435
- }) => {
9436
- try {
9437
- const mongoUri = mongodbUri ? mongodbUri : (
9438
- // Fallback to MongoDB Atlas connection string
9439
- `mongodb+srv://${dbUser}:${dbPassword}@${dbName}.mongodb.net/?retryWrites=true&w=majority&appName=${appName}`
9440
- );
9441
- await import_mongoose28.default.connect(mongoUri);
9442
- const connectionType = mongodbUri ? "Local MongoDB" : "MongoDB Atlas";
9443
- console.log(
9444
- `${connectionType} connected from server/src/service/database.ts`
9445
- );
9446
- } catch (err) {
9447
- console.error("Error connecting to MongoDB:", err);
9448
- throw err;
9449
- }
9450
- };
9451
-
9452
9378
  // src/service/saveNotificationsInDb.ts
9453
9379
  async function saveNotificationsInDb(payload) {
9454
9380
  const { data, message, title, type, userIds } = payload;
@@ -9582,6 +9508,285 @@ async function sendPushNotifications({
9582
9508
  }
9583
9509
  }
9584
9510
 
9511
+ // src/service/affiliate/createAffiliateReward.ts
9512
+ var AFFILIATE_REWARDS = {
9513
+ [EnumAffiliateRewardType.NEW_EVENT_REGISTRATION]: {
9514
+ description: "10 points for new event registration (one-time reward)",
9515
+ value: 10
9516
+ },
9517
+ [EnumAffiliateRewardType.NEW_VENDOR_REGISTRATION]: {
9518
+ description: "5 points for new vendor registration (one-time reward)",
9519
+ value: 5
9520
+ },
9521
+ [EnumAffiliateRewardType.ACTIVE_VENDOR_PRO_SUBSCRIPTION]: {
9522
+ description: "3 points for active vendor pro subscription (monthly reward)",
9523
+ value: 3
9524
+ },
9525
+ [EnumAffiliateRewardType.ACTIVE_VENDOR_STANDARD_SUBSCRIPTION]: {
9526
+ description: "1 point for active vendor standard subscription (monthly reward)",
9527
+ value: 1
9528
+ },
9529
+ [EnumAffiliateRewardType.ACTIVE_VENDOR_BONUS_REWARD]: {
9530
+ description: "5 bonus points for every 10th active vendor (one-time reward)",
9531
+ value: 5
9532
+ },
9533
+ [EnumAffiliateRewardType.ACTIVE_EVENT_WITH_VENDOR_REGISTRATIONS]: {
9534
+ description: "50 points for active event with vendor registrations (one-time reward)",
9535
+ value: 50
9536
+ }
9537
+ };
9538
+ function createAffiliateReward(rewardType, createdAt) {
9539
+ const reward = AFFILIATE_REWARDS[rewardType];
9540
+ return {
9541
+ createdAt,
9542
+ redeemedAt: null,
9543
+ rewardDescription: reward.description,
9544
+ rewardType,
9545
+ rewardValue: reward.value
9546
+ };
9547
+ }
9548
+
9549
+ // src/service/affiliate/vendorSubscriptionRewards.ts
9550
+ function mapVendorLicenceToSubscriptionRewardType(licences, now = /* @__PURE__ */ new Date()) {
9551
+ const validTypes = new Set(
9552
+ (licences ?? []).filter(
9553
+ (licence) => new Date(licence.expiryDate).getTime() > now.getTime()
9554
+ ).map((licence) => licence.licenceType)
9555
+ );
9556
+ if (validTypes.has(EnumUserLicence.PRO_VENDOR) || validTypes.has(EnumUserLicence.PRO_PLUS_VENDOR)) {
9557
+ return EnumAffiliateRewardType.ACTIVE_VENDOR_PRO_SUBSCRIPTION;
9558
+ }
9559
+ if (validTypes.has(EnumUserLicence.STANDARD_VENDOR)) {
9560
+ return EnumAffiliateRewardType.ACTIVE_VENDOR_STANDARD_SUBSCRIPTION;
9561
+ }
9562
+ return null;
9563
+ }
9564
+ function getSubscriptionRewardPeriodBounds(now = /* @__PURE__ */ new Date()) {
9565
+ const periodStart = new Date(
9566
+ Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1)
9567
+ );
9568
+ const periodEnd = new Date(
9569
+ Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1)
9570
+ );
9571
+ return { periodEnd, periodStart };
9572
+ }
9573
+
9574
+ // src/service/affiliate/awardAffiliateVendorSubscriptionRewards.ts
9575
+ function isEligibleVendorResource(resource) {
9576
+ return resource.resourceType === EnumResourceType.VENDOR && resource.resourceActive === true && resource.resourceDeletedAt == null;
9577
+ }
9578
+ async function findAffiliatesWithActiveVendorReferrals() {
9579
+ return await AffiliateModel.find({
9580
+ affiliateResources: {
9581
+ $elemMatch: {
9582
+ resourceActive: true,
9583
+ resourceDeletedAt: null,
9584
+ resourceType: EnumResourceType.VENDOR
9585
+ }
9586
+ },
9587
+ deletedAt: null
9588
+ }).select("_id affiliateCode affiliateResources owner").lean().exec();
9589
+ }
9590
+ async function findEligibleReferredVendor(resourceId, affiliateCode) {
9591
+ return await VendorModel.findOne({
9592
+ _id: resourceId,
9593
+ active: true,
9594
+ deletedAt: null,
9595
+ promoCodes: affiliateCode
9596
+ }).select("_id name owner.userId").lean().exec();
9597
+ }
9598
+ async function resolveSubscriptionRewardTypeForVendorOwner(vendorOwnerUserId, now) {
9599
+ const vendorOwner = await UserModel.findById(vendorOwnerUserId).select("licences").lean().exec();
9600
+ return mapVendorLicenceToSubscriptionRewardType(vendorOwner?.licences, now);
9601
+ }
9602
+ async function notifyAffiliateOwnerOfSubscriptionReward({
9603
+ affiliateId,
9604
+ affiliateOwnerUserId,
9605
+ resourceName,
9606
+ rewardValue
9607
+ }) {
9608
+ const payload = {
9609
+ data: {
9610
+ resourceId: String(affiliateId),
9611
+ resourceName,
9612
+ resourceType: EnumNotificationResourceType.AFFILIATE_REWARD_RECEIVED
9613
+ },
9614
+ message: `You earned ${rewardValue} points! Your referred vendor "${resourceName}" has an active subscription.`,
9615
+ title: "Affiliate points earned",
9616
+ type: EnumNotificationType.SYSTEM,
9617
+ userIds: [affiliateOwnerUserId]
9618
+ };
9619
+ try {
9620
+ await saveNotificationsInDb(payload);
9621
+ await sendPushNotifications(payload);
9622
+ } catch (error) {
9623
+ console.error(
9624
+ `[affiliate] subscription reward notification failed for affiliate ${String(affiliateId)}:`,
9625
+ error instanceof Error ? error.message : error
9626
+ );
9627
+ }
9628
+ }
9629
+ async function tryAwardSubscriptionReward({
9630
+ affiliate,
9631
+ createdAt,
9632
+ period,
9633
+ resource,
9634
+ rewardType,
9635
+ vendor
9636
+ }) {
9637
+ const reward = createAffiliateReward(rewardType, createdAt);
9638
+ const updateResult = await AffiliateModel.updateOne(
9639
+ {
9640
+ _id: affiliate._id,
9641
+ affiliateResources: {
9642
+ $elemMatch: {
9643
+ resourceActive: true,
9644
+ resourceDeletedAt: null,
9645
+ resourceId: vendor._id,
9646
+ resourceType: EnumResourceType.VENDOR,
9647
+ rewards: {
9648
+ $not: {
9649
+ $elemMatch: {
9650
+ createdAt: {
9651
+ $gte: period.periodStart,
9652
+ $lt: period.periodEnd
9653
+ },
9654
+ rewardType
9655
+ }
9656
+ }
9657
+ }
9658
+ }
9659
+ },
9660
+ deletedAt: null
9661
+ },
9662
+ {
9663
+ $inc: { overallPoints: reward.rewardValue },
9664
+ $push: { "affiliateResources.$.rewards": reward }
9665
+ }
9666
+ ).exec();
9667
+ if (updateResult.modifiedCount === 0) {
9668
+ return "skipped";
9669
+ }
9670
+ const affiliateOwnerUserId = affiliate.owner?.userId;
9671
+ if (affiliateOwnerUserId) {
9672
+ await notifyAffiliateOwnerOfSubscriptionReward({
9673
+ affiliateId: affiliate._id,
9674
+ affiliateOwnerUserId,
9675
+ resourceName: resource.resourceName || vendor.name || "vendor",
9676
+ rewardValue: reward.rewardValue
9677
+ });
9678
+ }
9679
+ return "awarded";
9680
+ }
9681
+ async function processAffiliateVendorReferral({
9682
+ affiliate,
9683
+ affiliateCode,
9684
+ createdAt,
9685
+ now,
9686
+ period,
9687
+ resource
9688
+ }) {
9689
+ const vendor = await findEligibleReferredVendor(
9690
+ resource.resourceId,
9691
+ affiliateCode
9692
+ );
9693
+ if (!vendor?.owner?.userId) {
9694
+ return "skipped";
9695
+ }
9696
+ const rewardType = await resolveSubscriptionRewardTypeForVendorOwner(
9697
+ vendor.owner.userId,
9698
+ now
9699
+ );
9700
+ if (!rewardType) {
9701
+ return "skipped";
9702
+ }
9703
+ return tryAwardSubscriptionReward({
9704
+ affiliate,
9705
+ createdAt,
9706
+ period,
9707
+ resource,
9708
+ rewardType,
9709
+ vendor
9710
+ });
9711
+ }
9712
+ async function awardAffiliateVendorSubscriptionRewards(now = /* @__PURE__ */ new Date()) {
9713
+ const period = getSubscriptionRewardPeriodBounds(now);
9714
+ const createdAt = now;
9715
+ const affiliates = await findAffiliatesWithActiveVendorReferrals();
9716
+ let awarded = 0;
9717
+ let skipped = 0;
9718
+ const seenPairs = /* @__PURE__ */ new Set();
9719
+ for (const affiliate of affiliates) {
9720
+ const affiliateCode = normalizePromoCode(affiliate.affiliateCode);
9721
+ if (!affiliateCode) {
9722
+ continue;
9723
+ }
9724
+ for (const resource of affiliate.affiliateResources) {
9725
+ if (!isEligibleVendorResource(resource)) {
9726
+ continue;
9727
+ }
9728
+ const pairKey = `${String(affiliate._id)}:${String(resource.resourceId)}`;
9729
+ if (seenPairs.has(pairKey)) {
9730
+ continue;
9731
+ }
9732
+ seenPairs.add(pairKey);
9733
+ const outcome = await processAffiliateVendorReferral({
9734
+ affiliate,
9735
+ affiliateCode,
9736
+ createdAt,
9737
+ now,
9738
+ period,
9739
+ resource
9740
+ });
9741
+ if (outcome === "awarded") {
9742
+ awarded += 1;
9743
+ } else {
9744
+ skipped += 1;
9745
+ }
9746
+ }
9747
+ }
9748
+ return { awarded, skipped };
9749
+ }
9750
+
9751
+ // src/service/affiliate/findAffiliateByPromoCode.ts
9752
+ async function findAffiliateByPromoCode(promoCode) {
9753
+ return AffiliateModel.findOne({
9754
+ affiliateCode: promoCode,
9755
+ deletedAt: null
9756
+ }).exec();
9757
+ }
9758
+
9759
+ // src/service/affiliate/normalizeAffiliatePromoCodes.ts
9760
+ function normalizeAffiliatePromoCodes(promoCodes) {
9761
+ const normalized = (promoCodes ?? []).map((code) => normalizePromoCode(code)).filter((code) => code !== null);
9762
+ return [...new Set(normalized)];
9763
+ }
9764
+
9765
+ // src/service/database.ts
9766
+ var import_mongoose29 = __toESM(require("mongoose"));
9767
+ var connectToDatabase = async ({
9768
+ appName,
9769
+ dbName,
9770
+ dbPassword,
9771
+ dbUser,
9772
+ mongodbUri
9773
+ }) => {
9774
+ try {
9775
+ const mongoUri = mongodbUri ? mongodbUri : (
9776
+ // Fallback to MongoDB Atlas connection string
9777
+ `mongodb+srv://${dbUser}:${dbPassword}@${dbName}.mongodb.net/?retryWrites=true&w=majority&appName=${appName}`
9778
+ );
9779
+ await import_mongoose29.default.connect(mongoUri);
9780
+ const connectionType = mongodbUri ? "Local MongoDB" : "MongoDB Atlas";
9781
+ console.log(
9782
+ `${connectionType} connected from server/src/service/database.ts`
9783
+ );
9784
+ } catch (err) {
9785
+ console.error("Error connecting to MongoDB:", err);
9786
+ throw err;
9787
+ }
9788
+ };
9789
+
9585
9790
  // src/service/updateAdStatus.ts
9586
9791
  async function updateAdStatuses() {
9587
9792
  const now = /* @__PURE__ */ new Date();
@@ -9618,9 +9823,9 @@ async function updateAdStatuses() {
9618
9823
  }
9619
9824
 
9620
9825
  // src/service/associate.ts
9621
- var import_mongoose30 = __toESM(require("mongoose"));
9826
+ var import_mongoose31 = __toESM(require("mongoose"));
9622
9827
  function normalizeObjectId(id) {
9623
- return typeof id === "string" ? new import_mongoose30.default.Types.ObjectId(id) : id;
9828
+ return typeof id === "string" ? new import_mongoose31.default.Types.ObjectId(id) : id;
9624
9829
  }
9625
9830
  async function getAssociateEmailsForResource({
9626
9831
  normalizedResourceId,
@@ -9772,12 +9977,12 @@ async function updateVendorBasedOnUserLicense(userId, licenceType) {
9772
9977
  }
9773
9978
 
9774
9979
  // src/service/objectIdToString.ts
9775
- var import_mongoose33 = __toESM(require("mongoose"));
9980
+ var import_mongoose34 = __toESM(require("mongoose"));
9776
9981
  function convertObjectIdsToStrings(obj) {
9777
9982
  if (obj === null || obj === void 0) {
9778
9983
  return obj;
9779
9984
  }
9780
- if (obj instanceof import_mongoose33.default.Types.ObjectId) {
9985
+ if (obj instanceof import_mongoose34.default.Types.ObjectId) {
9781
9986
  return obj.toString();
9782
9987
  }
9783
9988
  if (obj instanceof Date) {
@@ -9963,12 +10168,15 @@ function updateRelationDatesToUnavailable(relationDates, eventDateTime) {
9963
10168
  ACTIVE_NOT_DELETED_FILTER,
9964
10169
  AFFILIATE_REWARDS,
9965
10170
  activeAffiliateCodeExists,
10171
+ awardAffiliateVendorSubscriptionRewards,
9966
10172
  connectToDatabase,
9967
10173
  convertObjectIdsToStrings,
9968
10174
  createAffiliateReward,
9969
10175
  didRemoveAnyEventDates,
9970
10176
  findAffiliateByPromoCode,
9971
10177
  findEventOrImportedMarketById,
10178
+ getSubscriptionRewardPeriodBounds,
10179
+ mapVendorLicenceToSubscriptionRewardType,
9972
10180
  normalizeAffiliatePromoCodes,
9973
10181
  normalizePromoCode,
9974
10182
  saveNotificationsInDb,