Files
webstatement/app/Jobs/GenerateBiayaKartuCsvJob.php
Daeng Deni Mardaeni 428792ed1b feat(webstatement): ubah filter product_code 6021 berdasarkan ctdesc
Mengubah logika filter untuk product_code 6021 agar hanya mengecualikan yang memiliki ctdesc 'gold',
sementara product_code 6021 dengan ctdesc lainnya tetap diproses.

Perubahan yang dilakukan:
- Menghapus '6021' dari array whereNotIn product_code yang mengecualikan semua
- Menambahkan filter kondisional kompleks menggunakan nested where clause
- Implementasi logika: (product_code != '6021') OR (product_code = '6021' AND ctdesc != 'gold')
- Menambahkan logging detail untuk tracking filter khusus yang diterapkan
- Memperbarui dokumentasi function untuk menjelaskan logika bisnis baru
- Menambahkan informasi filter khusus dalam log hasil pengambilan data

Dengan perubahan ini:
- Product_code 6021 dengan ctdesc 'gold' akan dikecualikan dari biaya admin
- Product_code 6021 dengan ctdesc selain 'gold' tetap dikenakan biaya admin
- Product_code lainnya (6002, 6004, 6042, 6031) tetap dikecualikan sepenuhnya
- Meningkatkan fleksibilitas dalam pengelolaan biaya berdasarkan jenis kartu
2025-07-08 14:12:51 +07:00

447 lines
15 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();
$cardsByBranch = $cards->groupBy('branch');
$results = [];
foreach ($cardsByBranch as $branch => $branchCards) {
$dateTime = now()->format('Ymd_Hi');
$branchFilename = pathinfo($this->csvFilename, PATHINFO_FILENAME)
. '_' . $branch
. '_' . $dateTime . '.'
. pathinfo($this->csvFilename, PATHINFO_EXTENSION);
$filename = storage_path('app/' . $branchFilename);
$handle = fopen($filename, 'w+');
if (!$handle) {
throw new RuntimeException("Tidak dapat membuat file CSV: $filename");
}
try {
foreach ($branchCards 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, $card->branch);
$results[] = [
'branch' => $branch,
'localFilePath' => $filename,
'recordCount' => count($branchCards),
'uploadToSftp' => $uploadSuccess,
'timestamp' => now()->format('Y-m-d H:i:s')
];
}
return $results;
}
/**
* Get eligible ATM cards from database
* Mengambil data kartu ATM yang memenuhi syarat untuk dikenakan biaya admin
* dengan filter khusus untuk mengecualikan product_code 6021 yang ctdesc nya gold
*
* @return \Illuminate\Database\Eloquent\Collection
*/
private function getEligibleAtmCards()
{
// Log: Memulai proses pengambilan data kartu ATM yang eligible
Log::info('Starting to fetch eligible ATM cards', [
'periode' => $this->periode
]);
$cardTypes = array_keys($this->getDefaultFees());
$query = Atmcard::where('crsts', 1)
->whereNotNull('accflag')
->where('accflag', '!=', '')
->where('flag','')
->whereNotNull('branch')
->where('branch', '!=', '')
->whereNotNull('currency')
->where('currency', '!=', '')
->whereIn('ctdesc', $cardTypes)
->whereNotIn('product_code',['6002','6004','6042','6031']) // Hapus 6021 dari sini
->where('branch','!=','ID0019999')
// Filter khusus: Kecualikan product_code 6021 yang ctdesc nya gold
->where(function($subQuery) {
$subQuery->where('product_code', '!=', '6021')
->orWhere(function($nestedQuery) {
$nestedQuery->where('product_code', '6021')
->where('ctdesc', '!=', 'gold');
});
});
$cards = $query->get();
// Log: Hasil pengambilan data kartu ATM
Log::info('Eligible ATM cards fetched successfully', [
'total_cards' => $cards->count(),
'periode' => $this->periode,
'excluded_product_codes' => ['6002','6004','6042','6031'],
'special_filter' => 'product_code 6021 dengan ctdesc gold dikecualikan'
]);
return $cards;
}
/**
* 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, string $branch = ''): 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', '/');
// Add branch directory if provided
if (!empty($branch)) {
$remotePath = rtrim($remotePath, '/') . '/' . $branch;
// Create branch directory if it doesn't exist
if (!$disk->exists($remotePath)) {
$disk->makeDirectory($remotePath);
}
}
$remoteFilePath = rtrim($remotePath, '/') . '/' . $filename;
// Upload file ke server SFTP
$result = $disk->put($remoteFilePath, $fileContent);
if ($result) {
$this->updateSftpLogSuccess($branch);
Log::info("File CSV biaya kartu ATM untuk cabang {$branch} 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 untuk cabang {$branch} ke SFTP: {$remoteFilePath}");
return false;
}
} catch (Exception $e) {
$this->updateSftpLogFailed($e->getMessage());
Log::error("Error saat mengunggah file ke SFTP untuk cabang {$branch}: " . $e->getMessage(), [
'file' => $e->getFile(),
'line' => $e->getLine(),
'periode' => $this->periode
]);
return false;
}
}
private function updateSftpLogSuccess(string $branch = ''): void
{
$message = 'File berhasil diupload ke SFTP';
if (!empty($branch)) {
$message .= " untuk cabang {$branch}";
}
$this->syncLog->update([
'is_ftp' => true,
'ftp_at' => Carbon::now(),
'ftp_notes' => $message,
'ftp_destination' => env('SFTP_KARTU_HOST', '/'),
]);
Log::info($message . ' untuk periode ' . $this->periode);
}
/**
* 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 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($results): void
{
foreach ($results as $result) {
// Get file info
$fileInfo = pathinfo($result['localFilePath']);
$fileName = $fileInfo['basename'];
$this->syncLog->update([
'is_csv' => true,
'csv_at' => Carbon::now(),
'csv_notes' => 'File CSV untuk cabang ' . $result['branch'] . ' berhasil dibuat: ' . $fileName,
'file_path' => $result['localFilePath'],
'file_name' => $fileName,
]);
Log::info('File CSV untuk cabang ' . $result['branch'] . ' 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);
}
}