329 lines
13 KiB
PHP
329 lines
13 KiB
PHP
<?php
|
|
// ============================================================
|
|
// API: Penduduk
|
|
// GET ?action=list|detail&nik=...
|
|
// POST action=create
|
|
// PUT action=update&nik=...
|
|
// DELETE action=delete&nik=...
|
|
// ============================================================
|
|
|
|
require_once __DIR__ . '/../middleware/auth.php';
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
header('Access-Control-Allow-Origin: *');
|
|
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
|
|
header('Access-Control-Allow-Headers: Content-Type');
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { exit; }
|
|
|
|
$method = $_SERVER['REQUEST_METHOD'];
|
|
$action = $_GET['action'] ?? '';
|
|
$currentUser = getApiUser($pdo);
|
|
|
|
// ============================================================
|
|
// GET
|
|
// ============================================================
|
|
if ($method === 'GET') {
|
|
|
|
if ($action === 'list') {
|
|
$where = ['p.status_hidup = "hidup"'];
|
|
$params = [];
|
|
|
|
if (!empty($_GET['status_ekonomi'])) {
|
|
$where[] = 'p.status_ekonomi = :se';
|
|
$params[':se'] = $_GET['status_ekonomi'];
|
|
}
|
|
if (!empty($_GET['id_keluarga'])) {
|
|
$where[] = 'p.id_keluarga = :kk';
|
|
$params[':kk'] = (int)$_GET['id_keluarga'];
|
|
}
|
|
if (!empty($_GET['belum_dibantu'])) {
|
|
$where[] = 'NOT EXISTS (SELECT 1 FROM histori_bantuan hb WHERE hb.nik = p.nik AND hb.status_penyaluran="disalurkan")';
|
|
}
|
|
if (!empty($_GET['kondisi_kesehatan'])) {
|
|
$where[] = 'p.kondisi_kesehatan = :kk2';
|
|
$params[':kk2'] = $_GET['kondisi_kesehatan'];
|
|
}
|
|
if (!empty($_GET['search'])) {
|
|
$where[] = '(p.nama_lengkap LIKE :q OR p.nik LIKE :q2)';
|
|
$params[':q'] = '%' . $_GET['search'] . '%';
|
|
$params[':q2'] = '%' . $_GET['search'] . '%';
|
|
}
|
|
|
|
$whereStr = $where ? ('WHERE ' . implode(' AND ', $where)) : '';
|
|
|
|
$sql = "
|
|
SELECT
|
|
p.nik, p.nama_lengkap, p.jenis_kelamin, p.tanggal_lahir,
|
|
p.umur, p.status_keluarga, p.status_perkawinan,
|
|
p.status_ekonomi, p.kondisi_kesehatan,
|
|
p.pekerjaan, p.penghasilan,
|
|
p.pendidikan_terakhir, p.status_pendidikan,
|
|
p.alamat, p.latitude, p.longitude, p.foto,
|
|
p.id_keluarga,
|
|
k.no_kk, k.nama_kk, k.status_ekonomi AS status_ekonomi_kk,
|
|
ri.nama AS nama_rumah_ibadah, ri.jenis AS jenis_rumah_ibadah,
|
|
(SELECT COUNT(*) FROM histori_bantuan hb WHERE hb.nik = p.nik AND hb.status_penyaluran='disalurkan') AS jumlah_bantuan_diterima,
|
|
(SELECT MAX(hb2.tanggal) FROM histori_bantuan hb2 WHERE hb2.nik = p.nik AND hb2.status_penyaluran='disalurkan') AS terakhir_dibantu
|
|
FROM penduduk p
|
|
LEFT JOIN keluarga k ON k.id = p.id_keluarga
|
|
LEFT JOIN rumah_ibadah ri ON ri.id = k.rumah_ibadah_id
|
|
$whereStr
|
|
ORDER BY
|
|
CASE p.status_ekonomi WHEN 'miskin' THEN 1 WHEN 'rentan' THEN 2 ELSE 3 END ASC,
|
|
CASE p.kondisi_kesehatan WHEN 'sakit_parah' THEN 1 WHEN 'disabilitas' THEN 2 WHEN 'sakit_ringan' THEN 3 ELSE 4 END ASC
|
|
LIMIT 1000
|
|
";
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($params);
|
|
$rows = $stmt->fetchAll();
|
|
|
|
// Hitung prioritas untuk setiap penduduk
|
|
foreach ($rows as &$r) {
|
|
$belumDibantu = (int)$r['jumlah_bantuan_diterima'] === 0;
|
|
$r['prioritas_bantuan'] = hitungPrioritasBantuan($r['status_ekonomi'], $r['kondisi_kesehatan'], $belumDibantu);
|
|
}
|
|
unset($r);
|
|
|
|
jsonResponse(true, 'OK', ['data' => $rows, 'total' => count($rows)]);
|
|
}
|
|
|
|
if ($action === 'detail') {
|
|
$nik = sanitizeStr($_GET['nik'] ?? '');
|
|
if (!validateNIK($nik)) jsonResponse(false, 'NIK tidak valid.', [], 400);
|
|
|
|
$stmt = $pdo->prepare("
|
|
SELECT p.*, k.no_kk, k.nama_kk, ri.nama AS nama_ri
|
|
FROM penduduk p
|
|
LEFT JOIN keluarga k ON k.id = p.id_keluarga
|
|
LEFT JOIN rumah_ibadah ri ON ri.id = k.rumah_ibadah_id
|
|
WHERE p.nik = :nik
|
|
");
|
|
$stmt->execute([':nik' => $nik]);
|
|
$penduduk = $stmt->fetch();
|
|
if (!$penduduk) jsonResponse(false, 'Data tidak ditemukan.', [], 404);
|
|
|
|
// Histori bantuan
|
|
$stmtHB = $pdo->prepare("
|
|
SELECT hb.*, jb.nama AS nama_bantuan, jb.kategori, ri.nama AS nama_ri
|
|
FROM histori_bantuan hb
|
|
JOIN jenis_bantuan jb ON jb.id = hb.id_jenis_bantuan
|
|
LEFT JOIN rumah_ibadah ri ON ri.id = hb.rumah_ibadah_id
|
|
WHERE hb.nik = :nik
|
|
ORDER BY hb.tanggal DESC
|
|
");
|
|
$stmtHB->execute([':nik' => $nik]);
|
|
$histori = $stmtHB->fetchAll();
|
|
|
|
// Pelatihan
|
|
$stmtPl = $pdo->prepare("SELECT * FROM riwayat_pelatihan WHERE nik = :nik ORDER BY tanggal_mulai DESC");
|
|
$stmtPl->execute([':nik' => $nik]);
|
|
$pelatihan = $stmtPl->fetchAll();
|
|
|
|
// Validasi pendidikan
|
|
$validasi = validasiPendidikanUmur(
|
|
(int)$penduduk['umur'],
|
|
$penduduk['pendidikan_terakhir'],
|
|
$penduduk['status_pendidikan']
|
|
);
|
|
|
|
$belumDibantu = empty($histori);
|
|
$penduduk['prioritas_bantuan'] = hitungPrioritasBantuan($penduduk['status_ekonomi'], $penduduk['kondisi_kesehatan'], $belumDibantu);
|
|
|
|
jsonResponse(true, 'OK', [
|
|
'data' => $penduduk,
|
|
'histori' => $histori,
|
|
'pelatihan' => $pelatihan,
|
|
'validasi' => $validasi,
|
|
]);
|
|
}
|
|
|
|
if ($action === 'geojson') {
|
|
// Untuk layer Leaflet
|
|
$stmt = $pdo->query("
|
|
SELECT p.nik, p.nama_lengkap, p.status_ekonomi, p.kondisi_kesehatan,
|
|
p.latitude, p.longitude,
|
|
k.nama_kk,
|
|
(SELECT COUNT(*) FROM histori_bantuan hb WHERE hb.nik=p.nik AND hb.status_penyaluran='disalurkan') AS jml_bantuan
|
|
FROM penduduk p
|
|
LEFT JOIN keluarga k ON k.id = p.id_keluarga
|
|
WHERE p.latitude IS NOT NULL AND p.longitude IS NOT NULL
|
|
AND p.status_hidup = 'hidup'
|
|
");
|
|
$rows = $stmt->fetchAll();
|
|
|
|
$features = [];
|
|
foreach ($rows as $r) {
|
|
$color = match($r['status_ekonomi']) {
|
|
'miskin' => '#ef4444',
|
|
'rentan' => '#f59e0b',
|
|
default => '#22c55e'
|
|
};
|
|
$features[] = [
|
|
'type' => 'Feature',
|
|
'geometry' => [
|
|
'type' => 'Point',
|
|
'coordinates' => [(float)$r['longitude'], (float)$r['latitude']]
|
|
],
|
|
'properties' => array_merge($r, ['color' => $color])
|
|
];
|
|
}
|
|
|
|
header('Content-Type: application/json');
|
|
echo json_encode(['type' => 'FeatureCollection', 'features' => $features], JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
jsonResponse(false, 'Action tidak dikenal.', [], 400);
|
|
}
|
|
|
|
// ============================================================
|
|
// POST - Create
|
|
// ============================================================
|
|
if ($method === 'POST') {
|
|
if (!canEdit($currentUser)) jsonResponse(false, 'Akses ditolak.', [], 403);
|
|
|
|
$body = json_decode(file_get_contents('php://input'), true) ?? $_POST;
|
|
|
|
$nik = sanitizeStr($body['nik'] ?? '');
|
|
$nama = sanitizeStr($body['nama_lengkap'] ?? '');
|
|
$jk = sanitizeStr($body['jenis_kelamin'] ?? '');
|
|
$tgl = sanitizeStr($body['tanggal_lahir'] ?? '');
|
|
$idKk = !empty($body['id_keluarga']) ? (int)$body['id_keluarga'] : null;
|
|
|
|
if (!validateNIK($nik)) jsonResponse(false, 'Format NIK harus 16 digit angka.', [], 400);
|
|
if (strlen($nama) < 3) jsonResponse(false, 'Nama terlalu pendek.', [], 400);
|
|
if (!in_array($jk, ['L','P'])) jsonResponse(false, 'Jenis kelamin tidak valid.', [], 400);
|
|
if (!strtotime($tgl)) jsonResponse(false, 'Format tanggal lahir tidak valid.', [], 400);
|
|
|
|
// Cek duplikat NIK
|
|
$cek = $pdo->prepare("SELECT nik FROM penduduk WHERE nik = :nik");
|
|
$cek->execute([':nik' => $nik]);
|
|
if ($cek->fetch()) jsonResponse(false, 'NIK sudah terdaftar.', [], 409);
|
|
|
|
// Hitung umur untuk validasi pendidikan
|
|
$umur = (int)(new DateTime())->diff(new DateTime($tgl))->y;
|
|
$statusPendidikan = sanitizeStr($body['status_pendidikan'] ?? 'tidak_sekolah');
|
|
$pendidikan = sanitizeStr($body['pendidikan_terakhir'] ?? 'tidak_sekolah');
|
|
$validasi = validasiPendidikanUmur($umur, $pendidikan, $statusPendidikan);
|
|
|
|
$lat = !empty($body['latitude']) ? (float)$body['latitude'] : null;
|
|
$lng = !empty($body['longitude']) ? (float)$body['longitude'] : null;
|
|
if ($lat !== null && !validateCoord((string)$lat, 'lat')) jsonResponse(false, 'Latitude tidak valid.', [], 400);
|
|
if ($lng !== null && !validateCoord((string)$lng, 'lng')) jsonResponse(false, 'Longitude tidak valid.', [], 400);
|
|
|
|
$stmt = $pdo->prepare("
|
|
INSERT INTO penduduk
|
|
(nik, id_keluarga, nama_lengkap, jenis_kelamin, tanggal_lahir,
|
|
status_keluarga, status_perkawinan, status_hidup,
|
|
pendidikan_terakhir, status_pendidikan,
|
|
pekerjaan, penghasilan, status_ekonomi,
|
|
kondisi_kesehatan, catatan_kesehatan,
|
|
no_telp, alamat, latitude, longitude)
|
|
VALUES
|
|
(:nik,:kk,:nama,:jk,:tgl,
|
|
:sk,:sp,:sh,
|
|
:ptk,:spd,
|
|
:pkr,:pgn,:se,
|
|
:kkh,:ckkh,
|
|
:tlp,:almt,:lat,:lng)
|
|
");
|
|
$stmt->execute([
|
|
':nik' => $nik,
|
|
':kk' => $idKk,
|
|
':nama' => $nama,
|
|
':jk' => $jk,
|
|
':tgl' => $tgl,
|
|
':sk' => sanitizeStr($body['status_keluarga'] ?? 'anggota_lain'),
|
|
':sp' => sanitizeStr($body['status_perkawinan'] ?? 'belum_kawin'),
|
|
':sh' => sanitizeStr($body['status_hidup'] ?? 'hidup'),
|
|
':ptk' => $pendidikan,
|
|
':spd' => $statusPendidikan,
|
|
':pkr' => sanitizeStr($body['pekerjaan'] ?? '') ?: null,
|
|
':pgn' => !empty($body['penghasilan']) ? (float)$body['penghasilan'] : 0,
|
|
':se' => sanitizeStr($body['status_ekonomi'] ?? 'rentan'),
|
|
':kkh' => sanitizeStr($body['kondisi_kesehatan'] ?? 'sehat'),
|
|
':ckkh' => sanitizeStr($body['catatan_kesehatan'] ?? '') ?: null,
|
|
':tlp' => sanitizeStr($body['no_telp'] ?? '') ?: null,
|
|
':almt' => sanitizeStr($body['alamat'] ?? '') ?: null,
|
|
':lat' => $lat,
|
|
':lng' => $lng,
|
|
]);
|
|
|
|
logAktivitas($pdo, $currentUser['id'] ?? null, 'CREATE', 'penduduk', $nik, null, $body);
|
|
|
|
jsonResponse(true, 'Penduduk berhasil ditambahkan.', [
|
|
'nik' => $nik,
|
|
'validasi' => $validasi
|
|
], 201);
|
|
}
|
|
|
|
// ============================================================
|
|
// PUT - Update
|
|
// ============================================================
|
|
if ($method === 'PUT') {
|
|
if (!canEdit($currentUser)) jsonResponse(false, 'Akses ditolak.', [], 403);
|
|
|
|
$nik = sanitizeStr($_GET['nik'] ?? '');
|
|
if (!validateNIK($nik)) jsonResponse(false, 'NIK tidak valid.', [], 400);
|
|
|
|
$body = json_decode(file_get_contents('php://input'), true) ?? [];
|
|
|
|
// Ambil data lama
|
|
$old = $pdo->prepare("SELECT * FROM penduduk WHERE nik = :nik");
|
|
$old->execute([':nik' => $nik]);
|
|
$dataLama = $old->fetch();
|
|
if (!$dataLama) jsonResponse(false, 'Data tidak ditemukan.', [], 404);
|
|
|
|
$sets = [];
|
|
$params = [':nik' => $nik];
|
|
|
|
$fieldMap = [
|
|
'id_keluarga' => ':kk', 'nama_lengkap' => ':nama', 'jenis_kelamin' => ':jk',
|
|
'tanggal_lahir' => ':tgl', 'status_keluarga' => ':sk', 'status_perkawinan' => ':sp',
|
|
'status_hidup' => ':sh', 'pendidikan_terakhir' => ':ptk', 'status_pendidikan' => ':spd',
|
|
'pekerjaan' => ':pkr', 'penghasilan' => ':pgn', 'status_ekonomi' => ':se',
|
|
'kondisi_kesehatan' => ':kkh', 'catatan_kesehatan' => ':ckkh',
|
|
'no_telp' => ':tlp', 'alamat' => ':almt', 'latitude' => ':lat', 'longitude' => ':lng',
|
|
];
|
|
|
|
foreach ($fieldMap as $field => $param) {
|
|
if (array_key_exists($field, $body)) {
|
|
$sets[] = "$field = $param";
|
|
$params[$param] = $body[$field] === '' ? null : $body[$field];
|
|
}
|
|
}
|
|
|
|
if (empty($sets)) jsonResponse(false, 'Tidak ada data yang diubah.', [], 400);
|
|
|
|
$sql = "UPDATE penduduk SET " . implode(', ', $sets) . " WHERE nik = :nik";
|
|
$pdo->prepare($sql)->execute($params);
|
|
|
|
logAktivitas($pdo, $currentUser['id'] ?? null, 'UPDATE', 'penduduk', $nik, $dataLama, $body);
|
|
|
|
jsonResponse(true, 'Data penduduk berhasil diperbarui.', ['nik' => $nik]);
|
|
}
|
|
|
|
// ============================================================
|
|
// DELETE
|
|
// ============================================================
|
|
if ($method === 'DELETE') {
|
|
if (!isAdmin($currentUser)) jsonResponse(false, 'Hanya admin yang bisa menghapus data.', [], 403);
|
|
|
|
$nik = sanitizeStr($_GET['nik'] ?? '');
|
|
if (!validateNIK($nik)) jsonResponse(false, 'NIK tidak valid.', [], 400);
|
|
|
|
$old = $pdo->prepare("SELECT * FROM penduduk WHERE nik = :nik");
|
|
$old->execute([':nik' => $nik]);
|
|
$dataLama = $old->fetch();
|
|
if (!$dataLama) jsonResponse(false, 'Data tidak ditemukan.', [], 404);
|
|
|
|
$pdo->prepare("DELETE FROM penduduk WHERE nik = :nik")->execute([':nik' => $nik]);
|
|
logAktivitas($pdo, $currentUser['id'] ?? null, 'DELETE', 'penduduk', $nik, $dataLama, null);
|
|
|
|
jsonResponse(true, 'Data penduduk dihapus.');
|
|
}
|
|
|
|
jsonResponse(false, 'Method tidak didukung.', [], 405);
|