From 37fb5c90d58deb22068075fae98e78e27d948b83 Mon Sep 17 00:00:00 2001 From: Daeng Deni Mardaeni Date: Tue, 9 Dec 2025 15:38:28 +0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=B9=20feat(CleanupInspeksiDataCommand)?= =?UTF-8?q?:=20Implementasi=20command=20utama=20untuk=20batch=20cleanup=20?= =?UTF-8?q?data=20inspeksi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Membuat artisan command utama untuk cleanup data inspeksi secara batch dengan fitur preview, filter, dan progress tracking - Command signature: `lpj:cleanup-inspeksi` dengan opsi --permohonan-id, --sync, --dry-run, dan --force - Method getCleanupData() untuk query data yang memenuhi kriteria cleanup menggunakan DB::table - Method displayPreview() untuk menampilkan tabel preview data yang akan di-cleanup - Method runCleanup() dengan progress bar untuk tracking progress batch processing - Validasi mutual exclusion antara --dry-run dan --sync untuk mencegah konflik - Konfirmasi interaktif sebelum proses (dapat di-skip dengan --force) - Support mode sync (direct execution) dan async (queue dispatch) - Error handling per permohonan dengan continue pada exception - Comprehensive logging dengan context options dan error details - Hitungan total data yang dihapus dan jumlah error untuk reporting --- .../Commands/CleanupInspeksiDataCommand.php | 228 ++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 app/Console/Commands/CleanupInspeksiDataCommand.php diff --git a/app/Console/Commands/CleanupInspeksiDataCommand.php b/app/Console/Commands/CleanupInspeksiDataCommand.php new file mode 100644 index 0000000..a594de5 --- /dev/null +++ b/app/Console/Commands/CleanupInspeksiDataCommand.php @@ -0,0 +1,228 @@ + $this->options() + ]); + + try { + $permohonanId = $this->option('permohonan-id'); + $sync = $this->option('sync'); + $dryRun = $this->option('dry-run'); + $force = $this->option('force'); + + // Validasi opsi + if ($dryRun && $sync) { + $this->error('Opsi --dry-run dan --sync tidak dapat digunakan bersamaan.'); + return Command::FAILURE; + } + + // Tampilkan header + $this->info('=== Cleanup Data Inspeksi ==='); + $this->newLine(); + + // Ambil data yang akan di-cleanup + $cleanupData = $this->getCleanupData($permohonanId); + + if ($cleanupData->isEmpty()) { + $this->info('Tidak ada data yang perlu di-cleanup.'); + return Command::SUCCESS; + } + + // Tampilkan preview data + $this->displayPreview($cleanupData); + + if ($dryRun) { + $this->info('Mode dry-run: Tidak ada perubahan yang dilakukan.'); + return Command::SUCCESS; + } + + // Konfirmasi jika tidak force + if (!$force && !$this->confirm('Lanjutkan dengan cleanup?')) { + $this->info('Cleanup dibatalkan.'); + return Command::SUCCESS; + } + + // Jalankan cleanup + $this->runCleanup($cleanupData, $sync); + + $this->info('Proses cleanup selesai.'); + return Command::SUCCESS; + + } catch (\Exception $e) { + Log::error('CleanupInspeksiDataCommand: Terjadi error saat proses cleanup', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + $this->error('Terjadi kesalahan: ' . $e->getMessage()); + return Command::FAILURE; + } + } + + /** + * Ambil data yang akan di-cleanup + */ + private function getCleanupData(?int $permohonanId = null) + { + $this->info('Mencari data yang akan di-cleanup...'); + + $query = DB::table('inspeksi as i') + ->select( + 'i.permohonan_id', + 'i.created_by', + DB::raw('COUNT(CASE WHEN i.dokument_id IS NOT NULL AND i.deleted_at IS NULL THEN 1 END) as new_data_count'), + DB::raw('COUNT(CASE WHEN i.dokument_id IS NULL AND i.deleted_at IS NULL THEN 1 END) as old_data_count') + ) + ->whereNull('i.deleted_at') + ->groupBy('i.permohonan_id', 'i.created_by'); + + if ($permohonanId) { + $query->where('i.permohonan_id', $permohonanId); + } + + $results = $query->havingRaw('new_data_count > 0 AND old_data_count > 0') + ->get(); + + return $results; + } + + /** + * Tampilkan preview data + */ + private function displayPreview($cleanupData): void + { + $this->info('Data yang akan di-cleanup:'); + $this->table( + ['Permohonan ID', 'Created By', 'Data Baru', 'Data Lama'], + $cleanupData->map(function ($item) { + return [ + $item->permohonan_id, + $item->created_by, + $item->new_data_count, + $item->old_data_count + ]; + })->toArray() + ); + + $totalPermohonan = $cleanupData->count(); + $totalOldData = $cleanupData->sum('old_data_count'); + + $this->info("Total permohonan: {$totalPermohonan}"); + $this->info("Total data lama yang akan dihapus: {$totalOldData}"); + $this->newLine(); + } + + /** + * Jalankan cleanup + */ + private function runCleanup($cleanupData, bool $sync): void + { + $this->info('Memulai proses cleanup...'); + $this->newLine(); + + $progressBar = $this->output->createProgressBar($cleanupData->count()); + $progressBar->setFormat('Processing: %current%/%max% [%bar%] %percent:3s%% %message%'); + $progressBar->start(); + + $totalDeleted = 0; + $totalErrors = 0; + + foreach ($cleanupData as $data) { + try { + $progressBar->setMessage("Permohonan ID: {$data->permohonan_id}"); + + // Ambil data baru untuk mendapatkan dokument_id + $newInspeksi = Inspeksi::where('permohonan_id', $data->permohonan_id) + ->where('created_by', $data->created_by) + ->whereNotNull('dokument_id') + ->whereNull('deleted_at') + ->first(); + + if (!$newInspeksi) { + $this->warn("Tidak ditemukan data baru untuk permohonan {$data->permohonan_id}"); + $progressBar->advance(); + continue; + } + + // Jalankan cleanup + if ($sync) { + // Jalankan sync + $job = new CleanupInspeksiDataJob( + $data->permohonan_id, + $data->created_by, + $newInspeksi->dokument_id + ); + $job->handle(); + } else { + // Dispatch ke queue + CleanupInspeksiDataJob::dispatch( + $data->permohonan_id, + $data->created_by, + $newInspeksi->dokument_id + ); + } + + $totalDeleted += $data->old_data_count; + + } catch (\Exception $e) { + Log::error('CleanupInspeksiDataCommand: Error pada permohonan', [ + 'permohonan_id' => $data->permohonan_id, + 'created_by' => $data->created_by, + 'error' => $e->getMessage() + ]); + + $this->error("Error pada permohonan {$data->permohonan_id}: {$e->getMessage()}"); + $totalErrors++; + } + + $progressBar->advance(); + } + + $progressBar->finish(); + $this->newLine(); + $this->newLine(); + + // Tampilkan hasil + $this->info('=== Hasil Cleanup ==='); + $this->info("Data lama yang dihapus: {$totalDeleted}"); + $this->info("Error: {$totalErrors}"); + + if (!$sync) { + $this->info('Job telah di-dispatch ke queue. Monitor progress di log.'); + } + } +} \ No newline at end of file