|
|
|
@@ -3,7 +3,7 @@ import { pool } from '../../config/db.js';
|
|
|
|
|
const LIST_SELECT = `
|
|
|
|
|
SELECT r.id, r.name, r.description, r.project_id, p.name AS project_name,
|
|
|
|
|
r.responsible_user_id, u.name AS responsible_name,
|
|
|
|
|
r.interval_unit, r.interval_value, r.next_due_date,
|
|
|
|
|
r.interval_unit, r.interval_value, r.next_due_date, r.end_date,
|
|
|
|
|
r.reminder_days_before, r.reminder_hour, r.is_active, r.last_reminder_sent_at,
|
|
|
|
|
r.created_by, r.created_at, r.updated_at
|
|
|
|
|
FROM recurring_tasks r
|
|
|
|
@@ -25,11 +25,11 @@ export async function create(data) {
|
|
|
|
|
const [result] = await pool.query(
|
|
|
|
|
`INSERT INTO recurring_tasks
|
|
|
|
|
(name, description, project_id, responsible_user_id, interval_unit, interval_value,
|
|
|
|
|
next_due_date, reminder_days_before, reminder_hour, is_active, created_by)
|
|
|
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
|
|
|
next_due_date, end_date, reminder_days_before, reminder_hour, is_active, created_by)
|
|
|
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
|
|
|
[
|
|
|
|
|
data.name, data.description || null, data.projectId || null, data.responsibleUserId || null,
|
|
|
|
|
data.intervalUnit, data.intervalValue, data.nextDueDate,
|
|
|
|
|
data.intervalUnit, data.intervalValue, data.nextDueDate, data.endDate || null,
|
|
|
|
|
data.reminderDaysBefore ?? 7, data.reminderHour ?? 9,
|
|
|
|
|
data.isActive === false ? 0 : 1, data.createdBy,
|
|
|
|
|
]
|
|
|
|
@@ -41,11 +41,11 @@ export async function update(id, data) {
|
|
|
|
|
await pool.query(
|
|
|
|
|
`UPDATE recurring_tasks SET
|
|
|
|
|
name = ?, description = ?, project_id = ?, responsible_user_id = ?, interval_unit = ?,
|
|
|
|
|
interval_value = ?, next_due_date = ?, reminder_days_before = ?, reminder_hour = ?, is_active = ?
|
|
|
|
|
interval_value = ?, next_due_date = ?, end_date = ?, reminder_days_before = ?, reminder_hour = ?, is_active = ?
|
|
|
|
|
WHERE id = ?`,
|
|
|
|
|
[
|
|
|
|
|
data.name, data.description || null, data.projectId || null, data.responsibleUserId || null,
|
|
|
|
|
data.intervalUnit, data.intervalValue, data.nextDueDate,
|
|
|
|
|
data.intervalUnit, data.intervalValue, data.nextDueDate, data.endDate || null,
|
|
|
|
|
data.reminderDaysBefore ?? 7, data.reminderHour ?? 9,
|
|
|
|
|
data.isActive === false ? 0 : 1, id,
|
|
|
|
|
]
|
|
|
|
@@ -60,7 +60,8 @@ export async function remove(id) {
|
|
|
|
|
const SQL_UNIT = { days: 'DAY', months: 'MONTH', years: 'YEAR' };
|
|
|
|
|
|
|
|
|
|
// Avanza al siguiente ciclo: suma el intervalo a next_due_date y limpia el recordatorio ya enviado
|
|
|
|
|
// (para que el proximo ciclo pueda volver a mandar su propio aviso).
|
|
|
|
|
// (para que el proximo ciclo pueda volver a mandar su propio aviso). Si el nuevo vencimiento supera
|
|
|
|
|
// "hasta cuando" (end_date), la tarea se desactiva sola — ya cumplio su ultimo ciclo.
|
|
|
|
|
export async function advanceCycle(id) {
|
|
|
|
|
const [rows] = await pool.query('SELECT interval_unit, interval_value FROM recurring_tasks WHERE id = ?', [id]);
|
|
|
|
|
const row = rows[0];
|
|
|
|
@@ -72,6 +73,11 @@ export async function advanceCycle(id) {
|
|
|
|
|
WHERE id = ?`,
|
|
|
|
|
[row.interval_value, id]
|
|
|
|
|
);
|
|
|
|
|
await pool.query(
|
|
|
|
|
`UPDATE recurring_tasks SET is_active = 0
|
|
|
|
|
WHERE id = ? AND end_date IS NOT NULL AND next_due_date > end_date`,
|
|
|
|
|
[id]
|
|
|
|
|
);
|
|
|
|
|
return findById(id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -89,6 +95,7 @@ export async function findDueForReminder() {
|
|
|
|
|
JOIN users cu ON cu.id = r.created_by
|
|
|
|
|
WHERE r.is_active = 1
|
|
|
|
|
AND r.last_reminder_sent_at IS NULL
|
|
|
|
|
AND (r.end_date IS NULL OR r.next_due_date <= r.end_date)
|
|
|
|
|
AND DATE_SUB(r.next_due_date, INTERVAL r.reminder_days_before DAY) = CURDATE()
|
|
|
|
|
AND HOUR(NOW()) = r.reminder_hour`
|
|
|
|
|
);
|
|
|
|
|