feat(webstatement): tambah dukungan queue name pada StagingController dan WebstatementController

Menambahkan parameter queue_name untuk mengatur queue spesifik pada job processing:

- Menambahkan parameter queueName pada StagingController.processData() dan index()
- Menggunakan onQueue() method saat dispatch job di StagingController
- Memperbarui ProcessDailyStaging untuk mengirim queue_name ke controller
- Menambahkan parameter Request pada WebstatementController untuk menerima queue_name
- Menggunakan onQueue() method saat dispatch job di WebstatementController
- Menambahkan logging untuk queue_name di semua proses
- Memperbarui response JSON untuk menyertakan informasi queue_name
- Menambahkan komentar fungsi yang menjelaskan parameter queue_name
- Mempertahankan backward compatibility dengan default queue 'default'
- Meningkatkan fleksibilitas dalam manajemen queue untuk berbagai environment
- Memungkinkan pemisahan job berdasarkan prioritas atau resource yang tersedia
This commit is contained in:
Daeng Deni Mardaeni
2025-07-31 08:13:02 +07:00
parent e1740c0850
commit ca92f32ccb
2 changed files with 460 additions and 377 deletions

View File

@@ -1,199 +1,240 @@
<?php <?php
namespace Modules\Webstatement\Http\Controllers; namespace Modules\Webstatement\Http\Controllers;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use BadMethodCallException; use BadMethodCallException;
use Exception; use Exception;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Modules\Webstatement\Jobs\{ProcessAccountDataJob, use Modules\Webstatement\Jobs\{ProcessAccountDataJob,
ProcessArrangementDataJob, ProcessArrangementDataJob,
ProcessAtmTransactionJob, ProcessAtmTransactionJob,
ProcessBillDetailDataJob, ProcessBillDetailDataJob,
ProcessCategoryDataJob, ProcessCategoryDataJob,
ProcessCompanyDataJob, ProcessCompanyDataJob,
ProcessCustomerDataJob, ProcessCustomerDataJob,
ProcessDataCaptureDataJob, ProcessDataCaptureDataJob,
ProcessFtTxnTypeConditionJob, ProcessFtTxnTypeConditionJob,
ProcessFundsTransferDataJob, ProcessFundsTransferDataJob,
ProcessStmtEntryDataJob, ProcessStmtEntryDataJob,
ProcessStmtNarrFormatDataJob, ProcessStmtNarrFormatDataJob,
ProcessStmtNarrParamDataJob, ProcessStmtNarrParamDataJob,
ProcessTellerDataJob, ProcessTellerDataJob,
ProcessTransactionDataJob, ProcessTransactionDataJob,
ProcessSectorDataJob, ProcessSectorDataJob,
ProcessProvinceDataJob, ProcessProvinceDataJob,
ProcessStmtEntryDetailDataJob}; ProcessStmtEntryDetailDataJob};
class StagingController extends Controller class StagingController extends Controller
{
private const PROCESS_TYPES = [
'transaction' => ProcessTransactionDataJob::class,
'stmtNarrParam' => ProcessStmtNarrParamDataJob::class,
'stmtNarrFormat' => ProcessStmtNarrFormatDataJob::class,
'ftTxnTypeCondition' => ProcessFtTxnTypeConditionJob::class,
'category' => ProcessCategoryDataJob::class,
'company' => ProcessCompanyDataJob::class,
'customer' => ProcessCustomerDataJob::class,
'account' => ProcessAccountDataJob::class,
'stmtEntry' => ProcessStmtEntryDataJob::class,
'stmtEntryDetail' => ProcessStmtEntryDetailDataJob::class,
'dataCapture' => ProcessDataCaptureDataJob::class,
'fundsTransfer' => ProcessFundsTransferDataJob::class,
'teller' => ProcessTellerDataJob::class,
'atmTransaction' => ProcessAtmTransactionJob::class,
'arrangement' => ProcessArrangementDataJob::class,
'billDetail' => ProcessBillDetailDataJob::class,
'sector' => ProcessSectorDataJob::class,
'province' => ProcessProvinceDataJob::class
];
private const PARAMETER_PROCESSES = [
'transaction',
'stmtNarrParam',
'stmtNarrFormat',
'ftTxnTypeCondition',
'sector',
'province'
];
private const DATA_PROCESSES = [
'category',
'company',
'customer',
'account',
'stmtEntry',
'stmtEntryDetail',
'dataCapture',
'fundsTransfer',
'teller',
'atmTransaction',
'arrangement',
'billDetail'
];
public function __call($method, $parameters)
{ {
private const PROCESS_TYPES = [ if (strpos($method, 'process') === 0) {
'transaction' => ProcessTransactionDataJob::class, $type = lcfirst(substr($method, 7));
'stmtNarrParam' => ProcessStmtNarrParamDataJob::class, if (isset(self::PROCESS_TYPES[$type])) {
'stmtNarrFormat' => ProcessStmtNarrFormatDataJob::class, return $this->processData($type, $parameters[0] ?? '', $parameters[1] ?? 'default');
'ftTxnTypeCondition' => ProcessFtTxnTypeConditionJob::class,
'category' => ProcessCategoryDataJob::class,
'company' => ProcessCompanyDataJob::class,
'customer' => ProcessCustomerDataJob::class,
'account' => ProcessAccountDataJob::class,
'stmtEntry' => ProcessStmtEntryDataJob::class,
'stmtEntryDetail' => ProcessStmtEntryDetailDataJob::class, // Tambahan baru
'dataCapture' => ProcessDataCaptureDataJob::class,
'fundsTransfer' => ProcessFundsTransferDataJob::class,
'teller' => ProcessTellerDataJob::class,
'atmTransaction' => ProcessAtmTransactionJob::class,
'arrangement' => ProcessArrangementDataJob::class,
'billDetail' => ProcessBillDetailDataJob::class,
'sector' => ProcessSectorDataJob::class,
'province' => ProcessProvinceDataJob::class
];
private const PARAMETER_PROCESSES = [
'transaction',
'stmtNarrParam',
'stmtNarrFormat',
'ftTxnTypeCondition',
'sector',
'province'
];
private const DATA_PROCESSES = [
'category',
'company',
'customer',
'account',
'stmtEntry',
'stmtEntryDetail', // Tambahan baru
'dataCapture',
'fundsTransfer',
'teller',
'atmTransaction',
'arrangement',
'billDetail'
];
public function __call($method, $parameters)
{
if (strpos($method, 'process') === 0) {
$type = lcfirst(substr($method, 7));
if (isset(self::PROCESS_TYPES[$type])) {
return $this->processData($type, $parameters[0] ?? '');
}
}
throw new BadMethodCallException("Method {$method} does not exist.");
}
private function processData(string $type, string $period)
: JsonResponse
{
try {
$jobClass = self::PROCESS_TYPES[$type];
$jobClass::dispatch($period);
$message = sprintf('%s data processing job has been queued successfully', ucfirst($type));
Log::info($message);
return response()->json(['message' => $message]);
} catch (Exception $e) {
Log::error(sprintf('Error in %s processing: %s', $type, $e->getMessage()));
return response()->json(['error' => $e->getMessage()], 500);
} }
} }
/** throw new BadMethodCallException("Method {$method} does not exist.");
* Proses migrasi data dengan parameter dan periode yang dapat dikustomisasi }
*
* @param bool|string $processParameter Flag untuk memproses parameter
* @param string|null $period Periode yang akan diproses (default: -1 day)
* @return JsonResponse
*/
public function index($processParameter = false, $period = null)
{
try {
Log::info('Starting migration process', [
'process_parameter' => $processParameter,
'period' => $period
]);
$disk = Storage::disk('staging'); /**
* Memproses data dengan queue name yang dapat dikustomisasi
*
* @param string $type Tipe proses yang akan dijalankan
* @param string $period Periode data yang akan diproses
* @param string $queueName Nama queue untuk menjalankan job
* @return JsonResponse
*/
private function processData(string $type, string $period, string $queueName = 'default'): JsonResponse
{
try {
$jobClass = self::PROCESS_TYPES[$type];
if ($processParameter) { // Dispatch job dengan queue name yang spesifik
Log::info('Processing parameter data'); $jobClass::dispatch($period)->onQueue($queueName);
foreach (self::PARAMETER_PROCESSES as $process) { $message = sprintf('%s data processing job has been queued successfully on queue: %s', ucfirst($type), $queueName);
$this->processData($process, '_parameter'); Log::info($message, [
} 'type' => $type,
'period' => $period,
'queue_name' => $queueName
]);
Log::info('Parameter processes completed successfully'); return response()->json([
return response()->json(['message' => 'Parameter processes completed successfully']); 'message' => $message,
} 'queue_name' => $queueName
]);
// Tentukan periode yang akan diproses } catch (Exception $e) {
$targetPeriod = $this->determinePeriod($period); Log::error(sprintf('Error in %s processing: %s', $type, $e->getMessage()), [
'type' => $type,
Log::info('Processing data for period', ['period' => $targetPeriod]); 'period' => $period,
'queue_name' => $queueName,
if (!$disk->exists($targetPeriod)) { 'error' => $e->getMessage()
$errorMessage = "Period {$targetPeriod} folder not found in SFTP storage"; ]);
Log::warning($errorMessage); return response()->json(['error' => $e->getMessage()], 500);
return response()->json([
"message" => $errorMessage
], 404);
}
foreach (self::DATA_PROCESSES as $process) {
$this->processData($process, $targetPeriod);
}
$successMessage = "Data processing for period {$targetPeriod} has been queued successfully";
Log::info($successMessage);
return response()->json([
'message' => $successMessage
]);
} catch (Exception $e) {
Log::error('Error in migration index method: ' . $e->getMessage());
return response()->json(['error' => $e->getMessage()], 500);
}
}
/**
* Tentukan periode berdasarkan input atau gunakan default
*
* @param string|null $period Input periode
* @return string Periode dalam format Ymd
*/
private function determinePeriod($period = null): string
{
if ($period === null) {
// Default: -1 day
$calculatedPeriod = date('Ymd', strtotime('-1 day'));
Log::info('Using default period', ['period' => $calculatedPeriod]);
return $calculatedPeriod;
}
// Jika periode sudah dalam format Ymd (8 digit)
if (preg_match('/^\d{8}$/', $period)) {
Log::info('Using provided period in Ymd format', ['period' => $period]);
return $period;
}
// Jika periode dalam format relative date (contoh: -2 days, -1 week, etc.)
try {
$calculatedPeriod = date('Ymd', strtotime($period));
Log::info('Calculated period from relative date', [
'input' => $period,
'calculated' => $calculatedPeriod
]);
return $calculatedPeriod;
} catch (Exception $e) {
Log::warning('Invalid period format, using default', [
'input' => $period,
'error' => $e->getMessage()
]);
return date('Ymd', strtotime('-1 day'));
}
} }
} }
/**
* Proses migrasi data dengan parameter, periode, dan queue name yang dapat dikustomisasi
*
* @param bool|string $processParameter Flag untuk memproses parameter
* @param string|null $period Periode yang akan diproses (default: -1 day)
* @param string $queueName Nama queue untuk menjalankan job (default: default)
* @return JsonResponse
*/
public function index($processParameter = false, $period = null, $queueName = 'default')
{
try {
Log::info('Starting migration process', [
'process_parameter' => $processParameter,
'period' => $period,
'queue_name' => $queueName
]);
$disk = Storage::disk('staging');
if ($processParameter) {
Log::info('Processing parameter data', ['queue_name' => $queueName]);
foreach (self::PARAMETER_PROCESSES as $process) {
$this->processData($process, '_parameter', $queueName);
}
Log::info('Parameter processes completed successfully', ['queue_name' => $queueName]);
return response()->json([
'message' => 'Parameter processes completed successfully',
'queue_name' => $queueName
]);
}
// Tentukan periode yang akan diproses
$targetPeriod = $this->determinePeriod($period);
Log::info('Processing data for period', [
'period' => $targetPeriod,
'queue_name' => $queueName
]);
if (!$disk->exists($targetPeriod)) {
$errorMessage = "Period {$targetPeriod} folder not found in SFTP storage";
Log::warning($errorMessage, ['queue_name' => $queueName]);
return response()->json([
"message" => $errorMessage,
'queue_name' => $queueName
], 404);
}
foreach (self::DATA_PROCESSES as $process) {
$this->processData($process, $targetPeriod, $queueName);
}
$successMessage = "Data processing for period {$targetPeriod} has been queued successfully on queue: {$queueName}";
Log::info($successMessage, [
'period' => $targetPeriod,
'queue_name' => $queueName
]);
return response()->json([
'message' => $successMessage,
'queue_name' => $queueName
]);
} catch (Exception $e) {
Log::error('Error in migration index method: ' . $e->getMessage(), [
'queue_name' => $queueName,
'error' => $e->getMessage()
]);
return response()->json([
'error' => $e->getMessage(),
'queue_name' => $queueName
], 500);
}
}
/**
* Tentukan periode berdasarkan input atau gunakan default
*
* @param string|null $period Input periode
* @return string Periode dalam format Ymd
*/
private function determinePeriod($period = null): string
{
if ($period === null) {
// Default: -1 day
$calculatedPeriod = date('Ymd', strtotime('-1 day'));
Log::info('Using default period', ['period' => $calculatedPeriod]);
return $calculatedPeriod;
}
// Jika periode sudah dalam format Ymd (8 digit)
if (preg_match('/^\d{8}$/', $period)) {
Log::info('Using provided period in Ymd format', ['period' => $period]);
return $period;
}
// Jika periode dalam format relative date (contoh: -2 days, -1 week, etc.)
try {
$calculatedPeriod = date('Ymd', strtotime($period));
Log::info('Calculated period from relative date', [
'input' => $period,
'calculated' => $calculatedPeriod
]);
return $calculatedPeriod;
} catch (Exception $e) {
Log::warning('Invalid period format, using default', [
'input' => $period,
'error' => $e->getMessage()
]);
return date('Ymd', strtotime('-1 day'));
}
}
}

View File

@@ -1,204 +1,246 @@
<?php <?php
namespace Modules\Webstatement\Http\Controllers; namespace Modules\Webstatement\Http\Controllers;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Contracts\Bus\Dispatcher; use Illuminate\Contracts\Bus\Dispatcher;
use Modules\Webstatement\Jobs\ExportStatementJob; use Illuminate\Http\Request;
use Modules\Webstatement\Models\AccountBalance; use Modules\Webstatement\Jobs\ExportStatementJob;
use Modules\Webstatement\Jobs\ExportStatementPeriodJob; use Modules\Webstatement\Models\AccountBalance;
use Modules\Webstatement\Jobs\ExportStatementPeriodJob;
use Illuminate\Support\Facades\Log;
class WebstatementController extends Controller class WebstatementController extends Controller
{
/**
* Display a listing of the resource.
* Menjalankan export statement untuk semua akun dengan queue name yang dapat dikustomisasi
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request)
{ {
/** $queueName = $request->get('queue_name', 'default');
* Display a listing of the resource.
*/
public function index()
{
$jobIds = [];
$data = [];
foreach ($this->listAccount() as $clientName => $accounts) { Log::info('Starting statement export process', [
foreach ($accounts as $accountNumber) { 'queue_name' => $queueName
foreach ($this->listPeriod() as $period) { ]);
$job = new ExportStatementJob(
$accountNumber, $jobIds = [];
$period, $data = [];
$this->getAccountBalance($accountNumber, $period),
$clientName // Pass the client name to the job foreach ($this->listAccount() as $clientName => $accounts) {
); foreach ($accounts as $accountNumber) {
$jobIds[] = app(Dispatcher::class)->dispatch($job); foreach ($this->listPeriod() as $period) {
$data[] = [ $job = new ExportStatementJob(
'client_name' => $clientName, $accountNumber,
'account_number' => $accountNumber, $period,
'period' => $period $this->getAccountBalance($accountNumber, $period),
]; $clientName // Pass the client name to the job
} );
// Dispatch job dengan queue name yang spesifik
$jobIds[] = app(Dispatcher::class)->dispatch($job->onQueue($queueName));
$data[] = [
'client_name' => $clientName,
'account_number' => $accountNumber,
'period' => $period,
'queue_name' => $queueName
];
} }
} }
}
Log::info('Statement export jobs queued successfully', [
'total_jobs' => count($jobIds),
'queue_name' => $queueName
]);
return response()->json([
'message' => 'Statement export jobs have been queued',
'queue_name' => $queueName,
'jobs' => array_map(function ($index, $jobId) use ($data) {
return [
'job_id' => $jobId,
'client_name' => $data[$index]['client_name'],
'account_number' => $data[$index]['account_number'],
'period' => $data[$index]['period'],
'queue_name' => $data[$index]['queue_name'],
'file_name' => "{$data[$index]['client_name']}_{$data[$index]['account_number']}_{$data[$index]['period']}.csv"
];
}, array_keys($jobIds), $jobIds)
]);
}
function listAccount(){
return [
'PLUANG' => [
'1080426085',
'1080425781',
],
'OY' => [
'1081647484',
'1081647485',
],
'INDORAYA' => [
'1083123710',
'1083123711',
'1083123712',
'1083123713',
'1083123714',
'1083123715',
'1083123716',
'1083123718',
'1083123719',
'1083123721',
'1083123722',
'1083123723',
'1083123724',
'1083123726',
'1083123727',
'1083123728',
'1083123730',
'1083123731',
'1083123732',
'1083123734',
'1083123735',
],
'TDC' => [
'1086677889',
'1086677890',
'1086677891',
'1086677892',
'1086677893',
'1086677894',
'1086677895',
'1086677896',
'1086677897',
],
'ASIA_PARKING' => [
'1080119298',
'1080119361',
'1080119425',
'1080119387',
'1082208069',
],
'DAU' => [
'1085151668',
],
'EGR' => [
'1085368601',
],
'SARANA_PACTINDO' => [
'1078333878',
],
'SWADAYA_PANDU' => [
'0081272689',
],
"AWAN_LINTANG_SOLUSI"=> [
"1084269430"
],
"MONETA"=> [
"1085667890"
]
];
}
function listPeriod(){
return [
date('Ymd', strtotime('-1 day'))
];
}
function getAccountBalance($accountNumber, $period)
{
$accountBalance = AccountBalance::where('account_number', $accountNumber)
->where('period', '<', $period)
->orderBy('period', 'desc')
->first();
return $accountBalance->actual_balance ?? 0;
}
/**
* Print statement rekening dengan queue name yang dapat dikustomisasi
*
* @param string $accountNumber
* @param string|null $period
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
function printStatementRekening($accountNumber, $period = null, Request $request = null) {
$queueName = $request ? $request->get('queue_name', 'default') : 'default';
$period = $period ?? date('Ym');
$balance = AccountBalance::where('account_number', $accountNumber)
->when($period === '202505', function($query) {
return $query->where('period', '>=', '20250512')
->orderBy('period', 'asc');
}, function($query) use ($period) {
// Get balance from last day of previous month
$firstDayOfMonth = Carbon::createFromFormat('Ym', $period)->startOfMonth();
$lastDayPrevMonth = $firstDayOfMonth->copy()->subDay()->format('Ymd');
return $query->where('period', $lastDayPrevMonth);
})
->first()
->actual_balance ?? '0.00';
$clientName = 'client1';
try {
Log::info("Starting statement export for account: {$accountNumber}, period: {$period}, client: {$clientName}", [
'account_number' => $accountNumber,
'period' => $period,
'client_name' => $clientName,
'queue_name' => $queueName
]);
// Validate inputs
if (empty($accountNumber) || empty($period) || empty($clientName)) {
throw new \Exception('Required parameters missing');
}
// Dispatch the job dengan queue name yang spesifik
$job = ExportStatementPeriodJob::dispatch($accountNumber, $period, $balance, $clientName)
->onQueue($queueName);
Log::info("Statement export job dispatched successfully", [
'job_id' => $job->job_id ?? null,
'account' => $accountNumber,
'period' => $period,
'client' => $clientName,
'queue_name' => $queueName
]);
return response()->json([ return response()->json([
'message' => 'Statement export jobs have been queued', 'success' => true,
'jobs' => array_map(function ($index, $jobId) use ($data) { 'message' => 'Statement export job queued successfully',
return [ 'data' => [
'job_id' => $jobId, 'job_id' => $job->job_id ?? null,
'client_name' => $data[$index]['client_name'], 'account_number' => $accountNumber,
'account_number' => $data[$index]['account_number'], 'period' => $period,
'period' => $data[$index]['period'], 'client_name' => $clientName,
'file_name' => "{$data[$index]['client_name']}_{$data[$index]['account_number']}_{$data[$index]['period']}.csv" 'queue_name' => $queueName
]; ]
}, array_keys($jobIds), $jobIds) ]);
} catch (\Exception $e) {
Log::error("Failed to export statement", [
'error' => $e->getMessage(),
'account' => $accountNumber,
'period' => $period,
'queue_name' => $queueName
]);
return response()->json([
'success' => false,
'message' => 'Failed to queue statement export job',
'error' => $e->getMessage(),
'queue_name' => $queueName
]); ]);
} }
function listAccount(){
return [
'PLUANG' => [
'1080426085',
'1080425781',
],
'OY' => [
'1081647484',
'1081647485',
],
'INDORAYA' => [
'1083123710',
'1083123711',
'1083123712',
'1083123713',
'1083123714',
'1083123715',
'1083123716',
'1083123718',
'1083123719',
'1083123721',
'1083123722',
'1083123723',
'1083123724',
'1083123726',
'1083123727',
'1083123728',
'1083123730',
'1083123731',
'1083123732',
'1083123734',
'1083123735',
],
'TDC' => [
'1086677889',
'1086677890',
'1086677891',
'1086677892',
'1086677893',
'1086677894',
'1086677895',
'1086677896',
'1086677897',
],
'ASIA_PARKING' => [
'1080119298',
'1080119361',
'1080119425',
'1080119387',
'1082208069',
],
'DAU' => [
'1085151668',
],
'EGR' => [
'1085368601',
],
'SARANA_PACTINDO' => [
'1078333878',
],
'SWADAYA_PANDU' => [
'0081272689',
],
"AWAN_LINTANG_SOLUSI"=> [
"1084269430"
],
"MONETA"=> [
"1085667890"
]
];
}
function listPeriod(){
return [
date('Ymd', strtotime('-1 day'))
];
}
function getAccountBalance($accountNumber, $period)
{
$accountBalance = AccountBalance::where('account_number', $accountNumber)
->where('period', '<', $period)
->orderBy('period', 'desc')
->first();
return $accountBalance->actual_balance ?? 0;
}
function printStatementRekening($accountNumber, $period = null) {
$period = $period ?? date('Ym');
$balance = AccountBalance::where('account_number', $accountNumber)
->when($period === '202505', function($query) {
return $query->where('period', '>=', '20250512')
->orderBy('period', 'asc');
}, function($query) use ($period) {
// Get balance from last day of previous month
$firstDayOfMonth = Carbon::createFromFormat('Ym', $period)->startOfMonth();
$lastDayPrevMonth = $firstDayOfMonth->copy()->subDay()->format('Ymd');
return $query->where('period', $lastDayPrevMonth);
})
->first()
->actual_balance ?? '0.00';
$clientName = 'client1';
try {
\Log::info("Starting statement export for account: {$accountNumber}, period: {$period}, client: {$clientName}");
// Validate inputs
if (empty($accountNumber) || empty($period) || empty($clientName)) {
throw new \Exception('Required parameters missing');
}
// Dispatch the job
$job = ExportStatementPeriodJob::dispatch($accountNumber, $period, $balance, $clientName);
\Log::info("Statement export job dispatched successfully", [
'job_id' => $job->job_id ?? null,
'account' => $accountNumber,
'period' => $period,
'client' => $clientName
]);
return response()->json([
'success' => true,
'message' => 'Statement export job queued successfully',
'data' => [
'job_id' => $job->job_id ?? null,
'account_number' => $accountNumber,
'period' => $period,
'client_name' => $clientName
]
]);
} catch (\Exception $e) {
\Log::error("Failed to export statement", [
'error' => $e->getMessage(),
'account' => $accountNumber,
'period' => $period
]);
return response()->json([
'success' => false,
'message' => 'Failed to queue statement export job',
'error' => $e->getMessage()
]);
}
}
} }
}