feat(webstatement): implementasi pemrosesan multi account statement berdasarkan stmt_sent_type

- Modifikasi method printStatementRekening untuk mendukung request_type multi_account
- Tambah method processMultiAccountStatement untuk mengambil data account berdasarkan branch_code dan stmt_sent_type
- Tambah method processSingleAccountStatement untuk memisahkan logika single account
- Implementasi GenerateMultiAccountPdfJob untuk generate PDF multiple account secara parallel
- Tambah fungsi generateAccountPdf untuk generate PDF per account dengan Browsershot
- Tambah fungsi createZipFile untuk mengompres multiple PDF menjadi satu ZIP file
- Tambah method downloadMultiAccountZip untuk download ZIP file hasil pemrosesan
- Implementasi validasi stmt_sent_type dengan support JSON array format
- Tambah logging komprehensif untuk monitoring proses multi account
- Tambah error handling dengan database transaction rollback
- Update PrintStatementLog dengan informasi target_accounts dan status pemrosesan
- Tambah rute baru untuk download ZIP file multi account
- Support untuk pemrosesan chunk account untuk optimasi memory usage
- Implementasi status tracking untuk success_count dan failed_count
- Tambah validasi keberadaan account berdasarkan kriteria yang ditentukan
This commit is contained in:
Daeng Deni Mardaeni
2025-07-09 17:51:57 +07:00
parent 51697f017e
commit 8ee0dd2218
5 changed files with 620 additions and 24 deletions

View File

