id $wmap = []; foreach ($pdo->query("SELECT id, kode_wilayah FROM wilayah") as $w) { if ($w['kode_wilayah']) $wmap[trim($w['kode_wilayah'])] = $w['id']; } $header = fgetcsv($fh); if (!$header) sendError('CSV kosong'); $header = array_map(fn($h) => strtolower(trim($h)), $header); $idx = array_flip($header); $need = ['nama_kk', 'latitude', 'longitude']; foreach ($need as $col) { if (!isset($idx[$col])) sendError("Kolom wajib '$col' tidak ditemukan di CSV"); } $enumAir = ['SUMUR_BOR','PDAM','SUNGAI','HUJAN','TIDAK_ADA']; $enumListrik = ['PLN','NON_PLN','TIDAK_ADA']; $enumDinding = ['PERMANEN','SEMI_PERMANEN','TIDAK_PERMANEN']; $val = fn($row, $key) => isset($idx[$key]) && isset($row[$idx[$key]]) ? trim($row[$idx[$key]]) : null; $enumOrNull = fn($v, $allowed) => ($v && in_array(strtoupper($v), $allowed, true)) ? strtoupper($v) : null; $ins = $pdo->prepare(" INSERT INTO warga_miskin (nama_kk, nik_kk, wilayah_id, jumlah_jiwa, pekerjaan_kk, penghasilan, jumlah_tanggungan, sumber_air, status_listrik, material_dinding, status_verifikasi, created_by, geom) VALUES (?,?,?,?,?,?,?,?,?,?, 'belum', ?, ST_GeomFromText(?)) "); $ok = 0; $fail = 0; $errors = []; $line = 1; while (($row = fgetcsv($fh)) !== false) { $line++; if (count(array_filter($row, fn($x) => $x !== '' && $x !== null)) === 0) continue; // baris kosong $nama = $val($row, 'nama_kk'); $lat = $val($row, 'latitude'); $lng = $val($row, 'longitude'); if (!$nama) { $fail++; $errors[] = "Baris $line: nama_kk kosong"; continue; } if (!is_numeric($lat) || !is_numeric($lng)) { $fail++; $errors[] = "Baris $line: koordinat tidak valid"; continue; } $kode = $val($row, 'kode_kelurahan'); $wid = ($kode && isset($wmap[$kode])) ? $wmap[$kode] : null; try { $ins->execute([ $nama, $val($row, 'nik_kk'), $wid, ($val($row, 'jumlah_jiwa') !== null && $val($row, 'jumlah_jiwa') !== '') ? (int)$val($row, 'jumlah_jiwa') : null, $val($row, 'pekerjaan_kk'), (float)($val($row, 'penghasilan') ?? 0), (int)($val($row, 'jumlah_tanggungan') ?? 0), $enumOrNull($val($row, 'sumber_air'), $enumAir), $enumOrNull($val($row, 'status_listrik'), $enumListrik), $enumOrNull($val($row, 'material_dinding'), $enumDinding), $_SESSION['user_id'] ?? null, sprintf('POINT(%F %F)', (float)$lng, (float)$lat), ]); $ok++; } catch (Exception $e) { $fail++; $errors[] = "Baris $line: " . $e->getMessage(); } } fclose($fh); logActivity($pdo, 'create', 'warga_miskin', null, "Import CSV: $ok berhasil, $fail gagal"); sendSuccess(['berhasil' => $ok, 'gagal' => $fail, 'errors' => array_slice($errors, 0, 15)], 'Import selesai');