load(); $db = DBHandlerSelect::getInstance(); $pdo = $db->getConnection(); $today = date('Y-m-d'); $appUrl = rtrim($_ENV['APP_URL'] ?? 'http://localhost:8001', '/'); $sent = 0; $skipped = 0; $errors = 0; // Get active deadlines that are approaching or overdue $stmt = $pdo->query(" SELECT d.id, d.topic, s.name AS subject_name, d.due_date, d.notification_days FROM scad_deadlines d LEFT JOIN scad_subjects s ON s.id = d.subject_id WHERE d.status = 'active' AND d.due_date <= DATE_ADD(CURDATE(), INTERVAL d.notification_days DAY) "); $deadlines = $stmt->fetchAll(PDO::FETCH_ASSOC); if (empty($deadlines)) { echo date('Y-m-d H:i:s') . " — Nessuna scadenza da notificare.\n"; exit(0); } // Prepare statements $getRecipients = $pdo->prepare(" SELECT DISTINCT e.id as employee_id, au.email, e.first_name, e.last_name FROM scad_deadline_employee de JOIN employees e ON e.id = de.employee_id JOIN auth_users au ON au.id = e.auth_user_id WHERE de.deadline_id = ? AND e.auth_user_id IS NOT NULL AND au.email IS NOT NULL AND au.email != '' "); // Also get employees from assigned departments $getDeptRecipients = $pdo->prepare(" SELECT DISTINCT e.id as employee_id, au.email, e.first_name, e.last_name FROM employees e JOIN auth_users au ON au.id = e.auth_user_id WHERE e.department IN (SELECT TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(d.departments, ',', n.n), ',', -1)) FROM scad_deadlines d CROSS JOIN (SELECT 1 n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) n WHERE d.id = ? AND d.departments IS NOT NULL AND n.n <= 1 + LENGTH(d.departments) - LENGTH(REPLACE(d.departments, ',', ''))) AND e.auth_user_id IS NOT NULL AND au.email IS NOT NULL AND au.email != '' "); $checkSent = $pdo->prepare(" SELECT COUNT(*) FROM scad_deadline_notifications WHERE deadline_id = ? AND employee_id = ? AND type = ? AND DATE(sent_at) = CURDATE() "); $insertNotif = $pdo->prepare(" INSERT INTO scad_deadline_notifications (deadline_id, employee_id, type) VALUES (?, ?, ?) "); $insertHistory = $pdo->prepare(" INSERT INTO scad_deadline_histories (deadline_id, user_id, action, notes) VALUES (?, NULL, 'notification_sent', ?) "); foreach ($deadlines as $dl) { $isOverdue = $dl['due_date'] < $today; $type = $isOverdue ? 'overdue' : 'approaching'; $daysLeft = (int)((strtotime($dl['due_date']) - strtotime($today)) / 86400); // Collect all recipients (direct + department) $recipients = []; $getRecipients->execute([$dl['id']]); foreach ($getRecipients->fetchAll(PDO::FETCH_ASSOC) as $r) { $recipients[$r['employee_id']] = $r; } $getDeptRecipients->execute([$dl['id']]); foreach ($getDeptRecipients->fetchAll(PDO::FETCH_ASSOC) as $r) { $recipients[$r['employee_id']] = $r; } if (empty($recipients)) { continue; } foreach ($recipients as $emp) { // Check if already sent today $checkSent->execute([$dl['id'], $emp['employee_id'], $type]); if ($checkSent->fetchColumn() > 0) { $skipped++; continue; } // Send email try { $mail = new PHPMailer(true); // SMTP config from .env $mailer = $_ENV['MAIL_MAILER'] ?? 'mail'; if ($mailer === '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'] ?? ''; } $enc = $_ENV['MAIL_ENCRYPTION'] ?? ''; if ($enc && $enc !== 'null') { $mail->SMTPSecure = $enc; } } $mail->CharSet = 'UTF-8'; $mail->setFrom( $_ENV['MAIL_FROM_ADDRESS'] ?? 'noreply@zibogomma.it', $_ENV['MAIL_FROM_NAME'] ?? 'Scadenzario ZIBOGOMMA' ); $mail->addAddress($emp['email'], trim($emp['first_name'] . ' ' . $emp['last_name'])); $detailUrl = $appUrl . '/userarea/scadenzario/detail.php?id=' . $dl['id']; $topicText = (!empty($dl['subject_name']) ? $dl['subject_name'] . ' — ' : '') . $dl['topic']; if ($isOverdue) { $mail->Subject = '⚠️ Scadenza superata: ' . $dl['topic']; $mail->Body = buildHtml( 'Scadenza superata', $topicText, 'La scadenza era prevista per il ' . date('d/m/Y', strtotime($dl['due_date'])) . ' ed è stata superata da ' . abs($daysLeft) . ' giorni.', '#dc3545', $detailUrl ); } else { $mail->Subject = '📅 Scadenza in arrivo: ' . $dl['topic']; $daysText = $daysLeft === 0 ? 'oggi' : 'tra ' . $daysLeft . ' giorni'; $mail->Body = buildHtml( 'Scadenza in arrivo', $topicText, 'La scadenza è prevista per il ' . date('d/m/Y', strtotime($dl['due_date'])) . ' (' . $daysText . ').', '#e8930c', $detailUrl ); } $mail->isHTML(true); $mail->AltBody = strip_tags(str_replace('
', "\n", $mail->Body)); $mail->send(); // Record notification $insertNotif->execute([$dl['id'], $emp['employee_id'], $type]); $sent++; echo date('H:i:s') . " ✓ {$type} → {$emp['email']} — {$dl['topic']}\n"; } catch (Exception $e) { $errors++; echo date('H:i:s') . " ✗ Errore {$emp['email']}: {$e->getMessage()}\n"; } } // History (one per deadline, not per recipient) $recipientNames = implode(', ', array_map(fn($r) => trim($r['first_name'] . ' ' . $r['last_name']), $recipients)); $insertHistory->execute([$dl['id'], "Notifica {$type} inviata a: {$recipientNames}"]); } echo "\n" . date('Y-m-d H:i:s') . " — Completato. Inviate: {$sent}, Saltate: {$skipped}, Errori: {$errors}\n"; // --- HTML email template --- function buildHtml(string $title, string $topic, string $message, string $accentColor, string $url): string { return '

' . htmlspecialchars($title) . '

' . htmlspecialchars($topic) . '

' . $message . '

Vai alla scadenza

ZIBOGOMMA — Scadenzario

'; }