const pool = require('../db/connection'); const transporter = require('../services/mailService'); const contractsNearToEnd = async (req, res) => { try{ const countResult = await pool.query('SELECT contratcsneartoend() as total'); const contractsResult = await pool.query('SELECT * FROM contractsneartoenddata()'); const userEmails = await pool.query('SELECT * FROM getusersmailneartoend()'); const totalExpiring = countResult.rows[0].total; const contracts = contractsResult.rows; const users = userEmails.rows; if(totalExpiring >= 1 && users.length > 0){ const recipients = users.map(u => u.email); const mailOptions = { from: 'soporte@horuxfin.com', to: recipients, subject: 'Contratos próximos a expirar', html: `

Notificación de contratos

Actualmente hay ${totalExpiring} contrato(s) por expirar.

Los siguientes contratos son los que expiran:

${contracts.map(c => { const inicio = formatDateDMY(c.start_contract); const fin = formatDateDMY(c.end_contract); return ` `; }).join('')}
ID contract RFC Nombre Fecha inicio contrato Fecha fin contrato Salario diario
${c.id_contract} ${c.rfc_emp} ${c.name_employee} ${inicio} ${fin} ${c.dailypay}
Revisar en la web

Por favor considere si seran recontratados o finalizados.

Sistema de gestión financiera · Consultoría AS
` }; await transporter.sendMail(mailOptions); res.json({ message: 'Correo enviado con contratos por expirar.', data:totalExpiring }); }else{ res.json({ message: 'No hay contratos por expirar', data:totalExpiring }); } }catch(error){ console.error(error); res.status(500).json({ status: 500, message: 'No se pudo mandar el correo con los contratos por expirar' }); } }; const paymentDeadLine = async (req, res) => { try{ const deadLineCount = await pool.query('SELECT countdelaypayments() as total'); const deadLineResult = await pool.query('SELECT * FROM getdelaypayments()'); const usersDeadLine = await pool.query('SELECT * FROM getusersmailpaymentdelay()'); const totalDeadline = deadLineCount.rows[0].total; const deadLines = deadLineResult.rows; const users = usersDeadLine.rows; if(totalDeadline >= 1 && users.length >0){ const recipients = users.map(u => u.email); const mailOptions = { from: 'soporte@horuxfin.com', to: recipients, subject: 'WARNING: OVERDUE PAYMENTS', html: `

Notification regarding overdue payments

Currently there are ${totalDeadline} overdue payment(s).

${deadLines.map(c => { const fecha = new Date(c.payment_deadline); const fechaFormateada = fecha.toLocaleDateString('en-US', { day: '2-digit', month: 'long' }); return ` `; }).join('')}
ID Description Deadline Total
${c.id_expense} ${c.description} ${fechaFormateada} ${c.total || 'N/A'}
Please review and pay as soon as possible.

We recommend that review your overdue expenses as soon as possible.

Financial management system · Consultoría AS
` }; await transporter.sendMail(mailOptions); res.json({ message: 'Correo enviado con pagos atrasados.', data:totalDeadline }); }else{ res.json({ message: 'No hay pagos con atraso', data:totalDeadline }); } }catch(error){ console.error(error); res.status(500).json({ status: 500, message: 'No se pudo mandar el correo con con los pagos atrasados' }); } }; const expensesNearToDeadline = async (req, res) => { try{ const deadLineCount = await pool.query('SELECT COUNT(*) FROM expensesneartodeadline()'); const deadLineResult = await pool.query('SELECT * FROM expensesneartodeadline()'); const usersDeadLine = await pool.query('SELECT * FROM getusersmailpaymentdelay()'); const totalDeadline = deadLineCount.rows[0].count; const deadLines = deadLineResult.rows; const users = usersDeadLine.rows; console.log(totalDeadline); if(totalDeadline >= 1 && users.length >0){ const recipients = users.map(u => u.email); const mailOptions = { from: 'soporte@horuxfin.com', to: recipients, subject: 'WARNING: PAYMENTS DUE SOON FOR LATE PAYMENTS', html: `

Notification of payments approaching a deadline

Currently there are ${totalDeadline} payment(s) close to deadline.

${deadLines.map(c => { const fecha = new Date(c.payment_deadline); const fechaFormateada = fecha.toLocaleDateString('en-US', { day: '2-digit', month: 'long' }); return ` `; }).join('')}
ID Description Deadline Total
${c.id_expense} ${c.description} ${fechaFormateada} ${c.total || 'N/A'}
Review and pay spendings

We recommend reviewing this application before the deadline.

Financial management system · Consultoría AS
` }; await transporter.sendMail(mailOptions); res.json({ message: 'Correo enviado con pagos por expirar.', data:totalDeadline }); }else{ res.json({ message: 'No hay pagos con atraso', data:totalDeadline }); } }catch(error){ console.error(error); res.status(500).json({ status: 500, message: 'No se pudo mandar el correo con los pagos prontos a fecha limite' }); } }; const expensesspecial = async (req, res) => { try{ const expensesCount = await pool.query('SELECT COUNT(*) AS total FROM getexpensesspecial()'); const expensesResult = await pool.query('SELECT * FROM getexpensesspecial()'); const totalExpenses = expensesCount.rows[0].total; const expenses = expensesResult.rows; if(totalExpenses >= 1){ const mailOptions = { from: 'soporte@horuxfin.com', to: 'soporte@horuxfin.com', subject: 'Recordatorio: Hay gastos por aprobar', html: `

Notificación de gastos por aprobar

Actualmente hay ${totalExpenses} gasto(s) por aprobar

` }; await transporter.sendMail(mailOptions); res.json({ message: 'Correo enviado con gastos por aprobar', data:totalExpenses }); }else{ res.json({ message: 'No hay pagos por aprobar', data:totalExpenses }); } }catch(error){ console.error(error); res.status(500).json({ status: 500, message: 'No se pudo mandar el correo con los contratos por expirar' }); } }; const emailbirthday = async (req, res) => { try{ const endpointName = 'emailbirthday'; const current = new Date(); const mes = current.getMonth() + 1; const anio = current.getFullYear(); const validateEndpoint = await pool.query('SELECT validateendpoint($1,$2::int,$3::int) AS total',[endpointName,mes,anio]); if (validateEndpoint.rows[0].total > 0) { return res.status(400).json({ message: `Este endpoint ya fue ejecutado en ${current.toLocaleString('es-MX', { month: 'long' })}.` }); }else { await pool.query(`INSERT INTO endpoint_logs (endpoint_name) VALUES ($1)`,[endpointName]); const birthdayCount = await pool.query('SELECT COUNT(*) AS total FROM getbirthdaysemployees()'); const birthdayResult = await pool.query('SELECT * FROM getbirthdaysemployees()'); const userEmails = await pool.query('SELECT * FROM getusersmailbirthday()'); const totalBirthday = birthdayCount.rows[0].total; const birthdays = birthdayResult.rows; const users = userEmails.rows; const currentMonth = new Date().toLocaleString('en-US', { month: 'long' }); if(totalBirthday >= 1 && users.length >0){ const recipients = users.map(u => u.email); const mailOptions = { from: 'soporte@horuxfin.com', to: recipients, subject: `Friendly reminder: Birthdays of the month of ${currentMonth}`, html: `

In this month there are ${totalBirthday} birthday person(s)

The following employees are celebrating their birthdays this month:

${birthdays.map(c => { const fecha = new Date(c.birthday); const fechaFormateada = fecha.toLocaleDateString('en-US', { day: '2-digit', month: 'long' }); return ` `; }).join('')}
RFC Name Birthday
${c.rfc} ${c.fullname} ${fechaFormateada}

Remember to congratulate them on their special day!

Financial management system · Consultoría AS
`}; await transporter.sendMail(mailOptions); res.json({ message: 'Correo enviado con los cumpleaños', data:totalBirthday }); }else{ res.json({ message: 'No hay cumpleañeros este mes', data:totalBirthday }); }} }catch(error){ console.error(error); res.status(500).json({ status: 500, message: 'No se pudo enviar correo con los cumpleañeros' }); } }; const expiredcontracts = async (req, res) => { try{ const expiredCountTotal = await pool.query('SELECT expiredcontracts() as total'); const expiredResult = await pool.query('SELECT * FROM getexpirecontracts()'); const expiredCountDay = await pool.query('SELECT COUNT(*) AS total FROM getexpirecontracts()'); const totalExpired = expiredCountTotal.rows[0].total; const totalDayExpired = expiredCountDay.rows[0].total; const expiredContracts = expiredResult.rows; if(totalExpired >= 1){ const mailOptions = { from: 'soporte@horuxfin.com', to: 'soporte@horuxfin.com', subject: 'Contratos expirados el día de hoy', html: `

Notificación contratos expirados el día de hoy

Cantidad de contratos ${totalDayExpired} que expiraron hoy.

Por favor considere si seran recontratados o no para que se inicie el proceso.

` }; await transporter.sendMail(mailOptions); res.json({ message: 'Correo enviado con contratos expirados hoy', data:totalDayExpired }); }else{ res.json({ message: 'Hoy no expiro ningun contrato', data:totalDayExpired }); } }catch(error){ console.error(error); res.status(500).json({ status: 500, message: 'No se pudo mandar el correo con los contratos por expirar' }); } }; const expiredContractsMonth = async (req, res) => { try{ // Verifica si hoy es el último día del mes if (isLastDayOfMonth()) { return res.status(200).json({ message: 'El proceso solo se ejecuta el último día del mes', executed: false }); } const endpointName = 'expiredContractsMonth'; const current = new Date(); const mes = current.getMonth() + 1; const anio = current.getFullYear(); const validateEndpoint = await pool.query('SELECT validateendpoint($1,$2::int,$3::int) AS total',[endpointName,mes,anio]); if (validateEndpoint.rows[0].total > 0) { return res.status(400).json({ message: `Este endpoint ya fue ejecutado en ${current.toLocaleString('es-MX', { month: 'long' })}.` }); }else { await pool.query(`INSERT INTO endpoint_logs (endpoint_name) VALUES ($1)`,[endpointName]); const expiredCountTotal = await pool.query('SELECT COUNT(*) AS total FROM getexpirecontractsmonth()'); const expiredResult = await pool.query('SELECT * FROM getexpirecontractsmonth()'); const userEmails = await pool.query('SELECT * FROM getusersmailneartoend()'); const totalExpired = expiredCountTotal.rows[0].total; const expiredContracts = expiredResult.rows; const currentMonth = new Date().toLocaleString('es-MX', { month: 'long' }); const users = userEmails.rows; if(totalExpired >= 1 && users.length > 0){ const recipients = users.map(u => u.email); const mailOptions = { from: 'soporte@horuxfin.com', to: recipients, subject: `Contratos expirados en el mes ${currentMonth} `, html: `

Notificación contratos expirados del mes de ${currentMonth}

En este mes expiraron ${totalExpired}.

Los contratos expirados son en el mes fueron:

${expiredContracts.map(c => { const fin = formatDateDMY(c.end_contract); return ` `; }).join('')}
ID contract RFC Nombre Fecha que expiro:
${c.id_contract} ${c.rfc_employee} ${c.name_employee} ${fin}
Revisar en la web

Le recomendamos generar el contrato en caso de recontratación.

Sistema de gestión financiera · Consultoría AS
` }; await transporter.sendMail(mailOptions); res.json({ message: 'Correo enviado con contratos expirados en el mes', data:totalExpired }); }else{ res.json({ message: 'Este mes no expiro ningun contrato', data:totalExpired }); }} }catch(error){ console.error(error); res.status(500).json({ status: 500, message: 'No se pudo mandar el correo con los contratos por expirar' }); } }; const isLastDayOfMonth = () => { const today = new Date(); const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1); return tomorrow.getDate() === 1; }; const formatDateDMY = (value) => { if (!value) return ''; const date = value instanceof Date ? value : new Date(value); if (isNaN(date.getTime())) return ''; return date.toLocaleDateString('es-MX', { day: '2-digit', month: '2-digit', year: 'numeric' }); }; module.exports = {contractsNearToEnd,paymentDeadLine,expensesspecial, emailbirthday,expiredcontracts,expiredContractsMonth,expensesNearToDeadline};