✨ 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.
This commit is contained in:
508
database/seeders/MigrationDokumentJaminanSeeder.php
Normal file
508
database/seeders/MigrationDokumentJaminanSeeder.php
Normal file
@@ -0,0 +1,508 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Lpj\Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\Lpj\Models\Debiture;
|
||||
use Modules\Location\Models\City;
|
||||
use Modules\Location\Models\District;
|
||||
use Modules\Location\Models\Province;
|
||||
use Modules\Location\Models\Village;
|
||||
use Modules\Lpj\Models\DokumenJaminan;
|
||||
use Modules\Lpj\Models\Permohonan;
|
||||
use Modules\Lpj\Models\JenisJaminan;
|
||||
use Modules\Lpj\Models\PemilikJaminan;
|
||||
use Modules\Lpj\Models\HubunganPemilikJaminan;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
|
||||
class MigrationDokumentJaminanSeeder extends Seeder
|
||||
{
|
||||
protected $errorLogFile = __DIR__ . '/csv/dokumen_20251022_error_log.csv';
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user