initializeErrorLog(); // Path ke file csv $filePath = realpath(__DIR__ . '/csv/penilai-laporan/mig_penilai.csv'); if (!$filePath) { Log::error('File csv tidak ditemukan: ' . __DIR__ . '/csv/penilai-laporan/mig_penilai.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 = 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 = []; } } // info_harga_laporan_202505021522.csv // print_r($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 &$userData, int &$errorCount, array &$errorDebitureIds, int $totalData, int $batchCount, int $currentRow) { // Kelompokkan berdasarkan mig_nomor_lpj $groupedRows = $this->groupRowsByLpj($rows); foreach ($groupedRows as $nomorLpj => $groupRows) { try { // Ambil informasi permohonan dan dokument_id $nomorRegis = $this->getNomorRegistrasiPermohonan($nomorLpj, $branchCache); if (!$nomorRegis) { Log::warning("Nomor registrasi tidak ditemukan untuk nomor LPJ: {$nomorLpj}"); $errorCount++; $errorDebitureIds[] = $nomorLpj; continue; } // Dapatkan type_penilai (misal: standar, sederhana) $firstRow = reset($groupRows); $typePenilai = $this->checkTypePenilai($firstRow['mig_kode_jenis_laporan'] ?? ''); if (!$typePenilai) { Log::warning("Tidak ada jenis laporan valid untuk nomor LPJ: {$nomorLpj}"); $errorCount++; $errorDebitureIds[] = $nomorLpj; continue; } // Bangun JSON type_penilai $penilaiJson = $this->cekJenisPenilai($groupRows); // Simpan ke tabel Penilai // print_r(json_decode($penilaiJson, true)); // Mapping field JSON berdasarkan tipe penilaian $fillableFieldMap = [ 'memo' => 'memo', 'standar' => 'lpj', 'sederhana' => 'lpj', 'call_report' => 'call_report', 'rap' => 'rap', 'resume' => 'resume' ]; $fieldToUpdate = $fillableFieldMap[$typePenilai] ?? null; if (!$fieldToUpdate) { Log::warning("Field tidak dikenali untuk tipe: {$typePenilai}"); $errorCount++; $errorDebitureIds[] = $nomorLpj; continue; } // NO: 001/241917/LPJ/PJ-2251/VII/24 // 001 => kode cabang // 241917 => nomor lpj // LPJ => jenis laporan // PJ-2251 => nomor registrasi ambil nilai akhirnnya 242251 // VII => bulan // 24 => tahun // Generate nomor_laporan $tanggal = $firstRow['mig_crated_at']; $nomorD = $nomorRegis['nomor_registrasi']; $nomorRegistrasi = "PJ-{$nomorD}"; $nomorLaporan = $this->generateNomorLaporan($typePenilai, $nomorLpj, $nomorRegistrasi, $tanggal); // Simpan atau update ke tabel Penilai $penilaiLP = Penilai::updateOrCreate( [ 'permohonan_id' => $nomorRegis['id'], 'dokument_id' => $nomorRegis['dokument_id'] ], [ 'type' => $typePenilai, $fieldToUpdate => $penilaiJson, 'type_penilai' => $typePenilai, 'created_at' => $this->parseTimestamp($tanggal), 'updated_at' => $this->parseTimestamp($tanggal), ] ); // Simpan ke tabel Laporan Laporan::updateOrCreate( [ 'permohonan_id' => $penilaiLP->permohonan_id, 'dokumen_jaminan_id' => $penilaiLP->dokument_id ], [ 'nomor_laporan' => $nomorLaporan, 'created_at' => $this->parseTimestamp($tanggal), 'updated_at' => $this->parseTimestamp($tanggal) ] ); $this->command->info("Berhasil simpan data penilai untuk nomor LPJ: {$nomorLpj}"); } catch (\Exception $e) { Log::error("Error pada nomor LPJ {$nomorLpj}: " . $e->getMessage()); $errorCount++; $errorDebitureIds[] = $nomorLpj; continue; } } } private function getNomorRegistrasiPermohonan($nomorLpj, array &$cache) { if (isset($cache[$nomorLpj])) { return $cache[$nomorLpj]; } $permohonan = Permohonan::where('nomor_lpj', $nomorLpj)->first(); if (!$permohonan) { $cache[$nomorLpj] = null; return null; } $dokumenJaminan = DokumenJaminan::where('permohonan_id', $permohonan->id)->first(); $result = [ 'id' => $permohonan->id, 'dokument_id' => $dokumenJaminan ? $dokumenJaminan->id : null, 'nomor_registrasi' => $permohonan->nomor_registrasi ]; $cache[$nomorLpj] = $result; return $result; } private function groupRowsByLpj(array $rows): array { $grouped = []; foreach ($rows as $row) { $nomorLpj = $row['mig_nomor_lpj'] ?? null; if (!empty($nomorLpj)) { $grouped[$nomorLpj][] = $row; } } return $grouped; } private function checkTypePenilai($type) { $data = [ 'MAK' => 'memo', 'STD' => 'standar', 'SPL' => 'sederhana', 'RHP' => 'call-report', 'RAP' => 'rap', 'PRG' => 'resume', ]; return $data[$type]; } private function cekJenisPenilai(array $groupRows) { // Urutkan grup berdasarkan mig_urutan_seq usort($groupRows, function ($a, $b) { return ($a['mig_urutan_seq'] ?? 999) <=> ($b['mig_urutan_seq'] ?? 999); }); // Inisialisasi struktur JSON $penilaiJson = [ 'luas_tanah' => null, 'nilai_tanah_1' => null, 'nilai_tanah_2' => null, 'sarana_pelengkap_penilai' => null, 'nilai_sarana_pelengkap_1' => null, 'nilai_sarana_pelengkap_2' => null, 'total_nilai_pasar_wajar' => null, 'likuidasi' => null, 'likuidasi_nilai_1' => null, 'likuidasi_nilai_2' => null, 'asuransi_luas_bangunan' => null, 'asuransi_nilai_1' => null, 'asuransi_nilai_2' => "0", 'npw_tambahan' => [] ]; // Ambil mainRow (urutan pertama) $mainRow = null; foreach ($groupRows as $row) { if (($row['mig_urutan_seq'] ?? '') == 1) { $mainRow = $row; break; } } // Jika tidak ada mainRow, ambil baris pertama sebagai fallback if (!$mainRow && !empty($groupRows[0])) { $mainRow = $groupRows[0]; } if ($mainRow) { $penilaiJson['total_nilai_pasar_wajar'] = $mainRow['mig_nilai_total_nilai_pasar'] ?? null; $penilaiJson['likuidasi'] = $mainRow['mig_nilai_likudasi'] ?? null; // Hitung likuidasi nilai 2 jika ada total dan persen likuidasi $totalPasarWajar = (int)str_replace('.', '', $mainRow['mig_nilai_total_nilai_pasar'] ?? 0); $persenLikuidasi = (int)($mainRow['mig_nilai_likudasi'] ?? 0); $penilaiJson['likuidasi_nilai_1'] = $mainRow['mig_nilai_total_nilai_pasar'] ?? null; $penilaiJson['likuidasi_nilai_2'] = number_format( $totalPasarWajar * ($persenLikuidasi / 100), 0, '', '' ); // Isi data utama hanya untuk urutan 1 $penilaiJson['luas_tanah'] = $mainRow['mig_nilai_satuan'] ?? null; $penilaiJson['nilai_tanah_1'] = $mainRow['mig_harga_satuan'] ?? null; $penilaiJson['nilai_tanah_2'] = number_format( (int)str_replace('.', '', $mainRow['mig_nilai_satuan'] ?? 0) * (int)str_replace('.', '', $mainRow['mig_harga_satuan'] ?? 0), 0, '', '' ); } // Proses tambahan (urutan > 1) foreach ($groupRows as $row) { // Skip baris dengan urutan_seq = 1 karena sudah diproses if (($row['mig_urutan_seq'] ?? '') == 1) { continue; } // Hanya proses jika mig_urutan_seq ada $urutan = $row['mig_urutan_seq'] ?? ''; if (empty($urutan)) { continue; } // Tambahkan ke npw_tambahan $penilaiJson['npw_tambahan'][] = [ 'name' => $row['mig_keterangan'] ?? 'Luas Bangunan Tambahan', 'luas' => $row['mig_nilai_satuan'] ?? null, 'nilai_1' => $row['mig_harga_satuan'] ?? null, 'nilai_2' => number_format( (int)str_replace('.', '', $row['mig_nilai_satuan'] ?? 0) * (int)str_replace('.', '', $row['mig_harga_satuan'] ?? 0), 0, '', '' ) ]; } // Kosongkan npw_tambahan jika kosong if (empty($penilaiJson['npw_tambahan'])) { $penilaiJson['npw_tambahan'] = []; } return json_encode($penilaiJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); } private function convertToRoman($month) { $roman = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII']; return $month >= 1 && $month <= 12 ? $roman[$month - 1] : ''; } private function generateNomorLaporan($typePenilai, $nomorLpj, $nomorRegistrasi, $tanggal) { // Mapping type_penilai ke singkatan laporan $laporanMap = [ 'memo' => 'MEMO', 'standar' => 'LPJ', 'sederhana' => 'LPJ', 'call_report' => 'CALL', 'rap' => 'RAP', 'resume' => 'RESUME' ]; // Dapatkan tahun dan bulan dari tanggal $date = \Carbon\Carbon::parse($tanggal); $kodeCabang = '001'; // bisa diambil dari user atau parameter lain jika dinamis $tahun = substr($date->year, -2); // 2024 → 24 $bulan = $this->convertToRoman($date->month); // 7 → VII // Format akhir nomor registrasi (PJ-XXX) $nomorDebiturAkhir = substr($nomorRegistrasi, -4); // PJ-2251 → 2251 return sprintf( "%s/%s/%s/%s/%s/%s", $kodeCabang, $nomorLpj, $laporanMap[$typePenilai] ?? strtoupper($typePenilai), "PJ-" . $nomorDebiturAkhir, $bulan, $tahun ); } 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) return \Carbon\Carbon::createFromFormat('Y-m-d 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); } }