Files
webstatement/app/Jobs/GenerateBiayaKartuCsvJob.php
Daeng Deni Mardaeni 012d1629c9 refactor(webstatement): perbaikan struktur dan penyempurnaan kode pada GenerateBiayaKartuCsvJob
- Mengubah konversi konstanta MAX_EXECUTION_TIME menjadi properti.
- Memindahkan dan merapikan fungsi-fungsi `updateCsvLogStart`, `updateCsvLogSuccess`, dan `updateCsvLogFailed` untuk meningkatkan keterbacaan.
- Mengubah format deklarasi fungsi untuk konsistensi dalam penggunaan tipe data return.
- Memperbaiki logika pengambilan file info pada proses pembuatan dan pengunggahan CSV.
- Menambahkan logging yang lebih terstruktur untuk setiap proses (mulai, sukses, gagal).

Signed-off-by: Daeng Deni Mardaeni <ddeni05@gmail.com>
2025-05-11 17:14:08 +07:00

399 lines
12 KiB
PHP

<?php
namespace Modules\Webstatement\Jobs;
use Carbon\Carbon;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Modules\Webstatement\Models\Atmcard;
use Modules\Webstatement\Models\JenisKartu;
use Modules\Webstatement\Models\KartuSyncLog;
use RuntimeException;
class GenerateBiayaKartuCsvJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// Changed from const to property
private const MAX_EXECUTION_TIME = 3600; // 1 jam dalam detik
/**
* Periode yang akan diproses (YYYY-MM)
*/
protected $periode;
/**
* ID log sinkronisasi
*/
protected $syncLogId;
/**
* Model log sinkronisasi
*/
protected $syncLog;
private $csvFilename;
/**
* Create a new job instance.
*/
public function __construct()
{
$this->csvFilename = env('BIAYA_KARTU_CSV_FILENAME', 'biaya_kartu_atm.csv');
$this->periode = $periode ?? Carbon::now()->format('Y-m');
$this->syncLogId = KartuSyncLog::where('periode', $this->periode)->first();
}
/**
* Execute the job.
*/
public function handle()
: void
{
set_time_limit(self::MAX_EXECUTION_TIME);
// Load log sinkronisasi
$this->syncLog = KartuSyncLog::findOrFail($this->syncLogId->id);
try {
// Update status CSV generation dimulai
$this->updateCsvLogStart();
// Generate CSV file
$result = $this->generateAtmCardCsv();
// Update status CSV generation berhasil
$this->updateCsvLogSuccess($result);
Log::info('Pembuatan dan upload file CSV biaya kartu ATM selesai', [
'file' => $result['localFilePath'],
'jumlah_kartu' => $result['recordCount'],
'upload_sftp' => $result['uploadToSftp'] ? 'Berhasil' : 'Gagal',
'waktu' => $result['timestamp']
]);
if (!$result['uploadToSftp']) {
Log::warning('File CSV biaya kartu ATM tidak berhasil diunggah ke SFTP, tetapi tersedia secara lokal di: ' . $result['localFilePath']);
}
} catch (Exception $e) {
$this->updateCsvLogFailed($e->getMessage());
Log::error('Gagal membuat atau mengunggah file CSV biaya kartu ATM: ' . $e->getMessage(), [
'file' => $e->getFile(),
'line' => $e->getLine(),
'periode' => $this->periode
]);
throw $e;
}
}
/**
* Update log saat pembuatan CSV dimulai
*/
private function updateCsvLogStart()
: void
{
$this->syncLog->update([
'csv_notes' => 'Pembuatan file CSV untuk periode ' . $this->periode . ' dimulai',
'is_csv' => false,
'csv_at' => null,
]);
Log::info('Memulai pembuatan file CSV untuk periode ' . $this->periode);
}
/**
* Generate CSV file with ATM card data and upload to SFTP
*
* @return array Information about the generated file and upload status
*/
private function generateAtmCardCsv()
: array
{
$cards = $this->getEligibleAtmCards();
//$filename = storage_path('app/' . $this->csvFilename);
// Add date-time to filename
$dateTime = now()->format('Ymd_Hi');
$filenameWithDate = pathinfo($this->csvFilename, PATHINFO_FILENAME) .
'_' . $dateTime . '.' .
pathinfo($this->csvFilename, PATHINFO_EXTENSION);
$filename = storage_path('app/' . $filenameWithDate);
$handle = fopen($filename, 'w+');
if (!$handle) {
throw new RuntimeException("Tidak dapat membuat file CSV: $filename");
}
try {
foreach ($cards as $card) {
$fee = $this->determineCardFee($card);
$csvRow = $this->createCsvRow($card, $fee);
fputcsv($handle, $csvRow, '|');
}
} finally {
fclose($handle);
}
$this->cleanupCsvFile($filename);
// Upload file ke SFTP
$uploadSuccess = $this->uploadToSftpKartu($filename);
return [
'localFilePath' => $filename,
'recordCount' => count($cards),
'uploadToSftp' => $uploadSuccess,
'timestamp' => now()->format('Y-m-d H:i:s')
];
}
/**
* Get eligible ATM cards from database
*
* @return \Illuminate\Database\Eloquent\Collection
*/
private function getEligibleAtmCards()
{
$cardTypes = array_keys($this->getDefaultFees());
return Atmcard::where('crsts', 1)
->whereNotNull('accflag')
->where('accflag', '!=', '')
->whereNotNull('branch')
->where('branch', '!=', '')
->whereNotNull('currency')
->where('currency', '!=', '')
->whereIn('ctdesc', $cardTypes)
->get();
}
/**
* Get default fees from JenisKartu table
*
* @return array
*/
private function getDefaultFees()
: array
{
return JenisKartu::getDefaultFees();
}
/**
* Determine fee for a card based on its type
*
* @param Atmcard $card
*
* @return int
*/
private function determineCardFee(Atmcard $card)
: int
{
if ($card->fee) {
return $card->fee;
}
$defaultFees = $this->getDefaultFees();
return $defaultFees[$card->ctdesc] ?? 0;
}
/**
* Create CSV row data for a card
*
* @param Atmcard $card
* @param int $fee
*
* @return array
*/
private function createCsvRow(Atmcard $card, int $fee)
: array
{
$today = date('Ymd');
return [
'',
$card->accflag,
$card->currency ?? 'IDR',
$fee,
'PL65129',
'',
'',
$card->branch,
$today,
$today,
'',
'',
'ADMIN FEE ATM::' . $card->crdno . '::' . $today,
'',
'',
'',
'',
'',
'',
'ACAT'
];
}
/**
* Remove double quotes from CSV file
*
* @param string $filename
*
* @return void
*/
private function cleanupCsvFile(string $filename)
: void
{
$fileContent = file_get_contents($filename);
if ($fileContent === false) {
throw new RuntimeException("Tidak dapat membaca file CSV: $filename");
}
$fileContent = str_replace('"', '', $fileContent);
if (file_put_contents($filename, $fileContent) === false) {
throw new RuntimeException("Tidak dapat menulis ke file CSV: $filename");
}
}
/**
* Upload the generated CSV file to SFTP server
*
* @param string $localFilePath Path to the local CSV file
*
* @return bool True if upload successful, false otherwise
*/
private function uploadToSftpKartu(string $localFilePath)
: bool
{
try {
// Update status SFTP upload dimulai
$this->updateSftpLogStart();
// Ambil nama file dari path
$filename = basename($localFilePath);
// Ambil konten file
$fileContent = file_get_contents($localFilePath);
if ($fileContent === false) {
Log::error("Tidak dapat membaca file untuk upload: {$localFilePath}");
return false;
}
// Dapatkan disk SFTP
$disk = Storage::disk('sftpKartu');
// Tentukan path tujuan di server SFTP
$remotePath = env('BIAYA_KARTU_REMOTE_PATH', '/');
$remoteFilePath = rtrim($remotePath, '/') . '/' . $filename;
// Upload file ke server SFTP
$result = $disk->put($remoteFilePath, $fileContent);
if ($result) {
$this->updateSftpLogSuccess();
Log::info("File CSV biaya kartu ATM berhasil diunggah ke SFTP: {$remoteFilePath}");
return true;
} else {
$this->updateSftpLogFailed("Gagal mengunggah file CSV biaya kartu ATM ke SFTP: {$remoteFilePath}");
Log::error("Gagal mengunggah file CSV biaya kartu ATM ke SFTP: {$remoteFilePath}");
return false;
}
} catch (Exception $e) {
$this->updateSftpLogFailed($e->getMessage());
Log::error("Error saat mengunggah file ke SFTP: " . $e->getMessage(), [
'file' => $e->getFile(),
'line' => $e->getLine(),
'periode' => $this->periode
]);
return false;
}
}
/**
* Update log saat upload SFTP dimulai
*/
private function updateSftpLogStart()
: void
{
$this->syncLog->update([
'ftp_notes' => 'Upload ke SFTP untuk file periode ' . $this->periode . ' dimulai',
'is_ftp' => false,
'ftp_at' => null,
]);
Log::info('Memulai upload ke SFTP untuk periode ' . $this->periode);
}
/**
* Update log saat upload SFTP berhasil
*/
private function updateSftpLogSuccess()
: void
{
$this->syncLog->update([
'is_ftp' => true,
'ftp_at' => Carbon::now(),
'ftp_notes' => 'File berhasil diupload ke SFTP',
'ftp_destination' => env('SFTP_KARTU_HOST', '/'),
]);
Log::info('File berhasil diupload ke SFTP untuk periode ' . $this->periode);
}
/**
* Update log saat upload SFTP gagal
*/
private function updateSftpLogFailed($errorMessage)
: void
{
$this->syncLog->update([
'is_ftp' => false,
'ftp_notes' => 'Upload ke SFTP gagal: ' . $errorMessage
]);
Log::error('Upload ke SFTP gagal: ' . $errorMessage);
}
/**
* Update log saat pembuatan CSV berhasil
*/
private function updateCsvLogSuccess($result)
: void
{
// Get file info
$fileInfo = pathinfo($result['localFilePath']);
$fileName = $fileInfo['basename'];
$this->syncLog->update([
'is_csv' => true,
'csv_at' => Carbon::now(),
'csv_notes' => 'File CSV berhasil dibuat: ' . $fileName,
'file_path' => $result['localFilePath'],
'file_name' => $fileName,
]);
Log::info('File CSV berhasil dibuat: ' . $result['localFilePath']);
}
/**
* Update log saat pembuatan CSV gagal
*/
private function updateCsvLogFailed($errorMessage)
: void
{
$this->syncLog->update([
'is_csv' => false,
'csv_notes' => 'Pembuatan file CSV gagal: ' . $errorMessage
]);
Log::error('Pembuatan file CSV gagal: ' . $errorMessage);
}
}