error("❌ File tidak wujud!"); return 0; } $handle = fopen($file, 'r'); if (!$handle) { $this->error("❌ Gagal buka file!"); return 0; } // Skip empty header rows do { $header = fgetcsv($handle); } while ($header && count(array_filter($header)) === 0); if (!$header) { $this->error("❌ Header tidak dijumpai!"); return 0; } $header = array_map(fn($item) => trim(strtolower($item)), $header); $totalUpdated = 0; $totalInserted = 0; DB::beginTransaction(); try { $bar = $this->output->createProgressBar(); $bar->start(); while (($row = fgetcsv($handle)) !== false) { if (count(array_filter($row)) === 0) { continue; } $row = array_pad($row, count($header), null); $row = array_map('trim', $row); $csvData = array_combine($header, $row); if (empty($csvData['no_anggota'])) { continue; } $rowData = [ 'no_anggota' => $csvData['no_anggota'], 'name' => $csvData['name'] ?? '', 'saham' => $this->cleanNumber($csvData['saham'] ?? 0), 'yuran' => $this->cleanNumber($csvData['yuran'] ?? 0), 'pelaburan' => $this->cleanNumber($csvData['pelaburan'] ?? 0), 'tergempar' => $this->cleanNumber($csvData['tergempar'] ?? 0), 'barangan' => $this->cleanNumber($csvData['barangan'] ?? 0), 'peribadi' => $this->cleanNumber($csvData['peribadi'] ?? 0), 'berjamin_yuran' => $this->cleanNumber($csvData['berjamin_yuran'] ?? 0), 'roadtax' => $this->cleanNumber($csvData['roadtax'] ?? 0), 'pelbagai' => $this->cleanNumber($csvData['pelbagai'] ?? 0), ]; // Check existence $exists = DB::table('voter') ->where('no_anggota', $rowData['no_anggota']) ->exists(); if ($exists) { // UPDATE kewangan sahaja DB::table('voter') ->where('no_anggota', $rowData['no_anggota']) ->update([ 'saham' => $rowData['saham'], 'yuran' => $rowData['yuran'], 'pelaburan' => $rowData['pelaburan'], 'tergempar' => $rowData['tergempar'], 'barangan' => $rowData['barangan'], 'peribadi' => $rowData['peribadi'], 'berjamin_yuran' => $rowData['berjamin_yuran'], 'roadtax' => $rowData['roadtax'], 'pelbagai' => $rowData['pelbagai'], 'updated_at' => now(), ]); $totalUpdated++; } else { // INSERT rekod baru DB::table('voter')->insert([ 'no_anggota' => $rowData['no_anggota'], 'name' => $rowData['name'], 'unit' => '', 'no_kp' => '', 'telefon' => '', 'alamat' => '', 'saham' => $rowData['saham'], 'yuran' => $rowData['yuran'], 'pelaburan' => $rowData['pelaburan'], 'tergempar' => $rowData['tergempar'], 'barangan' => $rowData['barangan'], 'peribadi' => $rowData['peribadi'], 'berjamin_yuran' => $rowData['berjamin_yuran'], 'roadtax' => $rowData['roadtax'], 'pelbagai' => $rowData['pelbagai'], 'election_id' => 8, 'created_at' => now(), 'updated_at' => now(), ]); $totalInserted++; } $bar->advance(); } DB::commit(); $bar->finish(); $this->info("\n\n✅ Update: {$totalUpdated} rekod"); $this->info("✅ Insert: {$totalInserted} rekod"); } catch (\Exception $e) { DB::rollBack(); $this->error("\n❌ Error : " . $e->getMessage()); } fclose($handle); return 0; } private function cleanNumber($value) { if ($value === null) return 0; $value = (string) $value; // Remove RM, commas, spaces $value = str_replace(['RM', ',', ' '], '', $value); // Convert (1000) → 1000 if (preg_match('/^\((.*)\)$/', $value, $matches)) { $value = $matches[1]; } // Remove non numeric except dot and minus $value = preg_replace('/[^0-9\.\-]/', '', $value); return is_numeric($value) ? abs((float) $value) : 0; } }