@timardex/cluemart-server-shared 1.1.34 → 1.1.36

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.
@@ -18,12 +18,15 @@ import {
18
18
  EventModel,
19
19
  GoogleImportedMarketModel,
20
20
  NotificationModel,
21
+ PartnerModel,
21
22
  PushTokenModel,
22
23
  UserModel,
23
24
  VendorModel,
24
25
  dateFormat,
26
+ isNonVisitorResourceType,
27
+ licenseNiceNames,
25
28
  timeFormat
26
- } from "../chunk-UGGLUJIR.mjs";
29
+ } from "../chunk-DBGVZNUX.mjs";
27
30
  import "../chunk-6PNG5BI5.mjs";
28
31
 
29
32
  // src/service/promoCode/constants.ts
@@ -51,10 +54,28 @@ var mapArrayToOptions = (items) => items.map((item) => ({
51
54
  label: item,
52
55
  value: item
53
56
  }));
57
+ var dateFormat2 = "DD-MM-YYYY";
58
+ var timeFormat2 = "HH:mm";
54
59
  dayjs.extend(customParseFormat);
55
60
  dayjs.extend(utc);
56
61
  dayjs.extend(timezone);
57
62
  dayjs.extend(isSameOrAfter);
63
+ var formatDate = (dateStr, display = "datetime", timeStr) => {
64
+ const dateTimeStr = timeStr ? `${dateStr} ${timeStr}` : dateStr;
65
+ const dateTime = timeStr ? dayjs(dateTimeStr, `${dateFormat2} ${timeFormat2}`) : dayjs(dateStr, dateFormat2);
66
+ const formattedDate = dateTime.format("dddd, D MMMM, YYYY");
67
+ const formattedTime = dateTime.format("h:mm a");
68
+ switch (display) {
69
+ case "date":
70
+ return formattedDate;
71
+ case "time":
72
+ return formattedTime;
73
+ case "datetime":
74
+ return `${formattedDate} at ${formattedTime}`;
75
+ default:
76
+ return formattedDate;
77
+ }
78
+ };
58
79
  var futureTimePeriods = mapArrayToOptions(
59
80
  Object.values(EnumEventDateStatus2)
60
81
  ).filter(
@@ -96,7 +117,7 @@ var SHARE_RESOURCE_LABEL = {
96
117
  school: "School"
97
118
  };
98
119
 
99
- // node_modules/@timardex/cluemart-shared/dist/chunk-FGVNX6EN.mjs
120
+ // node_modules/@timardex/cluemart-shared/dist/chunk-364EX22V.mjs
100
121
  var PROMO_CODE_PREFIX = "CM-";
101
122
  var OBJECT_ID_PATH_SEGMENT = "[a-f0-9]{24}";
102
123
  var OBJECT_ID_PATH_SEGMENT_END = `${OBJECT_ID_PATH_SEGMENT}$`;
@@ -109,7 +130,7 @@ var gameScreenIdentifierList = [
109
130
  {
110
131
  clue: "Where you can find your loyalties.",
111
132
  id: "coupons",
112
- match: "/coupons"
133
+ match: "/profile/account/coupons"
113
134
  },
114
135
  {
115
136
  clue: "A single moment worth showing up for.",
@@ -139,7 +160,7 @@ var gameScreenIdentifierList = [
139
160
  {
140
161
  clue: "Where fun becomes a challenge.",
141
162
  id: "games",
142
- match: "/games"
163
+ match: "/profile/account/games"
143
164
  },
144
165
  {
145
166
  clue: "Your starting point for everything.",
@@ -208,7 +229,7 @@ var gameScreenIdentifierList = [
208
229
  }
209
230
  ];
210
231
 
211
- // node_modules/@timardex/cluemart-shared/dist/chunk-UPFNTXDX.mjs
232
+ // node_modules/@timardex/cluemart-shared/dist/chunk-5RXL62LO.mjs
212
233
  import dayjs2 from "dayjs";
213
234
  var statusOptions = [
214
235
  ...Object.values(EnumInviteStatus2).map((status) => ({
@@ -1390,7 +1411,7 @@ import dayjs3 from "dayjs";
1390
1411
  import timezone2 from "dayjs/plugin/timezone";
1391
1412
  import utc2 from "dayjs/plugin/utc";
1392
1413
 
1393
- // src/service/license.ts
1414
+ // src/service/license/stripe/stripe.ts
1394
1415
  var PRO_EVENT_PLANS = /* @__PURE__ */ new Set([
1395
1416
  EnumUserLicence2.PRO_EVENT,
1396
1417
  EnumUserLicence2.PRO_PLUS_EVENT
@@ -1749,46 +1770,6 @@ async function updateAdStatuses() {
1749
1770
  );
1750
1771
  }
1751
1772
 
1752
- // src/service/vendor.ts
1753
- async function updateVendorBasedOnUserLicense(userId, licenceType) {
1754
- try {
1755
- const user = await UserModel.findById(userId).select("vendor").lean().exec();
1756
- if (!user?.vendor) {
1757
- console.warn(`[updateVendor] No vendor found for userId=${userId}`);
1758
- return;
1759
- }
1760
- const vendor = await VendorModel.findById(user.vendor).lean().exec();
1761
- if (!vendor) {
1762
- console.warn(`[updateVendor] Vendor not found for id=${user.vendor}`);
1763
- return;
1764
- }
1765
- const updateData = {};
1766
- const isStandardVendor = licenceType === EnumUserLicence.STANDARD_VENDOR;
1767
- if (isStandardVendor) {
1768
- updateData.availability = {
1769
- corporate: false,
1770
- private: false,
1771
- school: false
1772
- };
1773
- updateData.products = {
1774
- active: false,
1775
- productsList: vendor.products?.productsList ?? []
1776
- };
1777
- updateData.calendar = {
1778
- active: false,
1779
- calendarData: vendor.calendar?.calendarData ?? []
1780
- };
1781
- }
1782
- updateData.images = (vendor.images ?? []).map((image, index) => ({
1783
- ...image,
1784
- active: isStandardVendor ? index < 6 : true
1785
- }));
1786
- await VendorModel.updateOne({ _id: vendor._id }, { $set: updateData });
1787
- } catch (error) {
1788
- console.error("[updateVendorBasedOnUserLicense] Failed:", error);
1789
- }
1790
- }
1791
-
1792
1773
  // src/service/objectIdToString.ts
1793
1774
  import mongoose2 from "mongoose";
1794
1775
  function isValidObjectId(value) {
@@ -1979,32 +1960,1026 @@ function updateRelationDatesToUnavailable(relationDates, eventDateTime) {
1979
1960
  };
1980
1961
  });
1981
1962
  }
1963
+
1964
+ // src/service/license/compliance/ensureUserLicenseCompliance.ts
1965
+ import dayjs8 from "dayjs";
1966
+
1967
+ // src/service/license/compliance/utils.ts
1968
+ import dayjs7 from "dayjs";
1969
+
1970
+ // src/service/license/compliance/event.ts
1971
+ var eventLicences = [
1972
+ EnumUserLicence.STANDARD_EVENT,
1973
+ EnumUserLicence.PRO_EVENT,
1974
+ EnumUserLicence.PRO_PLUS_EVENT
1975
+ ];
1976
+ async function handleEventLicenceCompliance(user, now) {
1977
+ if (!user.licences || !user.events?.length) {
1978
+ return;
1979
+ }
1980
+ await syncUserLicencesAfterExpiry(user._id, eventLicences, now, "extend");
1981
+ }
1982
+
1983
+ // src/service/license/compliance/licenceExpiryPipeline.ts
1984
+ function buildLicenceExpiryPipeline(params) {
1985
+ const {
1986
+ downgradeBranches,
1987
+ licenceTypes,
1988
+ nowDate,
1989
+ oneYearFromNow,
1990
+ mode = "downgrade"
1991
+ } = params;
1992
+ const expiredInTarget = mode === "extend" ? {
1993
+ // Extend: keep licenceType and all other fields, push expiry out by a year
1994
+ $mergeObjects: ["$$lic", { expiryDate: oneYearFromNow }]
1995
+ } : {
1996
+ $cond: {
1997
+ // Expired STANDARD_* → extend (keep, push expiry out by a year)
1998
+ if: "$$isStandard",
1999
+ then: {
2000
+ $mergeObjects: ["$$lic", { expiryDate: oneYearFromNow }]
2001
+ },
2002
+ else: {
2003
+ $cond: {
2004
+ // Expired PRO_* / PRO_PLUS_* → downgrade and set new dates
2005
+ if: { $ne: ["$$downgrade", null] },
2006
+ then: {
2007
+ $mergeObjects: [
2008
+ "$$lic",
2009
+ {
2010
+ expiryDate: oneYearFromNow,
2011
+ issuedDate: nowDate,
2012
+ licenceType: "$$downgrade",
2013
+ prevLicenceType: "$$lic.licenceType"
2014
+ }
2015
+ ]
2016
+ },
2017
+ // Unknown type in target set → keep as-is
2018
+ else: "$$lic"
2019
+ }
2020
+ }
2021
+ }
2022
+ };
2023
+ return [
2024
+ {
2025
+ // Stage 1: resolve each licence (extend / downgrade / keep)
2026
+ $set: {
2027
+ licences: {
2028
+ // Remove null entries (e.g. pre-existing null licences kept by the map)
2029
+ $filter: {
2030
+ as: "x",
2031
+ cond: { $ne: ["$$x", null] },
2032
+ input: {
2033
+ // Iterate over each licence in the document's licences array
2034
+ $map: {
2035
+ input: "$licences",
2036
+ as: "lic",
2037
+ in: {
2038
+ // Define variables once per licence for reuse in the condition tree
2039
+ $let: {
2040
+ vars: {
2041
+ // Target STANDARD_* type for this licence (from downgradeBranches)
2042
+ downgrade: {
2043
+ $switch: {
2044
+ branches: downgradeBranches.map((b) => ({
2045
+ case: {
2046
+ $eq: ["$$lic.licenceType", b.case]
2047
+ },
2048
+ then: b.then
2049
+ })),
2050
+ default: null
2051
+ }
2052
+ },
2053
+ // True if this licence has expiryDate <= now (expired)
2054
+ expired: {
2055
+ $and: [
2056
+ { $ne: ["$$lic", null] },
2057
+ { $lte: ["$$lic.expiryDate", nowDate] }
2058
+ ]
2059
+ },
2060
+ // True if this licence's type is in the list we're processing (e.g. vendor only)
2061
+ inTarget: { $in: ["$$lic.licenceType", licenceTypes] },
2062
+ // True if licenceType starts with "standard_" (e.g. standard_vendor)
2063
+ isStandard: {
2064
+ $regexMatch: {
2065
+ input: {
2066
+ $toString: { $ifNull: ["$$lic.licenceType", ""] }
2067
+ },
2068
+ regex: /^standard_/
2069
+ }
2070
+ }
2071
+ },
2072
+ // Compute the new value for this array element
2073
+ in: {
2074
+ $cond: {
2075
+ // Keep as-is: null licence, or not in target set, or not expired
2076
+ if: {
2077
+ $or: [
2078
+ { $eq: ["$$lic", null] },
2079
+ { $not: "$$inTarget" },
2080
+ { $gt: ["$$lic.expiryDate", nowDate] }
2081
+ ]
2082
+ },
2083
+ then: "$$lic",
2084
+ // In target set and expired — apply the configured handling
2085
+ else: expiredInTarget
2086
+ }
2087
+ }
2088
+ }
2089
+ }
2090
+ }
2091
+ }
2092
+ }
2093
+ }
2094
+ }
2095
+ },
2096
+ {
2097
+ // Stage 2: dedupe by licenceType — keep the entry with the latest expiryDate
2098
+ // (ties broken by the latest issuedDate). Runs inside the same atomic updateOne.
2099
+ $set: {
2100
+ licences: {
2101
+ $reduce: {
2102
+ input: "$licences",
2103
+ initialValue: [],
2104
+ in: {
2105
+ $let: {
2106
+ vars: {
2107
+ current: "$$this",
2108
+ index: {
2109
+ $indexOfArray: [
2110
+ {
2111
+ $map: {
2112
+ input: "$$value",
2113
+ as: "item",
2114
+ in: "$$item.licenceType"
2115
+ }
2116
+ },
2117
+ "$$this.licenceType"
2118
+ ]
2119
+ }
2120
+ },
2121
+ in: {
2122
+ $cond: {
2123
+ if: { $eq: ["$$index", -1] },
2124
+ then: { $concatArrays: ["$$value", ["$$current"]] },
2125
+ else: {
2126
+ $map: {
2127
+ input: "$$value",
2128
+ as: "item",
2129
+ in: {
2130
+ $cond: {
2131
+ if: {
2132
+ $eq: [
2133
+ "$$item.licenceType",
2134
+ "$$current.licenceType"
2135
+ ]
2136
+ },
2137
+ then: {
2138
+ $cond: {
2139
+ if: {
2140
+ $or: [
2141
+ {
2142
+ $gt: [
2143
+ "$$current.expiryDate",
2144
+ "$$item.expiryDate"
2145
+ ]
2146
+ },
2147
+ {
2148
+ $and: [
2149
+ {
2150
+ $eq: [
2151
+ "$$current.expiryDate",
2152
+ "$$item.expiryDate"
2153
+ ]
2154
+ },
2155
+ {
2156
+ $gt: [
2157
+ "$$current.issuedDate",
2158
+ "$$item.issuedDate"
2159
+ ]
2160
+ }
2161
+ ]
2162
+ }
2163
+ ]
2164
+ },
2165
+ then: "$$current",
2166
+ else: "$$item"
2167
+ }
2168
+ },
2169
+ else: "$$item"
2170
+ }
2171
+ }
2172
+ }
2173
+ }
2174
+ }
2175
+ }
2176
+ }
2177
+ }
2178
+ }
2179
+ }
2180
+ }
2181
+ }
2182
+ ];
2183
+ }
2184
+
2185
+ // src/service/license/compliance/partner.ts
2186
+ var partnerLicences = [
2187
+ EnumUserLicence.STANDARD_PARTNER
2188
+ ];
2189
+ async function handlePartnerLicenceCompliance(user, now) {
2190
+ if (!user.licences || !user.partner) {
2191
+ return;
2192
+ }
2193
+ await syncUserLicencesAfterExpiry(user._id, partnerLicences, now, "extend");
2194
+ }
2195
+
2196
+ // src/service/license/compliance/vendor.ts
2197
+ import dayjs6 from "dayjs";
2198
+
2199
+ // src/service/license/models.ts
2200
+ import dayjs5 from "dayjs";
2201
+ import { GraphQLError } from "graphql";
2202
+ var LicenceExpiryDate = /* @__PURE__ */ ((LicenceExpiryDate2) => {
2203
+ LicenceExpiryDate2["ONE_YEAR"] = "1 year";
2204
+ LicenceExpiryDate2["ONE_MONTH"] = "1 month";
2205
+ LicenceExpiryDate2["TWO_MONTHS"] = "2 months";
2206
+ return LicenceExpiryDate2;
2207
+ })(LicenceExpiryDate || {});
2208
+ var LicenceCategory = /* @__PURE__ */ ((LicenceCategory2) => {
2209
+ LicenceCategory2["EVENT"] = "event";
2210
+ LicenceCategory2["PARTNER"] = "partner";
2211
+ LicenceCategory2["VENDOR"] = "vendor";
2212
+ LicenceCategory2["AFFILIATE"] = "affiliate";
2213
+ LicenceCategory2["SCHOOL"] = "school";
2214
+ return LicenceCategory2;
2215
+ })(LicenceCategory || {});
2216
+ var licenceCategoryMapping = {
2217
+ [EnumUserLicence.PRO_EVENT]: "event" /* EVENT */,
2218
+ [EnumUserLicence.PRO_PLUS_EVENT]: "event" /* EVENT */,
2219
+ [EnumUserLicence.PRO_PLUS_VENDOR]: "vendor" /* VENDOR */,
2220
+ [EnumUserLicence.PRO_VENDOR]: "vendor" /* VENDOR */,
2221
+ [EnumUserLicence.STANDARD_EVENT]: "event" /* EVENT */,
2222
+ [EnumUserLicence.STANDARD_PARTNER]: "partner" /* PARTNER */,
2223
+ [EnumUserLicence.STANDARD_VENDOR]: "vendor" /* VENDOR */,
2224
+ [EnumUserLicence.STANDARD_AFFILIATE]: "affiliate" /* AFFILIATE */,
2225
+ [EnumUserLicence.STANDARD_SCHOOL]: "school" /* SCHOOL */
2226
+ };
2227
+ var licencePriority = {
2228
+ [EnumUserLicence.PRO_PLUS_EVENT]: 3,
2229
+ [EnumUserLicence.PRO_EVENT]: 2,
2230
+ [EnumUserLicence.STANDARD_EVENT]: 1,
2231
+ [EnumUserLicence.PRO_PLUS_VENDOR]: 3,
2232
+ [EnumUserLicence.PRO_VENDOR]: 2,
2233
+ [EnumUserLicence.STANDARD_VENDOR]: 1,
2234
+ [EnumUserLicence.STANDARD_PARTNER]: 1,
2235
+ [EnumUserLicence.STANDARD_AFFILIATE]: 1,
2236
+ [EnumUserLicence.STANDARD_SCHOOL]: 1
2237
+ };
2238
+ var standardLicences = [
2239
+ EnumUserLicence.STANDARD_VENDOR,
2240
+ EnumUserLicence.STANDARD_EVENT,
2241
+ EnumUserLicence.STANDARD_PARTNER
2242
+ ];
2243
+ var standardLicenceSet = new Set(standardLicences);
2244
+ function isStandardLicence(licence) {
2245
+ return standardLicenceSet.has(licence);
2246
+ }
2247
+ var categoryRegexMapping = {
2248
+ ["event" /* EVENT */]: /_event$/,
2249
+ ["partner" /* PARTNER */]: /_partner$/,
2250
+ ["vendor" /* VENDOR */]: /_vendor$/,
2251
+ ["affiliate" /* AFFILIATE */]: /_affiliate$/,
2252
+ ["school" /* SCHOOL */]: /_school$/
2253
+ };
2254
+ var categoryFallbackLicence = {
2255
+ ["event" /* EVENT */]: EnumUserLicence.STANDARD_EVENT,
2256
+ ["partner" /* PARTNER */]: EnumUserLicence.STANDARD_PARTNER,
2257
+ ["vendor" /* VENDOR */]: EnumUserLicence.STANDARD_VENDOR,
2258
+ ["affiliate" /* AFFILIATE */]: EnumUserLicence.STANDARD_AFFILIATE,
2259
+ ["school" /* SCHOOL */]: EnumUserLicence.STANDARD_SCHOOL
2260
+ };
2261
+ var LicenceFilterInput = {
2262
+ INPUT_USER_LICENCES: "$licences"
2263
+ };
2264
+ function getLicenceCategory(licence) {
2265
+ const category = licenceCategoryMapping[licence];
2266
+ if (!category) {
2267
+ throw new Error(`Missing licence category mapping for ${licence}`);
2268
+ }
2269
+ return category;
2270
+ }
2271
+ function getHighestLicenceForCategory(licences, category) {
2272
+ const categoryLicences = (licences ?? []).map((licence) => licence.licenceType).filter(
2273
+ (licenceType) => Boolean(licenceType && getLicenceCategory(licenceType) === category)
2274
+ );
2275
+ let highestLicence = null;
2276
+ let highestPriority = Number.NEGATIVE_INFINITY;
2277
+ for (const licenceType of categoryLicences) {
2278
+ const priority = licencePriority[licenceType];
2279
+ if (priority > highestPriority) {
2280
+ highestPriority = priority;
2281
+ highestLicence = licenceType;
2282
+ }
2283
+ }
2284
+ return highestLicence;
2285
+ }
2286
+ function createLicenceObject(expiryDate, licenceType) {
2287
+ const today = dayjs5();
2288
+ const expiryDateMapping = {
2289
+ ["1 year" /* ONE_YEAR */]: today.add(1, "year").endOf("day").toDate(),
2290
+ ["1 month" /* ONE_MONTH */]: today.add(1, "month").endOf("day").toDate(),
2291
+ ["2 months" /* TWO_MONTHS */]: today.add(2, "month").endOf("day").toDate()
2292
+ };
2293
+ const licenceObject = {
2294
+ expiryDate: expiryDateMapping[expiryDate],
2295
+ issuedDate: today.toDate(),
2296
+ licenceType
2297
+ };
2298
+ return licenceObject;
2299
+ }
2300
+ var buildLicenceReplacePipeline = ({
2301
+ fallbackType,
2302
+ inputField,
2303
+ licenceObject,
2304
+ typeRegex
2305
+ }) => [
2306
+ {
2307
+ $set: {
2308
+ licences: {
2309
+ $concatArrays: [
2310
+ {
2311
+ $filter: {
2312
+ as: "licence",
2313
+ cond: {
2314
+ $not: {
2315
+ $regexMatch: {
2316
+ input: {
2317
+ $toString: {
2318
+ $ifNull: ["$$licence.licenceType", fallbackType]
2319
+ }
2320
+ },
2321
+ regex: typeRegex
2322
+ }
2323
+ }
2324
+ },
2325
+ input: { $ifNull: [inputField, []] }
2326
+ }
2327
+ },
2328
+ [licenceObject]
2329
+ ]
2330
+ }
2331
+ }
2332
+ }
2333
+ ];
2334
+ async function replaceUserLicenceWithObject({
2335
+ userId,
2336
+ licenceObject,
2337
+ protectHigherLicence = true
2338
+ }) {
2339
+ const user = await UserModel.findById(userId, { licences: 1 }).lean();
2340
+ if (!user) throw new GraphQLError("User not found");
2341
+ if (user.licences?.some((l) => l.licenceType === licenceObject.licenceType)) {
2342
+ return;
2343
+ }
2344
+ const updatedLicenceObject = {
2345
+ ...licenceObject,
2346
+ prevLicenceType: user.licences?.find(
2347
+ (l) => getLicenceCategory(l.licenceType) === getLicenceCategory(licenceObject.licenceType)
2348
+ )?.licenceType
2349
+ };
2350
+ const category = getLicenceCategory(updatedLicenceObject.licenceType);
2351
+ if (protectHigherLicence) {
2352
+ const highestLicence = getHighestLicenceForCategory(
2353
+ user.licences,
2354
+ category
2355
+ );
2356
+ if (highestLicence && licencePriority[highestLicence] > licencePriority[updatedLicenceObject.licenceType]) {
2357
+ return;
2358
+ }
2359
+ }
2360
+ await UserModel.updateOne(
2361
+ { _id: userId },
2362
+ buildLicenceReplacePipeline({
2363
+ fallbackType: categoryFallbackLicence[category],
2364
+ inputField: LicenceFilterInput.INPUT_USER_LICENCES,
2365
+ licenceObject: updatedLicenceObject,
2366
+ typeRegex: categoryRegexMapping[category]
2367
+ })
2368
+ );
2369
+ }
2370
+ var upgradeUserToLicence = async ({
2371
+ licenceType,
2372
+ expiryDate,
2373
+ userId
2374
+ }) => {
2375
+ const licenceObject = createLicenceObject(expiryDate, licenceType);
2376
+ await replaceUserLicenceWithObject({ licenceObject, userId });
2377
+ const user = await UserModel.findById(userId).exec();
2378
+ return {
2379
+ licenceObject,
2380
+ updatedUser: user
2381
+ };
2382
+ };
2383
+ async function checkOwnerHasLicence({
2384
+ userId,
2385
+ resourceType
2386
+ }) {
2387
+ try {
2388
+ const owner = await UserModel.findById(userId);
2389
+ if (!owner) throw new GraphQLError("Owner not found");
2390
+ const categoryByResource = {
2391
+ [EnumResourceType.EVENT]: "event" /* EVENT */,
2392
+ [EnumResourceType.PARTNER]: "partner" /* PARTNER */,
2393
+ [EnumResourceType.VENDOR]: "vendor" /* VENDOR */,
2394
+ [EnumResourceType.AFFILIATE]: "affiliate" /* AFFILIATE */,
2395
+ [EnumResourceType.SCHOOL]: "school" /* SCHOOL */
2396
+ };
2397
+ if (!isNonVisitorResourceType(resourceType)) {
2398
+ throw new GraphQLError(`Invalid resource type: ${resourceType}.`);
2399
+ }
2400
+ const requiredCategory = categoryByResource[resourceType];
2401
+ const activeLicence = owner.licences?.some((licence) => {
2402
+ if (!licence.licenceType) return false;
2403
+ return getLicenceCategory(licence.licenceType) === requiredCategory;
2404
+ });
2405
+ if (!activeLicence) {
2406
+ throw new GraphQLError(
2407
+ `Owner does not have an active licence. Cannot update ${resourceType}.`
2408
+ );
2409
+ }
2410
+ } catch (error) {
2411
+ if (error instanceof GraphQLError) {
2412
+ throw error;
2413
+ }
2414
+ throw new GraphQLError(
2415
+ error instanceof Error ? `Failed to check user licence: ${error.message}` : "Failed to check user licence"
2416
+ );
2417
+ }
2418
+ }
2419
+
2420
+ // src/service/license/compliance/vendor.ts
2421
+ async function updateVendorBasedOnUserLicense(userId, licenceType) {
2422
+ try {
2423
+ const user = await UserModel.findById(userId).select("vendor").lean().exec();
2424
+ if (!user?.vendor) {
2425
+ console.warn(`[updateVendor] No vendor found for userId=${userId}`);
2426
+ return;
2427
+ }
2428
+ const vendor = await VendorModel.findById(user.vendor).lean().exec();
2429
+ if (!vendor) {
2430
+ console.warn(`[updateVendor] Vendor not found for id=${user.vendor}`);
2431
+ return;
2432
+ }
2433
+ const updateData = {};
2434
+ const isStandardVendor = licenceType === EnumUserLicence.STANDARD_VENDOR;
2435
+ if (isStandardVendor) {
2436
+ updateData.availability = {
2437
+ corporate: false,
2438
+ private: false,
2439
+ school: false
2440
+ };
2441
+ updateData.products = {
2442
+ active: false,
2443
+ productsList: vendor.products?.productsList ?? []
2444
+ };
2445
+ updateData.calendar = {
2446
+ active: false,
2447
+ calendarData: vendor.calendar?.calendarData ?? []
2448
+ };
2449
+ }
2450
+ updateData.images = (vendor.images ?? []).map((image, index) => ({
2451
+ ...image,
2452
+ active: isStandardVendor ? index < 6 : true
2453
+ }));
2454
+ await VendorModel.updateOne({ _id: vendor._id }, { $set: updateData });
2455
+ } catch (error) {
2456
+ console.error("[updateVendorBasedOnUserLicense] Failed:", error);
2457
+ }
2458
+ }
2459
+ var vendorLicences = [
2460
+ EnumUserLicence.STANDARD_VENDOR,
2461
+ EnumUserLicence.PRO_VENDOR,
2462
+ EnumUserLicence.PRO_PLUS_VENDOR
2463
+ ];
2464
+ async function handleVendorLicenceCompliance(user, now) {
2465
+ if (!user.licences || !user.vendor) {
2466
+ return;
2467
+ }
2468
+ const vendorLicencesOfUser = user.licences.filter(
2469
+ (licence) => licence?.licenceType?.includes("vendor")
2470
+ );
2471
+ if (vendorLicencesOfUser.length === 0) {
2472
+ return;
2473
+ }
2474
+ const proLicences = vendorLicencesOfUser.filter(
2475
+ (licence) => licence.licenceType !== EnumUserLicence.STANDARD_VENDOR
2476
+ );
2477
+ const expiredProLicence = proLicences.some(
2478
+ (licence) => !dayjs6(licence.expiryDate).isAfter(now)
2479
+ );
2480
+ const hasValidProLicence = hasValidLicence(proLicences, vendorLicences, now);
2481
+ const hasExpiredVendorLicence = vendorLicencesOfUser.some(
2482
+ (licence) => !dayjs6(licence.expiryDate).isAfter(now)
2483
+ );
2484
+ if (!hasExpiredVendorLicence) {
2485
+ return;
2486
+ }
2487
+ let vendor = null;
2488
+ if (expiredProLicence) {
2489
+ vendor = await VendorModel.findOne({
2490
+ _id: user.vendor,
2491
+ active: true,
2492
+ deletedAt: null,
2493
+ "owner.userId": user._id
2494
+ }).lean().exec();
2495
+ }
2496
+ await syncUserLicencesAfterExpiry(user._id, vendorLicences, now, "downgrade");
2497
+ if (!expiredProLicence || !vendor || hasValidProLicence) {
2498
+ return;
2499
+ }
2500
+ await updateVendorBasedOnUserLicense(
2501
+ user._id,
2502
+ EnumUserLicence.STANDARD_VENDOR
2503
+ );
2504
+ const payload = {
2505
+ data: {
2506
+ resourceId: String(vendor._id),
2507
+ resourceName: vendor.name,
2508
+ resourceType: EnumNotificationResourceType.DOWNGRADED_VENDOR
2509
+ },
2510
+ message: `Your Vendor license has been downgraded due to licence expiration.`,
2511
+ title: `Vendor License Downgraded`,
2512
+ type: EnumNotificationType.SYSTEM,
2513
+ userIds: [user._id]
2514
+ };
2515
+ await sendDeactivationNotification(payload, user._id, vendor.name, "vendor");
2516
+ }
2517
+ async function vendorOwnerHasProLicence(vendorId) {
2518
+ const vendor = await VendorModel.findOne({
2519
+ _id: vendorId,
2520
+ active: true,
2521
+ deletedAt: null
2522
+ }).lean().exec();
2523
+ if (!vendor) {
2524
+ return false;
2525
+ }
2526
+ const owner = await UserModel.findById(vendor.owner.userId, { licences: 1 }).lean().exec();
2527
+ const highestVendorLicence = getHighestLicenceForCategory(
2528
+ owner?.licences,
2529
+ "vendor" /* VENDOR */
2530
+ );
2531
+ return highestVendorLicence !== null && licencePriority[highestVendorLicence] >= licencePriority[EnumUserLicence.PRO_VENDOR];
2532
+ }
2533
+
2534
+ // src/service/license/compliance/utils.ts
2535
+ async function syncUserLicencesAfterExpiry(userId, licenceTypes, now, mode = "downgrade") {
2536
+ const nowDate = now.toDate();
2537
+ const oneYearFromNow = now.add(1, "year").endOf("day").toDate();
2538
+ const pipeline = buildLicenceExpiryPipeline({
2539
+ downgradeBranches: [
2540
+ {
2541
+ case: EnumUserLicence.PRO_PLUS_VENDOR,
2542
+ then: EnumUserLicence.STANDARD_VENDOR
2543
+ },
2544
+ {
2545
+ case: EnumUserLicence.PRO_VENDOR,
2546
+ then: EnumUserLicence.STANDARD_VENDOR
2547
+ }
2548
+ ],
2549
+ licenceTypes,
2550
+ mode,
2551
+ nowDate,
2552
+ oneYearFromNow
2553
+ });
2554
+ await UserModel.updateOne({ _id: userId }, pipeline).exec();
2555
+ }
2556
+ function hasValidLicence(licences, licenceTypes, now) {
2557
+ return licences.some(
2558
+ (licence) => licenceTypes.includes(licence.licenceType) && dayjs7(licence.expiryDate).isAfter(now)
2559
+ );
2560
+ }
2561
+ async function sendDeactivationNotification(payload, userId, resourceName, resourceType) {
2562
+ const sent = await notifyUsers({ payload });
2563
+ if (!sent) {
2564
+ console.error(
2565
+ `\u274C ${resourceType} notification not confirmed for user ${String(userId)} for "${resourceName}"`
2566
+ );
2567
+ return;
2568
+ }
2569
+ console.log(
2570
+ `\u2705 Sent ${resourceType} notification to user ${String(userId)} for "${resourceName}"`
2571
+ );
2572
+ }
2573
+ async function processUserCompliance(user, now) {
2574
+ if (!user.licences) {
2575
+ return;
2576
+ }
2577
+ await Promise.all([
2578
+ handleVendorLicenceCompliance(user, now),
2579
+ handlePartnerLicenceCompliance(user, now),
2580
+ handleEventLicenceCompliance(user, now)
2581
+ ]);
2582
+ }
2583
+
2584
+ // src/service/license/compliance/ensureUserLicenseCompliance.ts
2585
+ async function ensureUserLicenseCompliance() {
2586
+ const now = dayjs8();
2587
+ console.log(`\u{1F50D} Checking license compliance at ${now.format()}`);
2588
+ const nowDate = now.toDate();
2589
+ const users = await UserModel.find({
2590
+ licences: {
2591
+ $elemMatch: {
2592
+ expiryDate: {
2593
+ $lte: nowDate
2594
+ // Expired or expiring today
2595
+ }
2596
+ }
2597
+ }
2598
+ });
2599
+ console.log(
2600
+ `\u{1F4CA} Found ${users.length} users with expired or expiring licenses`
2601
+ );
2602
+ if (!users.length) {
2603
+ console.log("No users with licenses to process.");
2604
+ return;
2605
+ }
2606
+ let processedCount = 0;
2607
+ let errorCount = 0;
2608
+ for (const user of users) {
2609
+ try {
2610
+ await processUserCompliance(user, now);
2611
+ processedCount++;
2612
+ } catch (err) {
2613
+ errorCount++;
2614
+ console.error(
2615
+ `\u274C Error processing license compliance for user ${String(user._id)}:`,
2616
+ err instanceof Error ? err.message : err
2617
+ );
2618
+ }
2619
+ }
2620
+ const errorMessage = errorCount > 0 ? `, ${errorCount} errors` : "";
2621
+ console.log(
2622
+ `\u2705 Processed ${processedCount} users successfully${errorMessage}`
2623
+ );
2624
+ }
2625
+
2626
+ // src/service/license/reminder/event.ts
2627
+ async function getEventResourceInfo(userId, eventIds) {
2628
+ const event = await EventModel.findOne({
2629
+ _id: { $in: eventIds },
2630
+ active: true,
2631
+ deletedAt: null,
2632
+ "owner.userId": userId
2633
+ }).lean().exec();
2634
+ if (!event) {
2635
+ return null;
2636
+ }
2637
+ return {
2638
+ resourceId: String(event._id),
2639
+ resourceName: event.name
2640
+ };
2641
+ }
2642
+
2643
+ // src/service/license/reminder/partner.ts
2644
+ async function getPartnerResourceInfo(userId, partnerId) {
2645
+ const partner = await PartnerModel.findOne({
2646
+ _id: partnerId,
2647
+ active: true,
2648
+ deletedAt: null,
2649
+ "owner.userId": userId
2650
+ }).lean().exec();
2651
+ if (!partner) {
2652
+ return null;
2653
+ }
2654
+ return {
2655
+ resourceId: String(partner._id),
2656
+ resourceName: partner.name
2657
+ };
2658
+ }
2659
+
2660
+ // src/service/license/reminder/remindUsersAboutLicenseExpiration.ts
2661
+ import dayjs10 from "dayjs";
2662
+
2663
+ // src/service/license/reminder/utils.ts
2664
+ import dayjs9 from "dayjs";
2665
+
2666
+ // src/service/license/reminder/vendor.ts
2667
+ async function getVendorResourceInfo(userId, vendorId) {
2668
+ const vendor = await VendorModel.findOne({
2669
+ _id: vendorId,
2670
+ active: true,
2671
+ deletedAt: null,
2672
+ "owner.userId": userId
2673
+ }).lean().exec();
2674
+ if (!vendor) {
2675
+ return null;
2676
+ }
2677
+ return {
2678
+ resourceId: String(vendor._id),
2679
+ resourceName: vendor.name
2680
+ };
2681
+ }
2682
+
2683
+ // src/service/license/reminder/utils.ts
2684
+ async function checkAndCreateNotification(payload) {
2685
+ const query = {
2686
+ message: payload.message,
2687
+ title: payload.title,
2688
+ userId: payload.userIds[0]
2689
+ };
2690
+ if (payload.data.resourceId) {
2691
+ query["data.resourceId"] = payload.data.resourceId;
2692
+ }
2693
+ const notificationDoc = {
2694
+ createdAt: /* @__PURE__ */ new Date(),
2695
+ data: payload.data,
2696
+ isRead: false,
2697
+ message: payload.message,
2698
+ title: payload.title,
2699
+ type: payload.type,
2700
+ userId: payload.userIds[0]
2701
+ };
2702
+ try {
2703
+ const result = await UserModel.db.collection("notifications").findOneAndUpdate(
2704
+ query,
2705
+ { $setOnInsert: notificationDoc },
2706
+ {
2707
+ includeResultMetadata: true,
2708
+ returnDocument: "after",
2709
+ upsert: true
2710
+ }
2711
+ );
2712
+ const wasInserted = result?.lastErrorObject?.upserted != null;
2713
+ return !wasInserted;
2714
+ } catch (error) {
2715
+ console.error(
2716
+ `\u274C Error atomically checking notification:`,
2717
+ error instanceof Error ? error.message : error
2718
+ );
2719
+ return true;
2720
+ }
2721
+ }
2722
+ function isLicenseExpiringIn7Days(expiryDate, now) {
2723
+ const expiry = dayjs9(expiryDate);
2724
+ const daysUntilExpiry = expiry.diff(now, "day", true);
2725
+ return daysUntilExpiry >= 6.5 && daysUntilExpiry <= 7.5;
2726
+ }
2727
+ function getLicenseName(licenceType) {
2728
+ return licenseNiceNames[licenceType] || licenceType;
2729
+ }
2730
+ function getNotificationTypes(isVendorLicense, isPartnerLicense) {
2731
+ if (isVendorLicense) {
2732
+ return {
2733
+ notificationType: EnumNotificationType.SYSTEM,
2734
+ resourceType: EnumNotificationResourceType.EXPIRATION_REMINDER_VENDOR
2735
+ };
2736
+ }
2737
+ if (isPartnerLicense) {
2738
+ return {
2739
+ notificationType: EnumNotificationType.SYSTEM,
2740
+ resourceType: EnumNotificationResourceType.EXPIRATION_REMINDER_PARTNER
2741
+ };
2742
+ }
2743
+ return {
2744
+ notificationType: EnumNotificationType.SYSTEM,
2745
+ resourceType: EnumNotificationResourceType.EXPIRATION_REMINDER_EVENT
2746
+ };
2747
+ }
2748
+ async function getLicenseResourceInfo(user, licence) {
2749
+ const isVendorLicense = vendorLicences.includes(licence.licenceType);
2750
+ const isPartnerLicense = partnerLicences.includes(licence.licenceType);
2751
+ const licenceName = getLicenseName(licence.licenceType);
2752
+ const { notificationType, resourceType } = getNotificationTypes(
2753
+ isVendorLicense,
2754
+ isPartnerLicense
2755
+ );
2756
+ if (isVendorLicense && user.vendor) {
2757
+ const vendorInfo = await getVendorResourceInfo(user._id, user.vendor);
2758
+ if (!vendorInfo) {
2759
+ return null;
2760
+ }
2761
+ return {
2762
+ ...vendorInfo,
2763
+ notificationType,
2764
+ resourceType
2765
+ };
2766
+ }
2767
+ if (eventLicences.includes(licence.licenceType) && user.events?.length) {
2768
+ const eventInfo = await getEventResourceInfo(user._id, user.events);
2769
+ if (!eventInfo) {
2770
+ return null;
2771
+ }
2772
+ return {
2773
+ ...eventInfo,
2774
+ notificationType,
2775
+ resourceType
2776
+ };
2777
+ }
2778
+ if (isPartnerLicense && user.partner) {
2779
+ const partnerInfo = await getPartnerResourceInfo(user._id, user.partner);
2780
+ if (!partnerInfo) {
2781
+ return null;
2782
+ }
2783
+ return {
2784
+ ...partnerInfo,
2785
+ notificationType,
2786
+ resourceType
2787
+ };
2788
+ }
2789
+ return {
2790
+ notificationType,
2791
+ resourceId: String(user._id),
2792
+ resourceName: licenceName,
2793
+ resourceType
2794
+ };
2795
+ }
2796
+ function getLicenceExpiryMode(licenceType) {
2797
+ return licenceType === EnumUserLicence.PRO_VENDOR || licenceType === EnumUserLicence.PRO_PLUS_VENDOR ? "downgrade" : "extend";
2798
+ }
2799
+ async function sendLicenseReminder(user, licence) {
2800
+ const licenceName = getLicenseName(licence.licenceType);
2801
+ const expiryDate = dayjs9(licence.expiryDate).format(dateFormat);
2802
+ const userId = String(user._id);
2803
+ const resourceInfo = await getLicenseResourceInfo(user, licence);
2804
+ if (!resourceInfo) {
2805
+ console.log(
2806
+ `\u23ED\uFE0F Skipping 7-day reminder for user ${userId}, license ${licence.licenceType} (no resource info)`
2807
+ );
2808
+ return;
2809
+ }
2810
+ const isExtension = getLicenceExpiryMode(licence.licenceType) === "extend";
2811
+ const payload = {
2812
+ data: {
2813
+ resourceId: resourceInfo.resourceId,
2814
+ resourceName: resourceInfo.resourceName,
2815
+ resourceType: resourceInfo.resourceType
2816
+ },
2817
+ message: isExtension ? `Your ${licenceName} will be automatically extended for another year on ${formatDate(expiryDate, "date")}.` : `Your ${licenceName} expires in 7 days (${formatDate(expiryDate, "date")}). Renew now to avoid deactivation.`,
2818
+ title: isExtension ? "License Extension Reminder" : "License Expiring Soon",
2819
+ type: resourceInfo.notificationType,
2820
+ userIds: [user._id]
2821
+ };
2822
+ const alreadyExists = await checkAndCreateNotification(payload);
2823
+ if (alreadyExists) {
2824
+ console.log(
2825
+ `\u23ED\uFE0F Skipping 7-day reminder to user ${userId} for ${licenceName} (notification already exists)`
2826
+ );
2827
+ return;
2828
+ }
2829
+ await sendPushNotifications(payload);
2830
+ console.log(`\u2705 Sent 7-day reminder to user ${userId} for ${licenceName}`);
2831
+ }
2832
+ async function processLicenseReminder(user, licence, now) {
2833
+ if (dayjs9(licence.expiryDate).isBefore(now)) {
2834
+ return false;
2835
+ }
2836
+ if (!isLicenseExpiringIn7Days(licence.expiryDate, now)) {
2837
+ return false;
2838
+ }
2839
+ return true;
2840
+ }
2841
+ async function sendReminderSafely(user, licence) {
2842
+ try {
2843
+ await sendLicenseReminder(user, licence);
2844
+ return true;
2845
+ } catch (err) {
2846
+ console.error(
2847
+ `\u274C Error sending reminder to user ${String(user._id)} for license ${licence.licenceType}:`,
2848
+ err instanceof Error ? err.message : err
2849
+ );
2850
+ return false;
2851
+ }
2852
+ }
2853
+ async function processUserLicenseReminders(user, now) {
2854
+ if (!user.licences) {
2855
+ return 0;
2856
+ }
2857
+ const validLicences = user.licences.filter((licence) => licence !== null);
2858
+ if (validLicences.length === 0) {
2859
+ return 0;
2860
+ }
2861
+ const licenceChecks = await Promise.all(
2862
+ validLicences.map(async (licence) => {
2863
+ try {
2864
+ const shouldSend = await processLicenseReminder(user, licence, now);
2865
+ return { licence, shouldSend };
2866
+ } catch (err) {
2867
+ console.error(
2868
+ `\u274C Error checking license reminder for user ${String(user._id)} for license ${licence.licenceType}:`,
2869
+ err instanceof Error ? err.message : err
2870
+ );
2871
+ return { licence, shouldSend: false };
2872
+ }
2873
+ })
2874
+ );
2875
+ const licencesToNotify = licenceChecks.filter((check) => check.shouldSend).map((check) => check.licence);
2876
+ if (!licencesToNotify.length) {
2877
+ return 0;
2878
+ }
2879
+ const results = await Promise.all(
2880
+ licencesToNotify.map((licence) => sendReminderSafely(user, licence))
2881
+ );
2882
+ return results.filter(Boolean).length;
2883
+ }
2884
+
2885
+ // src/service/license/reminder/remindUsersAboutLicenseExpiration.ts
2886
+ async function remindUsersAboutLicenseExpiration() {
2887
+ const now = dayjs10();
2888
+ console.log(`\u{1F50D} Checking for licenses expiring in 7 days at ${now.format()}`);
2889
+ const minExpiryDate = now.add(6.5, "day").toDate();
2890
+ const maxExpiryDate = now.add(7.5, "day").toDate();
2891
+ const users = await UserModel.find({
2892
+ licences: {
2893
+ $elemMatch: {
2894
+ expiryDate: {
2895
+ $gte: minExpiryDate,
2896
+ $lte: maxExpiryDate
2897
+ }
2898
+ }
2899
+ }
2900
+ });
2901
+ console.log(
2902
+ `\u{1F4CA} Found ${users.length} users with licenses expiring in 7 days`
2903
+ );
2904
+ if (!users.length) {
2905
+ console.log("No users with licenses to process.");
2906
+ return;
2907
+ }
2908
+ let totalReminderCount = 0;
2909
+ for (const user of users) {
2910
+ try {
2911
+ const reminderCount = await processUserLicenseReminders(user, now);
2912
+ totalReminderCount += reminderCount;
2913
+ } catch (err) {
2914
+ console.error(
2915
+ `\u274C Error processing license reminders for user ${String(user._id)}:`,
2916
+ err instanceof Error ? err.message : err
2917
+ );
2918
+ }
2919
+ }
2920
+ console.log(
2921
+ `\u2705 Processed ${users.length} users, sent ${totalReminderCount} license expiration reminders`
2922
+ );
2923
+ }
1982
2924
  export {
1983
2925
  ACTIVE_NOT_DELETED_FILTER,
2926
+ LicenceCategory,
2927
+ LicenceExpiryDate,
1984
2928
  SUBSCRIPTION_REWARD_TIMEZONE,
1985
2929
  activeAffiliateCodeExists,
1986
2930
  awardAffiliateVendorSubscriptionRewards,
2931
+ buildLicenceExpiryPipeline,
2932
+ checkOwnerHasLicence,
1987
2933
  connectToDatabase,
1988
2934
  convertObjectIdsToStrings,
2935
+ createLicenceObject,
1989
2936
  didRemoveAnyEventDates,
2937
+ ensureUserLicenseCompliance,
2938
+ eventLicences,
1990
2939
  findAffiliateByPromoCode,
1991
2940
  findEventOrImportedMarketById,
2941
+ getEventResourceInfo,
2942
+ getHighestLicenceForCategory,
2943
+ getLicenceCategory,
2944
+ getLicenceExpiryMode,
2945
+ getPartnerResourceInfo,
1992
2946
  getPayingEventStripeSubscriptionPlan,
1993
2947
  getPayingStripeSubscriptionPlan,
1994
2948
  getPayingVendorStripeSubscriptionPlan,
1995
2949
  getSubscriptionRewardPeriodBounds,
2950
+ getVendorResourceInfo,
2951
+ handleEventLicenceCompliance,
2952
+ handlePartnerLicenceCompliance,
2953
+ handleVendorLicenceCompliance,
2954
+ hasValidLicence,
2955
+ isStandardLicence,
1996
2956
  isValidObjectId,
2957
+ licenceCategoryMapping,
2958
+ licencePriority,
1997
2959
  mapVendorLicenceToSubscriptionRewardType,
1998
2960
  normalizeAffiliatePromoCodes,
1999
2961
  normalizePromoCode,
2000
2962
  notifyUsers,
2963
+ partnerLicences,
2964
+ processLicenseReminder,
2965
+ processUserCompliance,
2966
+ processUserLicenseReminders,
2001
2967
  publishNotificationEvents,
2968
+ remindUsersAboutLicenseExpiration,
2969
+ replaceUserLicenceWithObject,
2002
2970
  saveNotificationsInDb,
2971
+ sendDeactivationNotification,
2972
+ sendLicenseReminder,
2003
2973
  sendPushNotifications,
2974
+ sendReminderSafely,
2975
+ syncUserLicencesAfterExpiry,
2004
2976
  updateAdStatuses,
2005
2977
  updateAllEventDateTimeStatuses,
2006
2978
  updateRelationDatesToUnavailable,
2007
2979
  updateSingleDateTimeStatus,
2008
- updateVendorBasedOnUserLicense
2980
+ updateVendorBasedOnUserLicense,
2981
+ upgradeUserToLicence,
2982
+ vendorLicences,
2983
+ vendorOwnerHasProLicence
2009
2984
  };
2010
2985
  //# sourceMappingURL=index.mjs.map