- 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.
298 lines
9.8 KiB
PHP
298 lines
9.8 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 DateTime;
|
|
|
|
class MigrationGambarInspeksiSeeder extends Seeder
|
|
{
|
|
/**
|
|
* Run the database seeds.
|
|
*/
|
|
protected $errorLogFile = __DIR__ . '/csv/inspeksi/foto_20251014-error.csv';
|
|
/**
|
|
* Migrasi data gambar inspeksi dari file csv ke tabel inspeksi_gambar
|
|
*
|
|
* @return void
|
|
*/
|
|
public function run()
|
|
{
|
|
$this->initializeErrorLog();
|
|
// Path ke file csv
|
|
$filePath = realpath(__DIR__ . '/csv/inspeksi/foto_20251014.csv');
|
|
|
|
if (!$filePath) {
|
|
Log::error('File csv tidak ditemukan: ' . __DIR__ . '/csv/inspeksi/foto_20251014.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[0]);
|
|
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_jaminan
|
|
$groupedRows = $this->groupRowsByJaminan($rows);
|
|
|
|
foreach ($groupedRows as $nomorJaminan => $groupRows) {
|
|
try {
|
|
// Ambil informasi permohonan dan dokument_id
|
|
$nomorRegis = $this->getNomorRegistrasiPermohonan($nomorJaminan, $branchCache);
|
|
if (!$nomorRegis) {
|
|
Log::warning("Nomor registrasi tidak ditemukan untuk nomor jaminan: {$nomorJaminan}");
|
|
$errorCount++;
|
|
$errorDebitureIds[] = $nomorJaminan;
|
|
continue;
|
|
}
|
|
|
|
// Bangun JSON foto_form
|
|
$fotoJson = $this->checkFoto($groupRows);
|
|
|
|
|
|
Inspeksi::updateOrCreate(
|
|
[
|
|
'permohonan_id' => $nomorRegis['id'],
|
|
'dokument_id' => $nomorRegis['dokument_id']
|
|
],
|
|
[
|
|
'foto_form' => $fotoJson,
|
|
'updated_at' => now()
|
|
]
|
|
);
|
|
|
|
$this->command->info("Berhasil update foto_form untuk nomor jaminan: {$nomorJaminan}");
|
|
|
|
} catch (\Exception $e) {
|
|
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 checkFoto(array $rows)
|
|
{
|
|
// Inisialisasi kelompok untuk tiap kategori
|
|
$kategoriPrioritas = [
|
|
'PETA LOKASI' => [],
|
|
'GAMBAR SITUASI / SURAT UKUR' => [],
|
|
'FOTO JAMINAN' => [],
|
|
'MAK' => [],
|
|
'lainnya' => []
|
|
];
|
|
|
|
foreach ($rows as $row) {
|
|
// Ambil kolom penting
|
|
$namaFoto = trim($row['mig_nama_gambar'] ?? '');
|
|
$pathFoto = trim($row['mig_url_gambar'] ?? '');
|
|
$kategori = trim($row['mig_kategori'] ?? 'lainnya');
|
|
$urutan = (int)($row['mig_urutan_gambar'] ?? 999);
|
|
$tgl = trim($row['mig_tgl'] ?? '');
|
|
$nomorLpj = trim($row['mig_nomor_laporan'] ?? '');
|
|
|
|
if (empty($pathFoto) || empty($tgl)) {
|
|
continue; // Lewati jika tidak lengkap
|
|
}
|
|
|
|
try {
|
|
$tanggal = \Carbon\Carbon::createFromFormat('d/m/Y H:i:s', $tgl)->startOfDay();
|
|
if (!$tanggal) {
|
|
throw new \Exception("Tanggal tidak valid");
|
|
}
|
|
} catch (\Exception $e) {
|
|
continue; // Lewati jika tanggal tidak valid
|
|
}
|
|
|
|
$tahun = $tanggal->format('Y');
|
|
$bulanAngka = $tanggal->format('n');
|
|
$bulanNama = [
|
|
1 => 'JANUARI', 2 => 'FEBRUARI', 3 => 'MARET',
|
|
4 => 'APRIL', 5 => 'MEI', 6 => 'JUNI',
|
|
7 => 'JULI', 8 => 'AGUSTUS', 9 => 'SEPTEMBER',
|
|
10 => 'OKTOBER', 11 => 'NOVEMBER', 12 => 'DESEMBER'
|
|
][(int)$bulanAngka] ?? 'UNKNOWN';
|
|
|
|
$tanggalFormat = $tanggal->format('dmY');
|
|
|
|
if (empty($namaFoto)) {
|
|
$namaFoto = basename($pathFoto) ?: 'image.jpg';
|
|
}
|
|
|
|
// Gunakan '/' sebagai separator path
|
|
$finalPath = "surveyor/{$tahun}/{$bulanNama}/{$tanggalFormat}/{$nomorLpj}/{$pathFoto}";
|
|
|
|
$fotoItem = [
|
|
'urutan' => $urutan,
|
|
'name' => $namaFoto,
|
|
'path' => $finalPath,
|
|
'category' => $kategori,
|
|
'sub' => null,
|
|
'description' => '',
|
|
'created_by' => null,
|
|
'created_at' => null
|
|
];
|
|
|
|
// Masukkan ke dalam kelompok kategori
|
|
if (isset($kategoriPrioritas[$kategori])) {
|
|
$kategoriPrioritas[$kategori][] = $fotoItem;
|
|
} else {
|
|
$kategoriPrioritas['lainnya'][] = $fotoItem;
|
|
}
|
|
}
|
|
|
|
// Urutkan masing-masing kategori berdasarkan urutan
|
|
foreach ($kategoriPrioritas as &$kelompok) {
|
|
usort($kelompok, function ($a, $b) {
|
|
return $a['urutan'] <=> $b['urutan'];
|
|
});
|
|
}
|
|
|
|
// Gabungkan dengan urutan prioritas: PETA LOKASI -> GAMBAR SITUASI -> FOTO JAMINAN -> lainnya
|
|
$finalFotos = array_merge(
|
|
$kategoriPrioritas['PETA LOKASI'],
|
|
$kategoriPrioritas['GAMBAR SITUASI / SURAT UKUR'],
|
|
$kategoriPrioritas['FOTO JAMINAN'],
|
|
$kategoriPrioritas['lainnya']
|
|
);
|
|
|
|
// Hapus indeks 'urutan'
|
|
$finalFotos = array_map(function ($foto) {
|
|
unset($foto['urutan']);
|
|
return $foto;
|
|
}, $finalFotos);
|
|
|
|
return json_encode([
|
|
'upload_foto' => $finalFotos
|
|
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
|
}
|
|
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 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);
|
|
}
|
|
}
|