@goweekdays/core 2.11.4 → 2.11.6
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/CHANGELOG.md +12 -0
- package/dist/index.d.ts +29 -1
- package/dist/index.js +191 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +190 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @goweekdays/core
|
|
2
2
|
|
|
3
|
+
## 2.11.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8736673: Add user count check for org member invites
|
|
8
|
+
|
|
9
|
+
## 2.11.5
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- cb8aa36: Enhance promo usage tracking and seat limit logic
|
|
14
|
+
|
|
3
15
|
## 2.11.4
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -344,6 +344,7 @@ declare function useMemberRepo(): {
|
|
|
344
344
|
updateStatusById: (_id: string | ObjectId, status: string, session?: ClientSession) => Promise<string>;
|
|
345
345
|
deleteById: (_id: string | ObjectId, session?: ClientSession) => Promise<string>;
|
|
346
346
|
updateStatusByOrg: (org: string | ObjectId, status: string, session?: ClientSession) => Promise<string>;
|
|
347
|
+
countUserByOrg: (org: string | ObjectId) => Promise<any>;
|
|
347
348
|
};
|
|
348
349
|
|
|
349
350
|
declare function useMemberController(): {
|
|
@@ -470,6 +471,33 @@ declare function usePromoController(): {
|
|
|
470
471
|
deleteById: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
471
472
|
};
|
|
472
473
|
|
|
474
|
+
type TPromoUsage = {
|
|
475
|
+
_id?: ObjectId;
|
|
476
|
+
promo: ObjectId;
|
|
477
|
+
org: ObjectId | string;
|
|
478
|
+
usedBy: string;
|
|
479
|
+
status?: "active" | "inactive";
|
|
480
|
+
createdAt?: Date | string;
|
|
481
|
+
updatedAt?: Date | string;
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
declare function usePromoUsageRepo(): {
|
|
485
|
+
createIndexes: () => Promise<void>;
|
|
486
|
+
add: (value: TPromoUsage, session?: ClientSession) => Promise<string>;
|
|
487
|
+
getAll: ({ page, limit, promo, org, }?: {
|
|
488
|
+
page?: number | undefined;
|
|
489
|
+
limit?: number | undefined;
|
|
490
|
+
promo?: string | undefined;
|
|
491
|
+
org?: string | undefined;
|
|
492
|
+
}) => Promise<TPaginate<TPromoUsage>>;
|
|
493
|
+
getByPromo: (promo: string | ObjectId) => Promise<TPromoUsage | null>;
|
|
494
|
+
getById: (_id: string | ObjectId) => Promise<TPromoUsage | null>;
|
|
495
|
+
getByOrgId: (orgId: string | ObjectId) => Promise<TPromoUsage[]>;
|
|
496
|
+
countByPromoId: (promoId: string | ObjectId) => Promise<number>;
|
|
497
|
+
updateStatusByOrgId: (orgId: string | ObjectId, status: "active" | "inactive", session?: ClientSession) => Promise<string>;
|
|
498
|
+
deleteById: (_id: string | ObjectId) => Promise<string>;
|
|
499
|
+
};
|
|
500
|
+
|
|
473
501
|
type TRole = {
|
|
474
502
|
_id?: ObjectId;
|
|
475
503
|
id?: string | ObjectId;
|
|
@@ -1255,4 +1283,4 @@ declare const XENDIT_BASE_URL: string;
|
|
|
1255
1283
|
declare const DOMAIN: string;
|
|
1256
1284
|
declare const APP_ORG: string;
|
|
1257
1285
|
|
|
1258
|
-
export { ACCESS_TOKEN_EXPIRY, ACCESS_TOKEN_SECRET, APP_ACCOUNT, APP_MAIN, APP_ORG, DEFAULT_USER_EMAIL, DEFAULT_USER_FIRST_NAME, DEFAULT_USER_LAST_NAME, DEFAULT_USER_PASSWORD, DOMAIN, MAILER_EMAIL, MAILER_PASSWORD, MAILER_TRANSPORT_HOST, MAILER_TRANSPORT_PORT, MAILER_TRANSPORT_SECURE, MBuilding, MBuildingUnit, MFile, MONGO_DB, MONGO_URI, PAYPAL_API_URL, PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PAYPAL_WEBHOOK_ID, PORT, PaypalWebhookHeaders, REDIS_HOST, REDIS_PASSWORD, REDIS_PORT, REFRESH_TOKEN_EXPIRY, REFRESH_TOKEN_SECRET, SECRET_KEY, SPACES_ACCESS_KEY, SPACES_BUCKET, SPACES_ENDPOINT, SPACES_REGION, SPACES_SECRET_KEY, TApp, TBuilding, TBuildingUnit, TCounter, TFile, TJobPost, TLedgerBill, TMember, TOrg, TPermission, TPermissionGroup, TPlan, TPromo, TRole, TSubscribe, TSubscription, TSubscriptionTransaction, TUser, TVerification, TVerificationMetadata, VERIFICATION_FORGET_PASSWORD_DURATION, VERIFICATION_USER_INVITE_DURATION, XENDIT_BASE_URL, XENDIT_SECRET_KEY, currencies, isDev, ledgerBillStatuses, ledgerBillTypes, modelApp, modelJobPost, modelLedgerBill, modelMember, modelOrg, modelPermission, modelPermissionGroup, modelPlan, modelPromo, modelRole, modelSubscription, modelSubscriptionTransaction, modelUser, modelVerification, schemaApp, schemaAppUpdate, schemaBuilding, schemaBuildingUnit, schemaInviteMember, schemaJobPost, schemaJobPostUpdate, schemaLedgerBill, schemaLedgerBillingSummary, schemaMember, schemaMemberRole, schemaMemberStatus, schemaOrg, schemaOrgAdd, schemaOrgUpdate, schemaPermission, schemaPermissionGroup, schemaPermissionGroupUpdate, schemaPermissionUpdate, schemaPlan, schemaPromo, schemaRole, schemaRoleUpdate, schemaSubscribe, schemaSubscription, schemaSubscriptionCompute, schemaSubscriptionPromoCode, schemaSubscriptionSeats, schemaSubscriptionTransaction, schemaSubscriptionUpdate, schemaUpdateOptions, schemaUser, schemaVerification, transactionSchema, useAppController, useAppRepo, useAppService, useAuthController, useAuthService, useBuildingController, useBuildingRepo, useBuildingService, useBuildingUnitController, useBuildingUnitRepo, useBuildingUnitService, useCounterModel, useCounterRepo, useFileController, useFileRepo, useFileService, useGitHubService, useJobPostController, useJobPostRepo, useJobPostService, useLedgerBillingController, useLedgerBillingRepo, useMemberController, useMemberRepo, useOrgController, useOrgRepo, useOrgService, usePaypalService, usePermissionController, usePermissionGroupController, usePermissionGroupRepo, usePermissionGroupService, usePermissionRepo, usePermissionService, usePlanController, usePlanRepo, usePlanService, usePromoController, usePromoRepo, useRoleController, useRoleRepo, useRoleService, useSubscriptionController, useSubscriptionRepo, useSubscriptionService, useSubscriptionTransactionController, useSubscriptionTransactionRepo, useUserController, useUserRepo, useUserService, useUtilController, useVerificationController, useVerificationRepo, useVerificationService };
|
|
1286
|
+
export { ACCESS_TOKEN_EXPIRY, ACCESS_TOKEN_SECRET, APP_ACCOUNT, APP_MAIN, APP_ORG, DEFAULT_USER_EMAIL, DEFAULT_USER_FIRST_NAME, DEFAULT_USER_LAST_NAME, DEFAULT_USER_PASSWORD, DOMAIN, MAILER_EMAIL, MAILER_PASSWORD, MAILER_TRANSPORT_HOST, MAILER_TRANSPORT_PORT, MAILER_TRANSPORT_SECURE, MBuilding, MBuildingUnit, MFile, MONGO_DB, MONGO_URI, PAYPAL_API_URL, PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PAYPAL_WEBHOOK_ID, PORT, PaypalWebhookHeaders, REDIS_HOST, REDIS_PASSWORD, REDIS_PORT, REFRESH_TOKEN_EXPIRY, REFRESH_TOKEN_SECRET, SECRET_KEY, SPACES_ACCESS_KEY, SPACES_BUCKET, SPACES_ENDPOINT, SPACES_REGION, SPACES_SECRET_KEY, TApp, TBuilding, TBuildingUnit, TCounter, TFile, TJobPost, TLedgerBill, TMember, TOrg, TPermission, TPermissionGroup, TPlan, TPromo, TRole, TSubscribe, TSubscription, TSubscriptionTransaction, TUser, TVerification, TVerificationMetadata, VERIFICATION_FORGET_PASSWORD_DURATION, VERIFICATION_USER_INVITE_DURATION, XENDIT_BASE_URL, XENDIT_SECRET_KEY, currencies, isDev, ledgerBillStatuses, ledgerBillTypes, modelApp, modelJobPost, modelLedgerBill, modelMember, modelOrg, modelPermission, modelPermissionGroup, modelPlan, modelPromo, modelRole, modelSubscription, modelSubscriptionTransaction, modelUser, modelVerification, schemaApp, schemaAppUpdate, schemaBuilding, schemaBuildingUnit, schemaInviteMember, schemaJobPost, schemaJobPostUpdate, schemaLedgerBill, schemaLedgerBillingSummary, schemaMember, schemaMemberRole, schemaMemberStatus, schemaOrg, schemaOrgAdd, schemaOrgUpdate, schemaPermission, schemaPermissionGroup, schemaPermissionGroupUpdate, schemaPermissionUpdate, schemaPlan, schemaPromo, schemaRole, schemaRoleUpdate, schemaSubscribe, schemaSubscription, schemaSubscriptionCompute, schemaSubscriptionPromoCode, schemaSubscriptionSeats, schemaSubscriptionTransaction, schemaSubscriptionUpdate, schemaUpdateOptions, schemaUser, schemaVerification, transactionSchema, useAppController, useAppRepo, useAppService, useAuthController, useAuthService, useBuildingController, useBuildingRepo, useBuildingService, useBuildingUnitController, useBuildingUnitRepo, useBuildingUnitService, useCounterModel, useCounterRepo, useFileController, useFileRepo, useFileService, useGitHubService, useJobPostController, useJobPostRepo, useJobPostService, useLedgerBillingController, useLedgerBillingRepo, useMemberController, useMemberRepo, useOrgController, useOrgRepo, useOrgService, usePaypalService, usePermissionController, usePermissionGroupController, usePermissionGroupRepo, usePermissionGroupService, usePermissionRepo, usePermissionService, usePlanController, usePlanRepo, usePlanService, usePromoController, usePromoRepo, usePromoUsageRepo, useRoleController, useRoleRepo, useRoleService, useSubscriptionController, useSubscriptionRepo, useSubscriptionService, useSubscriptionTransactionController, useSubscriptionTransactionRepo, useUserController, useUserRepo, useUserService, useUtilController, useVerificationController, useVerificationRepo, useVerificationService };
|
package/dist/index.js
CHANGED
|
@@ -161,6 +161,7 @@ __export(src_exports, {
|
|
|
161
161
|
usePlanService: () => usePlanService,
|
|
162
162
|
usePromoController: () => usePromoController,
|
|
163
163
|
usePromoRepo: () => usePromoRepo,
|
|
164
|
+
usePromoUsageRepo: () => usePromoUsageRepo,
|
|
164
165
|
useRoleController: () => useRoleController,
|
|
165
166
|
useRoleRepo: () => useRoleRepo,
|
|
166
167
|
useRoleService: () => useRoleService,
|
|
@@ -1269,6 +1270,7 @@ function useMemberRepo() {
|
|
|
1269
1270
|
try {
|
|
1270
1271
|
await collection.createIndexes([
|
|
1271
1272
|
{ key: { name: 1 } },
|
|
1273
|
+
{ key: { user: 1 } },
|
|
1272
1274
|
{ key: { status: 1 } },
|
|
1273
1275
|
{ key: { org: 1 } },
|
|
1274
1276
|
{ key: { name: "text", orgName: "text" }, name: "text_index" },
|
|
@@ -2008,6 +2010,55 @@ function useMemberRepo() {
|
|
|
2008
2010
|
);
|
|
2009
2011
|
}
|
|
2010
2012
|
}
|
|
2013
|
+
async function countUserByOrg(org) {
|
|
2014
|
+
try {
|
|
2015
|
+
org = new import_mongodb7.ObjectId(org);
|
|
2016
|
+
} catch (error) {
|
|
2017
|
+
throw new import_utils7.BadRequestError("Invalid organization ID.");
|
|
2018
|
+
}
|
|
2019
|
+
try {
|
|
2020
|
+
const cacheKey = (0, import_utils7.makeCacheKey)(namespace_collection, {
|
|
2021
|
+
org: String(org),
|
|
2022
|
+
tag: "countUserByOrg"
|
|
2023
|
+
});
|
|
2024
|
+
const cached = await getCache(cacheKey);
|
|
2025
|
+
if (cached) {
|
|
2026
|
+
import_utils7.logger.log({
|
|
2027
|
+
level: "info",
|
|
2028
|
+
message: `Cache hit for countUserByOrg members: ${cacheKey}`
|
|
2029
|
+
});
|
|
2030
|
+
return cached;
|
|
2031
|
+
}
|
|
2032
|
+
const data = await collection.aggregate([
|
|
2033
|
+
{ $match: { org, status: "active" } },
|
|
2034
|
+
{
|
|
2035
|
+
$group: {
|
|
2036
|
+
_id: "$user"
|
|
2037
|
+
}
|
|
2038
|
+
},
|
|
2039
|
+
{
|
|
2040
|
+
$count: "memberCount"
|
|
2041
|
+
}
|
|
2042
|
+
]).toArray();
|
|
2043
|
+
const count = data[0]?.memberCount ?? 0;
|
|
2044
|
+
setCache(cacheKey, count, 300).then(() => {
|
|
2045
|
+
import_utils7.logger.log({
|
|
2046
|
+
level: "info",
|
|
2047
|
+
message: `Cache set for countUserByOrg members: ${cacheKey}`
|
|
2048
|
+
});
|
|
2049
|
+
}).catch((err) => {
|
|
2050
|
+
import_utils7.logger.log({
|
|
2051
|
+
level: "error",
|
|
2052
|
+
message: `Failed to set cache for countUserByOrg members: ${err.message}`
|
|
2053
|
+
});
|
|
2054
|
+
});
|
|
2055
|
+
return count;
|
|
2056
|
+
} catch (error) {
|
|
2057
|
+
throw new import_utils7.InternalServerError(
|
|
2058
|
+
"Internal server error, failed to count users."
|
|
2059
|
+
);
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2011
2062
|
return {
|
|
2012
2063
|
createIndexes,
|
|
2013
2064
|
add,
|
|
@@ -2026,7 +2077,8 @@ function useMemberRepo() {
|
|
|
2026
2077
|
updateRoleById,
|
|
2027
2078
|
updateStatusById,
|
|
2028
2079
|
deleteById,
|
|
2029
|
-
updateStatusByOrg
|
|
2080
|
+
updateStatusByOrg,
|
|
2081
|
+
countUserByOrg
|
|
2030
2082
|
};
|
|
2031
2083
|
}
|
|
2032
2084
|
|
|
@@ -5810,7 +5862,7 @@ function useSubscriptionRepo() {
|
|
|
5810
5862
|
const validation = import_joi21.default.object({
|
|
5811
5863
|
seats: import_joi21.default.number().integer().min(1).optional().allow("", null),
|
|
5812
5864
|
paidSeats: import_joi21.default.number().integer().min(0).optional(),
|
|
5813
|
-
amount: import_joi21.default.number().positive().optional(),
|
|
5865
|
+
amount: import_joi21.default.number().positive().optional().allow(0),
|
|
5814
5866
|
promoCode: import_joi21.default.string().max(50).optional().allow("", null),
|
|
5815
5867
|
status: import_joi21.default.string().valid("active", "due", "overdue", "suspended").optional().allow("", null),
|
|
5816
5868
|
nextBillingDate: import_joi21.default.date().optional().allow("", null)
|
|
@@ -7803,7 +7855,8 @@ var import_mongodb23 = require("mongodb");
|
|
|
7803
7855
|
var schemaPromoUsage = import_joi34.default.object({
|
|
7804
7856
|
promo: import_joi34.default.string().hex().length(24).required(),
|
|
7805
7857
|
org: import_joi34.default.string().hex().length(24).required(),
|
|
7806
|
-
usedBy: import_joi34.default.string().email().required()
|
|
7858
|
+
usedBy: import_joi34.default.string().email().required(),
|
|
7859
|
+
status: import_joi34.default.string().valid("active", "inactive").optional()
|
|
7807
7860
|
});
|
|
7808
7861
|
function modelPromoUsage(value) {
|
|
7809
7862
|
const { error } = schemaPromoUsage.validate(value);
|
|
@@ -7817,14 +7870,14 @@ function modelPromoUsage(value) {
|
|
|
7817
7870
|
throw new import_utils40.BadRequestError("Invalid Promo Usage _id");
|
|
7818
7871
|
}
|
|
7819
7872
|
}
|
|
7820
|
-
if (typeof value.promo === "string") {
|
|
7873
|
+
if (value.promo && typeof value.promo === "string") {
|
|
7821
7874
|
try {
|
|
7822
7875
|
value.promo = new import_mongodb23.ObjectId(value.promo);
|
|
7823
7876
|
} catch (error2) {
|
|
7824
7877
|
throw new import_utils40.BadRequestError("Invalid Promo Usage promo");
|
|
7825
7878
|
}
|
|
7826
7879
|
}
|
|
7827
|
-
if (typeof value.org === "string") {
|
|
7880
|
+
if (value.org && typeof value.org === "string") {
|
|
7828
7881
|
try {
|
|
7829
7882
|
value.org = new import_mongodb23.ObjectId(value.org);
|
|
7830
7883
|
} catch (error2) {
|
|
@@ -7836,6 +7889,7 @@ function modelPromoUsage(value) {
|
|
|
7836
7889
|
promo: value.promo,
|
|
7837
7890
|
org: value.org,
|
|
7838
7891
|
usedBy: value.usedBy,
|
|
7892
|
+
status: value.status ?? "active",
|
|
7839
7893
|
createdAt: value.createdAt ? new Date(value.createdAt) : /* @__PURE__ */ new Date(),
|
|
7840
7894
|
updatedAt: value.updatedAt ?? ""
|
|
7841
7895
|
};
|
|
@@ -7868,6 +7922,9 @@ function usePromoUsageRepo() {
|
|
|
7868
7922
|
async function createIndexes() {
|
|
7869
7923
|
try {
|
|
7870
7924
|
await collection.createIndexes([
|
|
7925
|
+
{
|
|
7926
|
+
key: { status: 1 }
|
|
7927
|
+
},
|
|
7871
7928
|
{
|
|
7872
7929
|
key: { promo: 1, org: 1 },
|
|
7873
7930
|
name: "promo_org_index"
|
|
@@ -7880,10 +7937,10 @@ function usePromoUsageRepo() {
|
|
|
7880
7937
|
} catch (error) {
|
|
7881
7938
|
}
|
|
7882
7939
|
}
|
|
7883
|
-
async function add(value) {
|
|
7940
|
+
async function add(value, session) {
|
|
7884
7941
|
try {
|
|
7885
7942
|
value = modelPromoUsage(value);
|
|
7886
|
-
await collection.insertOne(value);
|
|
7943
|
+
await collection.insertOne(value, { session });
|
|
7887
7944
|
delCachedData();
|
|
7888
7945
|
return "Successfully added promo usage.";
|
|
7889
7946
|
} catch (error) {
|
|
@@ -8075,7 +8132,10 @@ function usePromoUsageRepo() {
|
|
|
8075
8132
|
if (cachedData !== null && cachedData !== void 0) {
|
|
8076
8133
|
return cachedData;
|
|
8077
8134
|
}
|
|
8078
|
-
const count = await collection.countDocuments({
|
|
8135
|
+
const count = await collection.countDocuments({
|
|
8136
|
+
promo: promoId,
|
|
8137
|
+
status: "active"
|
|
8138
|
+
});
|
|
8079
8139
|
setCache(cacheKey, count).then(() => {
|
|
8080
8140
|
import_utils41.logger.log({
|
|
8081
8141
|
level: "info",
|
|
@@ -8092,6 +8152,28 @@ function usePromoUsageRepo() {
|
|
|
8092
8152
|
throw new import_utils41.InternalServerError("Failed to count promo usages.");
|
|
8093
8153
|
}
|
|
8094
8154
|
}
|
|
8155
|
+
async function updateStatusByOrgId(orgId, status, session) {
|
|
8156
|
+
const { error } = import_joi35.default.string().hex().length(24).required().validate(orgId);
|
|
8157
|
+
if (error) {
|
|
8158
|
+
throw new import_utils41.BadRequestError(`Invalid org ID: ${error.message}`);
|
|
8159
|
+
}
|
|
8160
|
+
try {
|
|
8161
|
+
orgId = new import_mongodb24.ObjectId(orgId);
|
|
8162
|
+
} catch (error2) {
|
|
8163
|
+
throw new import_utils41.BadRequestError("Invalid org ID.");
|
|
8164
|
+
}
|
|
8165
|
+
try {
|
|
8166
|
+
await collection.updateMany(
|
|
8167
|
+
{ org: orgId, status: "active" },
|
|
8168
|
+
{ $set: { status, updatedAt: /* @__PURE__ */ new Date() } },
|
|
8169
|
+
{ session }
|
|
8170
|
+
);
|
|
8171
|
+
delCachedData();
|
|
8172
|
+
return "Successfully updated promo usage status.";
|
|
8173
|
+
} catch (error2) {
|
|
8174
|
+
throw new import_utils41.InternalServerError("Failed to update promo usage status.");
|
|
8175
|
+
}
|
|
8176
|
+
}
|
|
8095
8177
|
async function deleteById(_id) {
|
|
8096
8178
|
const { error } = import_joi35.default.string().hex().length(24).required().validate(_id);
|
|
8097
8179
|
if (error) {
|
|
@@ -8124,6 +8206,7 @@ function usePromoUsageRepo() {
|
|
|
8124
8206
|
getById,
|
|
8125
8207
|
getByOrgId,
|
|
8126
8208
|
countByPromoId,
|
|
8209
|
+
updateStatusByOrgId,
|
|
8127
8210
|
deleteById
|
|
8128
8211
|
};
|
|
8129
8212
|
}
|
|
@@ -8300,6 +8383,11 @@ function useSubscriptionService() {
|
|
|
8300
8383
|
const { getDefault: getDefaultPlan, getById: getPlanById } = usePlanRepo();
|
|
8301
8384
|
const { getById: getOrgById, updateStatusById: updateOrgStatusById } = useOrgRepo();
|
|
8302
8385
|
const { getByCode: getPromoByCode } = usePromoRepo();
|
|
8386
|
+
const {
|
|
8387
|
+
countByPromoId,
|
|
8388
|
+
add: addPromoUsage,
|
|
8389
|
+
updateStatusByOrgId: updatePromoUsageStatusByOrgId
|
|
8390
|
+
} = usePromoUsageRepo();
|
|
8303
8391
|
const { getByApp: getMembershipByApp } = useMemberRepo();
|
|
8304
8392
|
function calculateVolumeTierAmount(tiers, startSeat, seatCount, fallbackRate) {
|
|
8305
8393
|
const sortedTiers = [...tiers].sort((a, b) => a.minSeats - b.minSeats);
|
|
@@ -8350,16 +8438,33 @@ function useSubscriptionService() {
|
|
|
8350
8438
|
if (!promo) {
|
|
8351
8439
|
throw new import_utils44.BadRequestError("Promo code not found.");
|
|
8352
8440
|
}
|
|
8441
|
+
if (promo.usage && promo.usage > 0) {
|
|
8442
|
+
const currentUsageCount = await countByPromoId(
|
|
8443
|
+
promo._id?.toString() ?? ""
|
|
8444
|
+
);
|
|
8445
|
+
const isAlreadyUsingPromo = existingSubscription?.promoCode === promoCode;
|
|
8446
|
+
if (!isAlreadyUsingPromo && currentUsageCount >= promo.usage) {
|
|
8447
|
+
throw new import_utils44.BadRequestError(
|
|
8448
|
+
"Promo code has reached its maximum usage limit."
|
|
8449
|
+
);
|
|
8450
|
+
}
|
|
8451
|
+
}
|
|
8353
8452
|
}
|
|
8354
8453
|
let monthlyAmount = plan.price * value.seats;
|
|
8355
8454
|
if (promo) {
|
|
8455
|
+
const promoSeatLimit = promo.seats && promo.seats > 0 ? promo.seats : Infinity;
|
|
8356
8456
|
switch (promo.type) {
|
|
8357
|
-
case "fixed":
|
|
8358
|
-
|
|
8457
|
+
case "fixed": {
|
|
8458
|
+
const promoSeats = Math.min(value.seats, promoSeatLimit);
|
|
8459
|
+
const standardSeats = Math.max(value.seats - promoSeatLimit, 0);
|
|
8460
|
+
monthlyAmount = Math.max(promo.fixedRate ?? 0, 0) * promoSeats + plan.price * standardSeats;
|
|
8359
8461
|
break;
|
|
8360
|
-
|
|
8361
|
-
|
|
8462
|
+
}
|
|
8463
|
+
case "flat": {
|
|
8464
|
+
const standardSeats = Math.max(value.seats - promoSeatLimit, 0);
|
|
8465
|
+
monthlyAmount = (promo.flatRate ?? 0) + plan.price * standardSeats;
|
|
8362
8466
|
break;
|
|
8467
|
+
}
|
|
8363
8468
|
case "volume": {
|
|
8364
8469
|
if (promo.tiers && promo.tiers.length > 0) {
|
|
8365
8470
|
monthlyAmount = calculateVolumeTierAmount(
|
|
@@ -8402,17 +8507,32 @@ function useSubscriptionService() {
|
|
|
8402
8507
|
plan.price
|
|
8403
8508
|
);
|
|
8404
8509
|
} else if (promo?.type === "fixed") {
|
|
8405
|
-
const
|
|
8406
|
-
|
|
8407
|
-
|
|
8510
|
+
const promoSeatLimit = promo.seats && promo.seats > 0 ? promo.seats : Infinity;
|
|
8511
|
+
const startSeat = existingSubscription.paidSeats + 1;
|
|
8512
|
+
const endSeat = value.seats;
|
|
8513
|
+
const promoSeatsInRange = Math.max(
|
|
8514
|
+
0,
|
|
8515
|
+
Math.min(promoSeatLimit, endSeat) - startSeat + 1
|
|
8408
8516
|
);
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
plan.price - (promo.flatRate ?? 0) / value.seats,
|
|
8413
|
-
0
|
|
8517
|
+
const standardSeatsInRange = Math.max(
|
|
8518
|
+
0,
|
|
8519
|
+
additionalSeats - promoSeatsInRange
|
|
8414
8520
|
);
|
|
8415
|
-
additionalSeatsAmount =
|
|
8521
|
+
additionalSeatsAmount = (promo.fixedRate ?? 0) * promoSeatsInRange + plan.price * standardSeatsInRange;
|
|
8522
|
+
} else if (promo?.type === "flat") {
|
|
8523
|
+
const promoSeatLimit = promo.seats && promo.seats > 0 ? promo.seats : Infinity;
|
|
8524
|
+
const startSeat = existingSubscription.paidSeats + 1;
|
|
8525
|
+
const endSeat = value.seats;
|
|
8526
|
+
if (startSeat > promoSeatLimit) {
|
|
8527
|
+
additionalSeatsAmount = plan.price * additionalSeats;
|
|
8528
|
+
} else {
|
|
8529
|
+
const seatsStillCoveredByFlat = Math.max(
|
|
8530
|
+
0,
|
|
8531
|
+
Math.min(promoSeatLimit, endSeat) - startSeat + 1
|
|
8532
|
+
);
|
|
8533
|
+
const seatsAtPlanPrice = additionalSeats - seatsStillCoveredByFlat;
|
|
8534
|
+
additionalSeatsAmount = plan.price * seatsAtPlanPrice;
|
|
8535
|
+
}
|
|
8416
8536
|
} else {
|
|
8417
8537
|
additionalSeatsAmount = plan.price * additionalSeats;
|
|
8418
8538
|
}
|
|
@@ -8420,8 +8540,6 @@ function useSubscriptionService() {
|
|
|
8420
8540
|
proratedAmount = dailyRate * daysRemaining;
|
|
8421
8541
|
}
|
|
8422
8542
|
}
|
|
8423
|
-
const isDecrease = existingSubscription && value.seats < existingSubscription.paidSeats;
|
|
8424
|
-
const isNoChange = existingSubscription && value.seats === existingSubscription.paidSeats;
|
|
8425
8543
|
const isIncrease = existingSubscription && value.seats > existingSubscription.paidSeats;
|
|
8426
8544
|
let subscriptionAmount;
|
|
8427
8545
|
if (!existingSubscription) {
|
|
@@ -8486,6 +8604,13 @@ function useSubscriptionService() {
|
|
|
8486
8604
|
org: value.org,
|
|
8487
8605
|
plan: value.plan
|
|
8488
8606
|
});
|
|
8607
|
+
let promo = null;
|
|
8608
|
+
if (value.promoCode) {
|
|
8609
|
+
promo = await getPromoByCode(value.promoCode);
|
|
8610
|
+
if (!promo) {
|
|
8611
|
+
throw new import_utils44.BadRequestError("Promo code not found.");
|
|
8612
|
+
}
|
|
8613
|
+
}
|
|
8489
8614
|
const subId = await _add(
|
|
8490
8615
|
{
|
|
8491
8616
|
org: value.org,
|
|
@@ -8501,6 +8626,16 @@ function useSubscriptionService() {
|
|
|
8501
8626
|
},
|
|
8502
8627
|
session
|
|
8503
8628
|
);
|
|
8629
|
+
if (promo && promo._id) {
|
|
8630
|
+
await addPromoUsage(
|
|
8631
|
+
{
|
|
8632
|
+
promo: promo._id,
|
|
8633
|
+
org: value.org,
|
|
8634
|
+
usedBy: userData.email
|
|
8635
|
+
},
|
|
8636
|
+
session
|
|
8637
|
+
);
|
|
8638
|
+
}
|
|
8504
8639
|
await addTransaction(
|
|
8505
8640
|
{
|
|
8506
8641
|
type: "initiate",
|
|
@@ -8657,6 +8792,19 @@ function useSubscriptionService() {
|
|
|
8657
8792
|
{ promoCode: value.promoCode ?? "", amount: subscriptionAmount },
|
|
8658
8793
|
session
|
|
8659
8794
|
);
|
|
8795
|
+
if (subscription.promoCode) {
|
|
8796
|
+
await updatePromoUsageStatusByOrgId(value.org, "inactive", session);
|
|
8797
|
+
}
|
|
8798
|
+
if (promo && promo._id) {
|
|
8799
|
+
await addPromoUsage(
|
|
8800
|
+
{
|
|
8801
|
+
promo: promo._id,
|
|
8802
|
+
org: value.org,
|
|
8803
|
+
usedBy: userData.email
|
|
8804
|
+
},
|
|
8805
|
+
session
|
|
8806
|
+
);
|
|
8807
|
+
}
|
|
8660
8808
|
await addTransaction(
|
|
8661
8809
|
{
|
|
8662
8810
|
type: "promo-updated",
|
|
@@ -10435,7 +10583,7 @@ function useVerificationService() {
|
|
|
10435
10583
|
getVerifications: _getVerifications
|
|
10436
10584
|
} = useVerificationRepo();
|
|
10437
10585
|
const { getUserByEmail } = useUserRepo();
|
|
10438
|
-
const { add: addMember } = useMemberRepo();
|
|
10586
|
+
const { add: addMember, countUserByOrg } = useMemberRepo();
|
|
10439
10587
|
const { getById: getOrgById } = useOrgRepo();
|
|
10440
10588
|
const { getById: getRoleById } = useRoleRepo();
|
|
10441
10589
|
async function createUserInvite({
|
|
@@ -10734,6 +10882,7 @@ function useVerificationService() {
|
|
|
10734
10882
|
}
|
|
10735
10883
|
}
|
|
10736
10884
|
const { getByOrg } = useSubscriptionRepo();
|
|
10885
|
+
const { getByCode: getPromoByCode } = usePromoRepo();
|
|
10737
10886
|
async function inviteMember(value) {
|
|
10738
10887
|
const { error } = schemaInviteMember.validate(value);
|
|
10739
10888
|
if (error) {
|
|
@@ -10755,6 +10904,23 @@ function useVerificationService() {
|
|
|
10755
10904
|
"Organization does not have an active subscription."
|
|
10756
10905
|
);
|
|
10757
10906
|
}
|
|
10907
|
+
if (subscription.promoCode) {
|
|
10908
|
+
const promo = await getPromoByCode(subscription.promoCode);
|
|
10909
|
+
if (!promo) {
|
|
10910
|
+
throw new import_utils53.BadRequestError("Promo code not found.");
|
|
10911
|
+
}
|
|
10912
|
+
if (promo.apps && promo.apps.length && !promo.apps.includes(value.app)) {
|
|
10913
|
+
throw new import_utils53.BadRequestError(
|
|
10914
|
+
"Promo code is not valid for the specified app."
|
|
10915
|
+
);
|
|
10916
|
+
}
|
|
10917
|
+
}
|
|
10918
|
+
const memberCount = await countUserByOrg(String(value.org));
|
|
10919
|
+
if (subscription.seats <= memberCount) {
|
|
10920
|
+
throw new import_utils53.BadRequestError(
|
|
10921
|
+
"Organization has reached the maximum number of members for its subscription plan."
|
|
10922
|
+
);
|
|
10923
|
+
}
|
|
10758
10924
|
}
|
|
10759
10925
|
let verificationData = {
|
|
10760
10926
|
type: "user-invite",
|
|
@@ -13540,6 +13706,7 @@ function useJobPostController() {
|
|
|
13540
13706
|
usePlanService,
|
|
13541
13707
|
usePromoController,
|
|
13542
13708
|
usePromoRepo,
|
|
13709
|
+
usePromoUsageRepo,
|
|
13543
13710
|
useRoleController,
|
|
13544
13711
|
useRoleRepo,
|
|
13545
13712
|
useRoleService,
|