@@ -6,20 +6,17 @@ use App\Http\Controllers\Controller;
use Carbon\Carbon;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\{Auth, DB, Log, Mail, Storage};
use Illuminate\Validation\Rule;
use Modules\Basicdata\Models\Branch;
use Modules\Webstatement\{
Http\Requests\PrintStatementRequest,
Mail\StatementEmail,
Models\PrintStatementLog,
Models\Account,
Models\AccountBalance,
Jobs\ExportStatementPeriodJob
};
use Modules\Webstatement\Models\ProcessedStatement;
use ZipArchive;
use Modules\Webstatement\Http\Requests\PrintStatementRequest;
use Modules\Webstatement\Jobs\{ExportStatementPeriodJob, GenerateMultiAccountPdfJob};
use Modules\Webstatement\Mail\StatementEmail;
use Modules\Webstatement\Models\{Account, AccountBalance, PrintStatementLog, ProcessedStatement};
use Spatie\Browsershot\Browsershot;
use ZipArchive;
ini_set('memory_limit', '2G'); // Atau '1G' untuk data yang sangat besar
ini_set('max_execution_time', 300000);
class PrintStatementController extends Controller
{
@@ -83,7 +80,7 @@ use Spatie\Browsershot\Browsershot;
$validated = $request->validated();
$validated['request_type'] = 'single_account'; // Default untuk request manual
if($validated['branch_code'] && $validated['stmt_sent_type']){
if($validated['branch_code'] && !empty($validated['stmt_sent_type'])){
$validated['request_type'] = 'multi_account'; // Default untuk request manual
}
@@ -99,9 +96,9 @@ use Spatie\Browsershot\Browsershot;
$validated['processed_accounts'] = 0;
$validated['success_count'] = 0;
$validated['failed_count'] = 0;
$validated['stmt_sent_type'] = $request->input('stmt_sent_type') ? implode(',', $request->input('stmt_sent_type')) : '';
$validated['stmt_sent_type'] = $request->input('stmt_sent_type') ? json_encode($request->input('stmt_sent_type')) : '';
$validated['branch_code'] = $validated['branch_code'] ?? $branch_code; // Awal tidak tersedia
// Create the statement log
$statement = PrintStatementLog::create($validated);
@@ -942,7 +939,7 @@ use Spatie\Browsershot\Browsershot;
->format('A4')
->margins(0, 0, 0, 0)
->waitUntilNetworkIdle()
->timeout(60)
->timeout(6000)
->save($tempPath);
// Verifikasi file berhasil dibuat
@@ -1275,7 +1272,157 @@ use Spatie\Browsershot\Browsershot;
}
}
/**
* Process statement untuk multi account berdasarkan stmt_sent_type
*
* @param PrintStatementLog $statement
* @return \Illuminate\Http\JsonResponse
*/
function printStatementRekening($statement) {
try {
// DB::beginTransaction();
Log::info('Starting statement processing', [
'statement_id' => $statement->id,
'request_type' => $statement->request_type,
'stmt_sent_type' => $statement->stmt_sent_type,
'branch_code' => $statement->branch_code
]);
if ($statement->request_type === 'multi_account') {
return $this->processMultiAccountStatement($statement);
} else {
return $this->processSingleAccountStatement($statement);
}
} catch (\Exception $e) {
//DB::rollBack();
Log::error('Failed to process statement', [
'error' => $e->getMessage(),
'statement_id' => $statement->id,
'trace' => $e->getTraceAsString()
]);
return response()->json([
'success' => false,
'message' => 'Failed to process statement',
'error' => $e->getMessage()
], 500);
}
}
/**
* Process multi account statement berdasarkan stmt_sent_type
*
* @param PrintStatementLog $statement
* @return \Illuminate\Http\JsonResponse
*/
protected function processMultiAccountStatement($statement)
{
try {
$period = $statement->period_from ?? date('Ym');
$clientName = 'client1';
// Validasi stmt_sent_type
if (empty($statement->stmt_sent_type)) {
throw new \Exception('stmt_sent_type is required for multi account processing');
}
// Decode stmt_sent_type jika dalam format JSON array
$stmtSentTypes = is_string($statement->stmt_sent_type)
? json_decode($statement->stmt_sent_type, true)
: $statement->stmt_sent_type;
if (!is_array($stmtSentTypes)) {
$stmtSentTypes = [$stmtSentTypes];
}
Log::info('Processing multi account statement', [
'statement_id' => $statement->id,
'branch_code' => $statement->branch_code,
'stmt_sent_types' => $stmtSentTypes,
'period' => $period
]);
// Ambil accounts berdasarkan branch_code dan stmt_sent_type
$accounts = Account::where('branch_code', $statement->branch_code)
->whereIn('stmt_sent_type', $stmtSentTypes)
->with('customer')
->get();
if ($accounts->isEmpty()) {
throw new \Exception('No accounts found for the specified criteria');
}
Log::info('Found accounts for processing', [
'total_accounts' => $accounts->count(),
'branch_code' => $statement->branch_code,
'stmt_sent_types' => $stmtSentTypes
]);
// Update statement log dengan informasi accounts
$accountNumbers = $accounts->pluck('account_number')->toArray();
$statement->update([
'target_accounts' => $accountNumbers,
'total_accounts' => $accounts->count(),
'status' => 'processing',
'started_at' => now()
]);
// Dispatch job untuk generate PDF multi account
$job = GenerateMultiAccountPdfJob::dispatch(
$statement,
$accounts,
$period,
$clientName
);
DB::commit();
Log::info('Multi account PDF generation job dispatched', [
'job_id' => $job->job_id ?? null,
'statement_id' => $statement->id,
'total_accounts' => $accounts->count(),
'period' => $period
]);
return response()->json([
'success' => true,
'message' => 'Multi account statement processing queued successfully',
'data' => [
'job_id' => $job->job_id ?? null,
'statement_id' => $statement->id,
'total_accounts' => $accounts->count(),
'account_numbers' => $accountNumbers,
'period' => $period,
'client_name' => $clientName
]
]);
} catch (\Exception $e) {
DB::rollBack();
Log::error('Failed to process multi account statement', [
'error' => $e->getMessage(),
'statement_id' => $statement->id,
'trace' => $e->getTraceAsString()
]);
throw $e;
}
}
/**
* Process single account statement (existing logic)
*
* @param PrintStatementLog $statement
* @return \Illuminate\Http\JsonResponse
*/
protected function processSingleAccountStatement($statement)
{
$accountNumber = $statement->account_number;
$period = $statement->period_from ?? date('Ym');
$balance = AccountBalance::where('account_number', $accountNumber)
@@ -1301,7 +1448,7 @@ use Spatie\Browsershot\Browsershot;
}
// Dispatch the job
$job = ExportStatementPeriodJob::dispatch($statement, $accountNumber, $period, $balance, $clientName);
$job = ExportStatementPeriodJob::dispatch($statement->id, $accountNumber, $period, $balance, $clientName);
Log::info("Statement export job dispatched successfully", [
'job_id' => $job->job_id ?? null,
@@ -1335,4 +1482,80 @@ use Spatie\Browsershot\Browsershot;
]);
}
}
/**
* Download ZIP file untuk multi account statement
*
* @param int $statementId
* @return \Illuminate\Http\Response
*/
public function downloadMultiAccountZip($statementId)
{
try {
$statement = PrintStatementLog::findOrFail($statementId);
if ($statement->request_type !== 'multi_account') {
return response()->json([
'success' => false,
'message' => 'This statement is not a multi account request'
], 400);
}
if (!$statement->is_available) {
return response()->json([
'success' => false,
'message' => 'Statement files are not available for download'
], 404);
}
// Find ZIP file
$zipFiles = Storage::disk('local')->files("statements/{$statement->period_from}/multi_account/{$statementId}");
$zipFile = null;
foreach ($zipFiles as $file) {
if (pathinfo($file, PATHINFO_EXTENSION) === 'zip') {
$zipFile = $file;
break;
}
}
if (!$zipFile || !Storage::disk('local')->exists($zipFile)) {
return response()->json([
'success' => false,
'message' => 'ZIP file not found'
], 404);
}
$zipPath = Storage::disk('local')->path($zipFile);
$filename = basename($zipFile);
// Update download status
$statement->update([
'is_downloaded' => true,
'downloaded_at' => now()
]);
Log::info('Multi account ZIP downloaded', [
'statement_id' => $statementId,
'zip_file' => $zipFile,
'user_id' => auth()->id()
]);
return response()->download($zipPath, $filename, [
'Content-Type' => 'application/zip'
]);
} catch (Exception $e) {
Log::error('Failed to download multi account ZIP', [
'statement_id' => $statementId,
'error' => $e->getMessage()
]);
return response()->json([
'success' => false,
'message' => 'Failed to download ZIP file',
'error' => $e->getMessage()
], 500);
}
}
}