Files
2026-10-23 17:22:17 +00:00

64 lines
3.8 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// Direkter Web-Zugriff wird geblockt (nur CLI oder Einbindung aus dem Backend/Pseudo-Cron).
if (php_sapi_name() !== 'cli' && !defined('DESKHUB_CRON_RUNNER')) { http_response_code(403); exit('Kein Web-Zugriff.'); }
/**
* cron/remind_customers.php
*
* Schickt Kunden eine freundliche Erinnerung, wenn sie auf eine Antwort (Status "Beantwortet") mehrere Tage nicht reagiert haben.
* Pro Antwort wird nur eine Erinnerung gesendet. Ist das automatische Schließen eingeschaltet, nennt die Mail, wann das Ticket
* geschlossen wird. Einstellbar unter Einstellungen → Allgemein ("Kunden erinnern").
*/
require_once __DIR__ . '/../includes/bootstrap.php';
/** @return array{sent:int, log:string[]} */
function run_remind_customers(PDO $pdo, bool $verbose = false): array
{
$log = [];
if (!customer_reminder_enabled()) {
return ['sent' => 0, 'log' => ['[' . date('Y-m-d H:i:s') . '] Kundenerinnerung ist deaktiviert – nichts zu tun.']];
}
$days = customer_reminder_days();
$threshold = date('Y-m-d H:i:s', time() - $days * 86400);
$closeDays = get_setting('auto_close_enabled', '0') === '1' ? max(1, (int) get_setting('auto_close_days', '7')) : 0;
$stmt = $pdo->prepare(
"SELECT t.*, d.name AS department_name FROM tickets t LEFT JOIN departments d ON d.id = t.department_id
WHERE t.status = 'answered' AND t.is_spam = 0 AND t.source <> 'chat' AND t.updated_at < ?
AND (t.reminder_sent_at IS NULL OR t.reminder_sent_at < t.updated_at)
AND (t.snoozed_until IS NULL OR t.snoozed_until <= ?)
ORDER BY t.updated_at LIMIT 100"
);
$stmt->execute([$threshold, db_now()]);
$sent = 0;
foreach ($stmt->fetchAll() as $t) {
if (empty($t['requester_email']) || !filter_var($t['requester_email'], FILTER_VALIDATE_EMAIL)) continue;
$closeNote = '';
if ($closeDays > $days) {
$closeNote = '<p style="margin:16px 0 0;color:#475569;font-size:14px;">Hören wir bis dahin nichts von Ihnen, schließen wir das Ticket in ' . ($closeDays - $days) . ' ' . (($closeDays - $days) === 1 ? 'Tag' : 'Tagen') . ' automatisch. Sie können es jederzeit wieder öffnen, indem Sie antworten.</p>';
} elseif ($closeDays > 0) {
$closeNote = '<p style="margin:16px 0 0;color:#475569;font-size:14px;">Hören wir von Ihnen nichts mehr, schließen wir das Ticket in Kürze automatisch. Sie können es jederzeit wieder öffnen, indem Sie antworten.</p>';
}
[$subject, $body] = render_email_template('customer_reminder', [
'ticket_number' => $t['ticket_number'],
'subject' => e($t['subject']),
'customer_name' => e($t['requester_name'] ?? ''),
'ticket_url' => e(ticket_access_url($t)),
'close_note' => $closeNote,
], "Erinnerung zu Ihrem Ticket [#{$t['ticket_number']}]", email_customer_reminder_default_body());
$from = resolve_from_address($t['department_id'] ?? null, $t['priority_id'] ?? null);
email_send_and_log($t['requester_email'], $subject, email_wrap($body), $from, 'Erinnerung an den Kunden', $t['ticket_number']);
// updated_at bleibt unverändert, damit das automatische Schließen seine Frist behält
$pdo->prepare('UPDATE tickets SET reminder_sent_at = ?, updated_at = updated_at WHERE id = ?')->execute([db_now(), $t['id']]);
log_activity($pdo, (int) $t['id'], null, 'Erinnerung an den Kunden gesendet');
$sent++;
if ($verbose) $log[] = "[ok] Erinnerung für Ticket #{$t['ticket_number']}";
}
set_setting('cron_remind_customers_last_run', db_now());
$log[] = '[' . date('Y-m-d H:i:s') . "] Kundenerinnerung: {$sent} Mail(s) gesendet (nach {$days} Tagen ohne Reaktion).";
return ['sent' => $sent, 'log' => $log];
}
if (php_sapi_name() === 'cli') {
foreach (run_remind_customers(get_db(), true)['log'] as $line) echo $line . "\n";
}