import dayjs from "dayjs"; import axios from "axios"; import { logDone, logError, logIntent } from "../../config/logger.js"; import { Appointments, IAppointment, IAppointmentDocument } from "../Appointments/Appointments.js"; import { Companies } from "../Companies/Companies.js"; import { PlanSuscriptions } from "../PlanSubscriptions/PlanSubscriptions.js"; export type ApiVoidResult = { success: boolean; message: string; }; export type SendWapSystemNotificationParams = { appointmentId: string; systemToken: string; }; export class Notifications { private users: string[] = []; private companies: string[] = []; private appointments: IAppointmentDocument[] = []; private appointmentsCollection: Appointments; constructor() { this.users = []; this.companies = []; this.appointments = []; this.appointmentsCollection = new Appointments(); } private async loadUsers() { logIntent("Cargando lista de usuarios."); const loadedPlanIds = `${process.env.PLAN_LIST}`; if (loadedPlanIds === "") { logError("No se ha encontrado una lista de planes valida.", ""); process.exit(1); } const PLAN_IDS = loadedPlanIds.split(","); const subs = new PlanSuscriptions(); const result = await subs.planSuscriptionList.find({ planId: { $in: PLAN_IDS } }).exec(); this.users = result.map((x) => String(x.userId)); logDone("Lista de usuarios cargada correctamente."); } private async loadCompanies() { logIntent("Cargando lista de organizaciones."); const orgs = new Companies(); for (const user of this.users) { const organizations = await orgs.companyList .find({ ownerId: user, automaticNotifications: true }) .exec(); for (const orgItem of organizations) { this.companies.push(orgItem.id); } } logDone("Lista de organizaciones cargada correctamente."); } private async loadAppointments() { try { logIntent("Cargando nuevo lote de notificaciones"); this.appointments = []; const dateFrom = dayjs().clone().startOf("day"); const dateTo = dayjs().clone().endOf("day"); for (const company of this.companies) { const result = await this.appointmentsCollection.appointmentsList .findOne({ start: { $gte: dateFrom.toDate(), $lte: dateTo.toDate() }, companyId: company, $and: [ { $or: [{ notificated: false }, { notificated: { $exists: false } }] }, { $or: [ { notificationIntents: { $lt: 3 } }, { notificationIntents: { $exists: false } }, ], }, ], }) .exec(); if (!result) { continue; } this.appointments.push(result); } logDone("Nuevo lote de notificaciones cargado correctamente."); } catch (error) { logError("Error cargando nuevo lote de notificaciones:", error); } } public async start() { await this.loadUsers(); await this.loadCompanies(); await this.loadAppointments(); this.next(); } public async next() { const getDelay = () => { const timeBase = Number(process.env.TIME_BASE ? process.env.TIME_BASE : 8); const timeExtra = Number(process.env.TIME_EXTRA ? process.env.TIME_EXTRA : 8); return Math.floor(Math.random() * timeBase) + timeExtra; }; const app = this.appointments.shift(); if (!app) { logDone("Se ha finalizado el envío del lote de notificaciones."); setTimeout(() => { this.reload(); }, getDelay() * 1000); return; } try { await this.send(String(app.id)); app.notificated = true; } catch (error) { app.notificationIntents = app.notificationIntents ? app.notificationIntents + 1 : 1; logError("Error enviando notificación:", error); } await app.save(); setTimeout(() => { this.next(); }, getDelay() * 1000); } public async reload() { await this.loadAppointments(); if (this.appointments.length < 1) { this.end(); } this.next(); } public async end() { process.exit(0); } private async send(appointmentId: string): Promise { logIntent(`Enviando notificación para la cita ${appointmentId}.`); const dataApi: SendWapSystemNotificationParams = { appointmentId: appointmentId, systemToken: `${process.env.API_KEY}`, }; const response = await axios.post(`${process.env.API_URL}`, dataApi, { headers: { "Content-Type": "application/json", }, }); const result: ApiVoidResult = response.data; if (!result.success) { throw new Error(result.message); } logDone("Notificación enviada correctamente."); } }