diff --git a/api/daily_report_cron.php b/api/daily_report_cron.php index e5dd3fb..25cbc42 100644 --- a/api/daily_report_cron.php +++ b/api/daily_report_cron.php @@ -14,24 +14,41 @@ function cron_log($msg) { 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'])) { - // Silent exit if disabled or missing config exit; } $timezone = !empty($settings['timezone']) ? $settings['timezone'] : 'UTC'; date_default_timezone_set($timezone); - $reportTime = $settings['whatsapp_report_time']; + // 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); @@ -42,40 +59,97 @@ try { if ($diffToday >= 0 && $diffToday <= 900 && $lastReportDate !== $nowDt->format('Y-m-d')) { cron_log("Condition met: sending daily report for " . $nowDt->format('Y-m-d')); - $pdo = db(); $today = $nowDt->format('Y-m-d'); + $companyName = $settings['company_name'] ?? 'Company'; - // 1. Calculate Stats - // Total Revenue Today + // --- 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]); - $revenueToday = $stmt->fetchColumn() ?: 0; + $totalRevenue = $stmt->fetchColumn() ?: 0; // Total Orders Today $stmt = $pdo->prepare("SELECT COUNT(*) FROM orders WHERE DATE(created_at) = ? AND status != 'cancelled'"); $stmt->execute([$today]); - $ordersToday = $stmt->fetchColumn(); + $totalOrders = $stmt->fetchColumn() ?: 0; - // Total Expenses Today - $stmt = $pdo->prepare("SELECT SUM(amount) FROM expenses WHERE DATE(expense_date) = ?"); - $stmt->execute([$today]); - $expensesToday = $stmt->fetchColumn() ?: 0; - - // Currency - $currency = $settings['currency_symbol'] ?? '$'; + // --- 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"; - // 2. Format Message - $message = "๐Ÿ“… *Daily Report* ๐Ÿ“…\n"; - $message .= "Date: " . $today . "\n\n"; - $message .= "๐Ÿ’ฐ *Sales:* " . format_currency_simple($revenueToday, $settings) . "\n"; - $message .= "๐Ÿงพ *Orders:* " . $ordersToday . "\n"; - $message .= "๐Ÿ’ธ *Expenses:* " . format_currency_simple($expensesToday, $settings) . "\n"; - $message .= "\n--------------------------\n"; - $message .= "๐Ÿค– Auto-generated message"; + // --- 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(); - // 3. Send Message + 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); - // Handle multiple recipients (comma separated) $recipients = explode(',', $settings['whatsapp_report_number']); $anySuccess = false; @@ -83,7 +157,7 @@ try { $recipient = trim($recipient); if (empty($recipient)) continue; - cron_log("Sending report to: " . $recipient); + cron_log("Sending detailed report to: " . $recipient); $result = $wablas->sendMessage($recipient, $message); if (!empty($result['success']) && $result['success'] == true) { @@ -98,17 +172,7 @@ try { file_put_contents($lastReportFile, $today); } } - // Else: silent skip } catch (Exception $e) { cron_log("CRITICAL ERROR: " . $e->getMessage()); -} - -function format_currency_simple($amount, $settings) { - $symbol = $settings['currency_symbol'] ?? '$'; - $decimals = (int)($settings['currency_decimals'] ?? 2); - $position = $settings['currency_position'] ?? 'before'; - - $formatted = number_format((float)$amount, $decimals); - return ($position === 'after') ? "$formatted $symbol" : "$symbol $formatted"; -} +} \ No newline at end of file diff --git a/storage/cron_debug.log b/storage/cron_debug.log index 3bc6310..0574183 100644 --- a/storage/cron_debug.log +++ b/storage/cron_debug.log @@ -21657,3 +21657,8 @@ Array [2026-03-25 06:18:01] Settings retrieved: {"id":1,"company_name":"Al-Bidar Cafe","address":"al -hamra","phone":"99359472","email":"aalabry@gmail.com","vat_rate":"5.00","currency_symbol":"OMR","currency_decimals":3,"logo_url":"assets\/images\/company\/logo_699d0d4e79490.png","favicon_url":"assets\/images\/company\/favicon_699d0d4e7a2f6.png","ctr_number":"","vat_number":"OM99888","updated_at":"2026-03-25 01:59:39","auto_backup_enabled":0,"last_auto_backup":"2026-02-24 05:08:07","commission_enabled":0,"currency_position":"after","timezone":"Asia\/Muscat","whatsapp_report_number":"96897417667,96899359472","whatsapp_report_time":"23:59:00","whatsapp_report_enabled":1} [2026-03-25 06:18:01] Now: 2026-03-25 06:18:01 | Target: 2026-03-25 23:59:00 | Diff: -63659 | LastSent: [2026-03-25 06:18:01] Condition not met: skipping (Diff: -63659, LastSent: , Target: 23:59) +[2026-03-25 23:59:01] Condition met: sending daily report for 2026-03-25 +[2026-03-25 23:59:01] Sending report to: 96897417667 +[2026-03-25 23:59:02] Report sent successfully to 96897417667 +[2026-03-25 23:59:02] Sending report to: 96899359472 +[2026-03-25 23:59:03] Report sent successfully to 96899359472 diff --git a/storage/last_daily_report.txt b/storage/last_daily_report.txt new file mode 100644 index 0000000..f26217b --- /dev/null +++ b/storage/last_daily_report.txt @@ -0,0 +1 @@ +2026-03-25 \ No newline at end of file