38682-vm/api/daily_report_cron.php
2026-03-26 05:27:23 +00:00

178 lines
7.3 KiB
PHP

<?php
require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/../includes/functions.php';
require_once __DIR__ . '/../includes/WablasService.php';
// Enable error logging for cron
ini_set('log_errors', 1);
$logFile = __DIR__ . '/../storage/cron_debug.log';
ini_set('error_log', $logFile);
// Helper to log with timestamp
function cron_log($msg) {
global $logFile;
file_put_contents($logFile, "[" . date('Y-m-d H:i:s') . "] " . $msg . "\n", FILE_APPEND);
}
// Helper to format currency
function format_currency_custom($amount, $settings) {
$symbol = $settings['currency_symbol'] ?? '$';
$decimals = (int)($settings['currency_decimals'] ?? 3); // Default to 3 decimals as per user example (0.000 OMR)
$position = $settings['currency_position'] ?? 'after'; // Default to after as per user example (0.000 OMR)
$formatted = number_format((float)$amount, $decimals);
return ($position === 'after') ? "$formatted $symbol" : "$symbol $formatted";
}
try {
$settings = get_company_settings();
if (empty($settings['whatsapp_report_enabled']) || empty($settings['whatsapp_report_number']) || empty($settings['whatsapp_report_time'])) {
exit;
}
$timezone = !empty($settings['timezone']) ? $settings['timezone'] : 'UTC';
date_default_timezone_set($timezone);
// Sync MySQL Timezone
$pdo = db();
try {
$pdo->exec("SET time_zone = '" . date('P') . "'");
} catch (Exception $e) {
cron_log("Warning: Could not set MySQL timezone: " . $e->getMessage());
}
$reportTime = $settings['whatsapp_report_time'];
$lastReportFile = __DIR__ . '/../storage/last_daily_report.txt';
$lastReportDate = file_exists($lastReportFile) ? trim(file_get_contents($lastReportFile)) : '';
$nowDt = new DateTime('now', new DateTimeZone($timezone));
// Target time for today
$targetTodayDt = clone $nowDt;
$timeParts = explode(':', $reportTime);
$targetTodayDt->setTime((int)$timeParts[0], (int)($timeParts[1] ?? 0), 0);
$diffToday = $nowDt->getTimestamp() - $targetTodayDt->getTimestamp();
// Check if within 15 minutes (900 seconds) after the target time AND not sent today
if ($diffToday >= 0 && $diffToday <= 900 && $lastReportDate !== $nowDt->format('Y-m-d')) {
cron_log("Condition met: sending daily report for " . $nowDt->format('Y-m-d'));
$today = $nowDt->format('Y-m-d');
$companyName = $settings['company_name'] ?? 'Company';
// --- 1. Global Stats ---
// Total Revenue Today (Confirmed Orders)
// Note: Using status != 'cancelled' to include completed, ready, etc.
$stmt = $pdo->prepare("SELECT SUM(total_amount) FROM orders WHERE DATE(created_at) = ? AND status != 'cancelled'");
$stmt->execute([$today]);
$totalRevenue = $stmt->fetchColumn() ?: 0;
// Total Orders Today
$stmt = $pdo->prepare("SELECT COUNT(*) FROM orders WHERE DATE(created_at) = ? AND status != 'cancelled'");
$stmt->execute([$today]);
$totalOrders = $stmt->fetchColumn() ?: 0;
// --- 2. Build Message Header ---
$message = "๐Ÿ“Š *Daily Summary Report* ๐Ÿ“Š\n";
$message .= "๐Ÿข *" . $companyName . "*\n";
$message .= "๐Ÿ“… Date: " . $today . "\n";
$message .= "--------------------------------\n";
$message .= "๐Ÿ›’ *Total Orders:* " . $totalOrders . "\n";
$message .= "๐Ÿ’ฐ *Total Revenue:* " . format_currency_custom($totalRevenue, $settings) . "\n";
// --- 3. Per-Outlet Stats ---
// Get all active outlets
$stmtOutlets = $pdo->query("SELECT id, name FROM outlets WHERE is_deleted = 0 ORDER BY id ASC");
$outlets = $stmtOutlets->fetchAll();
foreach ($outlets as $outlet) {
$outletId = $outlet['id'];
$outletName = $outlet['name'];
// Outlet Revenue
$stmtRev = $pdo->prepare("SELECT SUM(total_amount) FROM orders WHERE outlet_id = ? AND DATE(created_at) = ? AND status != 'cancelled'");
$stmtRev->execute([$outletId, $today]);
$outletRevenue = $stmtRev->fetchColumn() ?: 0;
$message .= "\n๐Ÿช *" . $outletName . " Total:* " . format_currency_custom($outletRevenue, $settings) . "\n";
// Staff Breakdown for this Outlet
$message .= "๐Ÿง‘โ€๐Ÿณ *Staff Breakdown:*
";
$stmtStaff = $pdo->prepare("
SELECT u.username, u.full_name, COUNT(o.id) as order_count, SUM(o.total_amount) as revenue
FROM orders o
LEFT JOIN users u ON o.user_id = u.id
WHERE o.outlet_id = ? AND DATE(o.created_at) = ? AND o.status != 'cancelled'
GROUP BY o.user_id
");
$stmtStaff->execute([$outletId, $today]);
$staffStats = $stmtStaff->fetchAll();
if (empty($staffStats)) {
$message .= "- No staff sales\n";
} else {
foreach ($staffStats as $stat) {
$staffName = !empty($stat['full_name']) ? $stat['full_name'] : ($stat['username'] ?? 'Unknown');
$message .= "- " . $staffName . ": " . format_currency_custom($stat['revenue'], $settings) . " (" . $stat['order_count'] . " orders)\n";
}
}
// Payment Breakdown for this Outlet
$message .= "๐Ÿ’ณ *Payment Breakdown:*
";
$stmtPayment = $pdo->prepare("
SELECT pt.name, SUM(o.total_amount) as revenue
FROM orders o
LEFT JOIN payment_types pt ON o.payment_type_id = pt.id
WHERE o.outlet_id = ? AND DATE(o.created_at) = ? AND o.status != 'cancelled'
GROUP BY o.payment_type_id
");
$stmtPayment->execute([$outletId, $today]);
$paymentStats = $stmtPayment->fetchAll();
if (empty($paymentStats)) {
$message .= "- No payments\n";
} else {
foreach ($paymentStats as $stat) {
$paymentName = $stat['name'] ?? 'Unknown';
$message .= "- " . $paymentName . ": " . format_currency_custom($stat['revenue'], $settings) . "\n";
}
}
}
$message .= "--------------------------------\n";
$message .= "Generated automatically at " . $nowDt->format('H:i:s');
// --- 4. Send Message ---
$wablas = new WablasService($pdo);
$recipients = explode(',', $settings['whatsapp_report_number']);
$anySuccess = false;
foreach ($recipients as $recipient) {
$recipient = trim($recipient);
if (empty($recipient)) continue;
cron_log("Sending detailed report to: " . $recipient);
$result = $wablas->sendMessage($recipient, $message);
if (!empty($result['success']) && $result['success'] == true) {
cron_log("Report sent successfully to " . $recipient);
$anySuccess = true;
} else {
cron_log("Failed to send report to " . $recipient . ": " . ($result['message'] ?? 'Unknown error'));
}
}
if ($anySuccess) {
file_put_contents($lastReportFile, $today);
}
}
} catch (Exception $e) {
cron_log("CRITICAL ERROR: " . $e->getMessage());
}