import anggota
This commit is contained in:
@@ -2,14 +2,17 @@
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\DrawResult;
|
||||
use App\Models\ImportLog;
|
||||
use App\Models\Member;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class MemberImportService
|
||||
{
|
||||
/**
|
||||
* Import baris anggota. Tidak crash bila ada duplicate/ralat —
|
||||
* pulangkan ringkasan + simpan ImportLog.
|
||||
* Import baris anggota. Hanya 3 medan diproses: nama, no_anggota, no_kp.
|
||||
* Setiap import akan BUANG semua anggota lama dahulu (ganti penuh).
|
||||
* Tidak crash bila ada duplicate/ralat — pulangkan ringkasan + simpan ImportLog.
|
||||
*
|
||||
* @param array<int, array<string, string>> $rows
|
||||
*/
|
||||
@@ -20,73 +23,73 @@ class MemberImportService
|
||||
$failed = 0;
|
||||
$errors = [];
|
||||
|
||||
// Lindung integriti cabutan: jangan buang anggota jika sudah ada pemenang disahkan.
|
||||
if (DrawResult::where('status', DrawResult::STATUS_CONFIRMED)->exists()) {
|
||||
return ImportLog::create([
|
||||
'type' => 'members',
|
||||
'filename' => $filename,
|
||||
'total_rows' => count($rows),
|
||||
'success_count' => 0,
|
||||
'duplicate_count' => 0,
|
||||
'failed_count' => count($rows),
|
||||
'errors' => ['Import dibatalkan: sudah ada pemenang cabutan yang disahkan. Data anggota tidak boleh dibuang.'],
|
||||
'imported_by' => $userId,
|
||||
]);
|
||||
}
|
||||
|
||||
// Set pra-muat untuk kesan duplicate dalam fail itu sendiri
|
||||
$seenKp = [];
|
||||
$seenPekerja = [];
|
||||
$seenAnggota = [];
|
||||
|
||||
foreach ($rows as $i => $row) {
|
||||
$line = $i + 2; // baris fail (header = 1)
|
||||
DB::transaction(function () use ($rows, &$success, &$duplicate, &$failed, &$errors, &$seenKp, &$seenAnggota) {
|
||||
// Buang semua anggota lama (ganti penuh setiap import)
|
||||
Member::query()->delete();
|
||||
|
||||
$nama = trim($row['nama'] ?? '');
|
||||
$noKp = $this->clean($row['no_kp'] ?? '');
|
||||
$noPekerja = $this->clean($row['no_pekerja'] ?? '');
|
||||
$noAnggota = $this->clean($row['no_anggota'] ?? '');
|
||||
foreach ($rows as $i => $row) {
|
||||
$line = $i + 2; // baris fail (header = 1)
|
||||
|
||||
if ($nama === '') {
|
||||
$failed++;
|
||||
$errors[] = "Baris {$line}: nama wajib diisi.";
|
||||
continue;
|
||||
}
|
||||
$nama = trim($row['nama'] ?? '');
|
||||
$noKp = $this->clean($row['no_kp'] ?? '');
|
||||
$noAnggota = $this->clean($row['no_anggota'] ?? '');
|
||||
|
||||
// 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 ($nama === '') {
|
||||
$failed++;
|
||||
$errors[] = "Baris {$line}: nama wajib diisi.";
|
||||
continue;
|
||||
}
|
||||
if ($noPekerja) {
|
||||
$seenPekerja[$noPekerja] = true;
|
||||
|
||||
// Duplicate dalam fail
|
||||
if ($noKp && isset($seenKp[$noKp])) {
|
||||
$duplicate++;
|
||||
$errors[] = "Baris {$line}: no_kp '{$noKp}' duplicate dalam fail.";
|
||||
continue;
|
||||
}
|
||||
if ($noAnggota && isset($seenAnggota[$noAnggota])) {
|
||||
$duplicate++;
|
||||
$errors[] = "Baris {$line}: no_anggota '{$noAnggota}' duplicate dalam fail.";
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
Member::create([
|
||||
'no_anggota' => $noAnggota ?: null,
|
||||
'no_kp' => $noKp ?: null,
|
||||
'nama' => $nama,
|
||||
]);
|
||||
|
||||
if ($noKp) {
|
||||
$seenKp[$noKp] = true;
|
||||
}
|
||||
if ($noAnggota) {
|
||||
$seenAnggota[$noAnggota] = true;
|
||||
}
|
||||
$success++;
|
||||
} catch (\Throwable $e) {
|
||||
$failed++;
|
||||
$errors[] = "Baris {$line}: {$e->getMessage()}";
|
||||
}
|
||||
$success++;
|
||||
} catch (\Throwable $e) {
|
||||
$failed++;
|
||||
$errors[] = "Baris {$line}: {$e->getMessage()}";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return ImportLog::create([
|
||||
'type' => 'members',
|
||||
@@ -104,14 +107,4 @@ class MemberImportService
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user