From 57463f2429669f753cc354c49864d0498f173fa0 Mon Sep 17 00:00:00 2001 From: Daeng Deni Mardaeni Date: Fri, 23 May 2025 21:28:39 +0700 Subject: [PATCH] fix(webstatement): optimasi proses pengelolaan statement dan perbaikan logika pemrosesan data - Menghilangkan pengecekan data yang sebelumnya diproses dengan memindahkan logika perbandingan jumlah data ke dalam fungsi `processStatementData`. - Menambahkan beberapa fungsi baru untuk memisahkan logika ke dalam unit yang lebih kecil: 1. `getTotalEntryCount`: Menghitung total jumlah data berdasarkan kriteria akun dan periode. 2. `getExistingProcessedCount`: Menghitung jumlah data yang sudah diproses. 3. `deleteExistingProcessedData`: Menghapus data hasil proses sebelumnya jika ada ketidaksesuaian jumlah. 4. `processAndSaveStatementEntries`: Memproses dan menyimpan data dalam batch untuk efisiensi memori. 5. `prepareProcessedData`: Menyiapkan array data hasil pemrosesan sebelum disimpan ke database. 6. `formatTransactionDate`: Memformat tanggal transaksi dengan logika fallback pada error parsing. 7. `formatActualDate`: Memformat tanggal aktual dengan fallback dan logging untuk error parsing. - Memperbaiki logika pemrosesan data statement: - Menambahkan validasi jumlah data yang diproses untuk menghindari duplikasi atau penghapusan data yang tidak semestinya. - Menghapus semua data hasil proses sebelumnya untuk satu kombinasi akun dan periode hanya jika terjadi ketidaksesuaian jumlah data. - Menggunakan chunk batch untuk memproses data dengan lebih efisien, mengurangi penggunaan memori, dan meningkatkan kestabilan aplikasi. - Menyempurnakan logging untuk memberikan informasi lebih rinci terkait proses pemrosesan data dan mengantisipasi error. - Mengubah format data waktu pada proses narasi dengan fallback yang lebih aman guna mencegah kegagalan parsing. - Menambahkan penghapusan data lama sebelum proses penyimpanan ulang guna memastikan konsistensi. Signed-off-by: Daeng Deni Mardaeni --- app/Jobs/ExportStatementJob.php | 172 +++++++++++++++++++------------- 1 file changed, 103 insertions(+), 69 deletions(-) diff --git a/app/Jobs/ExportStatementJob.php b/app/Jobs/ExportStatementJob.php index b0b5d30..93861e3 100644 --- a/app/Jobs/ExportStatementJob.php +++ b/app/Jobs/ExportStatementJob.php @@ -55,15 +55,7 @@ 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(); - } + $this->processStatementData(); // Export data yang sudah diproses ke CSV $this->exportToCsv(); @@ -75,77 +67,119 @@ } } - /** - * Process statement data and save to database - */ - private function processStatementData() - : void + 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(); + $accountQuery = [ + 'account_number' => $this->account_number, + 'period' => $this->period + ]; + $totalCount = $this->getTotalEntryCount($accountQuery); + $existingDataCount = $this->getExistingProcessedCount($accountQuery); + + // Hanya proses jika data belum lengkap diproses + if ($existingDataCount !== $totalCount) { + $this->deleteExistingProcessedData($accountQuery); + $this->processAndSaveStatementEntries($totalCount); + } + } + + private function getTotalEntryCount(array $criteria): int + { + return StmtEntry::where('account_number', $criteria['account_number']) + ->where('booking_date', $criteria['period']) + ->count(); + } + + private function getExistingProcessedCount(array $criteria): int + { + return ProcessedStatement::where('account_number', $criteria['account_number']) + ->where('period', $criteria['period']) + ->count(); + } + + private function deleteExistingProcessedData(array $criteria): void + { + ProcessedStatement::where('account_number', $criteria['account_number']) + ->where('period', $criteria['period']) + ->delete(); + } + + private function processAndSaveStatementEntries(int $totalCount): void + { $runningBalance = (float) $this->saldo; - $totalCount = StmtEntry::where('account_number', $this->account_number) - ->where('booking_date', $this->period) - ->count(); + $globalSequence = 0; Log::info("Processing {$totalCount} statement entries for account: {$this->account_number}"); - // Track the global sequence number across chunks - $globalSequence = 0; - - // 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, &$globalSequence) { - $processedData = []; + ->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, &$globalSequence) { + $processedData = $this->prepareProcessedData($entries, $runningBalance, $globalSequence); - foreach ($entries as $item) { - $globalSequence++; // Increment the global sequence counter - $runningBalance += (float) $item->amount_lcy; + if (!empty($processedData)) { + DB::table('processed_statements')->insert($processedData); + } + }); + } - 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()); - } + private function prepareProcessedData($entries, &$runningBalance, &$globalSequence): array + { + $processedData = []; - 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()); - } + foreach ($entries as $item) { + $globalSequence++; + $runningBalance += (float) $item->amount_lcy; - $processedData[] = [ - 'account_number' => $this->account_number, - 'period' => $this->period, - 'sequence_no' => $globalSequence, - '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(), - ]; - } - // var_dump($processedData); - // Simpan data dalam batch untuk kinerja yang lebih baik - if (!empty($processedData)) { - DB::table('processed_statements')->insert($processedData); - } - }); + $transactionDate = $this->formatTransactionDate($item); + $actualDate = $this->formatActualDate($item); + + $processedData[] = [ + 'account_number' => $this->account_number, + 'period' => $this->period, + 'sequence_no' => $globalSequence, + '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(), + ]; + } + + return $processedData; + } + + private function formatTransactionDate($item): string + { + try { + return Carbon::createFromFormat( + 'YmdHi', + $item->booking_date . substr($item->ft?->date_time ?? '0000000000', 6, 4) + )->format('d/m/Y H:i'); + } catch (Exception $e) { + Log::warning("Error formatting transaction date: " . $e->getMessage()); + return Carbon::now()->format('d/m/Y H:i'); + } + } + + private function formatActualDate($item): string + { + try { + return Carbon::createFromFormat( + 'ymdHi', + $item->ft?->date_time ?? '2505120000' + )->format('d/m/Y H:i'); + } catch (Exception $e) { + Log::warning("Error formatting actual date: " . $e->getMessage()); + return Carbon::now()->format('d/m/Y H:i'); + } } /**