feat(webstatement): tambahkan pengelolaan kartu ATM dengan fitur batch processing dan CSV tunggal

- **Penambahan Fitur**:
  - Menambahkan metode baru `generateSingleAtmCardCsv` untuk membuat file CSV tunggal tanpa pemisahan cabang:
    - Mencakup seluruh data kartu ATM yang memenuhi syarat.
    - File diunggah ke SFTP tanpa direktori spesifik cabang.
  - Implementasi command `UpdateAllAtmCardsCommand` untuk batch update:
    - Dukungan konfigurasi parameter seperti batch size, ID log sinkronisasi, queue, filter, dan dry-run.

- **Optimasi Logging**:
  - Logging rinci ditambahkan pada semua proses, termasuk:
    - Generasi CSV tunggal.
    - Proses upload CSV ke SFTP.
    - Pembaruan atau pembuatan `KartuSyncLog` dalam batch processing.
    - Progress dan status tiap batch.
    - Error handling dengan detail informasi pada setiap exception.

- **Perbaikan dan Penyesuaian Job**:
  - Penambahan `UpdateAllAtmCardsBatchJob` yang mengatur proses batch update:
    - Mendukung operasi batch dengan pengaturan ukuran dan parameter filtering kartu.
    - Pencatatan log progres secara dinamis dengan kalkulasi batch dan persentase.
    - Menyusun delay antar job untuk performa yang lebih baik.
  - Menyertakan validasi untuk sinkronisasi dan pembaruan data kartu ATM.

- **Refaktor Provider**:
  - Pendaftaran command baru:
    - `UpdateAllAtmCardsCommand` untuk batch update seluruh kartu ATM.
    - Command disertakan dalam provider `WebstatementServiceProvider`.

- **Error Handling**:
  - Peningkatan mekanisme rollback pada database saat error.
  - Menambahkan notifikasi log `failure` apabila job gagal dijalankan.

- **Dokumentasi dan Komentar**:
  - Menambahkan komentar mendetail pada setiap fungsi baru untuk penjelasan lebih baik.
  - Mendokumentasikan seluruh proses dan perubahan pada job serta command baru terkait kartu ATM.

  Perubahan ini meningkatkan efisiensi pengelolaan data kartu ATM, termasuk generasi CSV, proses batch, dan pengunggahan data ke SFTP.

Signed-off-by: Daeng Deni Mardaeni <ddeni05@gmail.com>
This commit is contained in:
Daeng Deni Mardaeni
2025-06-16 22:51:26 +07:00
parent 7b32cb8d39
commit 4bfd937490
4 changed files with 648 additions and 4 deletions

View File

@@ -63,7 +63,9 @@
$this->updateCsvLogStart();
// Generate CSV file
$result = $this->generateAtmCardCsv();
// $result = $this->generateAtmCardCsv();
$result = $this->generateSingleAtmCardCsv();
// Update status CSV generation berhasil
$this->updateCsvLogSuccess($result);
@@ -415,4 +417,155 @@
Log::error('Pembuatan file CSV gagal: ' . $errorMessage);
}
/**
* Generate single CSV file with all ATM card data without branch separation
*
* @return array Information about the generated file and upload status
* @throws RuntimeException
*/
private function generateSingleAtmCardCsv(): array
{
Log::info('Memulai pembuatan file CSV tunggal untuk semua kartu ATM');
try {
// Ambil semua kartu yang memenuhi syarat
$cards = $this->getEligibleAtmCards();
if ($cards->isEmpty()) {
Log::warning('Tidak ada kartu ATM yang memenuhi syarat untuk periode ini');
throw new RuntimeException('Tidak ada kartu ATM yang memenuhi syarat untuk diproses');
}
// Buat nama file dengan timestamp
$dateTime = now()->format('Ymd_Hi');
$singleFilename = pathinfo($this->csvFilename, PATHINFO_FILENAME)
. '_ALL_BRANCHES_'
. $dateTime . '.'
. pathinfo($this->csvFilename, PATHINFO_EXTENSION);
$filename = storage_path('app/' . $singleFilename);
Log::info('Membuat file CSV: ' . $filename);
// Buka file untuk menulis
$handle = fopen($filename, 'w+');
if (!$handle) {
throw new RuntimeException("Tidak dapat membuat file CSV: $filename");
}
$recordCount = 0;
try {
// Tulis semua kartu ke dalam satu file
foreach ($cards as $card) {
$fee = $this->determineCardFee($card);
$csvRow = $this->createCsvRow($card, $fee);
if (fputcsv($handle, $csvRow, '|') === false) {
throw new RuntimeException("Gagal menulis data kartu ke file CSV: {$card->crdno}");
}
$recordCount++;
// Log progress setiap 1000 record
if ($recordCount % 1000 === 0) {
Log::info("Progress: {$recordCount} kartu telah diproses");
}
}
} finally {
fclose($handle);
}
Log::info("Selesai menulis {$recordCount} kartu ke file CSV");
// Bersihkan file CSV (hapus double quotes)
$this->cleanupCsvFile($filename);
Log::info('File CSV berhasil dibersihkan dari double quotes');
// Upload file ke SFTP (tanpa branch specific directory)
$uploadSuccess = true; // $this->uploadSingleFileToSftp($filename);
$result = [
'localFilePath' => $filename,
'recordCount' => $recordCount,
'uploadToSftp' => $uploadSuccess,
'timestamp' => now()->format('Y-m-d H:i:s'),
'fileName' => $singleFilename
];
Log::info('Pembuatan file CSV tunggal selesai', $result);
return $result;
} catch (Exception $e) {
Log::error('Error dalam generateSingleAtmCardCsv: ' . $e->getMessage(), [
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString()
]);
throw $e;
}
}
/**
* Upload single CSV file to SFTP server without branch directory
*
* @param string $localFilePath Path to the local CSV file
* @return bool True if upload successful, false otherwise
*/
private function uploadSingleFileToSftp(string $localFilePath): bool
{
try {
Log::info('Memulai upload file tunggal ke SFTP: ' . $localFilePath);
// 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 (root directory)
$remotePath = env('BIAYA_KARTU_REMOTE_PATH', '/');
$remoteFilePath = rtrim($remotePath, '/') . '/' . $filename;
Log::info('Mengunggah ke path remote: ' . $remoteFilePath);
// Upload file ke server SFTP
$result = $disk->put($remoteFilePath, $fileContent);
if ($result) {
$this->updateSftpLogSuccess();
Log::info("File CSV tunggal berhasil diunggah ke SFTP: {$remoteFilePath}");
return true;
} else {
$errorMsg = "Gagal mengunggah file CSV tunggal ke SFTP: {$remoteFilePath}";
$this->updateSftpLogFailed($errorMsg);
Log::error($errorMsg);
return false;
}
} catch (Exception $e) {
$errorMsg = "Error saat mengunggah file tunggal ke SFTP: " . $e->getMessage();
$this->updateSftpLogFailed($errorMsg);
Log::error($errorMsg, [
'file' => $e->getFile(),
'line' => $e->getLine(),
'periode' => $this->periode
]);
return false;
}
}
}