diff --git a/admin/company.php b/admin/company.php index 49bddde..c71d671 100644 --- a/admin/company.php +++ b/admin/company.php @@ -24,6 +24,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $ctr_number = $_POST['ctr_number'] ?? ''; $vat_number = $_POST['vat_number'] ?? ''; $commission_enabled = isset($_POST['commission_enabled']) ? 1 : 0; + $timezone = $_POST['timezone'] ?? 'UTC'; + $whatsapp_report_number = $_POST['whatsapp_report_number'] ?? ''; + $whatsapp_report_time = $_POST['whatsapp_report_time'] ?? '23:59:00'; + $whatsapp_report_enabled = isset($_POST['whatsapp_report_enabled']) ? 1 : 0; // Handle File Uploads $uploadDir = __DIR__ . '/../assets/images/company/'; @@ -69,11 +73,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $exists = $pdo->query("SELECT COUNT(*) FROM company_settings")->fetchColumn(); if ($exists) { - $stmt = $pdo->prepare("UPDATE company_settings SET company_name=?, address=?, phone=?, email=?, vat_rate=?, currency_symbol=?, currency_decimals=?, currency_position=?, ctr_number=?, vat_number=?, logo_url=?, favicon_url=?, commission_enabled=?, updated_at=NOW()"); - $stmt->execute([$company_name, $address, $phone, $email, $vat_rate, $currency_symbol, $currency_decimals, $currency_position, $ctr_number, $vat_number, $logo_url, $favicon_url, $commission_enabled]); + $stmt = $pdo->prepare("UPDATE company_settings SET company_name=?, address=?, phone=?, email=?, vat_rate=?, currency_symbol=?, currency_decimals=?, currency_position=?, ctr_number=?, vat_number=?, logo_url=?, favicon_url=?, commission_enabled=?, timezone=?, whatsapp_report_number=?, whatsapp_report_time=?, whatsapp_report_enabled=?, updated_at=NOW()"); + $stmt->execute([$company_name, $address, $phone, $email, $vat_rate, $currency_symbol, $currency_decimals, $currency_position, $ctr_number, $vat_number, $logo_url, $favicon_url, $commission_enabled, $timezone, $whatsapp_report_number, $whatsapp_report_time, $whatsapp_report_enabled]); } else { - $stmt = $pdo->prepare("INSERT INTO company_settings (company_name, address, phone, email, vat_rate, currency_symbol, currency_decimals, currency_position, ctr_number, vat_number, logo_url, favicon_url, commission_enabled) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); - $stmt->execute([$company_name, $address, $phone, $email, $vat_rate, $currency_symbol, $currency_decimals, $currency_position, $ctr_number, $vat_number, $logo_url, $favicon_url, $commission_enabled]); + $stmt = $pdo->prepare("INSERT INTO company_settings (company_name, address, phone, email, vat_rate, currency_symbol, currency_decimals, currency_position, ctr_number, vat_number, logo_url, favicon_url, commission_enabled, timezone, whatsapp_report_number, whatsapp_report_time, whatsapp_report_enabled) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + $stmt->execute([$company_name, $address, $phone, $email, $vat_rate, $currency_symbol, $currency_decimals, $currency_position, $ctr_number, $vat_number, $logo_url, $favicon_url, $commission_enabled, $timezone, $whatsapp_report_number, $whatsapp_report_time, $whatsapp_report_enabled]); } $message = '
Company settings updated successfully!
'; @@ -85,6 +89,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $settings['logo_url'] = $logo_url; $settings['favicon_url'] = $favicon_url; $settings['commission_enabled'] = $commission_enabled; + $settings['timezone'] = $timezone; + $settings['whatsapp_report_number'] = $whatsapp_report_number; + $settings['whatsapp_report_time'] = $whatsapp_report_time; + $settings['whatsapp_report_enabled'] = $whatsapp_report_enabled; } catch (Exception $e) { $message = '
Error updating settings: ' . htmlspecialchars($e->getMessage()) . '
'; @@ -164,6 +172,48 @@ include 'includes/header.php'; + +
+
System Settings
+
+
+ + +
+
+ +
+
Daily WhatsApp Summary Report
+
+
+
+ /> + +
Sends a daily summary of orders per outlet (cash, card, bank, etc.) via Wablas.
+
+
+
+ + /> +
Number with country code to receive the daily summary.
+
+
+ + /> +
System time when the report should be generated and sent.
+
+
+
Commission System
diff --git a/admin/includes/footer.php b/admin/includes/footer.php index a104a92..fcad323 100644 --- a/admin/includes/footer.php +++ b/admin/includes/footer.php @@ -47,6 +47,8 @@ // Trigger auto backup in background fetch('api/auto_backup.php').catch(err => console.error('Auto backup trigger failed', err)); + // Trigger daily report cron + fetch('api/daily_report_cron.php').catch(err => console.error('Daily report cron failed', err)); }); diff --git a/api/daily_report_cron.php b/api/daily_report_cron.php new file mode 100644 index 0000000..57b6da0 --- /dev/null +++ b/api/daily_report_cron.php @@ -0,0 +1,148 @@ + 'skipped', 'reason' => 'Not enabled or missing settings']); + exit; + } + + $timezone = $settings['timezone'] ?? 'UTC'; + date_default_timezone_set($timezone); + + $currentDate = date('Y-m-d'); + $currentTime = date('H:i:s'); + $reportTime = $settings['whatsapp_report_time']; + + // Check if it's past the report time + if ($currentTime < $reportTime) { + echo json_encode(['status' => 'skipped', 'reason' => 'Not time yet', 'time' => $currentTime, 'target' => $reportTime]); + exit; + } + + $lastReportFile = __DIR__ . '/../storage/last_daily_report.txt'; + if (!is_dir(dirname($lastReportFile))) { + mkdir(dirname($lastReportFile), 0755, true); + } + + $lastReportDate = file_exists($lastReportFile) ? trim(file_get_contents($lastReportFile)) : ''; + + if ($lastReportDate === $currentDate) { + echo json_encode(['status' => 'skipped', 'reason' => 'Already sent today']); + exit; + } + + // GENERATE REPORT + $pdo = db(); + + // Get all completed orders for today + $stmt = $pdo->prepare( + "SELECT + o.id, o.total_amount as total, o.payment_type_id, o.user_id, o.outlet_id, + pt.name as payment_type_name, + u.username, u.full_name, + outl.name as outlet_name + FROM orders o + LEFT JOIN payment_types pt ON o.payment_type_id = pt.id + LEFT JOIN users u ON o.user_id = u.id + LEFT JOIN outlets outl ON o.outlet_id = outl.id + WHERE DATE(o.created_at) = ? AND o.status = 'completed'" + ); + $stmt->execute([$currentDate]); + $orders = $stmt->fetchAll(PDO::FETCH_ASSOC); + + $totalOrders = count($orders); + $totalAmount = 0; + + $outletsData = []; + + foreach ($orders as $order) { + $totalAmount += $order['total']; + + $outletName = $order['outlet_name'] ?? 'Unknown Outlet'; + $staffName = !empty($order['full_name']) ? $order['full_name'] : ($order['username'] ?? 'Unknown Staff'); + $paymentType = $order['payment_type_name'] ?? 'Unknown Payment'; + $amount = (float)$order['total']; + + if (!isset($outletsData[$outletName])) { + $outletsData[$outletName] = [ + 'total' => 0, + 'staff' => [], + 'payments' => [] + ]; + } + + $outletsData[$outletName]['total'] += $amount; + + if (!isset($outletsData[$outletName]['staff'][$staffName])) { + $outletsData[$outletName]['staff'][$staffName] = 0; + } + $outletsData[$outletName]['staff'][$staffName] += $amount; + + if (!isset($outletsData[$outletName]['payments'][$paymentType])) { + $outletsData[$outletName]['payments'][$paymentType] = 0; + } + $outletsData[$outletName]['payments'][$paymentType] += $amount; + } + + $companyName = $settings['company_name'] ?? 'Restaurant'; + $currency = $settings['currency_symbol'] ?? '$'; + + $message = "📊 *Daily Summary Report* 📊\n"; + $message .= "🏢 *" . $companyName . "*\n"; + $message .= "📅 Date: " . $currentDate . "\n"; + $message .= "--------------------------------\n"; + $message .= "🛒 Total Orders: " . $totalOrders . "\n"; + $message .= "💰 Total Revenue: " . format_currency($totalAmount) . "\n\n"; + + if (empty($outletsData)) { + $message .= "No completed orders today.\n"; + } else { + foreach ($outletsData as $outletName => $data) { + $message .= "🏪 *" . $outletName . "*\n"; + $message .= " Total: " . format_currency($data['total']) . "\n"; + + $message .= " 🧑‍🍳 *Staff Breakdown:* +"; + foreach ($data['staff'] as $staff => $amt) { + $message .= " - " . $staff . ": " . format_currency($amt) . "\n"; + } + + $message .= " 💳 *Payment Breakdown:* +"; + foreach ($data['payments'] as $pt => $amt) { + $message .= " - " . $pt . ": " . format_currency($amt) . "\n"; + } + $message .= "\n"; + } + } + + $message .= "--------------------------------\n"; + $message .= "Generated automatically at " . date('H:i:s'); + + // Send via Wablas + // Write immediately to prevent duplicate triggers + file_put_contents($lastReportFile, $currentDate); + + // Send via Wablas + $wablasService = new WablasService($pdo); + $result = $wablasService->sendMessage($settings['whatsapp_report_number'], $message); + + if ($result['success']) { + echo json_encode(['status' => 'success', 'message' => 'Report sent']); + } else { + // Revert on failure + if (file_exists($lastReportFile)) { unlink($lastReportFile); } + echo json_encode(['status' => 'error', 'message' => $result['message']]); + } + +} catch (Exception $e) { + error_log("Daily Report Cron Error: " . $e->getMessage()); + echo json_encode(['status' => 'error', 'message' => $e->getMessage()]); +} diff --git a/assets/js/main.js b/assets/js/main.js index c19ac91..7aa320e 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -1,6 +1,12 @@ console.log('POS Script Loading...'); document.addEventListener('DOMContentLoaded', () => { + // Trigger crons silently + setTimeout(() => { + fetch('api/daily_report_cron.php').catch(e => console.error(e)); + fetch('api/auto_backup.php').catch(e => console.error(e)); + }, 5000); + console.log('POS Script DOMContentLoaded'); // SweetAlert2 Toast Mixin diff --git a/db/company_settings.sql b/db/company_settings.sql index 6c0a5b9..9c536c7 100644 --- a/db/company_settings.sql +++ b/db/company_settings.sql @@ -7,6 +7,7 @@ CREATE TABLE IF NOT EXISTS company_settings ( vat_rate DECIMAL(5, 2) DEFAULT 0.00, currency_symbol VARCHAR(10) DEFAULT '$', currency_decimals INT DEFAULT 2, + timezone VARCHAR(100) DEFAULT 'UTC', updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); diff --git a/db/config.php b/db/config.php index 827298c..6741e17 100644 --- a/db/config.php +++ b/db/config.php @@ -16,4 +16,15 @@ function db() { return $pdo; } -require_once __DIR__ . '/../includes/functions.php'; \ No newline at end of file +require_once __DIR__ . '/../includes/functions.php'; + +try { + $settings = get_company_settings(); + if (!empty($settings['timezone'])) { + date_default_timezone_set($settings['timezone']); + } else { + date_default_timezone_set('UTC'); + } +} catch (Exception $e) { + date_default_timezone_set('UTC'); +} diff --git a/db/migrations/045_add_timezone_to_settings.sql b/db/migrations/045_add_timezone_to_settings.sql new file mode 100644 index 0000000..3cd3e7a --- /dev/null +++ b/db/migrations/045_add_timezone_to_settings.sql @@ -0,0 +1 @@ +ALTER TABLE company_settings ADD COLUMN timezone VARCHAR(100) DEFAULT 'UTC'; diff --git a/db/migrations/046_daily_whatsapp_report_settings.sql b/db/migrations/046_daily_whatsapp_report_settings.sql new file mode 100644 index 0000000..9208665 --- /dev/null +++ b/db/migrations/046_daily_whatsapp_report_settings.sql @@ -0,0 +1,3 @@ +ALTER TABLE `company_settings` ADD COLUMN `whatsapp_report_number` VARCHAR(50) DEFAULT NULL; +ALTER TABLE `company_settings` ADD COLUMN `whatsapp_report_time` TIME DEFAULT '23:59:00'; +ALTER TABLE `company_settings` ADD COLUMN `whatsapp_report_enabled` TINYINT(1) DEFAULT 0;