get('per_page', 10); $kriterias = Kriteria::orderBy('kode', 'asc')->get(); // Eager loading 'details' untuk menghindari N+1 Query saat looping di tabel $query = Warga::with(['details.kriteria', 'details.subKriteria']); if ($request->filled('search')) { $search = $request->search; $query->where(function ($q) use ($search) { $q->where('nama', 'LIKE', "%$search%") ->orWhere('nik', 'LIKE', "%$search%"); }); } if ($request->filled('rt')) { $query->where('rt', str_pad($request->rt, 3, '0', STR_PAD_LEFT)); } if ($request->filled('rw')) { $query->where('rw', str_pad($request->rw, 3, '0', STR_PAD_LEFT)); } if ($request->filled('status')) { $query->where('status_verifikasi', $request->status); } foreach ($kriterias as $k) { $filterKey = 'f_kriteria_'.$k->id; if ($request->filled($filterKey)) { $nilaiFilter = $request->get($filterKey); $query->whereHas('details', function ($q) use ($k, $nilaiFilter) { $q->where('kriteria_id', $k->id) ->where('nilai_asli', $nilaiFilter); }); } } $wargas = $query->latest()->paginate($perPage)->appends($request->all()); return view('warga.index', compact('wargas', 'kriterias')); } /** * Form tambah warga. */ public function create() { $kriterias = Kriteria::with('subKriterias')->orderBy('kode', 'asc')->get(); return view('warga.create', compact('kriterias')); } /** * Menyimpan data warga manual (Identitas + Kriteria Dinamis + Files). */ public function store(Request $request) { // 1. Validasi Identitas Dasar & Dokumen $rules = [ 'nik' => 'required|digits:16|unique:wargas,nik', 'nama' => 'required|string|max:255', 'alamat' => 'required', 'rt' => 'required|max:3', 'rw' => 'required|max:3', 'files' => 'nullable|array', 'files.*' => 'nullable|mimes:jpg,jpeg,png,pdf|max:2048', ]; // 2. Validasi Dinamis untuk Input Kriteria $kriterias = Kriteria::all(); foreach ($kriterias as $k) { $rules['kriteria_'.$k->id] = 'required'; } $request->validate($rules); try { DB::beginTransaction(); // 3. Handling Multiple File Upload $paths = []; if ($request->hasFile('files')) { foreach ($request->file('files') as $file) { $paths[] = $file->store('dokumen_warga', 'public'); } } // 4. Simpan Data Utama Warga $warga = Warga::create([ 'nik' => $request->nik, 'nama' => $request->nama, 'alamat' => $request->alamat, 'rt' => $request->rt, 'rw' => $request->rw, 'dokumen_pendukung' => $paths, 'status_verifikasi' => 'pending', 'status_bansos_riil' => 'aktif', ]); // 5. Simpan Detail Kriteria $this->saveWargaDetails($warga, $request, $kriterias); DB::commit(); return redirect()->route('warga.index')->with('success', 'Data Warga Berhasil Ditambahkan!'); } catch (\Exception $e) { DB::rollback(); Log::error('Error Store Warga: '.$e->getMessage()); return redirect()->back()->withInput()->with('error', 'Gagal menyimpan data: '.$e->getMessage()); } } /** * Import Data dari Excel/CSV. */ public function importExcel(Request $request) { $request->validate([ 'file_excel' => 'required|mimes:xlsx,xls,csv|max:10240', ]); try { Excel::import(new WargaImport, $request->file('file_excel')); return redirect()->route('warga.index')->with('success', 'Import Data Berhasil!'); } catch (\Exception $e) { Log::error('Error Import Warga: '.$e->getMessage()); return redirect()->back()->with('error', 'Gagal Import: '.$e->getMessage()); } } /** * Form Edit Warga. */ public function edit($id) { $warga = Warga::with('details')->findOrFail($id); $kriterias = Kriteria::with('subKriterias')->orderBy('kode', 'asc')->get(); return view('warga.edit', compact('warga', 'kriterias')); } /** * Update data warga. */ public function update(Request $request, $id) { $warga = Warga::findOrFail($id); $rules = [ 'nik' => 'required|digits:16|unique:wargas,nik,'.$id, 'nama' => 'required|string|max:255', 'alamat' => 'required', 'rt' => 'required|max:3', 'rw' => 'required|max:3', 'files.*' => 'nullable|mimes:jpg,jpeg,png,pdf|max:2048', 'status_bansos_riil' => 'required|in:aktif,meninggal,pindah,mampu', ]; $kriterias = Kriteria::all(); foreach ($kriterias as $k) { $rules['kriteria_'.$k->id] = 'required'; } $request->validate($rules); try { DB::beginTransaction(); $paths = is_array($warga->dokumen_pendukung) ? $warga->dokumen_pendukung : []; if ($request->has('hapus_dokumen')) { foreach ($request->hapus_dokumen as $fileToDelete) { Storage::disk('public')->delete($fileToDelete); } $paths = array_diff($paths, [$fileToDelete]); } if ($request->hasFile('files')) { foreach ($request->file('files') as $file) { $path = $file->store('dokumen_warga', 'public'); $paths[] = $path; } } // --- LOGIKA CERDAS: ALUR PENOLAKAN --- $statusBaru = $warga->status_verifikasi; $catatanBaru = $warga->catatan; $verifikatorBaru = $warga->verified_by; // Jika sebelumnya ditolak, lalu datanya diperbaiki, kembalikan ke antrean verifikasi if ($warga->status_verifikasi === 'tolak') { $statusBaru = 'pending'; $catatanBaru = null; $verifikatorBaru = null; } // ------------------------------------- $warga->update([ 'nik' => $request->nik, 'nama' => $request->nama, 'alamat' => $request->alamat, 'rt' => str_pad($request->rt, 3, '0', STR_PAD_LEFT), 'rw' => str_pad($request->rw, 3, '0', STR_PAD_LEFT), 'dokumen_pendukung' => array_values($paths), 'status_verifikasi' => $statusBaru, 'catatan' => $catatanBaru, 'verified_by' => $verifikatorBaru, 'status_bansos_riil' => $request->status_bansos_riil, ]); $this->saveWargaDetails($warga, $request, $kriterias, true); DB::commit(); return redirect()->route('warga.index')->with('success', 'Data Berhasil Diperbarui!'); } catch (\Exception $e) { DB::rollback(); Log::error('Error Update Warga: '.$e->getMessage()); return redirect()->back()->with('error', 'Gagal update: '.$e->getMessage()); } } public function bulkUpdate(Request $request) { // 1. Validasi input $request->validate([ 'ids' => 'required|string', // Kita kirim string ID yang dipisah koma dari JS 'kriteria_id' => 'required|exists:kriterias,id', 'sub_kriteria_id' => 'required|exists:sub_kriterias,id' ]); try { DB::beginTransaction(); // Ubah string "1,2,3" menjadi array [1,2,3] $idsArray = explode(',', $request->ids); $sub = SubKriteria::findOrFail($request->sub_kriteria_id); // 2. Eksekusi Update Massal WargaDetail::whereIn('warga_id', $idsArray) ->where('kriteria_id', $request->kriteria_id) ->update([ 'sub_kriteria_id' => $sub->id, 'nilai_asli' => $sub->nama_sub ]); DB::commit(); return redirect()->back()->with('success', count($idsArray) . ' Data warga berhasil di-update secara massal!'); } catch (\Exception $e) { DB::rollBack(); return redirect()->back()->with('error', 'Gagal update massal: ' . $e->getMessage()); } } /** * Method Privat: Logika simpan detail kriteria. */ private function saveWargaDetails($warga, $request, $kriterias, $isUpdate = false) { foreach ($kriterias as $k) { $nilaiInput = $request->input('kriteria_'.$k->id); $sub = SubKriteria::where('kriteria_id', $k->id) ->where('nama_sub', $nilaiInput) ->first(); $dataDetail = [ 'sub_kriteria_id' => $sub ? $sub->id : null, 'nilai_asli' => $nilaiInput, ]; if ($isUpdate) { WargaDetail::updateOrCreate( ['warga_id' => $warga->id, 'kriteria_id' => $k->id], $dataDetail ); } else { WargaDetail::create(array_merge([ 'warga_id' => $warga->id, 'kriteria_id' => $k->id, ], $dataDetail)); } } } /** * Download Template XLSX Dinamis. */ public function downloadTemplate() { // Pastikan facade Excel diimport (use Maatwebsite\Excel\Facades\Excel;) return Excel::download(new TemplateWargaExport, 'template_import_warga.xlsx'); } public function exportExcel(Request $request) { $nama_file = 'Data_Warga_'.date('d-m-Y_H-i').'.xlsx'; return Excel::download(new WargaExport($request), $nama_file); } /** * Hapus Data Warga beserta filenya. */ public function destroy($id) { try { $warga = Warga::findOrFail($id); if ($warga->dokumen_pendukung) { foreach ($warga->dokumen_pendukung as $file) { Storage::disk('public')->delete($file); } } $warga->delete(); return redirect()->route('warga.index')->with('success', 'Data Warga Berhasil Dihapus!'); } catch (\Exception $e) { return redirect()->back()->with('error', 'Gagal menghapus data.'); } } public function bulkDelete(Request $request) { // 1. Validasi input $request->validate([ 'ids' => 'required|string', // String ID yang dipisah koma ]); try { DB::beginTransaction(); // Ubah string "1,2,3" menjadi array [1,2,3] $idsArray = explode(',', $request->ids); // Ambil data warga $wargas = Warga::whereIn('id', $idsArray)->get(); // Lakukan looping hapus agar file fisik dan detailnya ikut terhapus foreach ($wargas as $warga) { if ($warga->dokumen_pendukung) { foreach ($warga->dokumen_pendukung as $file) { Storage::disk('public')->delete($file); } } // Hapus warga (akan otomatis menghapus detail & hasil seleksi berkat fungsi boot di Model) $warga->delete(); } DB::commit(); return redirect()->back()->with('success', count($idsArray) . ' Data warga berhasil dihapus massal!'); } catch (\Exception $e) { DB::rollBack(); return redirect()->back()->with('error', 'Gagal menghapus massal: ' . $e->getMessage()); } } }