From f6df453ddc8113120da81790f7077996a6163cee Mon Sep 17 00:00:00 2001 From: Daeng Deni Mardaeni Date: Thu, 12 Jun 2025 09:15:38 +0700 Subject: [PATCH] refactor(webstatement): perbaiki pembentukan logika, struktur kode, dan validasi parameter pada SendStatementEmailCommand - **Perbaikan Struktur Kode:** - Melakukan perapihan kode dengan konsistensi indentasi dan penyusunan namespace. - Memisahkan logika kompleks dan mengorganisasi ulang kode untuk meningkatkan keterbacaan. - Menambahkan namespace `InvalidArgumentException`. - **Peningkatan Validasi:** - Menambahkan validasi komprehensif untuk parameter `period`, `type`, `--account`, dan `--branch`. - Validasi lebih spesifik untuk memastikan account atau branch terkait sesuai kebutuhan. - Memberikan pesan error informatif ketika validasi gagal. - **Peningkatan Metode Utility:** - Menambahkan metode `validateParameters` untuk menangani berbagai skenario validasi input. - Menambahkan metode `determineRequestTypeAndTarget` untuk memisahkan logika penentuan tipe request. - Memperbarui metode `createLogEntry` untuk menyesuaikan atribut log dengan lebih baik berdasarkan request type. - **Perbaikan Feedback Pengguna:** - Menampilkan informasi yang lebih rinci terkait status pengiriman email, seperti parameter validasi, log ID, dan batch ID. - Memberikan panduan untuk monitoring queue melalui command. - **Penanganan Error dan Logging:** - Menambahkan logging detail untuk error yang terjadi dalam proses pengiriman email. - Memastikan rollback jika terjadi kegagalan selama proses dispatch job. Signed-off-by: Daeng Deni Mardaeni --- app/Console/SendStatementEmailCommand.php | 449 +++++++++++----------- 1 file changed, 225 insertions(+), 224 deletions(-) diff --git a/app/Console/SendStatementEmailCommand.php b/app/Console/SendStatementEmailCommand.php index 2ccc05c..f7648b4 100644 --- a/app/Console/SendStatementEmailCommand.php +++ b/app/Console/SendStatementEmailCommand.php @@ -1,22 +1,23 @@ info('🚀 Memulai proses pengiriman email statement...'); + public function handle() + { + $this->info('🚀 Memulai proses pengiriman email statement...'); - try { - $period = $this->argument('period'); - $type = $this->option('type'); - $accountNumber = $this->option('account'); - $branchCode = $this->option('branch'); - $batchId = $this->option('batch-id'); - $queueName = $this->option('queue'); - $delay = (int) $this->option('delay'); + try { + $period = $this->argument('period'); + $type = $this->option('type'); + $accountNumber = $this->option('account'); + $branchCode = $this->option('branch'); + $batchId = $this->option('batch-id'); + $queueName = $this->option('queue'); + $delay = (int) $this->option('delay'); - // Validasi parameter - if (!$this->validateParameters($period, $type, $accountNumber, $branchCode)) { + // Validasi parameter + if (!$this->validateParameters($period, $type, $accountNumber, $branchCode)) { + return Command::FAILURE; + } + + // Tentukan request type dan target value + [$requestType, $targetValue] = $this->determineRequestTypeAndTarget($type, $accountNumber, $branchCode); + + // Buat log entry + $log = $this->createLogEntry($period, $requestType, $targetValue, $batchId); + + // Dispatch job + $job = SendStatementEmailJob::dispatch($period, $requestType, $targetValue, $batchId, $log->id) + ->onQueue($queueName); + + if ($delay > 0) { + $job->delay(now()->addMinutes($delay)); + $this->info("⏰ Job dijadwalkan untuk dijalankan dalam {$delay} menit"); + } + + $this->displayJobInfo($period, $requestType, $targetValue, $queueName, $log); + $this->info('✅ Job pengiriman email statement berhasil didispatch!'); + $this->info('📊 Gunakan command berikut untuk monitoring:'); + $this->line(" php artisan queue:work {$queueName}"); + $this->line(' php artisan webstatement:check-progress ' . $log->id); + + return Command::SUCCESS; + + } catch (Exception $e) { + $this->error('❌ Error saat mendispatch job: ' . $e->getMessage()); + Log::error('SendStatementEmailCommand failed', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); return Command::FAILURE; } + } - // Tentukan request type dan target value - [$requestType, $targetValue] = $this->determineRequestTypeAndTarget($type, $accountNumber, $branchCode); - - // Buat log entry - $log = $this->createLogEntry($period, $requestType, $targetValue, $batchId); - - // Dispatch job - $job = SendStatementEmailJob::dispatch($period, $requestType, $targetValue, $batchId, $log->id) - ->onQueue($queueName); - - if ($delay > 0) { - $job->delay(now()->addMinutes($delay)); - $this->info("⏰ Job dijadwalkan untuk dijalankan dalam {$delay} menit"); + private function validateParameters($period, $type, $accountNumber, $branchCode) + { + // Validasi format periode + if (!preg_match('/^\d{6}$/', $period)) { + $this->error('❌ Format periode tidak valid. Gunakan format YYYYMM (contoh: 202401)'); + return false; } - $this->displayJobInfo($period, $requestType, $targetValue, $queueName, $log); - $this->info('✅ Job pengiriman email statement berhasil didispatch!'); - $this->info('📊 Gunakan command berikut untuk monitoring:'); - $this->line(" php artisan queue:work {$queueName}"); - $this->line(' php artisan webstatement:check-progress ' . $log->id); + // Validasi type + if (!in_array($type, ['single', 'branch', 'all'])) { + $this->error('❌ Type tidak valid. Gunakan: single, branch, atau all'); + return false; + } - return Command::SUCCESS; + // Validasi parameter berdasarkan type + switch ($type) { + case 'single': + if (!$accountNumber) { + $this->error('❌ Parameter --account diperlukan untuk type=single'); + return false; + } - } catch (Exception $e) { - $this->error('❌ Error saat mendispatch job: ' . $e->getMessage()); - Log::error('SendStatementEmailCommand failed', [ - 'error' => $e->getMessage(), - 'trace' => $e->getTraceAsString() - ]); - return Command::FAILURE; + $account = Account::with('customer') + ->where('account_number', $accountNumber) + ->first(); + + if (!$account) { + $this->error("❌ Account {$accountNumber} tidak ditemukan"); + return false; + } + + $hasEmail = !empty($account->stmt_email) || + ($account->customer && !empty($account->customer->email)); + + if (!$hasEmail) { + $this->error("❌ Account {$accountNumber} tidak memiliki email"); + return false; + } + + $this->info("✅ Account {$accountNumber} ditemukan dengan email"); + break; + + case 'branch': + if (!$branchCode) { + $this->error('❌ Parameter --branch diperlukan untuk type=branch'); + return false; + } + + $branch = Branch::where('code', $branchCode)->first(); + if (!$branch) { + $this->error("❌ Branch {$branchCode} tidak ditemukan"); + return false; + } + + $accountCount = Account::with('customer') + ->where('branch_code', $branchCode) + ->where('stmt_sent_type', 'BY.EMAIL') + ->get() + ->filter(function ($account) { + return !empty($account->stmt_email) || + ($account->customer && !empty($account->customer->email)); + }) + ->count(); + + if ($accountCount === 0) { + $this->error("❌ Tidak ada account dengan email di branch {$branchCode}"); + return false; + } + + $this->info("✅ Ditemukan {$accountCount} account dengan email di branch {$branch->name}"); + break; + + case 'all': + $accountCount = Account::with('customer') + ->where('stmt_sent_type', 'BY.EMAIL') + ->get() + ->filter(function ($account) { + return !empty($account->stmt_email) || + ($account->customer && !empty($account->customer->email)); + }) + ->count(); + + if ($accountCount === 0) { + $this->error('❌ Tidak ada account dengan email ditemukan'); + return false; + } + + $this->info("✅ Ditemukan {$accountCount} account dengan email di seluruh cabang"); + break; + } + + return true; + } + + private function determineRequestTypeAndTarget($type, $accountNumber, $branchCode) + { + switch ($type) { + case 'single': + return ['single_account', $accountNumber]; + case 'branch': + return ['branch', $branchCode]; + case 'all': + return ['all_branches', null]; + default: + throw new InvalidArgumentException("Invalid type: {$type}"); + } + } + + private function createLogEntry($period, $requestType, $targetValue, $batchId) + { + $logData = [ + 'user_id' => null, // Command line execution + 'period_from' => $period, + 'period_to' => $period, + 'is_period_range' => false, + 'request_type' => $requestType, + 'batch_id' => $batchId ?? uniqid('cmd_'), + 'status' => 'pending', + 'authorization_status' => 'approved', // Auto-approved untuk command line + 'created_by' => null, + 'ip_address' => '127.0.0.1', + 'user_agent' => 'Command Line' + ]; + + // Set branch_code dan account_number berdasarkan request type + switch ($requestType) { + case 'single_account': + $account = Account::where('account_number', $targetValue)->first(); + $logData['branch_code'] = $account->branch_code; + $logData['account_number'] = $targetValue; + break; + case 'branch': + $logData['branch_code'] = $targetValue; + $logData['account_number'] = null; + break; + case 'all_branches': + $logData['branch_code'] = 'ALL'; + $logData['account_number'] = null; + break; + } + + return PrintStatementLog::create($logData); + } + + private function displayJobInfo($period, $requestType, $targetValue, $queueName, $log) + { + $this->info('📋 Detail Job:'); + $this->line(" Log ID: {$log->id}"); + $this->line(" Periode: {$period}"); + $this->line(" Request Type: {$requestType}"); + + switch ($requestType) { + case 'single_account': + $this->line(" Account: {$targetValue}"); + break; + case 'branch': + $branch = Branch::where('code', $targetValue)->first(); + $this->line(" Branch: {$targetValue} ({$branch->name})"); + break; + case 'all_branches': + $this->line(" Target: Seluruh cabang"); + break; + } + + $this->line(" Batch ID: {$log->batch_id}"); + $this->line(" Queue: {$queueName}"); } } - - private function validateParameters($period, $type, $accountNumber, $branchCode) - { - // Validasi format periode - if (!preg_match('/^\d{6}$/', $period)) { - $this->error('❌ Format periode tidak valid. Gunakan format YYYYMM (contoh: 202401)'); - return false; - } - - // Validasi type - if (!in_array($type, ['single', 'branch', 'all'])) { - $this->error('❌ Type tidak valid. Gunakan: single, branch, atau all'); - return false; - } - - // Validasi parameter berdasarkan type - switch ($type) { - case 'single': - if (!$accountNumber) { - $this->error('❌ Parameter --account diperlukan untuk type=single'); - return false; - } - - $account = Account::with('customer') - ->where('account_number', $accountNumber) - ->first(); - - if (!$account) { - $this->error("❌ Account {$accountNumber} tidak ditemukan"); - return false; - } - - $hasEmail = !empty($account->stmt_email) || - ($account->customer && !empty($account->customer->email)); - - if (!$hasEmail) { - $this->error("❌ Account {$accountNumber} tidak memiliki email"); - return false; - } - - $this->info("✅ Account {$accountNumber} ditemukan dengan email"); - break; - - case 'branch': - if (!$branchCode) { - $this->error('❌ Parameter --branch diperlukan untuk type=branch'); - return false; - } - - $branch = Branch::where('code', $branchCode)->first(); - if (!$branch) { - $this->error("❌ Branch {$branchCode} tidak ditemukan"); - return false; - } - - $accountCount = Account::with('customer') - ->where('branch_code', $branchCode) - ->where('stmt_sent_type', 'BY.EMAIL') - ->get() - ->filter(function ($account) { - return !empty($account->stmt_email) || - ($account->customer && !empty($account->customer->email)); - }) - ->count(); - - if ($accountCount === 0) { - $this->error("❌ Tidak ada account dengan email di branch {$branchCode}"); - return false; - } - - $this->info("✅ Ditemukan {$accountCount} account dengan email di branch {$branch->name}"); - break; - - case 'all': - $accountCount = Account::with('customer') - ->where('stmt_sent_type', 'BY.EMAIL') - ->get() - ->filter(function ($account) { - return !empty($account->stmt_email) || - ($account->customer && !empty($account->customer->email)); - }) - ->count(); - - if ($accountCount === 0) { - $this->error('❌ Tidak ada account dengan email ditemukan'); - return false; - } - - $this->info("✅ Ditemukan {$accountCount} account dengan email di seluruh cabang"); - break; - } - - return true; - } - - private function determineRequestTypeAndTarget($type, $accountNumber, $branchCode) - { - switch ($type) { - case 'single': - return ['single_account', $accountNumber]; - case 'branch': - return ['branch', $branchCode]; - case 'all': - return ['all_branches', null]; - default: - throw new \InvalidArgumentException("Invalid type: {$type}"); - } - } - - private function createLogEntry($period, $requestType, $targetValue, $batchId) - { - $logData = [ - 'user_id' => null, // Command line execution - 'period_from' => $period, - 'period_to' => $period, - 'is_period_range' => false, - 'request_type' => $requestType, - 'batch_id' => $batchId ?? uniqid('cmd_'), - 'status' => 'pending', - 'authorization_status' => 'approved', // Auto-approved untuk command line - 'created_by' => null, - 'ip_address' => '127.0.0.1', - 'user_agent' => 'Command Line' - ]; - - // Set branch_code dan account_number berdasarkan request type - switch ($requestType) { - case 'single_account': - $account = Account::where('account_number', $targetValue)->first(); - $logData['branch_code'] = $account->branch_code; - $logData['account_number'] = $targetValue; - break; - case 'branch': - $logData['branch_code'] = $targetValue; - $logData['account_number'] = null; - break; - case 'all_branches': - $logData['branch_code'] = 'ALL'; - $logData['account_number'] = null; - break; - } - - return PrintStatementLog::create($logData); - } - - private function displayJobInfo($period, $requestType, $targetValue, $queueName, $log) - { - $this->info('📋 Detail Job:'); - $this->line(" Log ID: {$log->id}"); - $this->line(" Periode: {$period}"); - $this->line(" Request Type: {$requestType}"); - - switch ($requestType) { - case 'single_account': - $this->line(" Account: {$targetValue}"); - break; - case 'branch': - $branch = Branch::where('code', $targetValue)->first(); - $this->line(" Branch: {$targetValue} ({$branch->name})"); - break; - case 'all_branches': - $this->line(" Target: Seluruh cabang"); - break; - } - - $this->line(" Batch ID: {$log->batch_id}"); - $this->line(" Queue: {$queueName}"); - } -}