- **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 <ddeni05@gmail.com>
250 lines
11 KiB
PHP
250 lines
11 KiB
PHP
<?php
|
|
|
|
namespace Modules\Webstatement\Console;
|
|
|
|
use Exception;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Modules\Basicdata\Models\Branch;
|
|
use Modules\Webstatement\Jobs\SendStatementEmailJob;
|
|
use Modules\Webstatement\Models\Account;
|
|
use Modules\Webstatement\Models\PrintStatementLog;
|
|
use InvalidArgumentException;
|
|
|
|
/**
|
|
* Command untuk mengirim email statement PDF ke nasabah
|
|
* Mendukung pengiriman per rekening, per cabang, atau seluruh cabang
|
|
*/
|
|
class SendStatementEmailCommand extends Command
|
|
{
|
|
protected $signature = 'webstatement:send-email
|
|
{period : Format periode YYYYMM (contoh: 202401)}
|
|
{--type=single : Tipe pengiriman: single, branch, all}
|
|
{--account= : Nomor rekening (untuk type=single)}
|
|
{--branch= : Kode cabang (untuk type=branch)}
|
|
{--batch-id= : ID batch untuk tracking (opsional)}
|
|
{--queue=emails : Nama queue untuk job (default: emails)}
|
|
{--delay=0 : Delay dalam menit sebelum job dijalankan}';
|
|
|
|
protected $description = 'Mengirim email statement PDF ke nasabah (per rekening, per cabang, atau seluruh cabang)';
|
|
|
|
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');
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
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}");
|
|
}
|
|
}
|