🧹 feat(CleanupInspeksiDataCommand): Implementasi command utama untuk batch cleanup data inspeksi

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
This commit is contained in:
Daeng Deni Mardaeni
2025-12-09 15:38:28 +07:00
parent ff994a7c95
commit 37fb5c90d5

View File

@@ -0,0 +1,228 @@
<?php
namespace Modules\Lpj\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Modules\Lpj\Jobs\CleanupInspeksiDataJob;
use Modules\Lpj\Models\Inspeksi;
use Modules\Lpj\Services\InspeksiCleanupService;
class CleanupInspeksiDataCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'lpj:cleanup-inspeksi
{--permohonan-id= : ID permohonan yang akan di-cleanup (opsional)}
{--sync : Jalankan secara synchronous}
{--dry-run : Tampilkan preview tanpa menjalankan cleanup}
{--force : Jalankan tanpa konfirmasi}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Cleanup data inspeksi lama yang tidak memiliki dokument_id';
/**
* Execute the console command.
*/
public function handle(): int
{
Log::info('CleanupInspeksiDataCommand: Memulai proses cleanup data inspeksi', [
'options' => $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.');
}
}
}