0, 'KTM' => 1, 'KP_KMU' => 1, 'PPAPM_MANUAL' => 2, 'PPAPM_KOMPUTER' => 2, 'PPAPM_BERGERAK' => 2, ]; private const PENGEPALA = [ 'Bil', 'DUN', 'Pusat Mengundi', 'Saluran', 'Jawatan', 'Nama', 'No. KP', 'No. Telefon', 'Emel', 'Tarikh Hadir', ]; /** * Eksport kehadiran semua petugas merentas semua sesi taklimat yang * dilihat pengguna, dikumpul kepada satu fail Excel: worksheet "Hadir" * dan "Tidak Hadir". */ public function __invoke(Request $request): Response { $user = $request->user(); $sesiSemua = SesiTaklimat::with('dun') ->when($user->isPengurus(), fn ($q) => $q->where('dun_id', $user->dun_id)) ->get(); $hadir = []; $tidakHadir = []; foreach ($sesiSemua->groupBy('dun_id') as $sesiDun) { $dun = $sesiDun->first()->dun; $dunLabel = trim(($dun->code ?? '').' '.($dun->nama ?? '')); $sesiIds = $sesiDun->pluck('id'); // Tarikh hadir paling awal bagi setiap petugas merentas sesi DUN ini. $tarikhHadir = []; $rekodKehadiran = KehadiranTaklimat::whereIn('sesi_taklimat_id', $sesiIds) ->orderBy('hadir_at') ->get(['permohonan_id', 'sesi_taklimat_id']); foreach ($rekodKehadiran as $rekod) { if (! array_key_exists($rekod->permohonan_id, $tarikhHadir)) { $tarikhHadir[$rekod->permohonan_id] = optional( $sesiDun->firstWhere('id', $rekod->sesi_taklimat_id)?->tarikh )->format('d/m/Y') ?? ''; } } $petugas = PetugasPermohonan::assignedUntukDun((int) $sesiDun->first()->dun_id) ->with(['assignments' => fn ($q) => $q->orderBy('urutan')->with(['pusatMengundi', 'saluran', 'jawatan'])]) ->get(); foreach ($petugas as $p) { $baris = $this->barisPetugas($p, $dunLabel); if (array_key_exists($p->id, $tarikhHadir)) { $baris['tarikh_hadir'] = $tarikhHadir[$p->id]; $hadir[] = $baris; } else { $tidakHadir[] = $baris; } } } $hadir = $this->susun($hadir); $tidakHadir = $this->susun($tidakHadir); $xlsx = (new SimpleXlsx) ->addSheet('Hadir', $this->keBaris($hadir)) ->addSheet('Tidak Hadir', $this->keBaris($tidakHadir)); $namaFail = 'Kehadiran-Taklimat-'.now()->format('Ymd-His').'.xlsx'; return response($xlsx->toString(), 200, [ 'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'Content-Disposition' => 'attachment; filename="'.$namaFail.'"', ]); } /** * Hasilkan satu baris data petugas berserta kunci susunan. * * @return array */ private function barisPetugas(PetugasPermohonan $p, string $dunLabel): array { $assignment = $p->assignmentUtama(); $pusatNama = $assignment?->pusatMengundi?->nama ?? ''; $saluranNo = $assignment?->saluran?->nombor_saluran; $kod = $assignment?->jawatan?->kod ?? ''; $kumpulan = self::JAWATAN_KUMPULAN[$kod] ?? 9; // Dalam kumpulan Saluran, KTM (0) didahulukan sebelum KP (1). $subJawatan = $kod === 'KTM' ? 0 : 1; return [ 'dun' => $dunLabel, 'pusat' => $pusatNama, 'saluran' => $saluranNo !== null ? 'Saluran '.$saluranNo : '', 'jawatan' => $assignment?->jawatan?->nama ?? '-', 'nama' => $p->nama_ic ?? '', 'no_kp' => $p->no_kp ?? '', 'no_telefon' => $p->no_telefon ?? '', 'emel' => $p->emel ?? '', 'tarikh_hadir' => '', '_sort' => [ $dunLabel, $pusatNama, $kumpulan, $kumpulan === 1 ? (int) ($saluranNo ?? 0) : 0, $subJawatan, $p->nama_ic ?? '', ], ]; } /** * Susun mengikut pusat mengundi > PPM > Saluran (KTM > KP) > PPAPM. * * @param array> $baris * @return array> */ private function susun(array $baris): array { usort($baris, function ($a, $b) { return $a['_sort'] <=> $b['_sort']; }); return $baris; } /** * Tukar baris data kepada matriks (pengepala + sel) untuk worksheet. * * @param array> $baris * @return array> */ private function keBaris(array $baris): array { $rows = [self::PENGEPALA]; foreach ($baris as $i => $b) { $rows[] = [ $i + 1, $b['dun'], $b['pusat'], $b['saluran'], $b['jawatan'], $b['nama'], $b['no_kp'], $b['no_telefon'], $b['emel'], $b['tarikh_hadir'], ]; } return $rows; } }