Server : Apache System : Linux webd003.cluster111.gra.hosting.ovh.net 5.15.206-ovh-vps-grsec-zfs-classid #1 SMP Fri May 15 02:41:25 UTC 2026 x86_64 User : edevmultrx ( 811899) PHP Version : 7.4.33 Disable Function : _dyuweyrj4,_dyuweyrj4r,dl Directory : /home/edevmultrx/www/terra-d-oro/api/ |
<?php
/**
* Terra D'Oro — Send Payment Reminder Emails
* Route: GET /api/send-reminders?key=SYNC_KEY
*
* Intended to be called by a cron job every 15-30 minutes.
* Finds all awaiting_payment bookings created 1–24 h ago where no reminder
* has been sent yet, sends one luxe HTML email per booking, and records
* the timestamp so no booking is ever emailed twice.
*
* On OVH mutualisé, configure the cron like:
* URL : https://terra-doro.com/api/send-reminders?key=YOUR_SYNC_KEY
* Frequency : every 30 minutes
*
* Protected by SYNC_KEY (same as the iCal sync endpoint).
*/
declare(strict_types=1);
if (!defined('ROOT_PATH')) {
define('ROOT_PATH', dirname(__DIR__));
}
require_once ROOT_PATH . '/core/config.php';
// ── Auth ──────────────────────────────────────────────────────────────────────
$provided_key = trim($_GET['key'] ?? $_SERVER['HTTP_X_CRON_KEY'] ?? '');
if (!hash_equals(SYNC_KEY, $provided_key)) {
http_response_code(403);
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['error' => 'Forbidden']);
exit;
}
// ── Bootstrap ─────────────────────────────────────────────────────────────────
require_once ROOT_PATH . '/core/db.php';
require_once ROOT_PATH . '/core/helpers.php';
require_once ROOT_PATH . '/core/payment.php';
// ── Find bookings to remind ───────────────────────────────────────────────────
// - status = awaiting_payment
// - created between 1 h ago and 24 h ago (outside this window = too soon or too old)
// - reminder not yet sent (reminder_sent_at IS NULL)
//
// DEV only: add &test=1 to use a 5-minute window (for local testing without waiting 1h)
$now = new DateTimeImmutable('now', new DateTimeZone(SITE_TIMEZONE));
if (ENV === 'development' && ($_GET['test'] ?? '') === '1') {
// Test mode: window = last 5 minutes (also resets reminder_sent_at so you can re-test)
$cutoff_from = $now->modify('-5 minutes')->format('Y-m-d H:i:s');
$cutoff_to = $now->format('Y-m-d H:i:s');
// Allow re-sending by ignoring reminder_sent_at
$ignore_sent = true;
} else {
$cutoff_from = $now->modify('-24 hours')->format('Y-m-d H:i:s');
$cutoff_to = $now->modify('-1 hour')->format('Y-m-d H:i:s');
$ignore_sent = false;
}
$sent_filter = $ignore_sent ? '1=1' : 'b.reminder_sent_at IS NULL';
$stmt = $db->prepare(
"SELECT b.id, b.guest_name, b.guest_email,
b.check_in, b.check_out, b.total_price, b.paid_amount, b.created_at,
u.name AS unit_name, u.slug AS unit_slug
FROM `" . TBL_BOOKINGS . "` b
JOIN `" . TBL_UNITS . "` u ON u.id = b.unit_id
WHERE b.status = 'awaiting_payment'
AND {$sent_filter}
AND b.guest_email != ''
AND b.created_at BETWEEN :from AND :to"
);
$stmt->execute([':from' => $cutoff_from, ':to' => $cutoff_to]);
$bookings = $stmt->fetchAll();
// ── Send reminders ────────────────────────────────────────────────────────────
$sent = 0;
$errors = 0;
$log = [];
foreach ($bookings as $b) {
// Build a signed resume token (HMAC — no extra DB column needed)
$token = hash_hmac('sha256', 'resume:' . $b['id'] . ':' . $b['created_at'], STRIPE_SECRET_KEY);
$resume_url = BASE_URL . '/api/resume-payment?bid=' . $b['id'] . '&tok=' . $token;
$html = build_reminder_email($b, $resume_url);
$subject = 'Votre séjour à Terra D\'Oro vous attend — finalisez votre réservation';
$ok = send_mail((string) $b['guest_email'], $subject, $html);
if ($ok) {
// Mark as sent so this booking is never reminded again
$db->prepare(
"UPDATE `" . TBL_BOOKINGS . "` SET reminder_sent_at = :now WHERE id = :id"
)->execute([':now' => date('Y-m-d H:i:s'), ':id' => $b['id']]);
$log[] = ['id' => $b['id'], 'email' => $b['guest_email'], 'status' => 'sent'];
$sent++;
} else {
$log[] = ['id' => $b['id'], 'email' => $b['guest_email'], 'status' => 'error'];
$errors++;
}
}
// ── Response ──────────────────────────────────────────────────────────────────
header('Content-Type: application/json; charset=utf-8');
echo json_encode([
'ok' => true,
'sent' => $sent,
'errors' => $errors,
'total' => count($bookings),
'window' => ['from' => $cutoff_from, 'to' => $cutoff_to],
'log' => $log,
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);