diff --git a/app/Http/Controllers/Admin/DashboardController.php b/app/Http/Controllers/Admin/DashboardController.php
index 983bf79..a99c3aa 100644
--- a/app/Http/Controllers/Admin/DashboardController.php
+++ b/app/Http/Controllers/Admin/DashboardController.php
@@ -4,7 +4,6 @@
use App\Http\Controllers\Controller;
use App\Services\System\DashboardService;
-use Carbon\Carbon;
use Inertia\Inertia;
use Inertia\Response;
@@ -16,33 +15,17 @@ public function __construct(
public function index(): Response
{
- $now = Carbon::now();
- $startOfMonth = $now->copy()->startOfMonth();
- $endOfMonth = $now->copy()->endOfMonth();
-
- $startOfDay = Carbon::today()->startOfDay();
- $endOfDay = Carbon::today()->endOfDay();
-
return Inertia::render('admin/Dashboard', [
+ 'attendance' => $this->dashboardService->getAttendance(),
+ 'cashOverview' => $this->dashboardService->getCashOverview(),
+ 'revenueSummary' => $this->dashboardService->getRevenueSummary(),
+ 'expenseSummary' => $this->dashboardService->getExpenseSummary(),
+
'topSuppliers' => $this->dashboardService->getTopSuppliers(),
'topCustomers' => $this->dashboardService->getTopCustomers(),
'topProducts' => $this->dashboardService->getTopProducts(),
- 'purchaseSummary' => $this->dashboardService->getPurchaseSummary($startOfDay, $endOfDay),
- 'cuttingSummary' => $this->dashboardService->getCuttingSummary(),
- 'cuttingByStatus' => $this->dashboardService->getCuttingByStatus(),
+
'orderStats' => $this->dashboardService->getOrderStats(),
- 'revenueSummary' => $this->dashboardService->getRevenueSummary($startOfDay, $endOfDay),
- 'marketplaceSummary' => $this->dashboardService->getMarketplaceSummary(),
- 'cashAccounts' => $this->dashboardService->getCashAccounts(),
- 'cashSummary' => $this->dashboardService->getCashSummary($startOfDay, $endOfDay),
- 'monthlyCashFlow' => $this->dashboardService->getMonthlyCashFlow(),
- 'monthlyExpenses' => $this->dashboardService->getMonthlyExpenses($startOfDay, $endOfDay),
- 'kasbonSummary' => $this->dashboardService->getKasbonSummary($startOfDay, $endOfDay),
- 'payrollSummary' => $this->dashboardService->getPayrollSummary($startOfMonth, $endOfMonth),
- 'employeeSummary' => $this->dashboardService->getEmployeeSummary(),
- 'attendanceToday' => $this->dashboardService->getAttendanceToday($startOfDay, $endOfDay),
- 'monthlyRevenueTrend' => $this->dashboardService->getMonthlyRevenueTrend(),
- 'monthlyPurchaseTrend' => $this->dashboardService->getMonthlyPurchaseTrend(),
]);
}
}
diff --git a/app/Services/System/DashboardService.php b/app/Services/System/DashboardService.php
index 1907ed8..c41dc7e 100644
--- a/app/Services/System/DashboardService.php
+++ b/app/Services/System/DashboardService.php
@@ -2,119 +2,133 @@
namespace App\Services\System;
-use App\Enums\CuttingStatus;
-use App\Enums\EmploymentStatus;
use App\Enums\OrderChannel;
use App\Enums\OrderStatus;
use App\Enums\PaymentType;
use App\Models\Attendance;
use App\Models\CashAccount;
use App\Models\CashTransaction;
-use App\Models\Category;
-use App\Models\Cutting;
-use App\Models\CuttingResult;
use App\Models\Employee;
use App\Models\EmployeeAdvance;
use App\Models\Expense;
use App\Models\LeaveRequest;
use App\Models\Order;
use App\Models\OrderItem;
-use App\Models\Payroll;
-use App\Models\PayrollPeriod;
-use App\Models\Product;
-use App\Models\ProductVariant;
use App\Models\Purchase;
-use App\Models\RawMaterialPrice;
use Carbon\Carbon;
class DashboardService
{
- public function getRawMaterialStock(): array
+ public function getAttendance(): array
{
- $stockSummary = RawMaterialPrice::query()
- ->selectRaw('SUM(stock) as total_stock, SUM(stock * price) as total_value')
- ->first();
+ $totalEmployees = Employee::query()->count();
+ $today = Carbon::today();
- $stockByUnit = RawMaterialPrice::query()
- ->join('raw_materials', 'raw_material_prices.raw_material_id', '=', 'raw_materials.id')
- ->selectRaw('raw_materials.unit, SUM(raw_material_prices.stock) as total_stock')
- ->groupBy('raw_materials.unit')
- ->get()
- ->mapWithKeys(fn ($item) => [
- $item->unit => (float) $item->total_stock,
- ])
- ->toArray();
+ $present = Attendance::query()
+ ->where('attendance_date', $today)
+ ->distinct('employee_id')
+ ->count('employee_id');
+
+ $onLeave = LeaveRequest::query()
+ ->approved()
+ ->where('start_date', '<=', $today)
+ ->where('end_date', '>=', $today)
+ ->distinct('employee_id')
+ ->count('employee_id');
+
+ $absent = max(0, $totalEmployees - $present - $onLeave);
return [
- 'total_stock' => (float) ($stockSummary->total_stock ?? 0),
- 'total_value' => (int) ($stockSummary->total_value ?? 0),
- 'by_unit' => $stockByUnit,
+ 'total_employees' => $totalEmployees,
+ 'percentage' => $totalEmployees > 0 ? round($present / $totalEmployees * 100) : 0,
+ 'present' => $present,
+ 'absent' => $absent,
+ 'on_leave' => $onLeave,
];
}
- public function getProductStock(): array
+ public function getCashOverview(): array
{
- $variantSummary = ProductVariant::query()
- ->selectRaw('SUM(stock) as total_stock, SUM(reject_stock) as total_reject, COUNT(*) as total_variants')
+ $totalBalance = CashAccount::query()->sum('balance');
+
+ $summary = CashTransaction::query()
+ ->whereDate('created_at', Carbon::today())
+ ->selectRaw("
+ COUNT(*) as total_transactions,
+ COALESCE(SUM(CASE WHEN type = 'deposit' THEN amount ELSE 0 END), 0) as total_deposit,
+ COALESCE(SUM(CASE WHEN type = 'withdrawal' THEN amount ELSE 0 END), 0) as total_withdrawal
+ ")
->first();
- $totalStock = (int) ($variantSummary->total_stock ?? 0);
-
- $totalValue = Cutting::query()
- ->whereNotNull('cost_per_unit')
- ->join('cutting_results', 'cuttings.id', '=', 'cutting_results.cutting_id')
- ->selectRaw('SUM(cutting_results.warehouse_stock * cuttings.cost_per_unit) as total_value')
- ->value('total_value');
-
- $totalProducts = Product::query()->count();
- $totalCategories = Category::query()->count();
-
return [
- 'total_stock' => $totalStock,
- 'total_reject' => (int) ($variantSummary->total_reject ?? 0),
- 'total_value' => (int) ($totalValue ?? 0),
- 'total_variants' => (int) ($variantSummary->total_variants ?? 0),
- 'total_products' => $totalProducts,
- 'total_categories' => $totalCategories,
+ 'total_balance' => (int) $totalBalance,
+ 'total_transactions' => (int) ($summary->total_transactions ?? 0),
+ 'total_deposit' => (int) ($summary->total_deposit ?? 0),
+ 'total_withdrawal' => (int) ($summary->total_withdrawal ?? 0),
];
}
- public function getLowStockProducts(): array
+ public function getRevenueSummary(): array
{
- return ProductVariant::query()
- ->where('stock', '<=', ProductVariant::minStock())
- ->join('products', 'product_variants.product_id', '=', 'products.id')
- ->selectRaw("CONCAT(products.name, ' - ', product_variants.name) as full_name, product_variants.stock")
- ->orderBy('stock')
- ->limit(5)
+ $revenueSummary = Order::query()
+ ->completed()
+ ->whereDate('created_at', Carbon::today())
+ ->selectRaw('SUM(total_amount) as total_revenue, SUM(discount) as total_discount, SUM(shipping_cost) as total_shipping, COUNT(*) as total_orders, AVG(total_amount) as avg_order')
+ ->first();
+
+ $totalMarketplaceFees = Order::query()
+ ->completed()
+ ->whereNotNull('marketplace_settings_snapshot')
+ ->whereDate('created_at', Carbon::today())
->get()
- ->map(fn ($item) => [
- 'name' => $item->full_name,
- 'stock' => (int) $item->stock,
- ])
- ->toArray();
+ ->sum(fn ($order) => (int) ($order->marketplace_settings_snapshot['total_fee_amount'] ?? 0));
+
+ return [
+ 'total_revenue' => (int) ($revenueSummary->total_revenue ?? 0),
+ 'total_discount' => (int) ($revenueSummary->total_discount ?? 0),
+ 'total_marketplace_fees' => $totalMarketplaceFees,
+ 'total_potongan' => (int) ($revenueSummary->total_discount ?? 0) + $totalMarketplaceFees,
+ 'total_shipping' => (int) ($revenueSummary->total_shipping ?? 0),
+ 'total_orders' => (int) ($revenueSummary->total_orders ?? 0),
+ 'avg_order' => (int) ($revenueSummary->avg_order ?? 0),
+ ];
}
- public function getLowStockMaterials(): array
+ public function getExpenseSummary(): array
{
- return RawMaterialPrice::query()
- ->where('stock', '<=', 5)
- ->join('raw_materials', 'raw_material_prices.raw_material_id', '=', 'raw_materials.id')
- ->selectRaw("CONCAT(raw_materials.name, ' - ', raw_material_prices.variant) as full_name, raw_material_prices.stock, raw_materials.unit")
- ->orderBy('stock')
- ->limit(5)
- ->get()
- ->map(fn ($item) => [
- 'name' => $item->full_name,
- 'stock' => (float) $item->stock,
- 'unit' => $item->unit,
- ])
- ->toArray();
+ $today = Carbon::today();
+
+ $purchase = Purchase::query()
+ ->whereDate('created_at', $today)
+ ->selectRaw('COALESCE(SUM(total), 0) as total')
+ ->first();
+
+ $expenses = Expense::query()
+ ->whereDate('created_at', $today)
+ ->selectRaw('COALESCE(SUM(amount), 0) as total')
+ ->first();
+
+ $employeeAdvance = EmployeeAdvance::query()
+ ->whereDate('created_at', $today)
+ ->selectRaw('COALESCE(SUM(amount), 0) as total')
+ ->first();
+
+ $purchaseTotal = (int) ($purchase->total ?? 0);
+ $expenseTotal = (int) ($expenses->total ?? 0);
+ $advanceTotal = (int) ($employeeAdvance->total ?? 0);
+
+ return [
+ 'total' => $purchaseTotal + $expenseTotal + $advanceTotal,
+ 'purchase_total' => $purchaseTotal,
+ 'expense_total' => $expenseTotal,
+ 'advance_total' => $advanceTotal,
+ ];
}
public function getTopSuppliers(): array
{
return Purchase::query()
+ ->whereDate('purchases.created_at', Carbon::today())
->join('suppliers', 'purchases.supplier_id', '=', 'suppliers.id')
->selectRaw('suppliers.name, SUM(purchases.total) as total_amount, COUNT(purchases.id) as purchase_count')
->groupBy('suppliers.id', 'suppliers.name')
@@ -133,6 +147,7 @@ public function getTopCustomers(): array
{
return Order::query()
->completed()
+ ->whereDate('orders.created_at', Carbon::today())
->join('customers', 'orders.customer_id', '=', 'customers.id')
->selectRaw('customers.name, SUM(orders.total_amount) as total_amount, COUNT(orders.id) as order_count')
->groupBy('customers.id', 'customers.name')
@@ -154,6 +169,7 @@ public function getTopProducts(): array
->join('product_variants', 'order_items.product_variant_id', '=', 'product_variants.id')
->join('products', 'product_variants.product_id', '=', 'products.id')
->where('orders.status', OrderStatus::COMPLETED)
+ ->whereDate('orders.created_at', Carbon::today())
->selectRaw("CONCAT(products.name, ' - ', product_variants.name) as full_name, SUM(order_items.quantity) as total_qty, SUM(order_items.subtotal) as total_revenue")
->groupBy('order_items.product_variant_id', 'products.name', 'product_variants.name')
->orderByDesc('total_qty')
@@ -167,57 +183,10 @@ public function getTopProducts(): array
->toArray();
}
- public function getPurchaseSummary(?Carbon $startDate = null, ?Carbon $endDate = null): array
- {
- $query = Purchase::query();
- if ($startDate && $endDate) {
- $query->whereBetween('created_at', [$startDate, $endDate]);
- }
- $purchaseSummary = $query->selectRaw('COUNT(*) as total_purchases, SUM(total) as total_spent, SUM(discount) as total_discount')
- ->first();
-
- return [
- 'total_purchases' => (int) ($purchaseSummary->total_purchases ?? 0),
- 'total_spent' => (int) ($purchaseSummary->total_spent ?? 0),
- 'total_discount' => (int) ($purchaseSummary->total_discount ?? 0),
- ];
- }
-
- public function getCuttingSummary(): array
- {
- $totalCost = Cutting::query()
- ->selectRaw('COALESCE(SUM(total_material_cost), 0) + COALESCE(SUM(sewing_cost), 0) + COALESCE(SUM(other_cost), 0) as total_cost')
- ->value('total_cost');
-
- $totalResults = CuttingResult::query()
- ->selectRaw('SUM(cutting_result) as total_cutting, SUM(warehouse_stock) as total_warehouse, SUM(cutting_reject) as total_reject')
- ->first();
-
- return [
- 'total_cost' => (int) ($totalCost ?? 0),
- 'total_cutting' => (int) ($totalResults->total_cutting ?? 0),
- 'total_warehouse' => (int) ($totalResults->total_warehouse ?? 0),
- 'total_reject' => (int) ($totalResults->total_reject ?? 0),
- ];
- }
-
- public function getCuttingByStatus(): array
- {
- return Cutting::query()
- ->selectRaw('status, COUNT(*) as count')
- ->groupBy('status')
- ->get()
- ->map(fn ($item) => [
- 'status' => $item->status instanceof CuttingStatus ? $item->status->value : $item->status,
- 'label' => $item->status instanceof CuttingStatus ? $item->status->label() : CuttingStatus::from($item->status)->label(),
- 'count' => (int) $item->count,
- ])
- ->toArray();
- }
-
public function getOrderStats(): array
{
$byChannel = Order::query()
+ ->whereDate('created_at', Carbon::today())
->selectRaw('channel, COUNT(*) as count, SUM(total_amount) as total')
->groupBy('channel')
->get()
@@ -229,6 +198,7 @@ public function getOrderStats(): array
]);
$byPaymentType = Order::query()
+ ->whereDate('created_at', Carbon::today())
->selectRaw('payment_type, COUNT(*) as count, SUM(total_amount) as total')
->groupBy('payment_type')
->get()
@@ -241,6 +211,7 @@ public function getOrderStats(): array
$byMarketing = Order::query()
->whereNotNull('marketing_id')
+ ->whereDate('orders.created_at', Carbon::today())
->join('users', 'orders.marketing_id', '=', 'users.id')
->leftJoin('user_profiles', 'users.id', '=', 'user_profiles.user_id')
->selectRaw('COALESCE(user_profiles.full_name, users.username) as name, COUNT(*) as count, SUM(orders.total_amount) as total')
@@ -255,6 +226,7 @@ public function getOrderStats(): array
]);
$byStatus = Order::query()
+ ->whereDate('created_at', Carbon::today())
->selectRaw('status, COUNT(*) as count')
->groupBy('status')
->get()
@@ -271,375 +243,4 @@ public function getOrderStats(): array
'by_status' => $byStatus->toArray(),
];
}
-
- public function getRevenueSummary(?Carbon $startDate = null, ?Carbon $endDate = null): array
- {
- $query = Order::query()->completed();
- if ($startDate && $endDate) {
- $query->whereBetween('created_at', [$startDate, $endDate]);
- }
- $revenueSummary = $query->selectRaw('SUM(total_amount) as total_revenue, SUM(discount) as total_discount, SUM(shipping_cost) as total_shipping, COUNT(*) as total_orders, AVG(total_amount) as avg_order')
- ->first();
-
- $feesQuery = Order::query()->completed()->whereNotNull('marketplace_settings_snapshot');
- if ($startDate && $endDate) {
- $feesQuery->whereBetween('created_at', [$startDate, $endDate]);
- }
- $totalMarketplaceFees = $feesQuery->get()
- ->sum(fn ($order) => (int) ($order->marketplace_settings_snapshot['total_fee_amount'] ?? 0));
-
- return [
- 'total_revenue' => (int) ($revenueSummary->total_revenue ?? 0),
- 'total_discount' => (int) ($revenueSummary->total_discount ?? 0),
- 'total_marketplace_fees' => $totalMarketplaceFees,
- 'total_potongan' => (int) ($revenueSummary->total_discount ?? 0) + $totalMarketplaceFees,
- 'total_shipping' => (int) ($revenueSummary->total_shipping ?? 0),
- 'total_orders' => (int) ($revenueSummary->total_orders ?? 0),
- 'avg_order' => (int) ($revenueSummary->avg_order ?? 0),
- ];
- }
-
- public function getMarketplaceSummary(): array
- {
- $marketplaceOrders = Order::query()
- ->completed()
- ->whereIn('channel', [OrderChannel::SHOPEE, OrderChannel::TIKTOK])
- ->whereNotNull('marketplace_settings_snapshot')
- ->get();
-
- $totalRevenue = $marketplaceOrders->sum('total_amount');
- $totalFees = $marketplaceOrders->sum(fn ($order) => (int) ($order->marketplace_settings_snapshot['total_fee_amount'] ?? 0));
- $totalNet = $marketplaceOrders->sum(fn ($order) => (int) ($order->marketplace_settings_snapshot['net_amount'] ?? 0));
- $totalOrders = $marketplaceOrders->count();
-
- return [
- 'total_revenue' => (int) $totalRevenue,
- 'total_fees' => (int) $totalFees,
- 'total_net' => (int) $totalNet,
- 'total_orders' => (int) $totalOrders,
- ];
- }
-
- public function getCashAccounts(): array
- {
- return CashAccount::query()
- ->selectRaw('name, balance')
- ->get()
- ->map(fn ($item) => [
- 'name' => $item->name,
- 'balance' => (int) $item->balance,
- ])
- ->toArray();
- }
-
- public function getCashSummary(?Carbon $startDate = null, ?Carbon $endDate = null): array
- {
- $query = CashTransaction::query();
- if ($startDate && $endDate) {
- $query->whereBetween('created_at', [$startDate, $endDate]);
- }
- $summary = $query->selectRaw("
- COUNT(*) as total_transactions,
- COALESCE(SUM(CASE WHEN type = 'deposit' THEN amount ELSE 0 END), 0) as total_deposit,
- COALESCE(SUM(CASE WHEN type = 'withdrawal' THEN amount ELSE 0 END), 0) as total_withdrawal
- ")
- ->first();
-
- return [
- 'total_transactions' => (int) ($summary->total_transactions ?? 0),
- 'total_deposit' => (int) ($summary->total_deposit ?? 0),
- 'total_withdrawal' => (int) ($summary->total_withdrawal ?? 0),
- ];
- }
-
- public function getMonthlyCashFlow(): array
- {
- $months = collect();
- for ($monthOffset = 5; $monthOffset >= 0; $monthOffset--) {
- $date = Carbon::now()->subMonths($monthOffset);
- $months->push([
- 'year' => $date->year,
- 'month' => $date->month,
- 'label' => $date->translatedFormat('M Y'),
- ]);
- }
-
- $result = $months->map(function ($month) {
- $start = Carbon::create($month['year'], $month['month'], 1)->startOfMonth();
- $end = $start->copy()->endOfMonth();
-
- $monthlyTransactions = CashTransaction::query()
- ->whereBetween('created_at', [$start, $end])
- ->selectRaw("
- COALESCE(SUM(CASE WHEN type = 'deposit' THEN amount ELSE 0 END), 0) as deposits,
- COALESCE(SUM(CASE WHEN type = 'withdrawal' THEN amount ELSE 0 END), 0) as withdrawals
- ")
- ->first();
-
- return [
- 'label' => $month['label'],
- 'deposits' => (int) $monthlyTransactions->deposits,
- 'withdrawals' => (int) $monthlyTransactions->withdrawals,
- ];
- });
-
- return $result->toArray();
- }
-
- public function getMonthlyExpenses(?Carbon $startDate = null, ?Carbon $endDate = null): array
- {
- $query = Expense::query();
- if ($startDate && $endDate) {
- $query->whereBetween('created_at', [$startDate, $endDate]);
- }
- $monthlyExpenses = $query->selectRaw('COALESCE(SUM(amount), 0) as total, COUNT(*) as count')
- ->first();
-
- return [
- 'total' => (int) ($monthlyExpenses->total ?? 0),
- 'count' => (int) ($monthlyExpenses->count ?? 0),
- ];
- }
-
- public function getKasbonSummary(?Carbon $startDate = null, ?Carbon $endDate = null): array
- {
- $pendingQuery = EmployeeAdvance::query()->pending();
- $approvedQuery = EmployeeAdvance::query()->approved();
- $paidQuery = EmployeeAdvance::query()->paid();
- $employeeQuery = EmployeeAdvance::query();
-
- if ($startDate && $endDate) {
- $pendingQuery->whereBetween('created_at', [$startDate, $endDate]);
- $approvedQuery->whereBetween('created_at', [$startDate, $endDate]);
- $paidQuery->whereBetween('created_at', [$startDate, $endDate]);
- $employeeQuery->whereBetween('created_at', [$startDate, $endDate]);
- }
-
- $pending = $pendingQuery->selectRaw('COUNT(*) as count, COALESCE(SUM(amount), 0) as total')->first();
- $approved = $approvedQuery->selectRaw('COUNT(*) as count, COALESCE(SUM(amount), 0) as total')->first();
- $paid = $paidQuery->selectRaw('COUNT(*) as count, COALESCE(SUM(amount), 0) as total')->first();
- $totalEmployees = $employeeQuery->distinct('employee_id')->count('employee_id');
-
- return [
- 'pending' => [
- 'count' => (int) ($pending->count ?? 0),
- 'total' => (int) ($pending->total ?? 0),
- ],
- 'approved' => [
- 'count' => (int) ($approved->count ?? 0),
- 'total' => (int) ($approved->total ?? 0),
- ],
- 'paid' => [
- 'count' => (int) ($paid->count ?? 0),
- 'total' => (int) ($paid->total ?? 0),
- ],
- 'total' => (int) ($pending->total ?? 0) + (int) ($approved->total ?? 0) + (int) ($paid->total ?? 0),
- 'total_employees' => $totalEmployees,
- ];
- }
-
- public function getPayrollSummary(Carbon $startOfMonth, Carbon $endOfMonth): array
- {
- $period = PayrollPeriod::query()
- ->where('year', $startOfMonth->year)
- ->where('month', $startOfMonth->month)
- ->first();
-
- if (! $period) {
- return [
- 'has_period' => false,
- 'total_employees' => 0,
- 'total_amount' => 0,
- 'paid_amount' => 0,
- 'unpaid_amount' => 0,
- 'paid_count' => 0,
- 'unpaid_count' => 0,
- ];
- }
-
- $payrolls = Payroll::query()
- ->where('payroll_period_id', $period->id)
- ->selectRaw("
- COUNT(*) as total_employees,
- COALESCE(SUM(total_amount), 0) as total_amount,
- COALESCE(SUM(CASE WHEN status = 'paid' THEN total_amount ELSE 0 END), 0) as paid_amount,
- COALESCE(SUM(CASE WHEN status = 'unpaid' THEN total_amount ELSE 0 END), 0) as unpaid_amount,
- SUM(CASE WHEN status = 'paid' THEN 1 ELSE 0 END) as paid_count,
- SUM(CASE WHEN status = 'unpaid' THEN 1 ELSE 0 END) as unpaid_count
- ")
- ->first();
-
- return [
- 'has_period' => true,
- 'period_status' => $period->status->value,
- 'total_employees' => (int) ($payrolls->total_employees ?? 0),
- 'total_amount' => (int) ($payrolls->total_amount ?? 0),
- 'paid_amount' => (int) ($payrolls->paid_amount ?? 0),
- 'unpaid_amount' => (int) ($payrolls->unpaid_amount ?? 0),
- 'paid_count' => (int) ($payrolls->paid_count ?? 0),
- 'unpaid_count' => (int) ($payrolls->unpaid_count ?? 0),
- ];
- }
-
- public function getLeaveRequestSummary(?Carbon $startDate = null, ?Carbon $endDate = null): array
- {
- $query = LeaveRequest::query();
- if ($startDate && $endDate) {
- $query->where(function ($query) use ($startDate, $endDate) {
- $query->whereBetween('start_date', [$startDate, $endDate])
- ->orWhereBetween('end_date', [$startDate, $endDate]);
- });
- }
- $leaveRequestSummary = $query->selectRaw("
- COUNT(*) as total,
- SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending_count,
- SUM(CASE WHEN status = 'approved' THEN 1 ELSE 0 END) as approved_count,
- SUM(CASE WHEN status = 'rejected' THEN 1 ELSE 0 END) as rejected_count
- ")
- ->first();
-
- return [
- 'total' => (int) ($leaveRequestSummary->total ?? 0),
- 'pending' => (int) ($leaveRequestSummary->pending_count ?? 0),
- 'approved' => (int) ($leaveRequestSummary->approved_count ?? 0),
- 'rejected' => (int) ($leaveRequestSummary->rejected_count ?? 0),
- ];
- }
-
- public function getEmployeeSummary(): array
- {
- $total = Employee::query()->count();
-
- $byStatus = Employee::query()
- ->selectRaw('employment_status, COUNT(*) as count')
- ->groupBy('employment_status')
- ->get()
- ->map(fn ($item) => [
- 'status' => $item->employment_status instanceof EmploymentStatus ? $item->employment_status->value : $item->employment_status,
- 'label' => $item->employment_status instanceof EmploymentStatus ? $item->employment_status->label() : EmploymentStatus::from($item->employment_status)->label(),
- 'count' => (int) $item->count,
- ]);
-
- return [
- 'total' => $total,
- 'by_status' => $byStatus->toArray(),
- ];
- }
-
- public function getAttendanceToday(?Carbon $startDate = null, ?Carbon $endDate = null): array
- {
- $totalEmployees = Employee::query()->count();
-
- if ($startDate && $endDate) {
- $present = Attendance::query()
- ->whereBetween('attendance_date', [$startDate, $endDate])
- ->count();
-
- $onLeave = LeaveRequest::query()
- ->approved()
- ->where(function ($query) use ($startDate, $endDate) {
- $query->whereBetween('start_date', [$startDate, $endDate])
- ->orWhereBetween('end_date', [$startDate, $endDate]);
- })
- ->count();
-
- $days = (int) $startDate->copy()->startOfDay()->diffInDays($endDate->copy()->startOfDay()) + 1;
- $totalPossible = $totalEmployees * $days;
- $absent = max(0, $totalPossible - $present - $onLeave);
-
- return [
- 'total_employees' => (int) $totalPossible,
- 'present' => (int) $present,
- 'absent' => (int) $absent,
- 'on_leave' => (int) $onLeave,
- ];
- } else {
- $today = Carbon::today();
-
- $present = Attendance::query()
- ->where('attendance_date', $today)
- ->distinct('employee_id')
- ->count('employee_id');
-
- $onLeave = LeaveRequest::query()
- ->approved()
- ->where('start_date', '<=', $today)
- ->where('end_date', '>=', $today)
- ->distinct('employee_id')
- ->count('employee_id');
-
- $notPresent = max(0, $totalEmployees - $present);
- $absent = max(0, $notPresent - $onLeave);
-
- return [
- 'total_employees' => $totalEmployees,
- 'present' => $present,
- 'absent' => $absent,
- 'on_leave' => $onLeave,
- ];
- }
- }
-
- public function getMonthlyRevenueTrend(): array
- {
- $months = collect();
- for ($monthOffset = 5; $monthOffset >= 0; $monthOffset--) {
- $date = Carbon::now()->subMonths($monthOffset);
- $months->push([
- 'year' => $date->year,
- 'month' => $date->month,
- 'label' => $date->translatedFormat('M Y'),
- ]);
- }
-
- $result = $months->map(function ($month) {
- $start = Carbon::create($month['year'], $month['month'], 1)->startOfMonth();
- $end = $start->copy()->endOfMonth();
-
- $monthlyRevenue = Order::query()
- ->completed()
- ->whereBetween('created_at', [$start, $end])
- ->selectRaw('COALESCE(SUM(total_amount), 0) as total, COUNT(*) as count')
- ->first();
-
- return [
- 'label' => $month['label'],
- 'total' => (int) $monthlyRevenue->total,
- 'count' => (int) $monthlyRevenue->count,
- ];
- });
-
- return $result->toArray();
- }
-
- public function getMonthlyPurchaseTrend(): array
- {
- $months = collect();
- for ($monthOffset = 5; $monthOffset >= 0; $monthOffset--) {
- $date = Carbon::now()->subMonths($monthOffset);
- $months->push([
- 'year' => $date->year,
- 'month' => $date->month,
- 'label' => $date->translatedFormat('M Y'),
- ]);
- }
-
- $result = $months->map(function ($month) {
- $start = Carbon::create($month['year'], $month['month'], 1)->startOfMonth();
- $end = $start->copy()->endOfMonth();
-
- $monthlyPurchases = Purchase::query()
- ->whereBetween('created_at', [$start, $end])
- ->selectRaw('COALESCE(SUM(total), 0) as total, COUNT(*) as count')
- ->first();
-
- return [
- 'label' => $month['label'],
- 'total' => (int) $monthlyPurchases->total,
- 'count' => (int) $monthlyPurchases->count,
- ];
- });
-
- return $result->toArray();
- }
}
diff --git a/resources/js/pages/admin/Dashboard.vue b/resources/js/pages/admin/Dashboard.vue
index 47f3787..ca29cba 100644
--- a/resources/js/pages/admin/Dashboard.vue
+++ b/resources/js/pages/admin/Dashboard.vue
@@ -1,4 +1,17 @@
-
+
+