exists(); if (!$hasData) { return back()->with('error', 'Gagal: Belum ada data penilaian warga yang diinput pada periode ' . $periode->nama . '.'); } return Excel::download(new PenilaianWargaExport($periode_id), 'Penilaian-Warga-'.$periode->nama.'.xlsx'); } public function import(Request $request) { $request->validate([ 'file' => 'required|mimes:xlsx,xls|max:5120', ], [ 'file.required' => 'File Excel harus diunggah.', 'file.mimes' => 'File harus berformat .xlsx atau .xls.', 'file.max' => 'Ukuran file maksimal 5MB.', ]); $periodeAktif = PeriodeSeleksi::where('status', 'aktif')->first(); if (!$periodeAktif) { return back()->with('error', 'Gagal: Tidak ada periode aktif. Silakan buat periode terlebih dahulu.'); } try { Excel::import(new PenilaianWargaImport($periodeAktif->id), $request->file('file')); return redirect()->route('admin.penilaian.index') ->with('success', 'Data penilaian berhasil diimpor dari file Excel.'); } catch (\Exception $e) { return back()->with('error', 'Gagal mengimpor data: ' . $e->getMessage()); } } public function index() { // Ambil periode aktif $periodeAktif = PeriodeSeleksi::where('status', 'aktif')->first(); if (!$periodeAktif) { return redirect()->route('admin.periode.index') ->with('warning', 'Tidak ada periode aktif. Silakan buat periode terlebih dahulu.'); } // Ambil data warga yang sudah dinilai di periode aktif $wargaDinilai = DB::table('penilaian_warga') ->select('warga_id') ->where('periode_id', $periodeAktif->id) ->distinct() ->get() ->pluck('warga_id'); // Gunakan relasi 'penilaian' sesuai dengan yang ada di Model Warga $warga = Warga::with(['wilayah', 'penilaian' => function ($q) use ($periodeAktif) { $q->where('periode_id', $periodeAktif->id); }]) ->whereIn('id', $wargaDinilai) ->orderBy('nama') ->get(); return view('admin.penilaian.index', compact('warga', 'periodeAktif')); } public function create() { $warga = Warga::where('is_aktif', true) ->with('wilayah') ->orderBy('nama') ->get(); $periodeAktif = PeriodeSeleksi::where('status', 'aktif')->first(); if (!$periodeAktif) { return redirect()->route('admin.periode.index') ->with('warning', 'Tidak ada periode aktif. Silakan buat periode terlebih dahulu.'); } $kriteria = Kriteria::with('subKriteria')->orderBy('kode')->get(); return view('admin.penilaian.create', compact('warga', 'periodeAktif', 'kriteria')); } public function store(Request $request) { $request->validate([ 'warga_id' => 'required|exists:warga,id', 'periode_id' => 'required|exists:periode_seleksi,id', 'nilai.*' => 'required|integer|min:1|max:5', ], [ 'warga_id.required' => 'Warga harus dipilih', 'periode_id.required' => 'Periode harus dipilih', 'nilai.*.required' => 'Semua kriteria harus diisi', 'nilai.*.integer' => 'Nilai harus berupa angka', 'nilai.*.min' => 'Nilai minimal 1', 'nilai.*.max' => 'Nilai maksimal 5', ]); // Cek apakah warga sudah dinilai di periode ini $exists = PenilaianWarga::where('warga_id', $request->warga_id) ->where('periode_id', $request->periode_id) ->exists(); if ($exists) { return back()->with('error', 'Warga ini sudah dinilai pada periode tersebut.') ->withInput(); } DB::beginTransaction(); try { // Simpan penilaian untuk setiap kriteria $kriteria = Kriteria::orderBy('kode')->get(); foreach ($kriteria as $k) { if (isset($request->nilai[$k->id])) { PenilaianWarga::create([ 'warga_id' => $request->warga_id, 'periode_id' => $request->periode_id, 'kriteria_id' => $k->id, 'nilai' => $request->nilai[$k->id], ]); } } DB::commit(); return redirect()->route('admin.penilaian.index') ->with('success', 'Penilaian berhasil disimpan.'); } catch (\Exception $e) { DB::rollBack(); return back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage()) ->withInput(); } } public function show(Request $request, $id) { $periodeId = $request->get('periode_id'); $periodeAktif = $periodeId ? PeriodeSeleksi::find($periodeId) : PeriodeSeleksi::where('status', 'aktif')->first(); if (!$periodeAktif) { return redirect()->route('admin.periode.index') ->with('warning', 'Tidak ada periode aktif atau periode yang dipilih.'); } $warga = Warga::with('wilayah')->findOrFail($id); // Gunakan relasi 'penilaian' dengan eager load kriteria $penilaian = PenilaianWarga::with('kriteria') ->where('warga_id', $id) ->where('periode_id', $periodeAktif->id) ->get(); $kriteria = Kriteria::with('subKriteria')->orderBy('kode')->get(); return view('admin.penilaian.show', compact('warga', 'penilaian', 'periodeAktif', 'kriteria')); } public function edit(Request $request, $id) { $periodeId = $request->get('periode_id'); $periodeAktif = $periodeId ? PeriodeSeleksi::find($periodeId) : PeriodeSeleksi::where('status', 'aktif')->first(); if (!$periodeAktif) { return redirect()->route('admin.periode.index') ->with('warning', 'Tidak ada periode aktif atau periode yang dipilih.'); } $warga = Warga::with('wilayah')->findOrFail($id); $penilaian = PenilaianWarga::where('warga_id', $id) ->where('periode_id', $periodeAktif->id) ->get() ->keyBy('kriteria_id'); $kriteria = Kriteria::with('subKriteria')->orderBy('kode')->get(); return view('admin.penilaian.edit', compact('warga', 'penilaian', 'periodeAktif', 'kriteria')); } public function update(Request $request, $id) { $request->validate([ 'nilai.*' => 'required|integer|min:1|max:5', 'periode_id' => 'required|exists:periode_seleksi,id', ], [ 'nilai.*.required' => 'Semua kriteria harus diisi', 'nilai.*.integer' => 'Nilai harus berupa angka', 'nilai.*.min' => 'Nilai minimal 1', 'nilai.*.max' => 'Nilai maksimal 5', ]); // ✅ BUG #6 FIX: Gunakan periode_id dari form, bukan periodeAktif // Ini mencegah data tersimpan ke periode yang salah $periodeId = $request->periode_id; DB::beginTransaction(); try { $kriteria = Kriteria::orderBy('kode')->get(); foreach ($kriteria as $k) { if (isset($request->nilai[$k->id])) { PenilaianWarga::updateOrCreate( [ 'warga_id' => $id, 'periode_id' => $periodeId, 'kriteria_id' => $k->id, ], [ 'nilai' => $request->nilai[$k->id], ] ); } } DB::commit(); return redirect()->route('admin.penilaian.index') ->with('success', 'Penilaian berhasil diperbarui.'); } catch (\Exception $e) { DB::rollBack(); return back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage()) ->withInput(); } } public function destroy($id) { $periodeAktif = PeriodeSeleksi::where('status', 'aktif')->first(); // ✅ BUG #3 FIX: Null-safety — jika tidak ada periode aktif, redirect dengan pesan if (!$periodeAktif) { return redirect()->route('admin.periode.index') ->with('warning', 'Tidak ada periode aktif. Tidak dapat menghapus penilaian.'); } DB::beginTransaction(); try { PenilaianWarga::where('warga_id', $id) ->where('periode_id', $periodeAktif->id) ->delete(); DB::commit(); return redirect()->route('admin.penilaian.index') ->with('success', 'Penilaian berhasil dihapus.'); } catch (\Exception $e) { DB::rollBack(); return back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage()); } } }