Files
lpj/database/seeders/MigrationInpseksiSeeder.php
Daeng Deni Mardaeni 70dda16699 feat(lpj-seeders): Inisialisasi master referensi, migrasi MIG, dan SQL seeding
- Menata LpjDatabaseSeeder untuk orkestrasi batch, aktifkan MigrationGambarInspeksiSeeder .
- Migrasi domain MIG → LPJ lengkap dengan parseTimestamp , initializeErrorLog , logError .
- Tambah seeders MIG eksternal & tim penilai; normalisasi mapping checkTujuanPenilaian .
- Perluasan master: JFK009–JFK014, TP0007–TP00010, hubungan pemilik, KJPP; TeamsSeeder via SQL.
- MasterDataSurveyorSeeder eksekusi SQL referensi (20+ tabel) via DB::unprepared .
- Tambah puluhan SQL referensi (jenis, kondisi, sarana, posisi, spek, dll).
- Normalisasi data inspeksi (duplikasi key dinamis), serialisasi JSON rapi.
- Logging seragam ke app log + CSV error untuk audit trail.
2025-11-10 21:06:03 +07:00

1002 lines
34 KiB
PHP

<?php
namespace Modules\Lpj\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Modules\Lpj\Models\Inspeksi;
use Modules\Basicdata\Models\Branch;
use Modules\Lpj\Models\DokumenJaminan;
use Modules\Lpj\Models\Permohonan;
use Modules\Location\Models\City;
use Modules\Location\Models\District;
use Modules\Location\Models\Province;
use Modules\Location\Models\Village;
// Load file helper
require_once __DIR__ . '/MigInspeksiHelper.php';
class MigrationInpseksiSeeder extends Seeder
{
protected $errorLogFile = __DIR__ . '/csv/inspeksi/inspeksi.09_error.csv';
/**
* Properti command disediakan oleh Laravel saat seeder dijalankan melalui Artisan.
* Dideklarasikan untuk menghindari error linter pada akses properti.
*
* @var mixed|null
*/
protected $command;
// protected $fielKesimpulan = ;
/**
* Run the database seeds.
*/
public function run()
{
$this->initializeErrorLog();
// Path ke file csv
$filePath = realpath(__DIR__ . '/csv/inspeksi/inspeksi.09.csv');
if (!$filePath) {
Log::error('File csv tidak ditemukan: ' . __DIR__ . '/csv/inspeksi/inspeksi.09.csv');
\Illuminate\Support\Facades\Log::error('File csv tidak ditemukan: ' . __DIR__ . '/csv/inspeksi/inspeksi.09.csv');
$this->command->error('File csv tidak ditemukan.');
return;
}
if (($handle = fopen($filePath, 'r')) === false) {
Log::error('Gagal membuka file CSV: ' . $filePath);
\Illuminate\Support\Facades\Log::error('Gagal membuka file CSV: ' . $filePath);
$this->command->error('Gagal membuka file CSV.');
return;
}
$header = fgetcsv($handle, 0, ',');
$rows = [];
$batchSize = 500;
$userData = [];
$branchCache = []; // <-- Gunakan sebagai cache
$totalData = 0;
while (($data = fgetcsv($handle, 0, ',')) !== false) {
$totalData++;
}
rewind($handle);
fgetcsv($handle, 0, ','); // Skip header
$batchCount = 0;
$currentRow = 0;
$errorCount = 0;
$errorDebitureIds = [];
while (($data = fgetcsv($handle, 0, ',')) !== false) {
if (count($data) != count($header)) {
Log::warning('Baris CSV memiliki jumlah kolom yang tidak sesuai: ' . json_encode($data));
continue;
}
$rows[] = array_combine($header, $data);
$currentRow++;
if (count($rows) >= $batchSize) {
$batchCount++;
$this->command->info("Memproses batch ke-{$batchCount} ({$currentRow}/{$totalData})");
$this->processBatch($rows, $branchCache, $userData, $errorCount, $errorDebitureIds, $totalData, $batchCount, $currentRow);
$rows = [];
}
}
if (!empty($rows)) {
$batchCount++;
$this->command->info("Memproses batch ke-{$batchCount} ({$currentRow}/{$totalData})");
$this->processBatch($rows, $branchCache, $userData, $errorCount, $errorDebitureIds, $totalData, $batchCount, $currentRow);
}
fclose($handle);
$this->command->info("Data debiture berhasil dimigrasikan. Total data: {$totalData}, Total batch: {$batchCount}");
}
private function processBatch(
array $rows,
array &$branchCache,
array &$debitureCache,
int &$errorCount,
array &$errorDebitureIds,
int $totalData,
int $batchCount,
int $currentRow
) {
// Kelompokkan baris berdasarkan mig_nomor_jaminan
$groupedData = $this->groupRowsByJaminan($rows);
foreach ($groupedData as $nomorJaminan => $groupRows) {
try {
// Ambil informasi permohonan
$nomorRegis = $this->getNomorRegistrasiPermohonan($nomorJaminan, $branchCache);
if (!$nomorRegis) {
Log::warning("Nomor registrasi tidak ditemukan untuk nomor jaminan: {$nomorJaminan}");
$errorCount++;
$errorDebitureIds[] = $nomorJaminan;
continue;
}
// Cek apakah sudah ada data
$existingRecord = Inspeksi::where('permohonan_id', $nomorRegis['id'])
->where('dokument_id', $nomorRegis['dokument_id'])
->whereNotNull('data_form')
->first();
if ($existingRecord) {
//$this->command->info("Data untuk nomor jaminan {$nomorJaminan} sudah ada. Lewati...");
//continue;
}
// Ambil baris pertama untuk created_at/updated_at
$firstRow = reset($groupRows);
// Bangun JSON lengkap
$dataFormJson = $this->buildFullDataForm($groupRows);
$jenisJaminan = $this->checkJenisJaminan($groupRows[0]['mig_name'] ?? '');
if (!$dataFormJson) {
Log::warning("Data form kosong untuk nomor jaminan: {$nomorJaminan}");
$errorCount++;
$errorDebitureIds[] = $nomorJaminan;
continue;
}
// Bangun JSON terkelompok berdasarkan mig_jenis_legalitas_jaminan_name
$groupedLegalitasJson = $this->buildGroupedLegalitas($groupRows);
Log::info("Grouped legalitas JSON dibangun untuk nomor jaminan {$nomorJaminan}.", ['length' => strlen($groupedLegalitasJson ?? '')]);
// Gunakan transaksi saat menyimpan
DB::beginTransaction();
Inspeksi::updateOrCreate([
'permohonan_id' => $nomorRegis['id'] ?? null,
'dokument_id' => $nomorRegis['dokument_id'] ?? null,
],[
'name' => $jenisJaminan,
'data_form' => $dataFormJson,
'foto_form' => null,
'data_pembanding' => null,
'permohonan_id' => $nomorRegis['id'] ?? null,
'dokument_id' => $nomorRegis['dokument_id'] ?? null,
'created_at' => $this->parseTimestamp($firstRow['created_at'] ?? null),
'updated_at' => $this->parseTimestamp($firstRow['updated_at'] ?? null),
'nomor_lpj' => $nomorJaminan,
'processed_at' => now(),
'mig_detail_data_jaminan' => $this->kv_to_json($groupRows[0]['alamat_bundle'] ?? null),
'mig_detail_legalitas_jaminan' => $groupedLegalitasJson,
'is_mig' => 1
]);
DB::commit();
$this->command->info("Berhasil simpan data inspeksi untuk nomor jaminan: {$nomorJaminan}");
} catch (\Exception $e) {
DB::rollBack();
Log::error("Error pada nomor jaminan {$nomorJaminan}: " . $e->getMessage());
$errorCount++;
$errorDebitureIds[] = $nomorJaminan;
continue;
}
}
}
private function groupRowsByJaminan(array $rows): array
{
$grouped = [];
foreach ($rows as $row) {
$nomorJaminan = $row['mig_nomor_jaminan'] ?? null;
if (!empty($nomorJaminan)) {
$grouped[$nomorJaminan][] = $row;
}
}
return $grouped;
}
private function getNomorRegistrasiPermohonan($nomor_jaminan_id, array &$cache)
{
// Cek apakah sudah ada di cache
if (isset($cache[$nomor_jaminan_id])) {
return $cache[$nomor_jaminan_id];
}
// Cari di tabel Permohonan berdasarkan nomor registrasi
$permohonan = Permohonan::where('nomor_registrasi', $nomor_jaminan_id)->first();
if (!$permohonan) {
// Tidak ditemukan
$cache[$nomor_jaminan_id] = null;
return null;
}
// Cari dokument jaminan terkait
$dokumenJaminan = DokumenJaminan::where('permohonan_id', $permohonan->id)->first();
// Simpan hasil ke cache
$result = [
'id' => $permohonan->id,
'dokument_id' => $dokumenJaminan ? $dokumenJaminan->id : null
];
$cache[$nomor_jaminan_id] = $result;
return $result;
}
private function buildFullDataForm(array $rows)
{
if (empty($rows)) {
return null;
}
$jenisJaminan = $rows[0]['mig_name'] ?? null;
if (!$jenisJaminan) {
return null;
}
try {
$jsonResult = $this->checkBuildJson($jenisJaminan, $rows);
// Validasi apakah hasil JSON valid
json_decode($jsonResult);
return $jsonResult;
} catch (\Exception $e) {
Log::error("Gagal build JSON untuk jenis jaminan {$jenisJaminan}: " . $e->getMessage());
return null;
}
}
private function loadKesimpulanByNomorLpj($nomorLpj)
{
$filePath = realpath(__DIR__ . '/csv/inspeksi/kesimpulan.09.csv');
if (!$filePath || !$nomorLpj) {
return [];
}
if (($handle = fopen($filePath, 'r')) === false) {
Log::error("Gagal membuka file CSV kesimpulan: " . $filePath);
return [];
}
$header = fgetcsv($handle, 0, ',');
$result = [];
while (($data = fgetcsv($handle, 0, ',')) !== false) {
if (count($data) != count($header)) {
continue;
}
$row = array_combine($header, $data);
if ($row['mig_nomor_lpj'] === $nomorLpj) {
$result[] = $row;
}
}
fclose($handle);
return $result;
}
private function checkLingkungan($rows)
{
$dataToInsertJson = [];
// Inisialisasi struktur lingkungan
$lingkungan = [
'jarak_jalan_utama' => null,
'jalan_linkungan' => null,
'jarak_cbd_point' => null,
'nama_cbd_point' => null,
'lebar_perkerasan_jalan' => null,
'perkerasan_jalan' => ['perkerasan_jalan' => [], 'lainnya' => null],
'lalu_lintas' => null,
'gol_mas_sekitar' => [],
'tingkat_keramaian' => [],
'terletak_diarea' => ['terletak_diarea' => [], 'lainnya' => null],
'disekitar_lokasi' => null,
'kondisi_bagunan_disekitar_lokasi' => null,
'sifat_bagunan_disekitar_lokasi' => null,
'dekat_makam' => 'tidak',
'jarak_makam' => null,
'nama_makam' => null,
'dekat_tps' => 'tidak',
'jarak_tps' => null,
'nama_tps' => null,
'dekat_lainnya' => null,
'merupakan_daerah' => [],
'fasilitas_dekat_object' => [],
'fasilitas_dekat_object_input' => [
'Tempat Ibadah' => null,
'Rumah Sakit' => null,
'Sekolah' => null,
'Kantor Pemerintahan' => null,
'Stasiun Kereta' => null,
'Terminal Bus' => null,
'Bandara' => null,
'Pos Polisi' => null,
'Lainnya' => null
]
];
foreach ($rows as $row) {
$name = trim($row['name']);
$value = !empty($row['mig_name_keterangan_lain']) ? $row['mig_name_keterangan_lain'] : $row['mig_name_keterangan'];
switch ($name) {
case 'Lebar jalan dimuka lokasi':
$lingkungan['lebar_perkerasan_jalan'] = $row['mig_name_keterangan_lain'];
break;
case 'Lapisan perkerasan jalan dari':
if ($value === 'Lainnya') {
$lingkungan['perkerasan_jalan']['perkerasan_jalan'][] = $value;
$lingkungan['perkerasan_jalan']['lainnya'] = $row['mig_name_keterangan_lain'];
} else {
$lingkungan['perkerasan_jalan']['perkerasan_jalan'][] = $value;
}
break;
case 'Lalulintas didepan lokasi':
$lingkungan['lalu_lintas'] = $value;
break;
case 'Golongan Masyarakat sekitar':
$lingkungan['gol_mas_sekitar'][] = $value;
break;
case 'Dengan kondisi':
$lingkungan['tingkat_keramaian'][] = $value;
break;
case 'Terletak didaerah':
if ($value === 'Lainnya') {
$lingkungan['terletak_diarea']['terletak_diarea'][] = $value;
$lingkungan['terletak_diarea']['lainnya'] = $row['mig_name_keterangan_lain'];
} else {
$lingkungan['terletak_diarea']['terletak_diarea'][] = $value;
}
break;
case 'Disekitar lokasi':
$lingkungan['disekitar_lokasi'] = $value === 'Telah ada bangunan' ? 'sesuai' : 'tidak sesuai';
break;
case 'Merupakan daerah':
$lingkungan['merupakan_daerah'][] = $value;
break;
case 'Fasilitas umum dekat lokasi':
$lingkungan['fasilitas_dekat_object'][] = $value;
if (isset($lingkungan['fasilitas_dekat_object_input'][$value])) {
$lingkungan['fasilitas_dekat_object_input'][$value] = $value;
} elseif ($value === 'Pasar / Swalayan') {
$lingkungan['fasilitas_dekat_object_input']['Lainnya'] = 'pasar';
}
break;
}
}
// Isi default jika kosong
if (empty($lingkungan['fasilitas_dekat_object'])) {
$lingkungan['fasilitas_dekat_object'] = [];
}
// Masukkan ke array JSON
$dataToInsertJson[] = json_encode([
'lingkungan' => $lingkungan
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
return $dataToInsertJson;
}
private function checkAsset(array $rows)
{
$dataToInsertJson = [];
// Ambil baris pertama saja
$firstRow = reset($rows);
if (!$firstRow) {
return [];
}
// Inisialisasi variabel dari baris pertama
$hubCadeb = null;
$hubPenghuni = null;
$jenisAsset = null;
// Ambil data utama dari baris pertama
$pihakBank = $firstRow['mig_pihak_bank'] ?? null;
$debiturPerwakilan = $firstRow['mig_debiture_perwakilan'] ?? null;
$address = $firstRow['address'] ?? null;
// Kode wilayah
$provinceCache = []; // cache untuk helper
$cityCache = [];
$districtCache = [];
$subdistrictCache = [];
$proviceCode = $this->getProvinceCode($firstRow['mig_province_name'] ?? '', $provinceCache);
$cityCode = $this->getCityCode($firstRow['mig_city_name'] ?? '', $cityCache);
$districtCode = $this->getDistrictCode($firstRow['mig_district_name'] ?? '', $districtCache);
$subdistrict = $this->getSubdistrictCode($firstRow['mig_village_name'] ?? '', $subdistrictCache, $districtCache);
// Proses hubungan pemilik/penghuni & jenis asset dari seluruh rows
foreach ($rows as $row) {
$name = trim($row['name'] ?? '');
$keySesuaiORTidak = !empty($row['mig_name_keterangan_lain']) ? 'sesuai' : 'tidak sesuai';
$value = !empty($row['mig_name_keterangan_lain'])
? $row['mig_name_keterangan_lain']
: $row['mig_name_keterangan'] ?? null;
switch ($name) {
case 'Hubungan Pemilik Jaminan dengan Debitur':
$hubCadeb = [
$keySesuaiORTidak => $value
];
break;
case 'Hubungan Penghuni Jaminan dengan Debitur':
$hubPenghuni = [
$keySesuaiORTidak => $value
];
break;
case 'Jenis Bangunan':
$jenisAsset = [
$keySesuaiORTidak => $value
];
break;
}
}
// Isi default jika kosong
if (empty($hubCadeb)) {
$hubCadeb = ["tidak sesuai" => null];
}
if (empty($hubPenghuni)) {
$hubPenghuni = ["tidak sesuai" => null];
}
if (empty($jenisAsset)) {
$jenisAsset = ["sesuai" => null];
}
// Bangun struktur JSON
$asset = [
"debitur_perwakilan" => $debiturPerwakilan,
"jenis_asset" => $jenisAsset,
"alamat" => [
"sesuai" => [
"address" => $address,
"village_code" => $subdistrict['code'],
"district_code" => $districtCode,
"city_code" => $cityCode,
"province_code" => $proviceCode
]
],
"hub_cadeb" => $hubCadeb,
"hub_cadeb_penghuni" => $hubPenghuni,
"pihak_bank" => $pihakBank,
"kordinat_lng" => null,
"kordinat_lat" => null
];
// Masukkan ke array JSON
$dataToInsertJson[] = json_encode([
"asset" => $asset
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
return $dataToInsertJson;
}
private function checkKesimpulan($rows)
{
$dataToInsertJson = [];
$fakta = [
'fakta_positif' => [],
'fakta_negatif' => [],
'rute_menuju' => null,
'batas_batas' => ["Utara", "Timur", "Selatan", "Barat"],
'batas_batas_input' => [
"Utara" => null,
"Timur Laut" => null,
"Timur" => null,
"Tenggara" => null,
"Selatan" => null,
"Barat Daya" => null,
"Barat" => null,
"Barat Laut" => null,
"Utara Timur Laut" => null,
"Timur Timur Laut" => null,
"Timur Tenggara" => null,
"Selatan Tenggara" => null,
"Selatan Barat Daya" => null,
"Barat Barat Daya" => null,
"Barat Barat Laut" => null,
"Utara Barat Laut" => null
],
'kondisi_lingkungan' => [],
'kondisi_lain_bangunan' => [],
'informasi_dokument' => [],
'peruntukan' => null,
'kdb' => null,
'kdh' => null,
'gsb' => null,
'max_lantai' => null,
'klb' => null,
'gss' => null,
'pelebaran_jalan' => null,
'nama_petugas' => null,
'keterangan' => [],
'saran' => []
];
foreach ($rows as $row) {
$jenis = trim($row['mig_keterangan']); // misal: Fakta Positif, Fakta Negatif, dll
$keterangan = trim($row['mig_kesimpulan']);
switch ($jenis) {
case 'Faktor Positif':
$fakta['fakta_positif'][] = $keterangan;
break;
case 'Faktor Negatif':
$fakta['fakta_negatif'][] = $keterangan;
break;
case 'Rute Menuju':
$fakta['rute_menuju'] = $keterangan;
break;
case 'Kondisi Lingkungan':
$fakta['kondisi_lingkungan'][] = $keterangan;
break;
case 'Kondisi Bangunan':
$fakta['kondisi_lain_bangunan'][] = $keterangan;
break;
case 'Lain - lain':
$fakta['informasi_dokument'][] = $keterangan;
break;
case 'CATATAN YANG PERLU DIPERHATIKAN':
$fakta['keterangan']['CATATAN YANG PERLU DIPERHATIKAN'][] = $keterangan;
break;
case 'Catatan':
$fakta['keterangan']['Catatan'][] = $keterangan;
break;
case 'Saran':
$fakta['saran'][] = $keterangan;
break;
}
}
$dataToInsertJson[] = json_encode([
'fakta' => $fakta
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
return $dataToInsertJson;
}
private function parseTimestamp(?string $timestamp): ?string
{
try {
if ($timestamp) {
// Cek jika format hanya tanggal (Y-m-d)
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $timestamp)) {
return \Carbon\Carbon::createFromFormat('Y-m-d', $timestamp)
->startOfDay()
->toDateTimeString();
}
// Format lengkap (Y-m-d H:i:s)
if (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', $timestamp)) {
return \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $timestamp)->toDateTimeString();
}
// Format d/m/Y H:i:s (contoh: 28/4/2047 14:43:43)
if (preg_match('/^\d{1,2}\/\d{1,2}\/\d{4} \d{2}:\d{2}:\d{2}$/', $timestamp)) {
return \Carbon\Carbon::createFromFormat('d/m/Y H:i:s', $timestamp)->toDateTimeString();
}
}
return null;
} catch (\Exception $e) {
Log::error('Gagal memparsing timestamp: ' . $timestamp . '. Pesan: ' . $e->getMessage());
return null;
}
}
private function getProvinceCode(string $name, array &$cache): ?string
{
$normalizedName = strtolower($name);
if (isset($cache[$normalizedName])) {
return $cache[$normalizedName];
}
$province = Province::whereRaw('LOWER(name) = ?', [strtolower($name)])->first();
if ($province) {
$cache[$normalizedName] = $province->code;
return $province->code;
}
return null;
}
private function getCityCode(string $name, array &$cache): ?string
{
$normalizedName = strtolower($name);
if (isset($cache[$normalizedName])) {
return $cache[$normalizedName];
}
$city = City::whereRaw('LOWER(name) = ?', [strtolower($name)])->first();
if ($city) {
$cache[$normalizedName] = $city->code;
return $city->code;
}
return null;
}
private function getDistrictCode(string $name, array &$cache): ?string
{
$normalizedName = strtolower($name);
if (isset($cache[$normalizedName])) {
return $cache[$normalizedName];
}
$district = District::whereRaw('LOWER(name) = ?', [strtolower($name)])->first();
if ($district) {
$cache[$normalizedName] = $district->code;
return $district->code;
}
return null;
}
private function getSubdistrictCode(string $name, array &$cache, array &$districtCache): ?array
{
$normalizedName = strtolower($name);
// Pastikan cache menyimpan array, bukan hanya kode
if (isset($cache[$normalizedName])) {
return $cache[$normalizedName];
}
// Ambil subdistrict dari database
$subdistrict = Village::whereRaw('LOWER(name) = ?', [$normalizedName])->first();
// Jika ditemukan, simpan ke dalam cache sebagai array lengkap
if ($subdistrict) {
$cache[$normalizedName] = [
'code' => $subdistrict->code,
'postal_code' => $subdistrict->postal_code
];
return $cache[$normalizedName];
}
// Jika tidak ditemukan, kembalikan null
return [
'code' => null,
'postal_code' => null
];
}
private function initializeErrorLog()
{
$file = $this->errorLogFile;
// Hapus file lama jika ada
if (file_exists($file)) {
unlink($file);
}
// Buat file baru dengan header
$handle = fopen($file, 'w');
fputcsv($handle, ['mig_mst_jaminan_nomor_jaminan', 'Error']);
fclose($handle);
}
private function logError($nomorJaminan, string $message)
{
Log::error("Error migrasi permohonan [$nomorJaminan]: $message");
// Tulis ke file error
$handle = fopen($this->errorLogFile, 'a');
fputcsv($handle, [$nomorJaminan, $message]);
}
public function checkJenisJaminan($input)
{
$input = trim($input);
switch ($input) {
case 'Tanah dan Bangunan eks KPR-BPPN':
return 'tanah, bangunan, lingkungan, fakta, informasi';
case 'Pabrik':
return 'tanah, bangunan, lingkungan, fakta, informasi';
case 'Kapal Laut':
return 'kapal-laut';
case 'Tanah dan/atau Bangunan':
return 'tanah, bangunan';
case 'Kendaraan Bermotor':
return 'kendaraan-';
case 'Mesin-mesin dan Peralatan':
return 'mesin';
case 'Barang Dagangan/FEO':
return 'barang-dagangan';
case 'Pesawat Udara':
return 'pesawat-udara';
case 'Alat Berat':
return 'alat-berat';
case 'Deposito':
return 'deposito';
case 'Rekening Giro / Tabungan':
return 'rekening-giro-tabungan';
case 'Emas':
return 'emas';
case 'Jaminan Pribadi / Personal Guarantee':
return 'jaminan-pribadi';
case 'Jaminan Perusahaan / Corporate Guarantee':
return 'jaminan-perusahaan';
case 'Resi Gudang':
return 'resi-gudang';
case 'Surat Berharga dan Saham':
return 'surat-berharga-saham';
case 'Tanah dan Bangunan (KerjaSama)':
return 'tanah-bangunan-kerja-sama';
case 'Tanah Kavling (Kerjasama)':
return 'tanah-kavling';
case 'Persediaan Barang / Barang Dagangan':
return 'persediaan-barang';
case 'Apartemen':
return 'apartemen';
case 'Tagihan / Piutang Dagang':
return 'tagihan-piutang';
case 'Tanah dan/atau Bangunan KPR - SEDERHANA':
return 'tanah-bangunan-kpr-sederhana';
default:
return 'lainnya';
}
}
public function checkBuildJson($input, $rows = [])
{
$input = trim($input);
// Pastikan rows selalu array
if (!is_array($rows)) {
$rows = [$rows];
}
switch ($input) {
case 'Tanah dan Bangunan eks KPR-BPPN':
case 'Pabrik':
case 'Tanah dan/atau Bangunan':
case 'Apartemen':
case 'Tanah dan/atau Bangunan KPR - SEDERHANA':
$assetJson = json_decode($this->checkAsset($rows)[0] ?? '', true);
$tanahJson = json_decode(buildInspeksiTanah($rows)[0] ?? '', true);
$bangunanJson = json_decode(buildInspeksiBangunan($rows)[0] ?? '', true);
$lingkunganJson = json_decode($this->checkLingkungan($rows)[0] ?? '', true);
$nomorLpj = $rows[0]['mig_nomor_lpj'] ?? null;
$kesimpulanRows = $this->loadKesimpulanByNomorLpj($nomorLpj);
$faktaJson = [];
if (!empty($kesimpulanRows)) {
$faktaResult = $this->checkKesimpulan($kesimpulanRows);
$faktaJson = json_decode($faktaResult[0] ?? '', true)['fakta'] ?? [];
}
if($nomorLpj === '252845'){
//dd($kesimpulanRows,$faktaResult, $faktaJson);
}
return json_encode([
'asset' => $assetJson['asset'] ?? [],
'tanah' => $tanahJson['tanah'] ?? [],
'bangunan' => $bangunanJson['bangunan'] ?? [],
'lingkungan' => $lingkunganJson['lingkungan'] ?? [],
'fakta' => $faktaJson
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
case 'Kapal Laut':
$kapal = createInspeksiKapal($rows);
return json_encode($kapal, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
case 'Kendaraan Bermotor':
$kendaraan = createInspeksiKendaraan($rows);
return json_encode($kendaraan, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
case 'Mesin-mesin dan Peralatan':
$mesin = createInspeksiMesin($rows);
return json_encode($mesin, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
case 'Pesawat Udara':
$pesawat = createInspeksiPesawat($rows);
return json_encode($pesawat, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
case 'Alat Berat':
$alatBerat = createInspeksiAlatBerat($rows);
return json_encode($alatBerat, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
case 'Barang Dagangan/FEO':
case 'Deposito':
case 'Rekening Giro / Tabungan':
case 'Emas':
case 'Jaminan Pribadi / Personal Guarantee':
case 'Jaminan Perusahaan / Corporate Guarantee':
case 'Resi Gudang':
case 'Surat Berharga dan Saham':
case 'Persediaan Barang / Barang Dagangan':
case 'Tagihan / Piutang Dagang':
return json_encode([
'status' => 'pending',
'message' => 'Fungsi untuk "' . $input . '" belum diimplementasikan.',
'data' => $rows
]);
case 'Tanah dan Bangunan (KerjaSama)':
case 'Tanah Kavling (Kerjasama)':
$pesawat = buildRapJsonData($rows);
return json_encode($pesawat, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
default:
return json_encode([
'status' => 'unknown',
'message' => 'Jenis aset tidak dikenali: ' . $input,
'data' => $rows
]);
}
}
/**
* Membangun JSON terstruktur yang dikelompokkan berdasarkan judul "mig_jenis_legalitas_jaminan_name".
* Setiap item berisi pasangan label dan value sesuai kolom "name" dan nilai dari
* "mig_name_keterangan_lain" (prioritas) atau "mig_name_keterangan" jika yang lain kosong.
*
* Contoh hasil:
* {
* "STATUS KEPEMILIKAN, HUBUNGAN DAN PENGHUNI": [
* {"label": "Hubungan Penghuni Jaminan dengan Debitur", "value": "Kosong"},
* {"label": "Hubungan Pemilik Jaminan dengan Debitur", "value": "SHGB An Developer"}
* ],
* "ANALISA TANAH DAN BANGUNAN": [
* {"label": "Partisi", "value": "Batako"}
* ]
* }
*
* Logging: Mencatat awal proses, jumlah kategori yang dibangun, dan panjang JSON hasil.
*
* @param array $rows Baris-baris CSV untuk satu nomor jaminan
* @return string|null JSON terstruktur atau null bila tidak ada data
*/
private function buildGroupedLegalitas(array $rows): ?string
{
Log::info('buildGroupedLegalitas: mulai membangun struktur JSON dari baris CSV', [
'rows_count' => count($rows)
]);
$grouped = [];
foreach ($rows as $row) {
$title = trim($row['mig_jenis_legalitas_jaminan_name'] ?? '');
if ($title === '') {
// Lewati baris tanpa judul kategori
continue;
}
$label = trim($row['name'] ?? '');
//$valueRaw = $row['mig_name_keterangan_lain'] ?? $row['mig_name_keterangan'] ?? null;
$other = trim((string)($row['mig_name_keterangan_lain'] ?? ''));
$val = trim((string)($row['mig_name_keterangan'] ?? ''));
$value = $other !== '' ? $val.', '.$other : $val;
if (!array_key_exists($title, $grouped)) {
$grouped[$title] = [];
}
// Simpan pasangan label-value sesuai spesifikasi
$grouped[$title][] = [
'label' => $label,
'value' => $value
];
}
if (empty($grouped)) {
Log::warning('buildGroupedLegalitas: tidak ada data terkelompok, mengembalikan null');
return null;
}
$json = json_encode($grouped, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
Log::info('buildGroupedLegalitas: selesai membangun JSON', [
'categories' => count($grouped),
'length' => strlen($json)
]);
return $json;
}
function kv_to_json(string $input, string $pairSep = ';', string $kvSep = ':'): string {
if($input === ''){
return '';
}
// Pecah berdasarkan ';' dan bersihkan spasi
$pairs = preg_split('/\s*' . preg_quote($pairSep, '/') . '\s*/u', trim($input), -1, PREG_SPLIT_NO_EMPTY);
$result = [];
$counts = [];
foreach ($pairs as $pair) {
// Bagi hanya pada pemisah ':' pertama agar nilai yang masih mengandung ':' tetap utuh
$parts = preg_split('/\s*' . preg_quote($kvSep, '/') . '\s*/u', $pair, 2);
if (count($parts) < 2) {
// jika format tidak valid, skip
continue;
}
[$rawKey, $rawVal] = $parts;
// Normalisasi ringan: trim & rapikan spasi berlebih pada key
$key = trim(preg_replace('/\s+/u', ' ', $rawKey));
$val = trim($rawVal);
// Tangani duplikasi key
if (isset($counts[$key])) {
$counts[$key]++;
$useKey = $key . '_' . $counts[$key]; // Atas Nama_2, Atas Nama_3, ...
} else {
$counts[$key] = 1;
$useKey = $key; // pertama kali pakai nama aslinya
}
$result[$useKey] = $val;
}
return json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
}
}