180 lines
6.4 KiB
PHP
180 lines
6.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
function ensurePendudukFeatureSchema(PDO $pdo): void
|
|
{
|
|
$columns = [
|
|
'kategori_kebutuhan' => "ALTER TABLE penduduk_miskin ADD COLUMN kategori_kebutuhan VARCHAR(100) NULL AFTER status_bantuan",
|
|
'deskripsi_kebutuhan' => "ALTER TABLE penduduk_miskin ADD COLUMN deskripsi_kebutuhan TEXT NULL AFTER kategori_kebutuhan",
|
|
'tindak_lanjut' => "ALTER TABLE penduduk_miskin ADD COLUMN tindak_lanjut VARCHAR(60) NOT NULL DEFAULT 'Belum disurvei' AFTER deskripsi_kebutuhan",
|
|
'kondisi_rumah' => "ALTER TABLE penduduk_miskin ADD COLUMN kondisi_rumah VARCHAR(80) NULL AFTER tindak_lanjut",
|
|
'penghasilan' => "ALTER TABLE penduduk_miskin ADD COLUMN penghasilan INT NULL AFTER kondisi_rumah",
|
|
'catatan_survei' => "ALTER TABLE penduduk_miskin ADD COLUMN catatan_survei TEXT NULL AFTER penghasilan",
|
|
'bukti_file' => "ALTER TABLE penduduk_miskin ADD COLUMN bukti_file VARCHAR(255) NULL AFTER catatan_survei",
|
|
'skor_prioritas' => "ALTER TABLE penduduk_miskin ADD COLUMN skor_prioritas INT NOT NULL DEFAULT 0 AFTER bukti_file",
|
|
];
|
|
|
|
foreach ($columns as $column => $sql) {
|
|
$stmt = $pdo->query("SHOW COLUMNS FROM penduduk_miskin LIKE " . $pdo->quote($column));
|
|
if ($stmt->fetch() === false) {
|
|
$pdo->exec($sql);
|
|
}
|
|
}
|
|
|
|
$pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS riwayat_bantuan (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
penduduk_id INT NOT NULL,
|
|
jenis_bantuan VARCHAR(120) NOT NULL,
|
|
tanggal_bantuan DATE NOT NULL,
|
|
nilai_bantuan VARCHAR(80) NULL,
|
|
pemberi_bantuan VARCHAR(120) NULL,
|
|
catatan TEXT NULL,
|
|
bukti_file VARCHAR(255) NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (penduduk_id) REFERENCES penduduk_miskin(id) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
|
");
|
|
}
|
|
|
|
function normalizeDateOrNull(?string $value): ?string
|
|
{
|
|
$value = trim((string)$value);
|
|
return $value === '' || $value === '0000-00-00' ? null : $value;
|
|
}
|
|
|
|
function normalizeNonNegativeIntOrNull(mixed $value, string $label): ?int
|
|
{
|
|
$value = trim((string)$value);
|
|
if ($value === '') {
|
|
return null;
|
|
}
|
|
|
|
if (!is_numeric($value) || (float)$value < 0) {
|
|
throw new InvalidArgumentException($label . ' tidak boleh bernilai negatif.');
|
|
}
|
|
|
|
return (int)$value;
|
|
}
|
|
|
|
function calculatePriorityScore(array $penduduk, array $anggota = []): int
|
|
{
|
|
$score = 0;
|
|
$anggotaCount = count($anggota);
|
|
$penghasilan = isset($penduduk['penghasilan']) ? (int)$penduduk['penghasilan'] : 0;
|
|
|
|
if (($penduduk['status_bantuan'] ?? '') === 'Belum dibantu') $score += 30;
|
|
if (($penduduk['status_bantuan'] ?? '') === 'Menunggu verifikasi') $score += 15;
|
|
if ((int)($penduduk['is_blank_spot'] ?? 0) === 1) $score += 15;
|
|
|
|
$score += min(20, $anggotaCount * 4);
|
|
|
|
foreach ($anggota as $a) {
|
|
$umur = isset($a['umur']) ? (int)$a['umur'] : null;
|
|
if ($umur !== null && ($umur < 6 || $umur >= 60)) {
|
|
$score += 5;
|
|
}
|
|
}
|
|
|
|
if ($penghasilan > 0 && $penghasilan <= 1000000) $score += 15;
|
|
elseif ($penghasilan > 1000000 && $penghasilan <= 2000000) $score += 8;
|
|
|
|
$kondisi = strtolower((string)($penduduk['kondisi_rumah'] ?? ''));
|
|
if (str_contains($kondisi, 'tidak layak')) $score += 15;
|
|
elseif (str_contains($kondisi, 'rentan')) $score += 8;
|
|
|
|
$kebutuhan = strtolower((string)($penduduk['kategori_kebutuhan'] ?? ''));
|
|
if (in_array($kebutuhan, ['kesehatan', 'rumah tidak layak', 'bantuan darurat'], true)) $score += 10;
|
|
|
|
return min(100, max(0, $score));
|
|
}
|
|
|
|
function getPriorityLabel(int $score): string
|
|
{
|
|
if ($score >= 70) return 'Prioritas Tinggi';
|
|
if ($score >= 40) return 'Prioritas Sedang';
|
|
return 'Prioritas Rendah';
|
|
}
|
|
|
|
function saveUploadedEvidence(string $fieldName): ?string
|
|
{
|
|
if (empty($_FILES[$fieldName]) || !is_array($_FILES[$fieldName])) {
|
|
return null;
|
|
}
|
|
|
|
$file = $_FILES[$fieldName];
|
|
if (($file['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) {
|
|
return null;
|
|
}
|
|
|
|
if (($file['error'] ?? UPLOAD_ERR_OK) !== UPLOAD_ERR_OK) {
|
|
throw new RuntimeException('Upload bukti gagal.');
|
|
}
|
|
|
|
if (($file['size'] ?? 0) > 3 * 1024 * 1024) {
|
|
throw new RuntimeException('Ukuran bukti maksimal 3 MB.');
|
|
}
|
|
|
|
$allowed = [
|
|
'image/jpeg' => 'jpg',
|
|
'image/png' => 'png',
|
|
'image/webp' => 'webp',
|
|
'application/pdf' => 'pdf',
|
|
];
|
|
$mime = mime_content_type($file['tmp_name']);
|
|
|
|
if (!isset($allowed[$mime])) {
|
|
throw new RuntimeException('Format bukti harus JPG, PNG, WEBP, atau PDF.');
|
|
}
|
|
|
|
$dir = __DIR__ . '/../uploads/bukti';
|
|
if (!is_dir($dir) && !mkdir($dir, 0775, true) && !is_dir($dir)) {
|
|
throw new RuntimeException('Folder upload tidak bisa dibuat.');
|
|
}
|
|
|
|
$filename = date('YmdHis') . '-' . bin2hex(random_bytes(6)) . '.' . $allowed[$mime];
|
|
$target = $dir . '/' . $filename;
|
|
|
|
if (!move_uploaded_file($file['tmp_name'], $target)) {
|
|
throw new RuntimeException('Bukti tidak bisa disimpan.');
|
|
}
|
|
|
|
return 'uploads/bukti/' . $filename;
|
|
}
|
|
|
|
function readPendudukInput(): array
|
|
{
|
|
if (str_starts_with((string)($_SERVER['CONTENT_TYPE'] ?? ''), 'multipart/form-data')) {
|
|
$input = $_POST;
|
|
$input['anggota'] = json_decode((string)($_POST['anggota'] ?? '[]'), true) ?: [];
|
|
return $input;
|
|
}
|
|
|
|
return json_decode(file_get_contents('php://input'), true) ?: [];
|
|
}
|
|
|
|
function updatePendudukPriority(PDO $pdo, int $pendudukId): void
|
|
{
|
|
$stmt = $pdo->prepare("SELECT * FROM penduduk_miskin WHERE id = ?");
|
|
$stmt->execute([$pendudukId]);
|
|
$penduduk = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
if (!$penduduk) return;
|
|
|
|
$stmtAnggota = $pdo->prepare("SELECT * FROM anggota_keluarga WHERE penduduk_id = ?");
|
|
$stmtAnggota->execute([$pendudukId]);
|
|
$anggota = $stmtAnggota->fetchAll(PDO::FETCH_ASSOC);
|
|
$score = calculatePriorityScore($penduduk, $anggota);
|
|
|
|
$update = $pdo->prepare("UPDATE penduduk_miskin SET skor_prioritas = ? WHERE id = ?");
|
|
$update->execute([$score, $pendudukId]);
|
|
}
|
|
|
|
function refreshAllPriorityScores(PDO $pdo): void
|
|
{
|
|
ensurePendudukFeatureSchema($pdo);
|
|
$ids = $pdo->query("SELECT id FROM penduduk_miskin")->fetchAll(PDO::FETCH_COLUMN);
|
|
foreach ($ids as $id) {
|
|
updatePendudukPriority($pdo, (int)$id);
|
|
}
|
|
}
|