@timardex/cluemart-server-shared 1.1.35 → 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.
- package/dist/{Affiliate-gqV1-654.d.ts → Affiliate-CZKOOaz_.d.ts} +62 -2
- package/dist/{Affiliate-B76iZ3fE.d.mts → Affiliate-xCVhO2Cy.d.mts} +62 -2
- package/dist/{chunk-ZVXL6B3M.mjs → chunk-DBGVZNUX.mjs} +53 -3000
- package/dist/chunk-DBGVZNUX.mjs.map +1 -0
- package/dist/index.cjs +1988 -3932
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +242 -8
- package/dist/index.d.ts +242 -8
- package/dist/index.mjs +1452 -3429
- package/dist/index.mjs.map +1 -1
- package/dist/mongoose/index.cjs +10 -3000
- package/dist/mongoose/index.cjs.map +1 -1
- package/dist/mongoose/index.d.mts +4 -64
- package/dist/mongoose/index.d.ts +4 -64
- package/dist/mongoose/index.mjs +1 -1
- package/dist/service/index.cjs +1993 -3937
- package/dist/service/index.cjs.map +1 -1
- package/dist/service/index.d.mts +243 -9
- package/dist/service/index.d.ts +243 -9
- package/dist/service/index.mjs +1018 -43
- package/dist/service/index.mjs.map +1 -1
- package/package.json +3 -2
- package/dist/chunk-ZVXL6B3M.mjs.map +0 -1
package/dist/service/index.mjs
CHANGED
|
@@ -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-
|
|
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(
|
|
@@ -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
|