> $rows */ public function import(array $rows, string $filename, ?int $userId = null): ImportLog { $success = 0; $duplicate = 0; $failed = 0; $errors = []; // Set pra-muat untuk kesan duplicate dalam fail itu sendiri $seenKp = []; $seenPekerja = []; foreach ($rows as $i => $row) { $line = $i + 2; // baris fail (header = 1) $nama = trim($row['nama'] ?? ''); $noKp = $this->clean($row['no_kp'] ?? ''); $noPekerja = $this->clean($row['no_pekerja'] ?? ''); $noAnggota = $this->clean($row['no_anggota'] ?? ''); if ($nama === '') { $failed++; $errors[] = "Baris {$line}: nama wajib diisi."; continue; } // Duplicate dalam fail if ($noKp && isset($seenKp[$noKp])) { $duplicate++; $errors[] = "Baris {$line}: no_kp '{$noKp}' duplicate dalam fail."; continue; } if ($noPekerja && isset($seenPekerja[$noPekerja])) { $duplicate++; $errors[] = "Baris {$line}: no_pekerja '{$noPekerja}' duplicate dalam fail."; continue; } // Duplicate dalam DB $exists = Member::query() ->when($noKp, fn ($q) => $q->orWhere('no_kp', $noKp)) ->when($noPekerja, fn ($q) => $q->orWhere('no_pekerja', $noPekerja)) ->when($noKp || $noPekerja, fn ($q) => $q, fn ($q) => $q->whereRaw('1 = 0')) ->exists(); if ($exists) { $duplicate++; $errors[] = "Baris {$line}: anggota '{$nama}' sudah wujud (no_kp/no_pekerja sepadan)."; continue; } try { Member::create([ 'no_anggota' => $noAnggota ?: null, 'no_pekerja' => $noPekerja ?: null, 'no_kp' => $noKp ?: null, 'nama' => $nama, 'jabatan' => $this->clean($row['jabatan'] ?? '') ?: null, 'bahagian' => $this->clean($row['bahagian'] ?? '') ?: null, 'telefon' => $this->clean($row['telefon'] ?? '') ?: null, 'status_aktif' => $this->parseAktif($row['status_aktif'] ?? ''), ]); if ($noKp) { $seenKp[$noKp] = true; } if ($noPekerja) { $seenPekerja[$noPekerja] = true; } $success++; } catch (\Throwable $e) { $failed++; $errors[] = "Baris {$line}: {$e->getMessage()}"; } } return ImportLog::create([ 'type' => 'members', 'filename' => $filename, 'total_rows' => count($rows), 'success_count' => $success, 'duplicate_count' => $duplicate, 'failed_count' => $failed, 'errors' => $errors ?: null, 'imported_by' => $userId, ]); } private function clean(string $value): string { return trim($value); } private function parseAktif(string $value): bool { $value = strtolower(trim($value)); if ($value === '') { return true; // default aktif } return in_array($value, ['1', 'aktif', 'active', 'ya', 'yes', 'true', 'y'], true); } }