feat(webstatement): fallback stmt_entry_id menggunakan field id pada CSV
Menambahkan dukungan fallback untuk nilai `stmt_entry_id` yang kosong/null dengan menggunakan field `id` dari CSV (jika tersedia di akhir file). Perubahan yang dilakukan: - Menambahkan 'id' sebagai bagian dari expected CSV headers - Mengimplementasikan handleStmtEntryIdFallback() untuk logika pengganti - Menggunakan field 'id' sebagai stmt_entry_id jika nilainya kosong atau null - Menyesuaikan validasi jumlah kolom terhadap struktur CSV terbaru - Melakukan pembersihan field 'id' sebelum data disimpan ke database - Memperkuat validasi di addToBatch() agar stmt_entry_id selalu valid - Menambahkan logging untuk proses fallback dan debugging - Meningkatkan error handling untuk kasus data tidak valid - Menjamin kompatibilitas dengan struktur model StmtEntryDetail - Optimasi batch insert melalui pengecekan dan pembersihan data lebih ketat
This commit is contained in:
@@ -114,6 +114,12 @@
|
|||||||
],
|
],
|
||||||
'SWADAYA_PANDU' => [
|
'SWADAYA_PANDU' => [
|
||||||
'0081272689',
|
'0081272689',
|
||||||
|
],
|
||||||
|
"AWAN_LINTANG_SOLUSI"=> [
|
||||||
|
"1084269430"
|
||||||
|
],
|
||||||
|
"MONETA"=> [
|
||||||
|
"1085667890"
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,17 +162,20 @@ class ProcessStmtEntryDetailDataJob implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
$headers = (new StmtEntryDetail())->getFillable();
|
$headers = (new StmtEntryDetail())->getFillable();
|
||||||
|
// Tambahkan field 'id' ke headers untuk menangani kolom tambahan di akhir CSV
|
||||||
|
$expectedHeaders = array_merge($headers, ['id']);
|
||||||
$rowCount = 0;
|
$rowCount = 0;
|
||||||
$chunkCount = 0;
|
$chunkCount = 0;
|
||||||
|
|
||||||
Log::info('Memulai proses file', [
|
Log::info('Memulai proses file', [
|
||||||
'file_path' => $filePath,
|
'file_path' => $filePath,
|
||||||
'headers_count' => count($headers)
|
'headers_count' => count($headers),
|
||||||
|
'expected_headers_count' => count($expectedHeaders)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
while (($row = fgetcsv($handle, 0, self::CSV_DELIMITER)) !== false) {
|
while (($row = fgetcsv($handle, 0, self::CSV_DELIMITER)) !== false) {
|
||||||
$rowCount++;
|
$rowCount++;
|
||||||
$this->processRow($row, $headers, $rowCount, $filePath);
|
$this->processRow($row, $expectedHeaders, $rowCount, $filePath);
|
||||||
|
|
||||||
// Process in chunks to avoid memory issues
|
// Process in chunks to avoid memory issues
|
||||||
if (count($this->entryBatch) >= self::CHUNK_SIZE) {
|
if (count($this->entryBatch) >= self::CHUNK_SIZE) {
|
||||||
@@ -192,39 +195,67 @@ class ProcessStmtEntryDetailDataJob implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Proses setiap baris data
|
* Proses setiap baris data dengan penanganan field id tambahan
|
||||||
*
|
*
|
||||||
* @param array $row Data baris
|
* @param array $row Data baris
|
||||||
* @param array $headers Header kolom
|
* @param array $expectedHeaders Header kolom yang diharapkan (termasuk id)
|
||||||
* @param int $rowCount Nomor baris
|
* @param int $rowCount Nomor baris
|
||||||
* @param string $filePath Path file
|
* @param string $filePath Path file
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function processRow(array $row, array $headers, int $rowCount, string $filePath): void
|
private function processRow(array $row, array $expectedHeaders, int $rowCount, string $filePath): void
|
||||||
{
|
{
|
||||||
if (count($headers) !== count($row)) {
|
// Validasi jumlah kolom - sekarang menggunakan expectedHeaders yang sudah include field 'id'
|
||||||
|
if (count($expectedHeaders) !== count($row)) {
|
||||||
Log::warning("Row $rowCount in $filePath has incorrect column count. Expected: " .
|
Log::warning("Row $rowCount in $filePath has incorrect column count. Expected: " .
|
||||||
count($headers) . ", Got: " . count($row));
|
count($expectedHeaders) . ", Got: " . count($row));
|
||||||
|
$this->errorCount++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = array_combine($headers, $row);
|
// Kombinasikan data dengan headers
|
||||||
|
$data = array_combine($expectedHeaders, $row);
|
||||||
|
|
||||||
|
// Log untuk debugging struktur data
|
||||||
|
Log::debug('Processing row data', [
|
||||||
|
'row_count' => $rowCount,
|
||||||
|
'stmt_entry_id' => $data['stmt_entry_id'] ?? 'not_set',
|
||||||
|
'id' => $data['id'] ?? 'not_set'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Logika untuk menggunakan field 'id' sebagai fallback jika stmt_entry_id kosong
|
||||||
|
$this->handleStmtEntryIdFallback($data);
|
||||||
|
|
||||||
|
// Hapus field 'id' dari data sebelum disimpan karena tidak ada di fillable model
|
||||||
|
unset($data['id']);
|
||||||
|
|
||||||
$this->cleanTransReference($data);
|
$this->cleanTransReference($data);
|
||||||
$this->addToBatch($data, $rowCount, $filePath);
|
$this->addToBatch($data, $rowCount, $filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bersihkan trans_reference dari karakter tidak diinginkan
|
* Menangani logika fallback untuk stmt_entry_id menggunakan field id
|
||||||
*
|
*
|
||||||
* @param array $data Data yang akan dibersihkan
|
* @param array $data Data yang akan diproses
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function cleanTransReference(array &$data): void
|
private function handleStmtEntryIdFallback(array &$data): void
|
||||||
{
|
{
|
||||||
if (isset($data['trans_reference'])) {
|
// Jika stmt_entry_id kosong atau null, gunakan value dari field 'id'
|
||||||
// Clean trans_reference from \\BNK if present
|
if (empty($data['stmt_entry_id']) || $data['stmt_entry_id'] === '' || $data['stmt_entry_id'] === null) {
|
||||||
$data['trans_reference'] = preg_replace('/\\\\.*$/', '', $data['trans_reference']);
|
if (isset($data['id']) && !empty($data['id'])) {
|
||||||
Log::debug('Trans reference cleaned', ['original' => $data['trans_reference']]);
|
$data['stmt_entry_id'] = $data['id'];
|
||||||
|
|
||||||
|
Log::info('Using id as stmt_entry_id fallback', [
|
||||||
|
'original_stmt_entry_id' => $data['stmt_entry_id'] ?? 'empty',
|
||||||
|
'fallback_id' => $data['id']
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
Log::warning('Both stmt_entry_id and id are empty', [
|
||||||
|
'stmt_entry_id' => $data['stmt_entry_id'] ?? 'not_set',
|
||||||
|
'id' => $data['id'] ?? 'not_set'
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,7 +270,11 @@ class ProcessStmtEntryDetailDataJob implements ShouldQueue
|
|||||||
private function addToBatch(array $data, int $rowCount, string $filePath): void
|
private function addToBatch(array $data, int $rowCount, string $filePath): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (isset($data['stmt_entry_id']) && $data['stmt_entry_id'] !== 'stmt_entry_id') {
|
// Validasi bahwa stmt_entry_id tidak kosong dan bukan header
|
||||||
|
if (isset($data['stmt_entry_id']) &&
|
||||||
|
$data['stmt_entry_id'] !== 'stmt_entry_id' &&
|
||||||
|
!empty($data['stmt_entry_id'])) {
|
||||||
|
|
||||||
// Add timestamp fields
|
// Add timestamp fields
|
||||||
$now = now();
|
$now = now();
|
||||||
$data['created_at'] = $now;
|
$data['created_at'] = $now;
|
||||||
@@ -249,7 +284,16 @@ class ProcessStmtEntryDetailDataJob implements ShouldQueue
|
|||||||
$this->entryBatch[] = $data;
|
$this->entryBatch[] = $data;
|
||||||
$this->processedCount++;
|
$this->processedCount++;
|
||||||
|
|
||||||
Log::debug('Record added to batch', ['row' => $rowCount, 'stmt_entry_id' => $data['stmt_entry_id']]);
|
Log::debug('Record added to batch', [
|
||||||
|
'row' => $rowCount,
|
||||||
|
'stmt_entry_id' => $data['stmt_entry_id']
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
Log::warning('Skipping row due to invalid stmt_entry_id', [
|
||||||
|
'row' => $rowCount,
|
||||||
|
'stmt_entry_id' => $data['stmt_entry_id'] ?? 'not_set'
|
||||||
|
]);
|
||||||
|
$this->errorCount++;
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$this->errorCount++;
|
$this->errorCount++;
|
||||||
@@ -257,6 +301,21 @@ class ProcessStmtEntryDetailDataJob implements ShouldQueue
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bersihkan trans_reference dari karakter tidak diinginkan
|
||||||
|
*
|
||||||
|
* @param array $data Data yang akan dibersihkan
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function cleanTransReference(array &$data): void
|
||||||
|
{
|
||||||
|
if (isset($data['trans_reference'])) {
|
||||||
|
// Clean trans_reference from \\BNK if present
|
||||||
|
$data['trans_reference'] = preg_replace('/\\\\.*$/', '', $data['trans_reference']);
|
||||||
|
Log::debug('Trans reference cleaned', ['original' => $data['trans_reference']]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simpan batch data ke database menggunakan updateOrCreate
|
* Simpan batch data ke database menggunakan updateOrCreate
|
||||||
* untuk menghindari error unique constraint
|
* untuk menghindari error unique constraint
|
||||||
|
|||||||
Reference in New Issue
Block a user