- 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.
283 lines
9.5 KiB
PHP
283 lines
9.5 KiB
PHP
<?php
|
|
|
|
namespace Modules\Lpj\Database\Seeders;
|
|
|
|
use Illuminate\Database\Seeder;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Modules\Lpj\Models\HubunganPemilikJaminan;
|
|
use Modules\Lpj\Models\Debiture;
|
|
use Modules\Lpj\Models\PemilikJaminan;
|
|
use Modules\Basicdata\Models\Branch;
|
|
use Modules\Usermanagement\Models\User;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Modules\Location\Models\Province;
|
|
use Modules\Location\Models\City;
|
|
use Modules\Location\Models\District;
|
|
use Modules\Location\Models\Village;
|
|
|
|
class MigrationPemilikJaminanSeeder extends Seeder
|
|
{
|
|
/**
|
|
* Run the database seeds.
|
|
*/
|
|
public function run()
|
|
{
|
|
$filePath = realpath(__DIR__ . '/csv/pemilik_20251002.csv');
|
|
|
|
if (!$filePath) {
|
|
Log::error('File CSV tidak ditemukan: ' . __DIR__ . '/csv/pemilik_20251002.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 = 100; // Ukuran batch
|
|
$branchCache = [];
|
|
$debitureCache = [];
|
|
$hubunganPemilikCache = [];
|
|
$provinceCache = [];
|
|
$cityCache = [];
|
|
$districtCache = [];
|
|
$subdistrictCache = [];
|
|
|
|
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);
|
|
|
|
if (count($rows) >= $batchSize) {
|
|
$this->processBatch($rows, $branchCache, $debitureCache, $hubunganPemilikCache, $provinceCache, $cityCache, $districtCache, $subdistrictCache);
|
|
$rows = [];
|
|
}
|
|
}
|
|
|
|
// print_r($rows);
|
|
if (!empty($rows)) {
|
|
$this->processBatch($rows, $branchCache, $debitureCache, $hubunganPemilikCache, $provinceCache, $cityCache, $districtCache, $subdistrictCache);
|
|
}
|
|
|
|
fclose($handle);
|
|
|
|
$this->command->info('Data permohonan berhasil dimigrasikan.');
|
|
}
|
|
|
|
private function processBatch(array $rows, array &$branchCache, array &$debitureCache, array &$hubunganPemilikCache, array &$provinceCache, array &$cityCache, array &$districtCache, array &$subdistrictCache)
|
|
{
|
|
foreach ($rows as $index => $row) {
|
|
$debitureId = $this->getDebiturId($row['mig_kd_debitur_seq'], $debitureCache);
|
|
|
|
if (!$debitureId) {
|
|
Log::warning('Debitur tidak ditemukan untuk kode: ' . $row['mig_kd_debitur_seq']);
|
|
continue;
|
|
}
|
|
|
|
$hubunganPemilik = $this->getHubunganPemilikId($row['mig_hubungan_pemilik_jaminan'], $hubunganPemilikCache);
|
|
|
|
|
|
$proviceCode = $this->getProvinceCode($row['mig_province_name'], $provinceCache);
|
|
$cityCode = $this->getCityCode($row['mig_city_name'], $cityCache);
|
|
$districtCode = $this->getDistrictCode($row['mig_district_name'], $districtCache);
|
|
|
|
$subdistrictCode = $this->getSubdistrictCode($row['mig_village_name'], $subdistrictCache, $districtCache);
|
|
|
|
|
|
PemilikJaminan::updateOrCreate([
|
|
'mig_kd_debitur_seq' => $row['mig_kd_debitur_seq'],
|
|
],[
|
|
'debiture_id' => $debitureId,
|
|
'hubungan_pemilik_jaminan_id' => $hubunganPemilik,
|
|
'name' => $row['name'],
|
|
'detail_sertifikat' => null,
|
|
'npwp' => null,
|
|
'nomor_id' => null,
|
|
'email' => null,
|
|
'phone' => null,
|
|
'province_code' => $proviceCode,
|
|
'city_code' => $cityCode,
|
|
'district_code' => $districtCode,
|
|
'village_code' => $subdistrictCode['code'],
|
|
'postal_code' => $subdistrictCode['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
|
|
]);
|
|
|
|
$this->command->info('Proses data Pemilik Jaminan ' . $row['name'] . ' (' . ($index + 1) . '/' . count($rows) . ')');
|
|
}
|
|
}
|
|
|
|
private function getDebiturId(string $code, array &$cache): ?int
|
|
{
|
|
if (isset($cache[$code])) {
|
|
return $cache[$code];
|
|
}
|
|
|
|
$debitur = Debiture::where('mig_kd_debitur_seq', $code)->first();
|
|
|
|
if ($debitur) {
|
|
$cache[$code] = $debitur->id;
|
|
return $debitur->id;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function getHubunganPemilikId(string $name, array &$cache): ?int
|
|
{
|
|
// Normalisasi nama
|
|
$normalizedName = strtolower(trim($name));
|
|
|
|
// Cek cache untuk menghindari query berulang
|
|
if (isset($cache[$normalizedName])) {
|
|
return $cache[$normalizedName];
|
|
}
|
|
|
|
// Query database dengan pengamanan tambahan
|
|
$hubunganPemilik = HubunganPemilikJaminan::whereRaw('LOWER(name) = ?', [$normalizedName])
|
|
->whereNull('deleted_at') // Tambahkan ini jika Anda menggunakan soft deletes
|
|
->first();
|
|
|
|
// Jika data ditemukan, simpan dalam cache
|
|
if ($hubunganPemilik) {
|
|
$cache[$normalizedName] = $hubunganPemilik->id;
|
|
return $hubunganPemilik->id;
|
|
}
|
|
|
|
// Default jika data tidak ditemukan
|
|
$cache[$normalizedName] = 1; // Cache nilai default untuk menghindari query berulang
|
|
return 1;
|
|
}
|
|
|
|
|
|
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 parseDate(?string $date): ?string
|
|
{
|
|
try {
|
|
return $date ? \Carbon\Carbon::createFromFormat('Y-m-d', $date)->toDateString() : null;
|
|
} catch (\Exception $e) {
|
|
Log::error('Gagal memparsing tanggal: ' . $date);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
}
|