Files
webstatement/app/Http/Controllers/CombinePdfController.php
Daeng Deni Mardaeni 3720a24690 feat(webstatement): dukung multiple file r23 pada proses combine PDF
- Memperbarui `CombinePdfController`:
  - Menambahkan logika untuk mendukung multiple file r23, baik dari `local` maupun `sftp`.
  - Mengimplementasikan pencarian file secara dinamis menggunakan pola glob untuk file lokal (`local`).
  - Menambahkan proses pengunduhan file r23 secara bertahap berdasarkan urutan dari SFTP.
  - Menyortir file r23 berdasarkan urutan numerik untuk memastikan urutan yang benar dalam penggabungan PDF.
  - Memindahkan semua file r23 ke direktori sementara sebelum proses gabungan.

- Memungkinkan konfigurasi sumber file r23:
  - Jika `local`, sistem akan mencari semua file dengan nama akun dan variasi urutan di folder penyimpanan lokal.
  - Jika `sftp`, sistem akan mengunduh semua file r23 dengan pola tertentu dari SFTP dan menyimpannya secara temporer.

- Memperbarui log:
  - Menambahkan informasi jumlah file r23 yang ditemukan untuk setiap akun.
  - Menambahkan log error detail saat terjadi kegagalan pengunduhan file dari SFTP.

Signed-off-by: Daeng Deni Mardaeni <ddeni05@gmail.com>
2025-06-08 10:33:27 +07:00

216 lines
8.3 KiB
PHP

