- 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.
1002 lines
34 KiB
PHP
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);
|
|
}
|
|
}
|