feat: implement comprehensive notification engine with policies, preferences, and automated dispatching services
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
ChangeEmployeeToOwnerParams,
|
||||
CountAppointmentsByMonthParams,
|
||||
CreateAppointmentParams,
|
||||
CreateImmediateAppointmentNotificationJobsParams,
|
||||
DeleteAppointmentDiscountParams,
|
||||
DeleteAppointmentParams,
|
||||
DeleteAppointmentsByCompanyParams,
|
||||
@@ -76,6 +77,7 @@ import SchedulesDisabledList from "../SchedulesDisabled/SchedulesDisabled";
|
||||
import DiscountsEmail from "../DiscountsEmail/DiscountsEmail";
|
||||
import SchedulesOverridesList from "../SchedulesOverrides/SchedulesOverrides";
|
||||
import { NotificationType } from "../../Models/SystemNotifications/SystemNotification.Interface";
|
||||
import { NotificationJobService } from "../NotificationPolicies/NotificationJobService";
|
||||
|
||||
dayjs.locale("es");
|
||||
dayjs.extend(isSameOrAfter);
|
||||
@@ -84,9 +86,11 @@ dayjs.extend(weekday);
|
||||
|
||||
class AppointmentManager implements IAppointmentsManager {
|
||||
Appointments: AppointmentsAdapterMongoose;
|
||||
private jobService: NotificationJobService;
|
||||
|
||||
constructor() {
|
||||
this.Appointments = new AppointmentsAdapterMongoose();
|
||||
this.jobService = new NotificationJobService();
|
||||
}
|
||||
|
||||
private isScheduleAvailableForService(schedule: ScheduleItem, serviceId?: string): boolean {
|
||||
@@ -526,36 +530,35 @@ class AppointmentManager implements IAppointmentsManager {
|
||||
code: String((newAppointment as any)._id)
|
||||
});
|
||||
|
||||
//Intento enviar notificacion al cliente por Email
|
||||
try {
|
||||
if (newAppointment.id) {
|
||||
await this.sendEmailNotification({
|
||||
appointmentId: String(newAppointment.id),
|
||||
type: APPOINTMENT_NOTIFICATION_TYPE.CREATION,
|
||||
sessionUser: String(companyCheck.ownerId),
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(
|
||||
`Error al enviar la notificacion por Email para ${companyCheck.name}(${companyCheck._id}):`,
|
||||
err
|
||||
);
|
||||
}
|
||||
//Create jobs for email and whatsapp notifications
|
||||
if (newAppointment.id) {
|
||||
const emailContent = await this.tryToSendNotification({
|
||||
appointmentId: String(newAppointment.id),
|
||||
sessionUser: String(companyCheck.ownerId),
|
||||
type: APPOINTMENT_NOTIFICATION_TYPE.CREATION,
|
||||
channel: "email",
|
||||
});
|
||||
const wapContent = await this.tryToSendNotification({
|
||||
appointmentId: String(newAppointment.id),
|
||||
sessionUser: String(companyCheck.ownerId),
|
||||
type: APPOINTMENT_NOTIFICATION_TYPE.CREATION,
|
||||
channel: "whatsapp",
|
||||
});
|
||||
const clientPhoneNumber = await this.getOptionalClientWapNumber(checkClient);
|
||||
|
||||
//Intento enviar notificacion al cliente por Whatsapp
|
||||
try {
|
||||
if (newAppointment.id) {
|
||||
await this.sendWapNotification({
|
||||
appointmentId: String(newAppointment.id),
|
||||
type: APPOINTMENT_NOTIFICATION_TYPE.CREATION,
|
||||
sessionUser: String(companyCheck.ownerId),
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(
|
||||
`Error al enviar la notificacion por Whatsapp para ${companyCheck.name}(${companyCheck._id}):`,
|
||||
err
|
||||
);
|
||||
await this.createCreationNotificationJobs({
|
||||
appointmentId: String(newAppointment.id),
|
||||
companyId: String(companyCheck._id),
|
||||
clientId: String(checkClient._id),
|
||||
clientUserId: checkClient.userId ? String(checkClient.userId) : undefined,
|
||||
clientEmail: checkClient.email,
|
||||
clientPhoneNumber,
|
||||
companyOwnerId: String(companyCheck.ownerId),
|
||||
companyName: companyCheck.name,
|
||||
appointmentStart: new Date(data.start),
|
||||
emailMessage: emailContent.message,
|
||||
wapMessage: wapContent.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2070,36 +2073,18 @@ public async updateAppointment(data: UpdateAppointmentParams): Promise<void> {
|
||||
code: String(checkAppointment._id)
|
||||
});
|
||||
|
||||
//Intento enviar notificacion al cliente por Email
|
||||
try {
|
||||
if (checkAppointment.id) {
|
||||
await this.sendEmailNotification({
|
||||
appointmentId: String(checkAppointment.id),
|
||||
type: APPOINTMENT_NOTIFICATION_TYPE.REMINDER,
|
||||
sessionUser: String(companyCheck.ownerId),
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(
|
||||
`Error al enviar la notificacion por Email para ${companyCheck.name}(${companyCheck._id}):`,
|
||||
err
|
||||
);
|
||||
}
|
||||
//Cancel existing pending jobs before creating new ones for the rescheduled appointment
|
||||
if (checkAppointment.id) {
|
||||
await this.jobService.cancelByAppointment(String(checkAppointment.id));
|
||||
|
||||
//Intento enviar notificacion al cliente por Whatsapp
|
||||
try {
|
||||
if (checkAppointment.id) {
|
||||
await this.sendWapNotification({
|
||||
appointmentId: String(checkAppointment.id),
|
||||
type: APPOINTMENT_NOTIFICATION_TYPE.REMINDER,
|
||||
sessionUser: String(companyCheck.ownerId),
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(
|
||||
`Error al enviar la notificacion por Whatsapp para ${companyCheck.name}(${companyCheck._id}):`,
|
||||
err
|
||||
);
|
||||
//Create jobs for email and whatsapp notifications
|
||||
await this.jobService.createJob({
|
||||
companyId: String(companyCheck._id),
|
||||
clientId: String(checkClient._id),
|
||||
appointmentId: String(checkAppointment.id),
|
||||
type: "update" as const,
|
||||
appointmentStart: new Date(data.start),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2155,8 +2140,89 @@ public async updateAppointment(data: UpdateAppointmentParams): Promise<void> {
|
||||
return config;
|
||||
}
|
||||
|
||||
private async createCancellationNotificationJobs(data: {
|
||||
appointmentId: string;
|
||||
companyId: string;
|
||||
clientId: string;
|
||||
clientUserId?: string;
|
||||
clientEmail?: string;
|
||||
clientPhoneNumber?: string;
|
||||
companyOwnerId: string;
|
||||
companyName: string;
|
||||
emailMessage: string;
|
||||
wapMessage: string;
|
||||
}): Promise<void> {
|
||||
const systemSubject = `Turno cancelado en ${data.companyName}`;
|
||||
|
||||
await this.jobService.createJob({
|
||||
companyId: data.companyId,
|
||||
clientId: data.clientId,
|
||||
appointmentId: data.appointmentId,
|
||||
type: "cancellation",
|
||||
scheduledAt: new Date(),
|
||||
payload: {
|
||||
email: data.clientEmail,
|
||||
phoneNumber: data.clientPhoneNumber,
|
||||
userId: data.clientUserId,
|
||||
companyOwnerId: data.companyOwnerId,
|
||||
subject: systemSubject,
|
||||
message: data.emailMessage,
|
||||
emailSubject: "TurnosXpress :: Turno cancelado",
|
||||
emailMessage: data.emailMessage,
|
||||
wapMessage: data.wapMessage,
|
||||
systemSubject,
|
||||
systemMessage: data.emailMessage,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private async createCreationNotificationJobs(data: {
|
||||
appointmentId: string;
|
||||
companyId: string;
|
||||
clientId: string;
|
||||
clientUserId?: string;
|
||||
clientEmail?: string;
|
||||
clientPhoneNumber?: string;
|
||||
companyOwnerId: string;
|
||||
companyName: string;
|
||||
appointmentStart: Date;
|
||||
emailMessage: string;
|
||||
wapMessage: string;
|
||||
}): Promise<void> {
|
||||
const systemSubject = `Turno reservado en ${data.companyName}`;
|
||||
|
||||
await this.jobService.createJob({
|
||||
companyId: data.companyId,
|
||||
clientId: data.clientId,
|
||||
appointmentId: data.appointmentId,
|
||||
type: "creation",
|
||||
appointmentStart: data.appointmentStart,
|
||||
payload: {
|
||||
email: data.clientEmail,
|
||||
phoneNumber: data.clientPhoneNumber,
|
||||
userId: data.clientUserId,
|
||||
companyOwnerId: data.companyOwnerId,
|
||||
subject: systemSubject,
|
||||
message: data.emailMessage,
|
||||
emailSubject: "TurnosXpress :: Alta de turno",
|
||||
emailMessage: data.emailMessage,
|
||||
wapMessage: data.wapMessage,
|
||||
systemSubject,
|
||||
systemMessage: data.emailMessage,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private async getOptionalClientWapNumber(client: IClientDocument): Promise<string | undefined> {
|
||||
try {
|
||||
return await ClientsManager.getClientWapNumber(client);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
public async deleteAppointment(data: DeleteAppointmentParams): Promise<void> {
|
||||
const { validation = false } = data;
|
||||
const { validation = false, notification = false } = data;
|
||||
const sessionUser = await UsersManager.users.findOne({
|
||||
_id: data.sessionUser,
|
||||
});
|
||||
@@ -2234,23 +2300,41 @@ public async updateAppointment(data: UpdateAppointmentParams): Promise<void> {
|
||||
try {
|
||||
const config = this.getHeatMapConfig(checkAppointment, serviceCheck.length);
|
||||
|
||||
// Cancel pending notification jobs for this appointment before deleting it
|
||||
await this.jobService.cancelByAppointment(String(checkAppointment._id));
|
||||
|
||||
if (notification) {
|
||||
const emailContent = await this.tryToSendNotification({
|
||||
appointmentId: String(checkAppointment._id),
|
||||
sessionUser: data.sessionUser,
|
||||
type: APPOINTMENT_NOTIFICATION_TYPE.CANCELLATION,
|
||||
channel: "email",
|
||||
});
|
||||
const wapContent = await this.tryToSendNotification({
|
||||
appointmentId: String(checkAppointment._id),
|
||||
sessionUser: data.sessionUser,
|
||||
type: APPOINTMENT_NOTIFICATION_TYPE.CANCELLATION,
|
||||
channel: "whatsapp",
|
||||
});
|
||||
|
||||
await this.createCancellationNotificationJobs({
|
||||
companyId: String(checkAppointment.companyId),
|
||||
clientId: String(checkAppointment.clientId),
|
||||
appointmentId: String(checkAppointment._id),
|
||||
clientUserId: checkClient.userId ? String(checkClient.userId) : undefined,
|
||||
clientEmail: checkClient.email,
|
||||
clientPhoneNumber: await this.getOptionalClientWapNumber(checkClient),
|
||||
companyOwnerId: String(companyCheck.ownerId),
|
||||
companyName: companyCheck.name,
|
||||
emailMessage: emailContent.message,
|
||||
wapMessage: wapContent.message,
|
||||
});
|
||||
}
|
||||
|
||||
await this.Appointments.AppointmentList.deleteOne({ _id: data.id });
|
||||
//Actualizar el heatmap.
|
||||
await this.updateHeatMap(config);
|
||||
|
||||
if (checkClient.userId) {
|
||||
//Enviamos la notificacion de cancelacion al cliente
|
||||
await NotificationsManager.sendSystemNotification({
|
||||
userId: String(checkClient.userId),
|
||||
subject: "Turno Cancelado",
|
||||
message: `Se ha cancelado el turno para el día ${dayjs(checkAppointment.start).format(
|
||||
"DD/MM/YYYY"
|
||||
)} a las ${dayjs(checkAppointment.start).format("HH:mm")}`,
|
||||
type: NotificationType.APPOINTMENT,
|
||||
code: String(checkAppointment._id)
|
||||
});
|
||||
}
|
||||
|
||||
//Enviamos la notificacion de cancelacion al profesional
|
||||
await NotificationsManager.sendSystemNotification({
|
||||
userId: String(employeeCheck.userId),
|
||||
@@ -2384,8 +2468,16 @@ public async updateAppointment(data: UpdateAppointmentParams): Promise<void> {
|
||||
throw new Error("La compañia no existe");
|
||||
}
|
||||
|
||||
if (!(await EmployeesList.checkPermission(companyCheck, data.sessionUser, EmployeeRoles.ADMIN))) {
|
||||
throw new Error(NoPermissionMessage());
|
||||
const hasSystemToken = this.hasValidSystemToken(data.systemToken);
|
||||
|
||||
if (!hasSystemToken) {
|
||||
if (!data.sessionUser) {
|
||||
throw new Error("No se ha encontrado el usuario o no tiene permisos para realizar esta acción");
|
||||
}
|
||||
|
||||
if (!(await EmployeesList.checkPermission(companyCheck, data.sessionUser, EmployeeRoles.ADMIN))) {
|
||||
throw new Error(NoPermissionMessage());
|
||||
}
|
||||
}
|
||||
|
||||
const checkClient = await ClientsManager.clients.findOne({
|
||||
@@ -2465,9 +2557,13 @@ public async updateAppointment(data: UpdateAppointmentParams): Promise<void> {
|
||||
wapMessage = wapMessage.replaceAll("<---ORGANIZACION--->", companyCheck.name);
|
||||
wapMessage = wapMessage.replaceAll("<---BR--->", "\r\n");
|
||||
} else if (data.type == APPOINTMENT_NOTIFICATION_TYPE.CREATION) {
|
||||
if (companyCheck.templateWapAltaId) {
|
||||
const templateId = data.channel === "email"
|
||||
? companyCheck.templateEmailAltaId || companyCheck.templateWapAltaId
|
||||
: companyCheck.templateWapAltaId;
|
||||
|
||||
if (templateId) {
|
||||
const template = await Templates.templates.findOne({
|
||||
id: String(companyCheck.templateWapAltaId),
|
||||
id: String(templateId),
|
||||
companyId: String(companyCheck._id),
|
||||
});
|
||||
|
||||
@@ -2477,7 +2573,9 @@ public async updateAppointment(data: UpdateAppointmentParams): Promise<void> {
|
||||
}
|
||||
|
||||
if (!wapMessage) {
|
||||
wapMessage = process.env.WAP_ALTA ? process.env.WAP_ALTA : "";
|
||||
wapMessage = data.channel === "email"
|
||||
? process.env.EMAIL_NEW_APPOINTMENT || process.env.EMAIL_ALTA || process.env.WAP_ALTA || ""
|
||||
: process.env.WAP_ALTA || "";
|
||||
}
|
||||
|
||||
wapMessage = wapMessage.replaceAll(
|
||||
@@ -2505,6 +2603,52 @@ public async updateAppointment(data: UpdateAppointmentParams): Promise<void> {
|
||||
wapMessage = wapMessage.replaceAll("<---SERVICIO--->", checkService.name);
|
||||
wapMessage = wapMessage.replaceAll("<---PRECIO--->", formatCurrency(checkAppointment.price));
|
||||
|
||||
wapMessage = wapMessage.replaceAll("<---ORGANIZACION--->", companyCheck.name);
|
||||
wapMessage = wapMessage.replaceAll("<---BR--->", "\r\n");
|
||||
} else if (data.type == APPOINTMENT_NOTIFICATION_TYPE.CANCELLATION) {
|
||||
const templateId = data.channel === "email"
|
||||
? companyCheck.templateEmailCancellationId || companyCheck.templateWapCancellationId
|
||||
: companyCheck.templateWapCancellationId;
|
||||
|
||||
if (templateId) {
|
||||
const template = await Templates.templates.findOne({
|
||||
id: String(templateId),
|
||||
companyId: String(companyCheck._id),
|
||||
});
|
||||
|
||||
if (template) {
|
||||
wapMessage = template.template;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wapMessage) {
|
||||
wapMessage = data.channel === "email"
|
||||
? process.env.EMAIL_CANCELLATION || process.env.EMAIL_CANCELACION || process.env.WAP_CANCELLATION || process.env.WAP_CANCELACION || ""
|
||||
: process.env.WAP_CANCELLATION || process.env.WAP_CANCELACION || "";
|
||||
}
|
||||
|
||||
wapMessage = wapMessage.replaceAll(
|
||||
"<---CLIENTE--->",
|
||||
ClientsManager.getClientFullName(checkClient)
|
||||
);
|
||||
wapMessage = wapMessage.replaceAll(
|
||||
"<---FECHA--->",
|
||||
dayjs(checkAppointment.start).format("DD/MM/YYYY")
|
||||
);
|
||||
wapMessage = wapMessage.replaceAll(
|
||||
"<---HORARIO--->",
|
||||
dayjs(checkAppointment.start).format("HH:mm") + "hs."
|
||||
);
|
||||
wapMessage = wapMessage.replaceAll(
|
||||
"<---DIRECCION--->",
|
||||
CompaniesManager.getCompanyAddress(companyCheck)
|
||||
);
|
||||
wapMessage = wapMessage.replaceAll(
|
||||
"<---PROFESIONAL--->",
|
||||
UsersManager.getUserFullName(checkEmployeeUser)
|
||||
);
|
||||
wapMessage = wapMessage.replaceAll("<---SERVICIO--->", checkService.name);
|
||||
wapMessage = wapMessage.replaceAll("<---PRECIO--->", formatCurrency(checkAppointment.price));
|
||||
wapMessage = wapMessage.replaceAll("<---ORGANIZACION--->", companyCheck.name);
|
||||
wapMessage = wapMessage.replaceAll("<---BR--->", "\r\n");
|
||||
}
|
||||
@@ -2517,15 +2661,24 @@ public async updateAppointment(data: UpdateAppointmentParams): Promise<void> {
|
||||
}
|
||||
|
||||
public async sendEmailNotification(data: SendAppointmentNotificationParams): Promise<void> {
|
||||
const sessionUser = await UsersManager.users.findOne({
|
||||
_id: data.sessionUser,
|
||||
});
|
||||
if (!this.hasValidSystemToken(data.systemToken)) {
|
||||
if (!data.sessionUser) {
|
||||
throw new Error("No se ha encontrado el usuario o no tiene permisos para realizar esta acción");
|
||||
}
|
||||
|
||||
if (!sessionUser) {
|
||||
throw new Error("No se ha encontrado el usuario o no tiene permisos para realizar esta acción");
|
||||
const sessionUser = await UsersManager.users.findOne({
|
||||
_id: data.sessionUser,
|
||||
});
|
||||
|
||||
if (!sessionUser) {
|
||||
throw new Error("No se ha encontrado el usuario o no tiene permisos para realizar esta acción");
|
||||
}
|
||||
}
|
||||
|
||||
const { message, checkClient, companyCheck } = await this.tryToSendNotification(data);
|
||||
const { message, checkClient, companyCheck } = await this.tryToSendNotification({
|
||||
...data,
|
||||
channel: "email",
|
||||
});
|
||||
|
||||
const canSend = await PlanSubscriptionsList.checkFeature({
|
||||
userId: String(companyCheck.ownerId),
|
||||
@@ -2548,6 +2701,8 @@ public async updateAppointment(data: UpdateAppointmentParams): Promise<void> {
|
||||
subjectEmail = "TurnosXpress :: Recordatorio";
|
||||
} else if (data.type == APPOINTMENT_NOTIFICATION_TYPE.CREATION) {
|
||||
subjectEmail = "TurnosXpress :: Alta de turno";
|
||||
} else if (data.type == APPOINTMENT_NOTIFICATION_TYPE.CANCELLATION) {
|
||||
subjectEmail = "TurnosXpress :: Turno cancelado";
|
||||
}
|
||||
|
||||
//Enviar email...
|
||||
@@ -2558,7 +2713,66 @@ public async updateAppointment(data: UpdateAppointmentParams): Promise<void> {
|
||||
});
|
||||
}
|
||||
|
||||
public async createImmediateNotificationJobs(data: CreateImmediateAppointmentNotificationJobsParams): Promise<void> {
|
||||
if (![APPOINTMENT_NOTIFICATION_TYPE.CREATION, APPOINTMENT_NOTIFICATION_TYPE.REMINDER].includes(data.type)) {
|
||||
throw new Error("El tipo de notificación no es válido para esta acción");
|
||||
}
|
||||
|
||||
const emailContent = await this.tryToSendNotification({
|
||||
appointmentId: data.appointmentId,
|
||||
sessionUser: data.sessionUser,
|
||||
type: data.type,
|
||||
channel: "email",
|
||||
});
|
||||
const wapContent = await this.tryToSendNotification({
|
||||
appointmentId: data.appointmentId,
|
||||
sessionUser: data.sessionUser,
|
||||
type: data.type,
|
||||
channel: "whatsapp",
|
||||
});
|
||||
|
||||
const checkAppointment = await this.Appointments.findOne({
|
||||
_id: data.appointmentId,
|
||||
});
|
||||
|
||||
if (!checkAppointment) {
|
||||
throw new Error("El turno no existe");
|
||||
}
|
||||
|
||||
const checkClient = emailContent.checkClient;
|
||||
const companyCheck = emailContent.companyCheck;
|
||||
const isCreation = data.type === APPOINTMENT_NOTIFICATION_TYPE.CREATION;
|
||||
const systemSubject = isCreation
|
||||
? `Turno reservado en ${companyCheck.name}`
|
||||
: `Recordatorio de turno en ${companyCheck.name}`;
|
||||
|
||||
await this.jobService.createImmediateJob({
|
||||
companyId: String(checkAppointment.companyId),
|
||||
clientId: String(checkAppointment.clientId),
|
||||
appointmentId: String(checkAppointment._id),
|
||||
type: data.type,
|
||||
scheduledAt: new Date(),
|
||||
payload: {
|
||||
email: checkClient.email,
|
||||
phoneNumber: await this.getOptionalClientWapNumber(checkClient),
|
||||
userId: checkClient.userId ? String(checkClient.userId) : undefined,
|
||||
companyOwnerId: String(companyCheck.ownerId),
|
||||
subject: systemSubject,
|
||||
message: emailContent.message,
|
||||
emailSubject: isCreation ? "TurnosXpress :: Alta de turno" : "TurnosXpress :: Recordatorio",
|
||||
emailMessage: emailContent.message,
|
||||
wapMessage: wapContent.message,
|
||||
systemSubject,
|
||||
systemMessage: emailContent.message,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public async sendWapNotification(data: SendAppointmentNotificationParams): Promise<void> {
|
||||
if (!data.sessionUser) {
|
||||
throw new Error("No se ha encontrado el usuario o no tiene permisos para realizar esta acción");
|
||||
}
|
||||
|
||||
const sessionUser = await UsersManager.users.findOne({
|
||||
_id: data.sessionUser,
|
||||
});
|
||||
@@ -2567,7 +2781,10 @@ public async updateAppointment(data: UpdateAppointmentParams): Promise<void> {
|
||||
throw new Error("No se ha encontrado el usuario o no tiene permisos para realizar esta acción");
|
||||
}
|
||||
|
||||
const { message, checkClient, companyCheck } = await this.tryToSendNotification(data);
|
||||
const { message, checkClient, companyCheck } = await this.tryToSendNotification({
|
||||
...data,
|
||||
channel: "whatsapp",
|
||||
});
|
||||
|
||||
const canSend = await PlanSubscriptionsList.checkFeature({
|
||||
userId: String(companyCheck.ownerId),
|
||||
@@ -2593,13 +2810,7 @@ public async updateAppointment(data: UpdateAppointmentParams): Promise<void> {
|
||||
}
|
||||
|
||||
public async sendWapSystemNotification(data: SendWapSystemNotificationParams): Promise<void> {
|
||||
if (!data.systemToken || data.systemToken == "") {
|
||||
throw new Error("No tiene permisos para realizar esta acción");
|
||||
}
|
||||
|
||||
const systemToken = `${process.env.SYSTEM_KEY}`;
|
||||
|
||||
if (systemToken != data.systemToken) {
|
||||
if (!this.hasValidSystemToken(data.systemToken)) {
|
||||
throw new Error("No tiene permisos para realizar esta acción");
|
||||
}
|
||||
|
||||
@@ -2622,7 +2833,8 @@ public async updateAppointment(data: UpdateAppointmentParams): Promise<void> {
|
||||
const { message, checkClient, companyCheck } = await this.tryToSendNotification({
|
||||
appointmentId: data.appointmentId,
|
||||
sessionUser: String(company.ownerId),
|
||||
type: APPOINTMENT_NOTIFICATION_TYPE.REMINDER,
|
||||
systemToken: data.systemToken,
|
||||
type: data.type,
|
||||
});
|
||||
|
||||
const canSend = await PlanSubscriptionsList.checkFeature({
|
||||
@@ -2838,6 +3050,11 @@ public async updateAppointment(data: UpdateAppointmentParams): Promise<void> {
|
||||
inRangeDates: [],
|
||||
} as GetAvailableDatesResult;
|
||||
}
|
||||
|
||||
private hasValidSystemToken(systemToken?: string): boolean {
|
||||
const expectedSystemToken = process.env.SYSTEM_KEY || process.env.API_KEY;
|
||||
return Boolean(systemToken && expectedSystemToken && systemToken === expectedSystemToken);
|
||||
}
|
||||
}
|
||||
|
||||
const AppointmentList = new AppointmentManager();
|
||||
|
||||
Reference in New Issue
Block a user