prepare($sql); $stmt->execute($params); $rows = $stmt->fetchAll(); jsonSuccess($rows); } /** GET /api/penduduk/:nik */ public function show(string $nik): void { requireAuth([ROLE_ADMIN, ROLE_PENGURUS, ROLE_PIMPINAN]); $db = getDB(); $stmt = $db->prepare( "SELECT p.*, TIMESTAMPDIFF(YEAR, p.tanggal_lahir, CURDATE()) AS umur, k.no_kk, k.nama_kepala, k.alamat, k.rt, k.rw, k.kelurahan, k.kecamatan, ri.nama AS nama_ri, ri.jenis AS jenis_ri FROM penduduk p JOIN keluarga k ON p.id_keluarga = k.id LEFT JOIN rumah_ibadah ri ON k.id_rumah_ibadah = ri.id WHERE p.nik = ?" ); $stmt->execute([$nik]); $row = $stmt->fetch(); if (!$row) jsonError('Penduduk tidak ditemukan', 404); // Histori bantuan $stmt2 = $db->prepare( "SELECT hb.*, b.nama_bantuan, b.kategori, ri.nama AS nama_ri FROM histori_bantuan hb JOIN bantuan b ON hb.id_bantuan = b.id LEFT JOIN rumah_ibadah ri ON hb.id_rumah_ibadah = ri.id WHERE hb.nik = ? ORDER BY hb.tanggal DESC" ); $stmt2->execute([$nik]); $row['histori_bantuan'] = $stmt2->fetchAll(); // Riwayat pendidikan $stmt3 = $db->prepare("SELECT * FROM riwayat_pendidikan WHERE nik = ? ORDER BY tahun_masuk DESC"); $stmt3->execute([$nik]); $row['riwayat_pendidikan'] = $stmt3->fetchAll(); // Peristiwa $stmt4 = $db->prepare("SELECT * FROM peristiwa_kependudukan WHERE nik = ? ORDER BY tanggal DESC"); $stmt4->execute([$nik]); $row['peristiwa'] = $stmt4->fetchAll(); jsonSuccess($row); } /** POST /api/penduduk */ public function store(): void { requireAuth([ROLE_ADMIN, ROLE_PENGURUS]); $body = getBody(); $errs = required($body, ['nik','id_keluarga','nama_lengkap','jenis_kelamin','tanggal_lahir']); if ($errs) jsonError(implode('; ', $errs)); // Validasi NIK 16 digit if (!preg_match('/^\d{16}$/', $body['nik'])) jsonError('NIK harus 16 digit angka'); $db = getDB(); // Cek duplikat $chk = $db->prepare("SELECT nik FROM penduduk WHERE nik = ?"); $chk->execute([$body['nik']]); if ($chk->fetch()) jsonError('NIK sudah terdaftar', 409); // Hitung umur $tgl = new DateTime($body['tanggal_lahir']); $umur = (new DateTime())->diff($tgl)->y; // Validasi pendidikan $warnings = validasiPendidikan( $umur, $body['pendidikan_terakhir'] ?? 'tidak_sekolah', $body['status_pendidikan'] ?? 'tidak_sekolah' ); $db->prepare( "INSERT INTO penduduk (nik, id_keluarga, nama_lengkap, jenis_kelamin, tanggal_lahir, tempat_lahir, status_keluarga, status_perkawinan, status_hidup, agama, pekerjaan, penghasilan, status_ekonomi, pendidikan_terakhir, status_pendidikan, kondisi_kesehatan, keterangan_kesehatan, lat, lng) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)" )->execute([ $body['nik'], (int)$body['id_keluarga'], sanitize($body['nama_lengkap']), $body['jenis_kelamin'], $body['tanggal_lahir'], sanitize($body['tempat_lahir'] ?? ''), $body['status_keluarga'] ?? 'anak', $body['status_perkawinan'] ?? 'belum_kawin', $body['status_hidup'] ?? 'hidup', $body['agama'] ?? null, sanitize($body['pekerjaan'] ?? ''), (int)($body['penghasilan'] ?? 0), $body['status_ekonomi'] ?? 'rentan', $body['pendidikan_terakhir'] ?? 'tidak_sekolah', $body['status_pendidikan'] ?? 'tidak_sekolah', $body['kondisi_kesehatan'] ?? 'sehat', sanitize($body['keterangan_kesehatan'] ?? ''), $body['lat'] ?? null, $body['lng'] ?? null, ]); logActivity('create_penduduk', 'penduduk', $body['nik'], [], $body); jsonSuccess(['nik' => $body['nik'], 'warnings' => $warnings], 'Data penduduk berhasil disimpan', 201); } /** PUT /api/penduduk/:nik */ public function update(string $nik): void { requireAuth([ROLE_ADMIN, ROLE_PENGURUS]); $db = getDB(); $old = $db->prepare("SELECT * FROM penduduk WHERE nik = ?"); $old->execute([$nik]); $existing = $old->fetch(); if (!$existing) jsonError('Penduduk tidak ditemukan', 404); $body = getBody(); $tgl = new DateTime($body['tanggal_lahir'] ?? $existing['tanggal_lahir']); $umur = (new DateTime())->diff($tgl)->y; $warnings = validasiPendidikan( $umur, $body['pendidikan_terakhir'] ?? $existing['pendidikan_terakhir'], $body['status_pendidikan'] ?? $existing['status_pendidikan'] ); $db->prepare( "UPDATE penduduk SET nama_lengkap=?, jenis_kelamin=?, tanggal_lahir=?, tempat_lahir=?, status_keluarga=?, status_perkawinan=?, status_hidup=?, agama=?, pekerjaan=?, penghasilan=?, status_ekonomi=?, pendidikan_terakhir=?, status_pendidikan=?, kondisi_kesehatan=?, keterangan_kesehatan=?, lat=?, lng=? WHERE nik=?" )->execute([ sanitize($body['nama_lengkap'] ?? $existing['nama_lengkap']), $body['jenis_kelamin'] ?? $existing['jenis_kelamin'], $body['tanggal_lahir'] ?? $existing['tanggal_lahir'], sanitize($body['tempat_lahir'] ?? $existing['tempat_lahir']), $body['status_keluarga'] ?? $existing['status_keluarga'], $body['status_perkawinan'] ?? $existing['status_perkawinan'], $body['status_hidup'] ?? $existing['status_hidup'], $body['agama'] ?? $existing['agama'], sanitize($body['pekerjaan'] ?? $existing['pekerjaan']), (int)($body['penghasilan'] ?? $existing['penghasilan']), $body['status_ekonomi'] ?? $existing['status_ekonomi'], $body['pendidikan_terakhir'] ?? $existing['pendidikan_terakhir'], $body['status_pendidikan'] ?? $existing['status_pendidikan'], $body['kondisi_kesehatan'] ?? $existing['kondisi_kesehatan'], sanitize($body['keterangan_kesehatan'] ?? $existing['keterangan_kesehatan']), $body['lat'] ?? $existing['lat'], $body['lng'] ?? $existing['lng'], $nik, ]); logActivity('update_penduduk', 'penduduk', $nik, $existing, $body); jsonSuccess(['nik' => $nik, 'warnings' => $warnings], 'Data penduduk berhasil diperbarui'); } /** DELETE /api/penduduk/:nik */ public function destroy(string $nik): void { requireAuth([ROLE_ADMIN]); $db = getDB(); $stmt = $db->prepare("SELECT nik FROM penduduk WHERE nik = ?"); $stmt->execute([$nik]); if (!$stmt->fetch()) jsonError('Penduduk tidak ditemukan', 404); $db->prepare("DELETE FROM penduduk WHERE nik = ?")->execute([$nik]); logActivity('delete_penduduk', 'penduduk', $nik); jsonSuccess([], 'Data penduduk dihapus'); } /** GET /api/penduduk/:nik/validasi-pendidikan */ public function validasiPendidikan(string $nik): void { requireAuth([ROLE_ADMIN, ROLE_PENGURUS]); $db = getDB(); $stmt = $db->prepare( "SELECT nik, nama_lengkap, TIMESTAMPDIFF(YEAR, tanggal_lahir, CURDATE()) AS umur, pendidikan_terakhir, status_pendidikan FROM penduduk WHERE nik = ?" ); $stmt->execute([$nik]); $row = $stmt->fetch(); if (!$row) jsonError('Penduduk tidak ditemukan', 404); $warnings = validasiPendidikan($row['umur'], $row['pendidikan_terakhir'], $row['status_pendidikan']); jsonSuccess(['penduduk' => $row, 'warnings' => $warnings]); } }