pkjDashboardRepository = $pkjDashboardRepository; } /** * Get total PKJ assets */ public function getTotalAssets(array $filters = [], $user = null): int { return $this->pkjDashboardRepository->getTotalHoldings($filters, $user); } /** * Get operational PKJ assets (BP status) */ public function getOperationalAssets(array $filters = [], $user = null): int { $holdings = $this->pkjDashboardRepository->getHoldingsBySpecificStatus('BP', $filters, $user); return $holdings['pagination']['total']; } /** * Get under repair PKJ assets (TBDG status) */ public function getUnderRepairAssets(array $filters = [], $user = null): int { $holdings = $this->pkjDashboardRepository->getHoldingsBySpecificStatus('TBDG', $filters, $user); return $holdings['pagination']['total']; } /** * Get maintenance due PKJ assets (BDG status) */ public function getMaintenanceDueAssets(array $filters = [], $user = null): int { $holdings = $this->pkjDashboardRepository->getHoldingsBySpecificStatus('BDG', $filters, $user); return $holdings['pagination']['total']; } /** * Get active PKJ repairs */ public function getActiveRepairs(array $filters = []): int { $dateRange = $this->getDateRange($filters); return PKJRepair::query() ->whereBetween('created_at', [$dateRange['from'], $dateRange['to']]) ->where('status', 'active') ->count(); } /** * Get pending PKJ reports */ public function getPendingReports(array $filters = []): int { $dateRange = $this->getDateRange($filters); return PKJReport::query() ->whereBetween('created_at', [$dateRange['from'], $dateRange['to']]) ->where('status', 'pending') ->count(); } /** * Get PKJ entitlement vs holdings pie chart */ public function getEntitlementVsHoldingsPieChart(array $filters = [], $user = null): array { $totalEntitlement = $this->pkjDashboardRepository->getTotalEntitlement($filters, $user); $totalHoldings = $this->pkjDashboardRepository->getTotalHoldings($filters, $user); $data = [ [ 'name' => 'Perjawatan', 'value' => $totalEntitlement, 'percentage' => ($totalEntitlement + $totalHoldings) > 0 ? round(($totalEntitlement / ($totalEntitlement + $totalHoldings)) * 100, 2) : 0 ], [ 'name' => 'Pegangan', 'value' => $totalHoldings, 'percentage' => ($totalEntitlement + $totalHoldings) > 0 ? round(($totalHoldings / ($totalEntitlement + $totalHoldings)) * 100, 2) : 0 ] ]; return $this->formatPieChartData( 'Perjawatan vs Pegangan PKJ', $data, '', // No drill-down [] ); } /** * Get PKJ holdings status breakdown pie chart */ public function getHoldingsStatusBreakdownPieChart(array $filters = [], $user = null): array { $statusCounts = $this->pkjDashboardRepository->getHoldingsByStatus($filters, $user); // Map status codes to readable names $statusNames = [ 'BP' => 'Baik dalam Perhatian', 'BDG' => 'Boleh Digunakan', 'TBDG' => 'Tidak Boleh Digunakan', 'BT' => 'Boleh Tembak', 'BG' => 'Baik Guna' ]; $data = []; foreach ($statusCounts as $status) { $statusName = $statusNames[$status['status']] ?? $status['status']; $data[] = [ 'name' => $statusName, 'value' => $status['count'], 'percentage' => 0 // Will be calculated after total ]; } // Calculate percentages $total = array_sum(array_column($data, 'value')); foreach ($data as &$item) { $item['percentage'] = $total > 0 ? round(($item['value'] / $total) * 100, 2) : 0; } return $this->formatPieChartData( 'PKJ Status Pegangan', $data, '', // No drill-down [] ); } /** * Get PKJ monthly trends chart */ public function getMonthlyTrendsChart(array $filters = [], $user = null): array { $monthlyData = $this->pkjDashboardRepository->getMonthlyTrends($filters, $user); $categories = []; $data = []; foreach ($monthlyData as $trend) { $categories[] = Carbon::createFromFormat('Y-m', $trend['month'])->format('M Y'); $data[] = $trend['total_reports']; } return $this->formatBarChartData( 'Trend Bulanan PKJ 2025', [ ['name' => 'Laporan', 'data' => $data] ], $categories ); } /** * Get PKJ holdings by category bar chart */ public function getHoldingsByCategoryBarChart(array $filters = [], $user = null): array { $categoryData = $this->pkjDashboardRepository->getHoldingsByCategory($filters, $user); $categories = []; $categoryIds = []; $data = []; foreach ($categoryData as $category) { $categories[] = $category['category_name']; $categoryIds[] = (int) $category['category_id']; $data[] = (int) $category['total_holding']; } $chartData = $this->formatBarChartData( 'Pegangan PKJ Mengikut Kategori', [ ['name' => 'Jumlah Pegangan', 'data' => $data] ], $categories ); // Add category IDs to the chart data for drill-down functionality $chartData['category_ids'] = $categoryIds; return $chartData; } /** * Get PKJ category metrics bar chart (drill-down) */ public function getCategoryMetricsBarChart(int $categoryId, array $filters = [], $user = null): array { $metrics = $this->pkjDashboardRepository->getCategoryMetrics($categoryId, $filters, $user); $categories = ['KEUPAYAAN (%)', 'KESIAGAAN (%)', 'SERVISIBILITI (%)']; $data = [ $metrics['keupayaan'], $metrics['kesiagaan'], $metrics['servisibiliti'] ]; $chartData = $this->formatBarChartData( 'Metrik Kategori PKJ', [ ['name' => 'Metrics', 'data' => $data] ], $categories ); // Add category information to the response $chartData['category_id'] = $metrics['category_id']; $chartData['category_name'] = $metrics['category_name']; return $chartData; } /** * Get PKJ category status breakdown pie chart (drill-down) */ public function getCategoryStatusBreakdownPieChart(int $categoryId, array $filters = [], $user = null): array { $breakdown = $this->pkjDashboardRepository->getCategoryStatusBreakdown($categoryId, $filters, $user); // Map status codes to readable names $statusNames = [ 'BP' => 'Baik dalam Perhatian', 'BDG' => 'Boleh Digunakan', 'TBDG' => 'Tidak Boleh Digunakan', 'BT' => 'Boleh Tembak', 'TBT' => 'Tidak Boleh Tembak', 'BG' => 'Baik Guna', 'TBG' => 'Tidak Baik Guna', ]; $data = []; foreach ($breakdown['status_breakdown'] as $status) { $statusCode = $status['status']; // In the breakdown, status_code is null when the asset has no status (DB column is NULL). if ($statusCode === null || $statusCode === '') { $statusName = 'Status Tidak Diketahui'; } else { $statusName = $statusNames[$statusCode] ?? $statusCode; } $data[] = [ 'name' => $statusName, 'value' => $status['count'], 'percentage' => 0, // Will be calculated after total 'status_code' => $statusCode // null when DB status column is NULL (Belum Diberi Status) ]; } // Calculate percentages $total = array_sum(array_column($data, 'value')); foreach ($data as &$item) { $item['percentage'] = $total > 0 ? round(($item['value'] / $total) * 100, 2) : 0; } $chartData = $this->formatPieChartData( 'PKJ Status Pegangan Mengikut Kategori', $data, '/v1/dashboard/pkj/category/' . $categoryId . '/status-details', ['status'] ); // Add category information to the response $chartData['category_id'] = $breakdown['category_id']; $chartData['category_name'] = $breakdown['category_name']; return $chartData; } /** * Get unit ID column name for PKJ */ protected function getUnitIdColumn(): string { return 'pkj_asset_holdings.unit_id'; } /** * Get asset model class for PKJ */ protected function getAssetModelClass(): string { return PKJAssetHolding::class; } /** * Get repair model class for PKJ */ protected function getRepairModelClass(): string { return PKJRepair::class; } }