initializeErrorLog(); // Path ke file csv $filePath = realpath(__DIR__ . '/csv/dokumen_20251022.csv'); if (!$filePath) { Log::error('File csv tidak ditemukan: ' . __DIR__ . '/csv/dokumen_20251022.csv'); $this->command->error('File csv tidak ditemukan.'); return; } if (($handle = fopen($filePath, 'r')) === false) { Log::error('Gagal membuka file CSV: ' . $filePath); $this->command->error('Gagal membuka file CSV.'); return; } $header = fgetcsv($handle, 0, ','); $rows = []; $batchSize = 1000; // Ukuran batch $permohonanCache = []; $jenisJaminanCache = []; $pemilikJaminanCache = []; $provinceCache = []; $cityCache = []; $districtCache = []; $subdistrictCache = []; $totalData = 0; $errorCount = 0; $errorDebitureIds = []; $hubunganPemilikCache = []; // Menghitung total data di file CSV while (($data = fgetcsv($handle, 0, ',')) !== false) { $totalData++; } rewind($handle); // Reset pointer ke awal file fgetcsv($handle, 0, ','); // Skip header $batchCount = 0; $currentRow = 0; // Membaca setiap baris dalam CSV while (($data = fgetcsv($handle, 0, ',')) !== false) { if (count($data) != count($header)) { Log::warning('Baris CSV memiliki jumlah kolom yang tidak sesuai: ' . json_encode($data)); $errorCount++; $errorDebitureIds[] = $data[0] ?? 'ID tidak valid'; // Menyimpan ID yang error continue; } $rows[] = array_combine($header, $data); $currentRow++; // print_r($rows); if (count($rows) >= $batchSize) { $errorDebitureIds[] = $data[0] ?? 'ID tidak valid'; // Menyimpan ID yang error $this->processBatch($rows, $permohonanCache, $jenisJaminanCache, $pemilikJaminanCache, $provinceCache, $cityCache, $districtCache, $subdistrictCache, $batchCount, $currentRow, $totalData, $errorCount, $errorDebitureIds, $hubunganPemilikCache); $rows = []; } } // print_r($rows[0]); if (!empty($rows)) { $this->processBatch($rows, $permohonanCache, $jenisJaminanCache, $pemilikJaminanCache, $provinceCache, $cityCache, $districtCache, $subdistrictCache, $batchCount, $currentRow, $totalData, $errorCount, $errorDebitureIds, $hubunganPemilikCache); } fclose($handle); $this->command->info('Data debiture berhasil dimigrasikan.'); } /** * Proses batch data. */ private function processBatch( array $rows, array &$permohonanCache, array &$jenisJaminanCache, array &$pemilikJaminanCache, array &$provinceCache, array &$cityCache, array &$districtCache, array &$subdistrictCache, int $batchCount, int $currentRow, int $totalData, int &$errorCount, array &$errorDebitureIds, array &$hubunganPemilikCache ) { foreach ($rows as $index => $row) { try { // Jalankan transaksi per-baris // DB::beginTransaction(); // Cari permohonan $permohonan = Permohonan::where('nomor_registrasi', $row['mig_nomor_jaminan'])->first(); if (empty($permohonan)) { throw new \Exception('Missing debiture_id' . $row['mig_nomor_jaminan']); continue; } // Pastikan permohonan_id belum digunakan di dokumen_jaminan $existingDokumen = DokumenJaminan::where('permohonan_id', $permohonan->id)->first(); if ($existingDokumen) { //throw new \Exception("permohonan_id {$permohonan->id} sudah digunakan di dokumen_jaminan"); //continue; } // Ambil lokasi // jika external silahkan matikan ini $proviceCode = $this->getProvinceCode($row['mig_province_name'], $provinceCache); $cityCode = $this->getCityCode($row['mig_city_name'], $cityCache); $districtCode = $this->getDistrictCode($row['mig_district_name'], $districtCache); $subdistrict = $this->getSubdistrictCode($row['mig_village_name'], $subdistrictCache, $districtCache); // $hubunganPemilik = $this->getHubunganPemilikJaminanId($row['mig_hubungan_pemilik_jaminan'], $hubunganPemilikCache); $pemilik_jaminan_name = $this->getDebitureId($row['mig_kd_debitur_seq'], $pemilikJaminanCache); // Buat Pemilik Jaminan $pemilik_jaminan = PemilikJaminan::updateOrCreate([ 'debiture_id' => $permohonan->debiture_id, 'hubungan_pemilik_jaminan_id' => 1, // 'name' => $row['name'], 'name' => $pemilik_jaminan_name, 'detail_sertifikat' => null, 'npwp' => null, 'nomor_id' => null, 'email' => null, 'phone' => null, // jika external silahkan matikan ini 'province_code' => $proviceCode, 'city_code' => $cityCode, 'district_code' => $districtCode, 'village_code' => $subdistrict['code'], 'postal_code' => $subdistrict['postal_code'], 'address' => $row['address'], 'created_at' => $this->parseTimestamp($row['created_at']), 'updated_at' => $this->parseTimestamp($row['updated_at']), 'mig_kd_debitur_seq' => $row['mig_kd_debitur_seq'], 'processed_at' => now(), 'is_mig' => 1 ]); // Buat Dokumen Jaminan $dokumenJaminan = DokumenJaminan::updateOrCreate([ 'permohonan_id' => $permohonan->id, 'mig_kd_debitur_seq' => $row['mig_kd_debitur_seq'], 'nomor_lpj' => $row['mig_nomor_jaminan'] ],[ 'debiture_id' => $permohonan->debiture_id, 'permohonan_id' => $permohonan->id, 'jenis_jaminan_id' => $this->getJaminanId($row['mig_jenis_seq']) ?? '', 'pemilik_jaminan_id' => $pemilik_jaminan->id, // jika external silahkan matikan ini 'province_code' => $proviceCode ?? '', 'city_code' => $cityCode ?? '', 'district_code' => $districtCode ?? '', 'village_code' => $subdistrict['code'] ?? '', 'postal_code' => $subdistrict['postal_code'] ?? '', 'address' => $row['address'], 'created_at' => $this->parseTimestamp($row['created_at']), 'updated_at' => $this->parseTimestamp($row['updated_at']), 'mig_kd_debitur_seq' => $row['mig_kd_debitur_seq'], 'processed_at' => now(), 'nomor_lpj' => $row['mig_nomor_jaminan'], 'is_mig' => 1 ]); // Commit jika semua sukses // DB::commit(); $this->command->info("Proses dokumen jaminan: " . $row['mig_kd_debitur_seq'] . "Batch: {$batchCount} Baris: {$currentRow} Total: {$totalData} Error: {$errorCount}"); } catch (\Exception $e) { // Rollback hanya untuk baris ini Log::error("Error pada baris: " . json_encode($row) . ". Pesan: " . $e->getMessage()); $this->logError($row['mig_kd_debitur_seq'] ?? '-', $e->getMessage()); $errorDebitureIds[] = $row['mig_kd_debitur_seq'] ?? '-'; // DB::rollBack(); continue; } } $this->command->info("Batch {$batchCount} selesai. Total error: " . count($errorDebitureIds)); } // private function getPermohonanId($code,$cache) // { // if (isset($cache[$code])) { // return $cache[$code]; // } // $permohonan = Permohonan::where('mig_kd_debitur_seq', $code)->where('nomor_registrasi', $mig_nomor_jaminan)->first(); // if ($permohonan) { // $cache[$code] = $permohonan; // return $permohonan; // } // return null; // } private function getJaminanId($code): ?int { /*$mapping = [ 7 => 17, 8 => 13, 6 => 32, 1 => 17, 2 => 26, 3 => 27, 4 => 50, 5 => 21, 138051314724 => 23, 138027243057 => 34, 138027664224 => 35, 138027738489 => 10, 138051485796 => 48, 138051492883 => 47, 138051515419 => 40, 138051753311 => 41, 138051754843 => 46, 138051759078 => 42, 138051480538 => 45, 123382184742 => 18, 138051483711 => 44, 991 => 52 ];*/ $mapping = [ 1 => 1, 2 => 17, 3 => 19, 4 => 15, 5 => 18, 6 => 26, 7 => 26, 8 => 26, 9 => 26, 10 => 24, 11 => 28, 12 => 29, 13 => 32, 991001 => 17, 121965631354 => 17, 122267387302 => 13, 122267391891 => 27, 123242566528 => 1, 123391628912 => 18, 123779076991 => 26, 123779092232 => 26, 123837866231 => 19, 124159228236 => 14, 124280447242 => 32, 124385048902 => 30, 124539856281 => 22, 124635294016 => 13, 124963468687 => 18, 125178371127 => 31, 125228814911 => 17, 125749523699 => 27, 126156105725 => 15, 127407367039 => 15, 132065123922 => 32, 138027244724 => 33, 138027246193 => 34, 138027693348 => 35, 138027764236 => 10, 138050882693 => 15, 138050910670 => 20, 138051316169 => 23, 138051517359 => 36, 138051519318 => 37, 138051522331 => 38, 138051601738 => 39, 138051602831 => 40, 138051773783 => 41, 138051776693 => 46, 138051780489 => 42, 164921358499 => 32, 165216289979 => 49, 165216294371 => 49, 173035895092 => 24 ]; return $mapping[$code] ?? 17; } private function getPemilikJaminanId(string $code, array &$cache): ?int { if (isset($cache[$code])) { return $cache[$code]; } $jaminan = PemilikJaminan::where('mig_kd_debitur_seq', $code)->first(); if ($jaminan) { $cache[$code] = $jaminan->id; return $jaminan->id; } return 1; } private function getDebitureId(string $code, array &$cache): ?string { if (isset($cache[$code])) { return $cache[$code]; } $debiture = Debiture::where('mig_kd_debitur_seq', $code)->first(); if ($debiture) { $cache[$code] = $debiture->name; return $debiture->name; } 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 getHubunganPemilikJaminanId(string $code, array &$cache): ?int { if (isset($cache[$code])) { return $cache[$code]; } $jaminan = HubunganPemilikJaminan::whereRaw('LOWER(name) = ?', [strtolower($code)])->first(); if ($jaminan) { $cache[$code] = $jaminan->id; return $jaminan->id; } return null; } /** * Mengonversi nilai TIMESTAMP menjadi format datetime yang valid. */ 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/2017 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 initializeErrorLog() { $file = $this->errorLogFile; if (file_exists($file)) { unlink($file); // Hapus file lama } $handle = fopen($file, 'w'); fputcsv($handle, ['mig_kd_debitur_seq', 'Error']); fclose($handle); } private function logError(string $kode, string $message) { Log::error("Error migrasi dokumen jaminan [$kode]: $message"); $handle = fopen($this->errorLogFile, 'a'); fputcsv($handle, [$kode, $message]); fclose($handle); } }