prepare("SELECT p.*, k.no_kk, k.alamat as alamat_kk, k.rt, k.rw, k.kelurahan, k.kecamatan, k.rumah_ibadah_id FROM v_penduduk p JOIN keluarga k ON k.id = p.keluarga_id WHERE p.id = ?"); $st->execute([$id]); $row = $st->fetch(); if (!$row) jsonErr('Data tidak ditemukan.', 404); // histori bantuan $hb = $db->prepare("SELECT hb.*, b.nama as bantuan_nama, b.jenis, b.satuan, u.nama_lengkap as disalurkan_nama FROM histori_bantuan hb JOIN bantuan b ON b.id = hb.bantuan_id LEFT JOIN user u ON u.id = hb.disalurkan_oleh WHERE hb.penduduk_id = ? ORDER BY hb.tanggal DESC"); $hb->execute([$id]); $row['histori_bantuan'] = $hb->fetchAll(); // pelatihan $plt = $db->prepare("SELECT rp.*, p.nama_pelatihan, p.penyelenggara FROM riwayat_pelatihan rp JOIN pelatihan p ON p.id = rp.pelatihan_id WHERE rp.penduduk_id = ?"); $plt->execute([$id]); $row['riwayat_pelatihan'] = $plt->fetchAll(); // validasi pendidikan $warn = validasiPendidikan((int)$row['umur'], $row['pendidikan_terakhir'], $row['status_pendidikan']); $row['peringatan_pendidikan'] = $warn; jsonOk($row); } // list dengan filter $where = ["p.status_hidup = 'hidup'"]; $params = []; if (!empty($_GET['status_ekonomi'])) { $where[] = "p.status_ekonomi = ?"; $params[] = $_GET['status_ekonomi']; } if (!empty($_GET['keluarga_id'])) { $where[] = "p.keluarga_id = ?"; $params[] = (int)$_GET['keluarga_id']; } if (!empty($_GET['kelurahan'])) { $where[] = "k.kelurahan = ?"; $params[] = $_GET['kelurahan']; } if (!empty($_GET['q'])) { $where[] = "(p.nama LIKE ? OR p.nik LIKE ?)"; $params[] = '%'.$_GET['q'].'%'; $params[] = '%'.$_GET['q'].'%'; } $wStr = implode(' AND ', $where); $st = $db->prepare("SELECT p.id, p.nik, p.nama, p.jenis_kelamin, p.tanggal_lahir, p.umur, p.profil_umur, p.status_keluarga, p.status_perkawinan, p.status_ekonomi, p.kondisi_kesehatan, p.pekerjaan, p.penghasilan, p.lat, p.lng, p.keluarga_id, k.no_kk, k.kelurahan, k.alamat as alamat_kk, (SELECT COUNT(*) FROM histori_bantuan hb WHERE hb.penduduk_id=p.id AND hb.status='disalurkan') as total_bantuan FROM v_penduduk p JOIN keluarga k ON k.id=p.keluarga_id WHERE $wStr ORDER BY p.nama ASC LIMIT 500"); $st->execute($params); jsonOk($st->fetchAll()); break; // ── POST: Tambah ── case 'POST': requireRole(['superadmin','pengurus','relawan']); $b = json_decode(file_get_contents('php://input'), true); $nik = sanitize($b['nik'] ?? ''); $nama = sanitize($b['nama'] ?? ''); $tgl = $b['tanggal_lahir'] ?? ''; $kjId = (int)($b['keluarga_id'] ?? 0); if (!$nik || strlen($nik) !== 16) jsonErr('NIK harus 16 digit.'); if (!$nama) jsonErr('Nama wajib diisi.'); if (!$tgl) jsonErr('Tanggal lahir wajib diisi.'); if (!$kjId) jsonErr('Keluarga (KK) wajib dipilih.'); // cek NIK unik $chk = $db->prepare("SELECT id FROM penduduk WHERE nik=?"); $chk->execute([$nik]); if ($chk->fetch()) jsonErr('NIK sudah terdaftar di sistem.'); $umur = hitungUmur($tgl); $pendid = $b['pendidikan_terakhir'] ?? 'tidak_sekolah'; $stPend = $b['status_pendidikan'] ?? 'tidak_sekolah'; $db->prepare("INSERT INTO penduduk (nik,nama,jenis_kelamin,tanggal_lahir,status_keluarga,status_perkawinan,status_hidup, keluarga_id,pendidikan_terakhir,status_pendidikan,pekerjaan,penghasilan, status_ekonomi,kondisi_kesehatan,lat,lng,catatan,created_by) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)") ->execute([ $nik, $nama, $b['jenis_kelamin'] ?? 'L', $tgl, $b['status_keluarga'] ?? 'anggota', $b['status_perkawinan'] ?? 'belum_kawin', $b['status_hidup'] ?? 'hidup', $kjId, $pendid, $stPend, sanitize($b['pekerjaan'] ?? ''), (float)($b['penghasilan'] ?? 0), $b['status_ekonomi'] ?? 'rentan', $b['kondisi_kesehatan'] ?? 'sehat', isset($b['lat']) ? (float)$b['lat'] : null, isset($b['lng']) ? (float)$b['lng'] : null, sanitize($b['catatan'] ?? ''), $user['id'] ]); $newId = (int)$db->lastInsertId(); log_aksi($user['id'], 'CREATE', 'penduduk', $newId, "Tambah: $nama (NIK: $nik)"); $warn = validasiPendidikan($umur, $pendid, $stPend); jsonOk(['id'=>$newId,'peringatan'=>$warn], 'Penduduk berhasil ditambahkan.'); break; // ── PUT: Edit ── case 'PUT': requireRole(['superadmin','pengurus','relawan']); if (!$id) jsonErr('ID tidak valid.'); $b = json_decode(file_get_contents('php://input'), true); $chk = $db->prepare("SELECT id,nik FROM penduduk WHERE id=?"); $chk->execute([$id]); if (!$chk->fetch()) jsonErr('Data tidak ditemukan.', 404); $tgl = $b['tanggal_lahir'] ?? ''; $umur = $tgl ? hitungUmur($tgl) : 0; $pendid = $b['pendidikan_terakhir'] ?? 'tidak_sekolah'; $stPend = $b['status_pendidikan'] ?? 'tidak_sekolah'; $db->prepare("UPDATE penduduk SET nama=?,jenis_kelamin=?,tanggal_lahir=?,status_keluarga=?,status_perkawinan=?, status_hidup=?,keluarga_id=?,pendidikan_terakhir=?,status_pendidikan=?, pekerjaan=?,penghasilan=?,status_ekonomi=?,kondisi_kesehatan=?, lat=?,lng=?,catatan=?,updated_at=NOW() WHERE id=?") ->execute([ sanitize($b['nama'] ?? ''), $b['jenis_kelamin'] ?? 'L', $tgl, $b['status_keluarga'] ?? 'anggota', $b['status_perkawinan'] ?? 'belum_kawin', $b['status_hidup'] ?? 'hidup', (int)($b['keluarga_id'] ?? 0), $pendid, $stPend, sanitize($b['pekerjaan'] ?? ''), (float)($b['penghasilan'] ?? 0), $b['status_ekonomi'] ?? 'rentan', $b['kondisi_kesehatan'] ?? 'sehat', isset($b['lat']) ? (float)$b['lat'] : null, isset($b['lng']) ? (float)$b['lng'] : null, sanitize($b['catatan'] ?? ''), $id ]); log_aksi($user['id'], 'UPDATE', 'penduduk', $id, "Edit ID: $id"); $warn = validasiPendidikan($umur, $pendid, $stPend); jsonOk(['peringatan'=>$warn], 'Data berhasil diperbarui.'); break; // ── DELETE ── case 'DELETE': requireRole(['superadmin']); if (!$id) jsonErr('ID tidak valid.'); $chk = $db->prepare("SELECT nama FROM penduduk WHERE id=?"); $chk->execute([$id]); $row = $chk->fetch(); if (!$row) jsonErr('Data tidak ditemukan.', 404); $db->prepare("DELETE FROM penduduk WHERE id=?")->execute([$id]); log_aksi($user['id'], 'DELETE', 'penduduk', $id, 'Hapus: '.$row['nama']); jsonOk(null, 'Data berhasil dihapus.'); break; default: jsonErr('Method tidak didukung.', 405); }