From 13e077073bf8c01f6d7f1b6a736491cbf59bc2a7 Mon Sep 17 00:00:00 2001 From: Daeng Deni Mardaeni Date: Thu, 31 Jul 2025 10:35:05 +0700 Subject: [PATCH] fix(closing-balance): Perbaikan logika pengecekan duplikasi untuk memperbolehkan trans_reference duplikat dengan amount_lcy berbeda - Mengubah kriteria pengecekan duplikasi dari hanya trans_reference menjadi kombinasi trans_reference + amount_lcy - Memperbarui query existingReferences untuk memeriksa kombinasi trans_reference dan amount_lcy - Memperbolehkan trans_reference yang sama selama amount_lcy berbeda value - Menambahkan validasi yang lebih presisi untuk mencegah duplikasi data yang sebenarnya - Mengurangi false positive pada pengecekan duplikasi --- app/Jobs/GenerateClosingBalanceReportJob.php | 73 ++++++++++++++------ 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/app/Jobs/GenerateClosingBalanceReportJob.php b/app/Jobs/GenerateClosingBalanceReportJob.php index b48c194..6eb82bb 100644 --- a/app/Jobs/GenerateClosingBalanceReportJob.php +++ b/app/Jobs/GenerateClosingBalanceReportJob.php @@ -467,12 +467,12 @@ class GenerateClosingBalanceReportJob implements ShouldQueue } /** - * Build transaction query dengan eliminasi duplicate yang efektif - * Membangun query transaksi dengan menghilangkan duplicate berdasarkan trans_reference dan amount_lcy + * Build transaction query dengan eliminasi duplicate yang lebih ketat + * Membangun query transaksi dengan menghilangkan duplicate berdasarkan kombinasi lengkap */ private function buildTransactionQuery() { - Log::info('Building transaction query with effective duplicate elimination', [ + Log::info('Building transaction query with strict duplicate elimination', [ 'group_name' => $this->groupName, 'account_number' => $this->accountNumber, 'period' => $this->period @@ -481,20 +481,19 @@ class GenerateClosingBalanceReportJob implements ShouldQueue $modelClass = $this->getModelByGroup(); $tableName = (new $modelClass)->getTable(); - // PERBAIKAN: Gunakan subquery untuk mendapatkan ID unik berdasarkan trans_reference + amount_lcy - // Karena trans_reference sudah unique, fokus pada kombinasi trans_reference + amount_lcy + // Gunakan kombinasi lengkap untuk eliminasi duplikasi $uniqueIds = DB::table($tableName) ->select(DB::raw('MIN(id) as min_id')) ->where('account_number', $this->accountNumber) ->where('booking_date', $this->period) - ->groupBy('trans_reference', 'amount_lcy') // Simplified grouping + ->groupBy('trans_reference', 'amount_lcy', 'booking_date') // Kombinasi lengkap ->pluck('min_id'); - Log::info('Unique transaction IDs identified based on trans_reference + amount_lcy', [ - 'total_unique_transactions' => $uniqueIds->count() + Log::info('Unique transaction IDs identified', [ + 'total_unique_transactions' => $uniqueIds->count(), + 'elimination_criteria' => 'trans_reference + amount_lcy + booking_date' ]); - // Query hanya transaksi dengan ID yang unik $query = $modelClass::select([ 'id', 'trans_reference', @@ -518,24 +517,53 @@ class GenerateClosingBalanceReportJob implements ShouldQueue ->orderBy('booking_date') ->orderBy('date_time'); - Log::info('Transaction query built successfully with simplified duplicate elimination', [ - 'model_class' => $modelClass, - 'table_name' => $tableName, - 'unique_transactions' => $uniqueIds->count() - ]); - return $query; } /** - * Prepare processed closing balance data tanpa validasi duplicate (sudah dieliminasi di query) - * Mempersiapkan data closing balance tanpa perlu validasi duplicate lagi + * Prepare processed closing balance data dengan validasi duplikasi yang ketat + * Mempersiapkan data closing balance dengan pencegahan duplikasi berbasis trans_reference unik */ private function prepareProcessedClosingBalanceData($transactions, &$runningBalance, &$sequenceNo): array { $processedData = []; + $seenReferences = []; + + // Buat lookup array untuk validasi cepat - periksa kombinasi trans_reference + amount_lcy + $existingReferences = ProcessedClosingBalance::where('account_number', $this->accountNumber) + ->where('period', $this->period) + ->where('group_name', $this->groupName) + ->get(['trans_reference', 'amount_lcy']) + ->map(function ($item) { + return md5($item->trans_reference . '_' . $item->amount_lcy); + }) + ->toArray(); + + // Buat lookup array untuk validasi cepat + $existingReferences = array_flip($existingReferences); foreach ($transactions as $transaction) { + // Validasi duplikasi berbasis trans_reference + amount_lcy + booking_date + $uniqueKey = md5($transaction->trans_reference . '_' . $transaction->amount_lcy); + + if (isset($seenReferences[$uniqueKey])) { + Log::warning('Duplicate transaction skipped', [ + 'trans_reference' => $transaction->trans_reference, + 'amount_lcy' => $transaction->amount_lcy + ]); + continue; + } + + // Periksa kombinasi trans_reference + amount_lcy, bukan hanya trans_reference + if (isset($existingReferences[$uniqueKey])) { + Log::warning('Transaction already exists in database', [ + 'trans_reference' => $transaction->trans_reference, + 'amount_lcy' => $transaction->amount_lcy + ]); + continue; + } + + $seenReferences[$uniqueKey] = true; $sequenceNo++; // Process transaction data @@ -548,7 +576,7 @@ class GenerateClosingBalanceReportJob implements ShouldQueue // Format transaction date $transactionDate = $this->formatDateTime($processedTransactionData['date_time']); - // Prepare data for database insert + // Prepare data untuk database insert dengan composite key yang lebih robust $processedData[] = [ 'account_number' => $this->accountNumber, 'period' => $this->period, @@ -580,12 +608,15 @@ class GenerateClosingBalanceReportJob implements ShouldQueue 'term_id' => $processedTransactionData['term_id'], 'closing_balance' => $runningBalance, 'created_at' => now(), - 'updated_at' => now() + 'updated_at' => now(), + // Tambahkan hash unik untuk memastikan keunikan + 'unique_hash' => md5($this->accountNumber . $this->period . $this->groupName . $transaction->trans_reference . $transaction->amount_lcy . $transaction->booking_date) ]; } - Log::info('Processed closing balance data prepared without duplicates', [ - 'total_records' => count($processedData) + Log::info('Processed closing balance data prepared with duplicate prevention', [ + 'total_records' => count($processedData), + 'skipped_duplicates' => count($transactions) - count($processedData) ]); return $processedData;