AMS_Backend/app/Controllers/Backend/DashboardController.php
2025-11-06 13:41:06 +08:00

279 lines
10 KiB
PHP

<?php
namespace App\Controllers\Backend;
use CodeIgniter\RESTful\ResourceController;
use App\Models\Orders;
use App\Models\TopupModel;
use App\Models\Customer;
use App\Models\Outlet;
class DashboardController extends ResourceController
{
private $orders;
private $topup;
private $customer;
private $outlets;
public function __construct()
{
$this->orders = new Orders();
$this->topup = new TopupModel();
$this->customer = new Customer();
$this->outlets = new Outlet();
}
public function dashboard()
{
$today = date('Y-m-d');
$month = date('m');
$year = date('Y');
// 1. Net Sales Today (sum of grand_total where paid)
$netSalesToday = $this->orders
->selectSum('grand_total')
->where('DATE(created_at)', $today)
->where('payment_status', 'paid')
->get()->getRow()->grand_total ?? 0;
// 2. Today Transaction (count orders today)
$todayTransaction = $this->orders
->where('DATE(created_at)', $today)
->where('payment_status', 'paid')
->countAllResults();
// 3. Net Sales Month to Date
$netSalesMonthToDate = $this->orders
->selectSum('grand_total')
->where('MONTH(created_at)', $month)
->where('YEAR(created_at)', $year)
->where('payment_status', 'paid')
->get()->getRow()->grand_total ?? 0;
// 4. Net Sales Year to Date
$netSalesYearToDate = $this->orders
->selectSum('grand_total')
->where('YEAR(created_at)', $year)
->where('payment_status', 'paid')
->get()->getRow()->grand_total ?? 0;
// 5. Topup
$topup1 = $this->topup
->selectSum('amount')
->where('DATE(created_at)', $today)
->where('status', 'Success')
->get()->getRow()->amount ?? 0;
$topup2 = $this->topup
->selectSum('other_amount')
->where('DATE(created_at)', $today)
->where('status', 'Success')
->get()->getRow()->other_amount ?? 0;
// 6. Total Customer Wallet Balance
$wallet_balance = $this->customer
->selectSum('customer_wallet')
->get()->getRow()->customer_wallet ?? 0;
// 7. Today Voucher Redeemed / Discount
$today_voucher_amount = $this->orders
->selectSum('voucher_discount_amount')
->where('DATE(created_at)', $today)
->where('payment_status', 'paid')
->get()->getRow()->voucher_discount_amount ?? 0;
$today_promo_amount = $this->orders
->selectSum('promo_discount_amount')
->where('DATE(created_at)', $today)
->where('payment_status', 'paid')
->get()->getRow()->promo_discount_amount ?? 0;
$today_discount_amount = $this->orders
->selectSum('promo_discount_amount')
->where('DATE(created_at)', $today)
->where('payment_status', 'paid')
->get()->getRow()->promo_discount_amount ?? 0;
$data = [
'today_net_sales' => $netSalesToday,
'today_total_transaction' => $todayTransaction,
'net_sales_month_to_date' => $netSalesMonthToDate,
'net_sales_year_to_date' => $netSalesYearToDate,
'today_topup' => $topup1 + $topup2,
'total_wallet_balance' => $wallet_balance,
'today_total_discount_amount' => $today_voucher_amount + $today_promo_amount + $today_discount_amount,
];
return $this->respond(['status' => 200, 'data' => $data]);
}
public function dashboardSummary ()
{
$data = [
'today' => $this->orders->getTodayOrdersRevenueByHour(),
'yesterday' => $this->orders->getYesterdayOrdersRevenueByHour(),
'last7days' => $this->orders->getLast7DaysOrdersRevenue(),
'last30days' => $this->orders->getLast30DaysOrdersRevenue(),
];
return $this->respond(['status' => 200, 'data' => $data]);
}
public function liveMonitor()
{
//Current Offline outlets
$outlets = $this->outlets->getOperatingHoursWithDaysList();
$onlineCount = 0;
$offlineCount = 0;
foreach ($outlets as $outlet) {
if ($this->isOutletOnline($outlet)) {
$onlineCount++;
} else {
$offlineCount++;
}
}
// Cancelled Orders (all time, or do you also want by date range?)
$cancelledOrders = $this->orders
->where('payment_status', 'cancelled')
->countAllResults();
// Dates
$endDateCurrent = date('Y-m-d'); // today
$startDateCurrent = date('Y-m-d', strtotime('-7 days')); // 7 days ago
$endDatePrevious = date('Y-m-d', strtotime('-8 days')); // day before current range
$startDatePrevious = date('Y-m-d', strtotime('-15 days')); // 15 days ago
// Function to fetch stats for a range
$getStats = function($startDate, $endDate) {
// Gross Sales
$grossSales = $this->orders
->selectSum('grand_total', 'gross_sales')
->where('payment_status', 'paid')
->where('created_at >=', $startDate)
->where('created_at <=', $endDate)
->where('promo_discount_amount <=', 0) // No promo discount
->where('voucher_discount_amount <=', 0) // No voucher discount
->where('discount_amount <=', 0) // No regular discount
->get()->getRow()->gross_sales ?? 0;
// Total Customer
$totalCustomer = $this->orders
->select('COUNT(DISTINCT customer_id) as total_customer')
->where('payment_status', 'paid')
->where('created_at >=', $startDate)
->where('created_at <=', $endDate)
->get()->getRow()->total_customer ?? 0;
// Net Sales from Offers
$netSalesOffers = $this->orders
->selectSum('grand_total', 'net_sales_offers')
->where('payment_status', 'paid')
->where('created_at >=', $startDate)
->where('created_at <=', $endDate)
->groupStart()
->where('promo_discount_amount >', 0)
->orWhere('voucher_discount_amount >', 0)
->orWhere('discount_amount >', 0)
->groupEnd()
->get()->getRow()->net_sales_offers ?? 0;
// Average Transaction
$avgTransaction = $this->orders
->selectAvg('grand_total', 'avg_transaction')
->where('payment_status', 'paid')
->where('created_at >=', $startDate)
->where('created_at <=', $endDate)
->get()->getRow()->avg_transaction ?? 0;
return [
'gross_sales' => $grossSales,
'total_customer' => $totalCustomer,
'net_sales_from_offers' => $netSalesOffers,
'avg_transaction' => $avgTransaction,
];
};
// Current 7 days
$current = $getStats($startDateCurrent, $endDateCurrent);
// Previous 7 days
$previous = $getStats($startDatePrevious, $endDatePrevious);
// Function to calculate percentage difference
$calcPercentage = function($currentValue, $previousValue) {
if ($previousValue == 0) {
return $currentValue > 0 ? 100 : 0;
}
return (($currentValue - $previousValue) / $previousValue) * 100;
};
$data = [
'offline_outlets' => $offlineCount,
'cancelled_orders' => $cancelledOrders,
'gross_sales' => [
'current' => $current['gross_sales'],
'previous' => $previous['gross_sales'],
'percentage' => $calcPercentage($current['gross_sales'], $previous['gross_sales']),
],
'total_customer' => [
'current' => $current['total_customer'],
'previous' => $previous['total_customer'],
'percentage' => $calcPercentage($current['total_customer'], $previous['total_customer']),
],
'net_sales_from_offers' => [
'current' => $current['net_sales_from_offers'],
'previous' => $previous['net_sales_from_offers'],
'percentage' => $calcPercentage($current['net_sales_from_offers'], $previous['net_sales_from_offers']),
],
'avg_transaction' => [
'current' => $current['avg_transaction'],
'previous' => $previous['avg_transaction'],
'percentage' => $calcPercentage($current['avg_transaction'], $previous['avg_transaction']),
],
];
return $this->respond(['status' => 200, 'data' => $data]);
}
private function isOutletOnline($outlet)
{
// Get current day and time
$currentDay = date('l'); // e.g., "Monday"
$currentTime = date('H:i:s'); // Current time in 24-hour format
// Check if outlet operates on current day
if (!isset($outlet['operating_schedule'][$currentDay]) ||
!$outlet['operating_schedule'][$currentDay]['is_operated']) {
return false;
}
$operatingHours = $outlet['operating_schedule'][$currentDay]['operating_hours'];
// Check if current time falls within any operating hour slot
foreach ($operatingHours as $timeSlot) {
$startTime = $timeSlot['start_time'];
$endTime = $timeSlot['end_time'];
// Handle cases where end time is 23:59:00 (which means until midnight)
if ($endTime === '23:59:00') {
$endTime = '23:59:59';
}
if ($currentTime >= $startTime && $currentTime <= $endTime) {
return true;
}
}
return false;
}
}