feat: implement sysadmin subscription management and plan usage cycle recalculation tools
This commit is contained in:
@@ -5,6 +5,7 @@ import wapRoutes from "./routes/wap.routes";
|
||||
import usersRoutes from "./routes/users.routes";
|
||||
import companiesRoutes from "./routes/companies.routes";
|
||||
import servicesRoutes from "./routes/services.routes";
|
||||
import plansRoutes from "./routes/plans.routes";
|
||||
|
||||
const app = express();
|
||||
|
||||
@@ -16,5 +17,6 @@ app.use("/wap", wapRoutes);
|
||||
app.use("/users", usersRoutes);
|
||||
app.use("/companies", companiesRoutes);
|
||||
app.use("/services", servicesRoutes);
|
||||
app.use("/plans", plansRoutes);
|
||||
|
||||
export default app;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Request, Response } from "express";
|
||||
import { PlansService } from "../services/plans.service";
|
||||
import { SysAdminUpdatePlanParams } from "../models/Plans.Model";
|
||||
|
||||
const plansService = new PlansService();
|
||||
|
||||
export class PlansController {
|
||||
public listPlans = async (_req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const plans = await plansService.listPlans();
|
||||
res.json(plans);
|
||||
} catch (error: any) {
|
||||
console.error("Error listing plans:", error?.response?.data || error);
|
||||
res.status(500).json(error?.response?.data || { success: false, message: "Internal Server Error" });
|
||||
}
|
||||
};
|
||||
|
||||
public updatePlan = async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const data: SysAdminUpdatePlanParams = req.body;
|
||||
const result = await plansService.updatePlan(data);
|
||||
res.json(result);
|
||||
} catch (error: any) {
|
||||
console.error("Error updating plan:", error?.response?.data || error);
|
||||
res.status(500).json(error?.response?.data || { success: false, message: "Internal Server Error" });
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -6,6 +6,9 @@ import {
|
||||
SysAdminSetVerifiedParams,
|
||||
SysAdminDeleteUserParams,
|
||||
SysAdminOrganizationsStatusParams,
|
||||
SysAdminRecalculatePlanUsageCycleParams,
|
||||
SysAdminExtendUserSubscriptionParams,
|
||||
SysAdminUserSubscriptionDetailsParams,
|
||||
} from "../models/Users.Model";
|
||||
|
||||
const usersService = new UsersService();
|
||||
@@ -65,4 +68,37 @@ export class UsersController {
|
||||
res.status(500).json(error?.response?.data || { success: false, message: "Internal Server Error" });
|
||||
}
|
||||
};
|
||||
|
||||
public recalculatePlanUsageCycle = async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const data: SysAdminRecalculatePlanUsageCycleParams = req.body;
|
||||
const result = await usersService.recalculatePlanUsageCycle(data);
|
||||
res.json(result);
|
||||
} catch (error: any) {
|
||||
console.error("Error recalculating plan usage cycle:", error?.response?.data || error);
|
||||
res.status(500).json(error?.response?.data || { success: false, message: "Internal Server Error" });
|
||||
}
|
||||
};
|
||||
|
||||
public subscriptionDetails = async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const data: SysAdminUserSubscriptionDetailsParams = req.body;
|
||||
const result = await usersService.getSubscriptionDetails(data);
|
||||
res.json(result);
|
||||
} catch (error: any) {
|
||||
console.error("Error fetching subscription details:", error?.response?.data || error);
|
||||
res.status(500).json(error?.response?.data || { success: false, message: "Internal Server Error" });
|
||||
}
|
||||
};
|
||||
|
||||
public extendSubscription = async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const data: SysAdminExtendUserSubscriptionParams = req.body;
|
||||
const result = await usersService.extendSubscription(data);
|
||||
res.json(result);
|
||||
} catch (error: any) {
|
||||
console.error("Error extending subscription:", error?.response?.data || error);
|
||||
res.status(500).json(error?.response?.data || { success: false, message: "Internal Server Error" });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
export type SysAdminPlan = {
|
||||
id?: string;
|
||||
_id?: string;
|
||||
name: string;
|
||||
description: string;
|
||||
features: string[];
|
||||
code: string;
|
||||
price: number;
|
||||
annualPrice: number;
|
||||
limitOrganizations: number;
|
||||
limitEmployees: number;
|
||||
limitServices: number;
|
||||
limitAppointments: number;
|
||||
limitClients: number;
|
||||
limitRepeats: number;
|
||||
mailNotifications: boolean;
|
||||
smsNotifications: boolean;
|
||||
wapNotifications: boolean;
|
||||
payments: boolean;
|
||||
bot: boolean;
|
||||
active: boolean;
|
||||
dateLimit: boolean;
|
||||
discount3Months?: number;
|
||||
discount6Months?: number;
|
||||
discount12Months?: number;
|
||||
featured?: boolean;
|
||||
};
|
||||
|
||||
export type SysAdminUpdatePlanParams = Partial<Omit<SysAdminPlan, "id" | "_id">> & {
|
||||
planId: string;
|
||||
};
|
||||
@@ -52,3 +52,67 @@ export type SysAdminUserOrganizationsResult = {
|
||||
clientIn: { companyId: string; companyName: string }[];
|
||||
collaboratorIn: { companyId: string; companyName: string }[];
|
||||
};
|
||||
|
||||
export type SysAdminRecalculatePlanUsageCycleParams = {
|
||||
userId: string;
|
||||
};
|
||||
|
||||
export type SysAdminRecalculatePlanUsageCycleResult = {
|
||||
userId: string;
|
||||
subscriptionId: string;
|
||||
planId: string;
|
||||
cycleStart: string;
|
||||
cycleEnd: string;
|
||||
appointmentsCount: number;
|
||||
};
|
||||
|
||||
export type SysAdminUserSubscriptionDetailsParams = {
|
||||
userId: string;
|
||||
};
|
||||
|
||||
export type SysAdminExtendUserSubscriptionParams = {
|
||||
userId: string;
|
||||
mode: "add_months" | "set_end_date";
|
||||
months?: 1 | 2;
|
||||
endDate?: string;
|
||||
reason?: string;
|
||||
};
|
||||
|
||||
export type SysAdminExtendUserSubscriptionResult = {
|
||||
userId: string;
|
||||
subscriptionId: string;
|
||||
previousEndDate: string;
|
||||
newEndDate: string;
|
||||
paymentId: string;
|
||||
transactionId?: string;
|
||||
};
|
||||
|
||||
export type SysAdminUserSubscriptionDetailsResult = {
|
||||
userId: string;
|
||||
currentSubscription: {
|
||||
id: string;
|
||||
plan: {
|
||||
id: string;
|
||||
name: string;
|
||||
code: string;
|
||||
price: number;
|
||||
} | null;
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
isActive: boolean;
|
||||
mpStatus?: string;
|
||||
billingMonths?: number;
|
||||
pendingPaymentType?: "extension" | "upgrade";
|
||||
pendingPaymentPreferenceId?: string;
|
||||
lastPaymentStatus?: string;
|
||||
} | null;
|
||||
payments: {
|
||||
id: string;
|
||||
subscriptionId: string;
|
||||
amount: number;
|
||||
paymentDate: string;
|
||||
paymentMethod?: string;
|
||||
status: string;
|
||||
transactionId?: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Router } from "express";
|
||||
import { PlansController } from "../controllers/plans.controller";
|
||||
|
||||
const router = Router();
|
||||
const plansController = new PlansController();
|
||||
|
||||
router.post("/list", plansController.listPlans);
|
||||
router.post("/update", plansController.updatePlan);
|
||||
|
||||
export default router;
|
||||
@@ -8,6 +8,9 @@ router.post("/paginate", usersController.paginateUsers);
|
||||
router.post("/update", usersController.updateProfile);
|
||||
router.post("/set-verified", usersController.setVerifiedStatus);
|
||||
router.post("/organizations-status", usersController.organizationsStatus);
|
||||
router.post("/recalculate-plan-usage-cycle", usersController.recalculatePlanUsageCycle);
|
||||
router.post("/subscription-details", usersController.subscriptionDetails);
|
||||
router.post("/extend-subscription", usersController.extendSubscription);
|
||||
router.post("/delete", usersController.deleteUser);
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import axios from "axios";
|
||||
import { getSysAdminNonce } from "../helpers/GetSysAdminNonce";
|
||||
import { getApiHost } from "../helpers/GetApiHost";
|
||||
import { getPayload } from "../helpers/GetPayload";
|
||||
import { SysAdminPlan, SysAdminUpdatePlanParams } from "../models/Plans.Model";
|
||||
|
||||
export class PlansService {
|
||||
public async listPlans(): Promise<SysAdminPlan[]> {
|
||||
const nonce = await getSysAdminNonce();
|
||||
const postData = { payload: getPayload(nonce) };
|
||||
|
||||
const response = await axios.post(`${getApiHost()}/sysadmin/plans/list`, postData, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
timeout: 5000,
|
||||
});
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async updatePlan(data: SysAdminUpdatePlanParams): Promise<any> {
|
||||
const nonce = await getSysAdminNonce();
|
||||
const postData = { ...data, payload: getPayload(nonce) };
|
||||
|
||||
const response = await axios.post(`${getApiHost()}/sysadmin/plans/update`, postData, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
timeout: 5000,
|
||||
});
|
||||
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,12 @@ import {
|
||||
SysAdminDeleteUserParams,
|
||||
SysAdminOrganizationsStatusParams,
|
||||
SysAdminUserOrganizationsResult,
|
||||
SysAdminRecalculatePlanUsageCycleParams,
|
||||
SysAdminRecalculatePlanUsageCycleResult,
|
||||
SysAdminExtendUserSubscriptionParams,
|
||||
SysAdminExtendUserSubscriptionResult,
|
||||
SysAdminUserSubscriptionDetailsParams,
|
||||
SysAdminUserSubscriptionDetailsResult,
|
||||
} from "../models/Users.Model";
|
||||
|
||||
export class UsersService {
|
||||
@@ -72,4 +78,46 @@ export class UsersService {
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async recalculatePlanUsageCycle(
|
||||
data: SysAdminRecalculatePlanUsageCycleParams
|
||||
): Promise<SysAdminRecalculatePlanUsageCycleResult> {
|
||||
const nonce = await getSysAdminNonce();
|
||||
const postData = { ...data, ...{ payload: getPayload(nonce) } };
|
||||
|
||||
const response = await axios.post(`${getApiHost()}/sysadmin/plan-usage-cycle/recalculate-user`, postData, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async getSubscriptionDetails(
|
||||
data: SysAdminUserSubscriptionDetailsParams
|
||||
): Promise<SysAdminUserSubscriptionDetailsResult> {
|
||||
const nonce = await getSysAdminNonce();
|
||||
const postData = { ...data, ...{ payload: getPayload(nonce) } };
|
||||
|
||||
const response = await axios.post(`${getApiHost()}/sysadmin/subscriptions/user-details`, postData, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async extendSubscription(
|
||||
data: SysAdminExtendUserSubscriptionParams
|
||||
): Promise<SysAdminExtendUserSubscriptionResult> {
|
||||
const nonce = await getSysAdminNonce();
|
||||
const postData = { ...data, ...{ payload: getPayload(nonce) } };
|
||||
|
||||
const response = await axios.post(`${getApiHost()}/sysadmin/subscriptions/extend-user`, postData, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user