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
This commit is contained in:
Daeng Deni Mardaeni
2025-07-31 10:35:05 +07:00
parent eff951c600
commit 13e077073b

View File

@@ -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;