account_number = $account_number; $this->period = $period; $this->saldo = $saldo; $this->disk = $disk; $this->fileName = "{$account_number}_{$period}.csv"; } /** * Execute the job. */ public function handle() : void { try { Log::info("Starting export statement job for account: {$this->account_number}, period: {$this->period}"); // Cek apakah data sudah diproses sebelumnya $existingData = ProcessedStatement::where('account_number', $this->account_number) ->where('period', $this->period) ->exists(); if (!$existingData) { // Jika belum ada data yang diproses, lakukan pemrosesan $this->processStatementData(); } // Export data yang sudah diproses ke CSV $this->exportToCsv(); Log::info("Export statement job completed successfully for account: {$this->account_number}, period: {$this->period}"); } catch (Exception $e) { Log::error("Error in ExportStatementJob: " . $e->getMessage()); throw $e; } } /** * Process statement data and save to database */ private function processStatementData() : void { // Hapus data yang mungkin sudah ada untuk kombinasi account dan period yang sama ProcessedStatement::where('account_number', $this->account_number) ->where('period', $this->period) ->delete(); $runningBalance = (float) $this->saldo; $totalCount = StmtEntry::where('account_number', $this->account_number) ->where('booking_date', $this->period) ->count(); Log::info("Processing {$totalCount} statement entries for account: {$this->account_number}"); // Proses data dalam chunk untuk mengurangi penggunaan memori StmtEntry::with(['ft', 'transaction']) ->where('account_number', $this->account_number) ->where('booking_date', $this->period) ->orderBy('date_time', 'ASC') ->orderBy('trans_reference', 'ASC') ->chunk($this->chunkSize, function ($entries) use (&$runningBalance) { $processedData = []; foreach ($entries as $index => $item) { $runningBalance += (float) $item->amount_lcy; try { $transactionDate = Carbon::createFromFormat('YmdHi', $item->booking_date . substr($item->ft?->date_time ?? '0000000000', 6, 4)) ->format('d/m/Y H:i'); } catch (Exception $e) { $transactionDate = Carbon::now()->format('d/m/Y H:i'); Log::warning("Error formatting transaction date: " . $e->getMessage()); } try { $actualDate = Carbon::createFromFormat('ymdHi', $item->ft?->date_time ?? '2505120000') ->format('d/m/Y H:i'); } catch (Exception $e) { $actualDate = Carbon::now()->format('d/m/Y H:i'); Log::warning("Error formatting actual date: " . $e->getMessage()); } $processedData[] = [ 'account_number' => $this->account_number, 'period' => $this->period, 'sequence_no' => $index + 1, 'transaction_date' => $transactionDate, 'reference_number' => $item->trans_reference, 'transaction_amount' => $item->amount_lcy, 'transaction_type' => $item->amount_lcy < 0 ? 'D' : 'C', 'description' => $this->generateNarrative($item), 'end_balance' => $runningBalance, 'actual_date' => $actualDate, 'created_at' => now(), 'updated_at' => now(), ]; } // Simpan data dalam batch untuk kinerja yang lebih baik if (!empty($processedData)) { DB::table('processed_statements')->insert($processedData); } }); } /** * Generate narrative for a statement entry */ private function generateNarrative($item) { $narr = ''; if ($item->transaction->narr_type) { $narr .= $item->transaction->stmt_narr . ' '; $narr .= $this->getFormatNarrative($item->transaction->narr_type, $item); } else { $narr .= $item->transaction->stmt_narr . ' '; } if ($item->ft?->recipt_no) { $narr .= 'Receipt No: ' . $item->ft->recipt_no; } return $narr; } /** * Get formatted narrative based on narrative type */ private function getFormatNarrative($narr, $item) { $narrParam = TempStmtNarrParam::where('_id', $narr)->first(); if (!$narrParam) { return ''; } $fmt = ''; if ($narrParam->_id == 'FTIN') { $fmt = 'FT.IN'; } else if ($narrParam->_id == 'FTOUT') { $fmt = 'FT.IN'; } else { $fmt = $narrParam->_id; } $narrFormat = TempStmtNarrFormat::where('_id', $fmt)->first(); if (!$narrFormat) { return ''; } // Get the format string from the database $formatString = $narrFormat->text_data ?? ''; // Parse the format string // Split by the separator ']' $parts = explode(']', $formatString); $result = ''; foreach ($parts as $index => $part) { if (empty($part)) { continue; } if ($index === 0) { // For the first part, take only what's before the '!' $splitPart = explode('!', $part); if (count($splitPart) > 0) { // Remove quotes, backslashes, and other escape characters $cleanPart = trim($splitPart[0]); // Remove quotes at the beginning and end $cleanPart = preg_replace('/^["\'\\\\]+|["\'\\\\]+$/', '', $cleanPart); // Remove any remaining backslashes $cleanPart = str_replace('\\', '', $cleanPart); // Remove any remaining quotes $cleanPart = str_replace('"', '', $cleanPart); $result .= $cleanPart; } } else { // For other parts, these are field placeholders $fieldName = strtolower(str_replace('.', '_', $part)); // Get the corresponding parameter value from narrParam $paramValue = null; // Check if the field exists as a property in narrParam if (property_exists($narrParam, $fieldName)) { $paramValue = $narrParam->$fieldName; } else if (isset($narrParam->$fieldName)) { $paramValue = $narrParam->$fieldName; } // If we found a value, add it to the result if ($paramValue !== null) { $result .= $paramValue; } else { // If no value found, try to use the original field name as a fallback if ($fieldName != 'recipt_no') { $result .= $this->getTransaction($item->trans_reference, $fieldName) . ' '; } } } } return $result; } /** * Get transaction data by reference and field */ private function getTransaction($ref, $field) { $trans = TempFundsTransfer::where('ref_no', $ref)->first(); return $trans->$field ?? ""; } /** * Export processed data to CSV file */ private function exportToCsv() : void { $csvContent = "NO|TRANSACTION.DATE|REFERENCE.NUMBER|TRANSACTION.AMOUNT|TRANSACTION.TYPE|DESCRIPTION|END.BALANCE|ACTUAL.DATE\n"; // Ambil data yang sudah diproses dalam chunk untuk mengurangi penggunaan memori ProcessedStatement::where('account_number', $this->account_number) ->where('period', $this->period) ->orderBy('sequence_no') ->chunk($this->chunkSize, function ($statements) use (&$csvContent) { foreach ($statements as $statement) { $csvContent .= implode('|', [ $statement->sequence_no, $statement->transaction_date, $statement->reference_number, $statement->transaction_amount, $statement->transaction_type, $statement->description, $statement->end_balance, $statement->actual_date ]) . "\n"; } // Tulis ke file secara bertahap untuk mengurangi penggunaan memori Storage::disk($this->disk)->append("statements/{$this->fileName}", $csvContent); $csvContent = ''; // Reset content setelah ditulis }); Log::info("Statement exported to {$this->disk} disk: statements/{$this->fileName}"); } }