diff --git a/app/Jobs/GenerateClosingBalanceReportJob.php b/app/Jobs/GenerateClosingBalanceReportJob.php index 6e290c7..b48c194 100644 --- a/app/Jobs/GenerateClosingBalanceReportJob.php +++ b/app/Jobs/GenerateClosingBalanceReportJob.php @@ -3,7 +3,7 @@ namespace Modules\Webstatement\Jobs; use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue +use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\{InteractsWithQueue, SerializesModels}; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Support\Facades\{DB, Log, Storage}; @@ -209,6 +209,7 @@ class GenerateClosingBalanceReportJob implements ShouldQueue } } + /** * Delete existing processed data dengan verifikasi lengkap * Menghapus data processed yang sudah ada dengan verifikasi untuk memastikan tidak ada sisa @@ -297,6 +298,174 @@ class GenerateClosingBalanceReportJob implements ShouldQueue Log::info('No duplicates found after insert - verification passed', $criteria); } + /** + * Export from database to CSV (very fast) + */ + private function exportFromDatabaseToCsv(): string + { + Log::info('Starting CSV export from database for closing balance report', [ + 'account_number' => $this->accountNumber, + 'period' => $this->period, + 'group_name' => $this->groupName + ]); + + // Create directory structure + $basePath = "closing_balance_reports"; + $accountPath = "{$basePath}/{$this->accountNumber}"; + + Storage::disk($this->disk)->makeDirectory($basePath); + Storage::disk($this->disk)->makeDirectory($accountPath); + + // Generate filename + $fileName = "closing_balance_{$this->accountNumber}_{$this->period}_{$this->groupName}.csv"; + $filePath = "{$accountPath}/{$fileName}"; + + // Delete existing file if exists + if (Storage::disk($this->disk)->exists($filePath)) { + Storage::disk($this->disk)->delete($filePath); + } + + // Create CSV header + $csvHeader = [ + 'NO', + 'TRANS_REFERENCE', + 'BOOKING_DATE', + 'TRANSACTION_DATE', + 'AMOUNT_LCY', + 'DEBIT_ACCT_NO', + 'DEBIT_VALUE_DATE', + 'DEBIT_AMOUNT', + 'CREDIT_ACCT_NO', + 'BIF_RCV_ACCT', + 'BIF_RCV_NAME', + 'CREDIT_VALUE_DATE', + 'CREDIT_AMOUNT', + 'AT_UNIQUE_ID', + 'BIF_REF_NO', + 'ATM_ORDER_ID', + 'RECIPT_NO', + 'API_ISS_ACCT', + 'API_BENFF_ACCT', + 'AUTHORISER', + 'REMARKS', + 'PAYMENT_DETAILS', + 'REF_NO', + 'MERCHANT_ID', + 'TERM_ID', + 'CLOSING_BALANCE' + ]; + + $csvContent = implode('|', $csvHeader) . "\n"; + Storage::disk($this->disk)->put($filePath, $csvContent); + + // Export data from database in chunks dengan ordering berdasarkan booking_date dan date_time + ProcessedClosingBalance::where('account_number', $this->accountNumber) + ->where('period', $this->period) + ->where('group_name', $this->groupName) + ->orderBy('booking_date') + ->orderBy('transaction_date') // Menggunakan transaction_date yang sudah dikonversi dari date_time + ->chunk($this->chunkSize, function ($records) use ($filePath) { + $csvContent = ''; + foreach ($records as $record) { + $csvRow = [ + $record->sequence_no, + $record->trans_reference ?? '', + $record->booking_date ?? '', + $record->transaction_date ?? '', + $record->amount_lcy ?? '', + $record->debit_acct_no ?? '', + $record->debit_value_date ?? '', + $record->debit_amount ?? '', + $record->credit_acct_no ?? '', + $record->bif_rcv_acct ?? '', + $record->bif_rcv_name ?? '', + $record->credit_value_date ?? '', + $record->credit_amount ?? '', + $record->at_unique_id ?? '', + $record->bif_ref_no ?? '', + $record->atm_order_id ?? '', + $record->recipt_no ?? '', + $record->api_iss_acct ?? '', + $record->api_benff_acct ?? '', + $record->authoriser ?? '', + $record->remarks ?? '', + $record->payment_details ?? '', + $record->ref_no ?? '', + $record->merchant_id ?? '', + $record->term_id ?? '', + $record->closing_balance ?? '' + ]; + + $csvContent .= implode('|', $csvRow) . "\n"; + } + + if (!empty($csvContent)) { + Storage::disk($this->disk)->append($filePath, $csvContent); + } + }); + + // Verify file creation + if (!Storage::disk($this->disk)->exists($filePath)) { + throw new Exception("Failed to create CSV file: {$filePath}"); + } + + Log::info('CSV export from database completed successfully', [ + 'file_path' => $filePath, + 'file_size' => Storage::disk($this->disk)->size($filePath) + ]); + + return $filePath; + } + + /** + * Get processed record count + */ + private function getProcessedRecordCount(): int + { + return ProcessedClosingBalance::where('account_number', $this->accountNumber) + ->where('period', $this->period) + ->where('group_name', $this->groupName) + ->count(); + } + + /** + * Get opening balance from account balance table + * Mengambil saldo awal dari tabel account balance + */ + private function getOpeningBalance(): float + { + Log::info('Getting opening balance', [ + 'account_number' => $this->accountNumber, + 'period' => $this->period + ]); + + // Get previous period based on current period + $previousPeriod = $this->period === '20250512' + ? Carbon::createFromFormat('Ymd', $this->period)->subDays(2)->format('Ymd') + : Carbon::createFromFormat('Ymd', $this->period)->subDay()->format('Ymd'); + + $accountBalance = AccountBalance::where('account_number', $this->accountNumber) + ->where('period', $previousPeriod) + ->first(); + + if (!$accountBalance) { + Log::warning('Account balance not found, using 0 as opening balance', [ + 'account_number' => $this->accountNumber, + 'period' => $this->period + ]); + return 0.0; + } + + $openingBalance = (float) $accountBalance->actual_balance; + + Log::info('Opening balance retrieved', [ + 'account_number' => $this->accountNumber, + 'opening_balance' => $openingBalance + ]); + + return $openingBalance; + } + /** * Build transaction query dengan eliminasi duplicate yang efektif * Membangun query transaksi dengan menghilangkan duplicate berdasarkan trans_reference dan amount_lcy @@ -336,10 +505,10 @@ class GenerateClosingBalanceReportJob implements ShouldQueue ->with([ 'ft' => function($query) { $query->select('ref_no', 'date_time', 'debit_acct_no', 'debit_value_date', - 'credit_acct_no', 'bif_rcv_acct', 'bif_rcv_name', 'credit_value_date', - 'at_unique_id', 'bif_ref_no', 'atm_order_id', 'recipt_no', - 'api_iss_acct', 'api_benff_acct', 'authoriser', 'remarks', - 'payment_details', 'ref_no', 'merchant_id', 'term_id'); + 'credit_acct_no', 'bif_rcv_acct', 'bif_rcv_name', 'credit_value_date', + 'at_unique_id', 'bif_ref_no', 'atm_order_id', 'recipt_no', + 'api_iss_acct', 'api_benff_acct', 'authoriser', 'remarks', + 'payment_details', 'ref_no', 'merchant_id', 'term_id'); }, 'dc' => function($query) { $query->select('id', 'date_time');