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 @@