Files
zibo-dashboard/public/userarea/manutenzioni/cron/send_notifications.php
T
2026-08-12 21:29:55 +03:00

197 lines
6.5 KiB
PHP

<?php
/**
* Manutenzioni — email notifications
* Run daily, e.g.: 0 7 * * * php /var/www/html/public/userarea/manutenzioni/cron/send_notifications.php
*
* Sends:
* - "advance" when next_due_date <= today + alert_days
* - "overdue" when next_due_date < today
*
* Recipients are the assignee and the supervisor of the maintenance
* (employees.auth_user_id -> auth_users.email). Deduplicated per
* maintenance + email + type + day by maint_notifications.
*/
require_once __DIR__ . '/../../class/db-functions.php';
require_once __DIR__ . '/../include/functions.php';
require_once __DIR__ . '/../../../../vendor/autoload.php';
use Dotenv\Dotenv;
use PHPMailer\PHPMailer\PHPMailer;
$dotenv = Dotenv::createImmutable(__DIR__ . '/../../../../');
$dotenv->safeLoad();
$pdo = mnt_pdo();
$today = date('Y-m-d');
$appUrl = rtrim($_ENV['APP_URL'] ?? 'http://localhost:8001', '/');
/**
* --dry-run (or MNT_MAIL_DRYRUN=1) works out the queue and prints it without
* sending anything and without writing to maint_notifications, so a run leaves
* no trace and can be repeated. Useful before a change to see what tonight
* would deliver, and it is what the test suite drives.
*
* One line per queued message, tab separated:
* QUEUE <type> <email> <maintenance_id> <label>
*/
$dryRun = in_array('--dry-run', $argv ?? [], true) || !empty($_ENV['MNT_MAIL_DRYRUN']);
if ($dryRun) {
echo "DRY-RUN — nothing is sent, nothing is recorded\n";
}
$sent = 0;
$skipped = 0;
$errors = 0;
// Only active maintenances of active equipment, with a real due date
$stmt = $pdo->prepare("
SELECT m.id, m.code, m.title, m.next_due_date, m.alert_days, m.is_critical,
e.id AS equipment_id, e.name AS equipment_name,
m.assignee_employee_id, m.supervisor_employee_id
FROM maint_maintenances m
INNER JOIN inv_equipment e ON e.id = m.equipment_id
WHERE m.is_active = 1
AND e.status = 'active'
AND m.next_due_date IS NOT NULL
AND m.next_due_date <= DATE_ADD(?, INTERVAL m.alert_days DAY)
");
$stmt->execute([$today]);
$maintenances = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (!$maintenances) {
echo date('Y-m-d H:i:s') . " — Nessuna manutenzione da notificare.\n";
exit(0);
}
$getRecipient = $pdo->prepare("
SELECT e.id AS employee_id, e.first_name, e.last_name, u.email
FROM employees e
INNER JOIN auth_users u ON u.id = e.auth_user_id
WHERE e.id = ?
AND e.auth_user_id IS NOT NULL
AND u.email IS NOT NULL
AND u.email <> ''
");
$checkSent = $pdo->prepare("
SELECT COUNT(*) FROM maint_notifications
WHERE maintenance_id = ? AND email = ? AND type = ? AND sent_date = ?
");
$insertNotification = $pdo->prepare("
INSERT INTO maint_notifications (maintenance_id, employee_id, email, type, sent_date)
VALUES (?, ?, ?, ?, ?)
");
// mnt_mail_body() and mnt_notification_mail() live in include/functions.php,
// so that the preview renders the very same markup this cron sends.
foreach ($maintenances as $maintenance) {
$isOverdue = $maintenance['next_due_date'] < $today;
$type = $isOverdue ? 'overdue' : 'advance';
$daysLeft = (int)((strtotime($maintenance['next_due_date']) - strtotime($today)) / 86400);
// Assignee + supervisor, de-duplicated by employee id
$recipients = [];
foreach ([$maintenance['assignee_employee_id'], $maintenance['supervisor_employee_id']] as $employeeId) {
if (!$employeeId) {
continue;
}
$getRecipient->execute([(int)$employeeId]);
$recipient = $getRecipient->fetch(PDO::FETCH_ASSOC);
if ($recipient) {
$recipients[(int)$recipient['employee_id']] = $recipient;
}
}
if (!$recipients) {
$skipped++;
continue;
}
$label = ($maintenance['code'] ? $maintenance['code'] . ' — ' : '') . $maintenance['title'];
$detailUrl = $appUrl . '/userarea/manutenzioni/equipment.php?id=' . (int)$maintenance['equipment_id'];
foreach ($recipients as $recipient) {
$checkSent->execute([$maintenance['id'], $recipient['email'], $type, $today]);
if ((int)$checkSent->fetchColumn() > 0) {
$skipped++;
continue;
}
if ($dryRun) {
printf("QUEUE\t%s\t%s\t%d\t%s\n", $type, $recipient['email'], (int)$maintenance['id'], $label);
$sent++;
continue;
}
try {
$mail = new PHPMailer(true);
if (($_ENV['MAIL_MAILER'] ?? 'mail') === 'smtp') {
$mail->isSMTP();
$mail->Host = $_ENV['MAIL_HOST'] ?? 'localhost';
$mail->Port = (int)($_ENV['MAIL_PORT'] ?? 587);
if (!empty($_ENV['MAIL_USERNAME']) && $_ENV['MAIL_USERNAME'] !== 'null') {
$mail->SMTPAuth = true;
$mail->Username = $_ENV['MAIL_USERNAME'];
$mail->Password = $_ENV['MAIL_PASSWORD'] ?? '';
}
$encryption = $_ENV['MAIL_ENCRYPTION'] ?? '';
if ($encryption && $encryption !== 'null') {
$mail->SMTPSecure = $encryption;
}
}
$mail->CharSet = 'UTF-8';
$mail->isHTML(true);
$mail->setFrom(
$_ENV['MAIL_FROM_ADDRESS'] ?? 'noreply@zibogomma.it',
$_ENV['MAIL_FROM_NAME'] ?? 'Manutenzioni ZIBOGOMMA'
);
$mail->addAddress($recipient['email'], trim($recipient['first_name'] . ' ' . $recipient['last_name']));
$composed = mnt_notification_mail($maintenance, $label, $daysLeft, $detailUrl, $today);
$mail->Subject = $composed['subject'];
$mail->Body = $composed['body'];
$mail->send();
$insertNotification->execute([
$maintenance['id'],
(int)$recipient['employee_id'],
$recipient['email'],
$type,
$today,
]);
mnt_log(
$pdo,
'notification_sent',
(int)$maintenance['equipment_id'],
(int)$maintenance['id'],
null,
null,
null,
$type . ' → ' . $recipient['email']
);
$sent++;
} catch (Throwable $e) {
$errors++;
echo date('Y-m-d H:i:s') . ' — Errore invio a ' . $recipient['email'] . ': ' . $e->getMessage() . "\n";
}
}
}
echo date('Y-m-d H:i:s')
. ($dryRun ? " — In coda: $sent" : " — Inviate: $sent")
. ", saltate: $skipped, errori: $errors\n";