<?php
namespace Modules\Webstatement\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
use Modules\Webstatement\Jobs\CombinePdfJob;
use Modules\Webstatement\Models\Account;
use Carbon\Carbon;
class CombinePdfController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
return view('webstatement::index');
}
/**
* Combine PDF files from r14 and r23 folders for all accounts
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function combinePdfs($period)
{
// Configuration: Set r23 file source - 'local' or 'sftp'
$file_r23 = 'local'; // Change this to 'sftp' to use SFTP for r23 files
// Configuration: Set output destination - 'local' or 'sftp'
$output_destination = 'local'; // Change this to 'sftp' to upload combined PDFs to SFTP
// Get period from request or use current period
$period = $period ?? date('Ym');
// Get all accounts with customer relation
$accounts = Account::where('branch_code','ID0010052')->get();
$processedCount = 0;
$skippedCount = 0;
$errorCount = 0;
foreach ($accounts as $account) {
$branchCode = $account->branch_code;
$accountNumber = $account->account_number;
// Define file paths
$r14Path = storage_path("app/r14/{$accountNumber}_{$period}.pdf");
// Define temporary path for r23 files downloaded from SFTP
$tempDir = storage_path("app/temp/{$period}");
if (!File::exists($tempDir)) {
File::makeDirectory($tempDir, 0755, true);
}
$outputDir = storage_path("app/combine/{$period}/{$branchCode}");
$outputFilename = "{$accountNumber}_{$period}.pdf";
// Check if r14 file exists locally
$r14Exists = File::exists($r14Path);
// Check for multiple r23 files based on configuration
$r23Files = [];
$r23Exists = false;
if ($file_r23 === 'local') {
// Use local r23 files - check for multiple files
$r23Pattern = storage_path("app/r23/{$accountNumber}.*.pdf");
$foundR23Files = glob($r23Pattern);
if (!empty($foundR23Files)) {
// Sort files numerically by their sequence number
usort($foundR23Files, function($a, $b) {
preg_match('/\.(\d+)\.pdf$/', $a, $matchesA);
preg_match('/\.(\d+)\.pdf$/', $b, $matchesB);
return (int)$matchesA[1] - (int)$matchesB[1];
});
$r23Files = $foundR23Files;
$r23Exists = true;
Log::info("Found " . count($r23Files) . " r23 files locally for account {$accountNumber}");
}
} elseif ($file_r23 === 'sftp') {
// Use SFTP r23 files - check for multiple files
try {
$sftpFiles = Storage::disk('sftpStatement')->files('r23');
$accountR23Files = array_filter($sftpFiles, function($file) use ($accountNumber) {
return preg_match("/r23\/{$accountNumber}\.(\d+)\.pdf$/", $file);
});
if (!empty($accountR23Files)) {
// Sort files numerically by their sequence number
usort($accountR23Files, function($a, $b) {
preg_match('/\.(\d+)\.pdf$/', $a, $matchesA);
preg_match('/\.(\d+)\.pdf$/', $b, $matchesB);
return (int)$matchesA[1] - (int)$matchesB[1];
});
// Download all r23 files
foreach ($accountR23Files as $index => $sftpFile) {
$r23Content = Storage::disk('sftpStatement')->get($sftpFile);
$tempFileName = "{$tempDir}/{$accountNumber}_r23_" . ($index + 1) . ".pdf";
File::put($tempFileName, $r23Content);
$r23Files[] = $tempFileName;
}
$r23Exists = true;
Log::info("Downloaded " . count($r23Files) . " r23 files for account {$accountNumber} from SFTP");
}
} catch (\Exception $e) {
Log::error("Error downloading r23 files from SFTP for account {$accountNumber}: {$e->getMessage()}");
}
}
// Skip if neither file exists
if (!$r14Exists && !$r23Exists) {
//Log::warning("No PDF files found for account {$accountNumber}");
$skippedCount++;
continue;
}
// Prepare file list for processing
$pdfFiles = [];
if ($r14Exists) {
$pdfFiles[] = $r14Path;
}
if ($r23Exists) {
// Add all r23 files to the list
$pdfFiles = array_merge($pdfFiles, $r23Files);
}
try {
// Generate password based on customer relation data
$password = $this->generatePassword($account);
// Dispatch job to combine PDFs or apply password protection
CombinePdfJob::dispatch($pdfFiles, $outputDir, $outputFilename, $password, $output_destination, $branchCode, $period);
$processedCount++;
Log::info("Queued PDF processing for account {$accountNumber} - r14: local, r23: {$file_r23}, output: {$output_destination}, password: {$password}");
} catch (\Exception $e) {
Log::error("Error processing PDF for account {$accountNumber}: {$e->getMessage()}");
$errorCount++;
}
}
Log::info("Processed {$processedCount} accounts, skipped {$skippedCount} accounts, and encountered {$errorCount} errors.");
return response()->json([
'message' => "PDF combination process has been queued (r14: local, r23: {$file_r23}, output: {$output_destination})",
'processed' => $processedCount,
'skipped' => $skippedCount,
'errors' => $errorCount,
'period' => $period
]);
}
/**
* Generate password based on customer relation data
* Format: date+end 2 digit account_number
* Example: 05Oct202585
*
* @param Account $account
* @return string
*/
private function generatePassword(Account $account)
{
$customer = $account->customer;
$accountNumber = $account->account_number;
// Get last 2 digits of account number
$lastTwoDigits = substr($accountNumber, -2);
// Determine which date to use based on sector
$dateToUse = null;
if ($customer && $customer->sector) {
$firstDigitSector = substr($customer->sector, 0, 1);
if ($firstDigitSector === '1') {
// Use date_of_birth if available, otherwise birth_incorp_date
$dateToUse = $customer->date_of_birth ?: $customer->birth_incorp_date;
} else {
// Use birth_incorp_date for sector > 1
$dateToUse = $customer->birth_incorp_date;
}
}
// If no date found, fallback to account number
if (!$dateToUse) {
Log::warning("No date found for account {$accountNumber}, using account number as password");
return $accountNumber;
}
try {
// Parse the date and format it
$date = Carbon::parse($dateToUse);
$day = $date->format('d');
$month = $date->format('M'); // 3-letter month abbreviation
$year = $date->format('Y');
// Format: ddMmmyyyyXX (e.g., 05Oct202585)
$password = $day . $month . $year . $lastTwoDigits;
return $password;
} catch (\Exception $e) {
Log::error("Error parsing date for account {$accountNumber}: {$e->getMessage()}");
return $accountNumber; // Fallback to account number
}
}
}