orderBy('semester', 'desc') ->get(); // Get active form (either from request or first active form) $activeForm = $request->filled('status_form_id') ? $forms->where('id', $request->status_form_id)->first() : $forms->where('status', 'Dibuka')->first(); $baseQuery = HasilPenilaian::with(['pengajuan.mahasiswa.user', 'pengajuan.form']) ->whereHas('pengajuan', function ($q) use ($request) { $q->where('status_validasi', 'valid'); if ($request->filled('status_form_id')) { $q->where('status_form_id', $request->status_form_id); } if ($request->filled('jenis_form')) { $q->whereHas('form', function ($formQuery) use ($request) { $formQuery->where('jenis_form', $request->jenis_form); }); } }) ->orderBy('nilai_preferensi', 'desc'); // Get all results first to determine ranking and quota status $allResults = $baseQuery->get(); $selectedFormId = $activeForm->id ?? null; $form = $activeForm; $quota = $activeForm->kuota ?? 0; $withinQuotaIds = []; // Calculate global ranking and quota status for all results if ($request->filled('status_form_id')) { $selectedFormId = $request->status_form_id; $form = Form::find($selectedFormId); $quota = $form->kuota ?? 0; // Get rankings for this specific form $formResults = $allResults->filter(function ($item) use ($selectedFormId) { return optional($item->pengajuan)->status_form_id == $selectedFormId; })->sortByDesc('nilai_preferensi')->values(); // Determine which results are within quota $withinQuotaIds = $formResults->take($quota)->pluck('id')->toArray(); // Add quota status to all results foreach ($allResults as $result) { if (optional($result->pengajuan)->status_form_id == $selectedFormId) { $rank = $formResults->search(function ($item) use ($result) { return $item->id === $result->id; }) + 1; $result->current_rank = $rank; $result->is_beyond_quota = $rank > $quota && $quota > 0; } } } // Apply quota filter if requested if ($request->filled('kuota_filter') && $request->filled('status_form_id')) { if ($request->kuota_filter == 'available') { $baseQuery->whereIn('id', $withinQuotaIds); } elseif ($request->kuota_filter == 'exceeded') { $baseQuery->whereNotIn('id', $withinQuotaIds) ->whereHas('pengajuan', function($q) use ($selectedFormId) { $q->where('status_form_id', $selectedFormId); }); } } // Get paginated results $rankings = $baseQuery->paginate(20); // Mark which results are beyond quota for display foreach ($rankings as $ranking) { if ($selectedFormId && optional($ranking->pengajuan)->status_form_id == $selectedFormId) { $ranking->is_beyond_quota = !in_array($ranking->id, $withinQuotaIds); } } // Initialize semester reports $semesterReports = []; // Group forms by unique semester-year combinations $uniqueSemesters = $forms->unique(function ($item) { return $item->semester.$item->tahun; }); foreach ($uniqueSemesters as $form) { $key = $form->semester.'_'.$form->tahun; $semesterReports[$key] = [ 'semester' => $form->semester, 'tahun' => $form->tahun, 'forms' => [], 'total_ukt_saat_ini' => 0, 'total_ukt_penyesuaian' => 0, 'total_mahasiswa' => 0, 'kuota_total' => 0, 'kuota_terpakai' => 0, 'total_average' => 0, 'total_selisih' => 0, 'persentase_terpakai' => 0 ]; } // Calculate statistics for each semester foreach ($semesterReports as $key => &$report) { $formsInSemester = $forms->where('semester', $report['semester']) ->where('tahun', $report['tahun']); foreach ($formsInSemester as $form) { $formResults = $allResults->filter(function ($item) use ($form) { return optional($item->pengajuan)->form_id == $form->id; }); $formData = [ 'id' => $form->id, 'nama_form' => $form->nama_form, 'jenis_form' => $form->jenis_form, 'ukt_saat_ini' => $formResults->sum(function ($item) { return optional($item->pengajuan)->ukt_saat_ini ?? 0; }), 'ukt_penyesuaian' => $formResults->sum(function ($item) { return $item->ukt_penyesuaian ?? 0; }), 'jumlah_mahasiswa' => $formResults->count(), 'kuota' => $form->kuota, 'kuota_terpakai' => $formResults->count(), 'average' => 0, 'selisih' => 0 ]; // Calculate averages and differences if ($formData['jumlah_mahasiswa'] > 0) { $formData['average'] = $formData['ukt_penyesuaian'] / $formData['jumlah_mahasiswa']; } $formData['selisih'] = $formData['ukt_saat_ini'] - $formData['ukt_penyesuaian']; $report['forms'][] = $formData; // Aggregate semester totals $report['total_ukt_saat_ini'] += $formData['ukt_saat_ini']; $report['total_ukt_penyesuaian'] += $formData['ukt_penyesuaian']; $report['total_mahasiswa'] += $formData['jumlah_mahasiswa']; $report['kuota_total'] += $formData['kuota']; $report['kuota_terpakai'] += $formData['kuota_terpakai']; } // Calculate semester-level metrics $report['total_average'] = $report['total_mahasiswa'] > 0 ? $report['total_ukt_penyesuaian'] / $report['total_mahasiswa'] : 0; $report['total_selisih'] = $report['total_ukt_saat_ini'] - $report['total_ukt_penyesuaian']; $report['persentase_terpakai'] = $report['kuota_total'] > 0 ? ($report['kuota_terpakai'] / $report['kuota_total']) * 100 : 0; } // Convert associative array to indexed array and sort $semesterReports = array_values($semesterReports); // Sort semester reports by year (descending) and semester (Ganjil first) usort($semesterReports, function ($a, $b) { if ($a['tahun'] == $b['tahun']) { return $a['semester'] == 'Ganjil' ? -1 : 1; } return $b['tahun'] - $a['tahun']; }); // Overall statistics $totalUktSaatIni = $allResults->sum(function($item) { return optional($item->pengajuan)->ukt_saat_ini ?? 0; }); $totalUktPenyesuaian = $allResults->sum(function($item) { return $item->ukt_penyesuaian ?? 0; }); $averageUktPenyesuaian = $allResults->count() > 0 ? $totalUktPenyesuaian / $allResults->count() : 0; $selisihUkt = $totalUktSaatIni - $totalUktPenyesuaian; $countMahasiswa = $allResults->count(); // Budget calculations $budget = HasilPenilaian::getCurrentBudget(); $budgetDifference = $budget - $totalUktPenyesuaian; return view('admin.ranking.index', compact( 'rankings', 'forms', 'semesterReports', 'totalUktSaatIni', 'totalUktPenyesuaian', 'averageUktPenyesuaian', 'selisihUkt', 'countMahasiswa', 'budget', 'budgetDifference' )); } public function setBudget(Request $request) { $request->validate([ 'budget' => 'required' ]); try { $budget = str_replace('.', '', $request->budget); HasilPenilaian::updateBudget((int)$budget); return back()->with('success', 'Budget berhasil disimpan!'); } catch (\Exception $e) { return back()->with('error', 'Gagal menyimpan budget: '.$e->getMessage()); } } public function setActiveBudget(Request $request) { $request->validate([ 'status_form_id' => 'required|exists:forms,id', 'budget' => 'required' ]); try { $budget = str_replace('.', '', $request->budget); $form = Form::findOrFail($request->status_form_id); // Update budget in keterangan column for all results of this form HasilPenilaian::whereHas('pengajuan', function($q) use ($request) { $q->where('status_form_id', $request->status_form_id); })->update(['keterangan' => $budget]); return back()->with('success', 'Budget untuk form aktif berhasil disimpan!'); } catch (\Exception $e) { return back()->with('error', 'Gagal menyimpan budget: '.$e->getMessage()); } } public function export(Request $request) { try { $request->validate([ 'status_form_id' => 'required|exists:forms,id' ]); $form = Form::findOrFail($request->status_form_id); $rankings = HasilPenilaian::with([ 'pengajuan:id,mahasiswa_id,form_id,ukt_saat_ini,status_validasi', 'pengajuan.mahasiswa:id,user_id,nim,program_studi', 'pengajuan.mahasiswa.user:id,name' ]) ->whereHas('pengajuan', function($q) use ($request) { $q->where('status_validasi', 'valid') ->where('status_form_id', $request->status_form_id); }) ->orderBy('nilai_preferensi', 'desc') ->get(); if ($rankings->isEmpty()) { return back()->with('error', 'Tidak ada data yang dapat diexport untuk form ini'); } $judul = strtoupper($form->jenis_form) . ' UKT MAHASISWA ' . $form->semester . ' POLITEKNIK NEGERI JEMBER TAHUN AKADEMIK ' . $form->tahun; // Debug: Check if view exists if (!view()->exists('admin.ranking.export')) { throw new \Exception("View 'admin.ranking.export' not found"); } $pdf = PDF::loadView('admin.ranking.export', [ 'judul' => $judul, 'form' => $form, 'mahasiswa' => $rankings ]); return $pdf->download('ranking-ukt-' . strtolower($form->jenis_form) . '-' . $form->semester . '-' . $form->tahun . '.pdf'); } catch (\Exception $e) { \Log::error('PDF Export Error', [ 'message' => $e->getMessage(), 'trace' => $e->getTraceAsString(), 'request' => $request->all() ]); return back()->with('error', 'Gagal export PDF: ' . $e->getMessage()); } } public function recalculateAll(SawCalculationService $sawService) { try { $validIds = PengajuanUkt::where('status_validasi', 'valid') ->pluck('id') ->toArray(); $result = $sawService->processBatch($validIds); return back()->with([ 'status' => $result['status'], 'message' => $result['message'] ]); } catch (\Exception $e) { return back()->with('error', 'Gagal memproses: '.$e->getMessage()); } } public function updateUkt(Request $request, $id) { $request->validate([ 'ukt_penyesuaian' => 'required' ]); try { // Remove formatting and convert to integer $uktValue = str_replace('.', '', $request->ukt_penyesuaian); $uktValue = (int)$uktValue; $ranking = HasilPenilaian::findOrFail($id); $ranking->update([ 'ukt_penyesuaian' => $uktValue, 'status_penyesuaian' => 'sudah dilakukan penyesuaian' ]); return back()->with('success', 'UKT Penyesuaian berhasil diperbarui!'); } catch (\Exception $e) { return back()->with('error', 'Gagal memperbarui UKT: '.$e->getMessage()); } }}