user(); $isGlobalAdmin = $user->isGlobalAdmin(); $query = User::with(['divisi', 'jabatan', 'kantor', 'roles']); if (!$isGlobalAdmin) { $query->where('id_kantor', $user->id_kantor); } if ($request->filled('filter_jabatan')) { $query->where('id_jabatan', $request->filter_jabatan); } if ($request->filled('filter_role')) { $query->whereHas('roles', function ($q) use ($request) { $q->where('detail_user_roles.id_role', $request->filter_role); }); } if ($request->filled('filter_kantor')) { $query->where('id_kantor', $request->filter_kantor); } if ($request->filled('filter_status')) { $status = $request->filter_status == 'active' ? 1 : 0; $query->where('status_aktif', $status); } if ($request->filled('search')) { $search = $request->search; $query->where(function ($q) use ($search) { $q->where('nama_lengkap', 'like', "%{$search}%") ->orWhere('email', 'like', "%{$search}%") ->orWhere('nik', 'like', "%{$search}%"); }); } $pegawai = $query->latest()->paginate(10)->withQueryString(); $allKantorQuery = Kantor::withCount('users as total_pegawai'); if (!$isGlobalAdmin) { $allKantorQuery->where('id_kantor', $user->id_kantor); $totalActive = User::where('id_kantor', $user->id_kantor)->where('status_aktif', 1)->count(); $totalPegawaiStats = User::where('id_kantor', $user->id_kantor)->count(); } else { $totalActive = User::where('status_aktif', 1)->count(); $totalPegawaiStats = User::count(); } $allKantor = $allKantorQuery->get(); $stats = [ 'kantor_list' => $allKantor, 'total' => $totalPegawaiStats, 'active' => $totalActive, ]; $allJabatan = Jabatan::all(); $allRoles = Role::all(); return view('pegawai.index', compact('pegawai', 'stats', 'allJabatan', 'allKantor', 'allRoles')); } private function generateIdKaryawan($tglBergabung, $idDivisi, $idJabatan) { // 1. Ambil Tahun & Bulan (YYYYMM) $date = \Carbon\Carbon::parse($tglBergabung); $yearMonth = $date->format('Ym'); // 2. Ambil 2 huruf dari Divisi & Jabatan (XXYY) $divisi = Divisi::find($idDivisi); $jabatan = Jabatan::find($idJabatan); $kodeDivisi = 'XX'; if ($divisi) { $words = explode(' ', $divisi->nama_divisi); if (count($words) >= 2) { $kodeDivisi = strtoupper(substr($words[0], 0, 1) . substr($words[1], 0, 1)); } else { $kodeDivisi = strtoupper(substr($divisi->nama_divisi, 0, 2)); } } $kodeJabatan = 'YY'; if ($jabatan) { $words = explode(' ', $jabatan->nama_jabatan); if (count($words) >= 2) { $kodeJabatan = strtoupper(substr($words[0], 0, 1) . substr($words[1], 0, 1)); } else { $kodeJabatan = strtoupper(substr($jabatan->nama_jabatan, 0, 2)); } } $kodeTengah = $kodeDivisi . $kodeJabatan; // 3. Generate Nomor Urut (NNN) per tahun bergabun $yearStarts = $date->copy()->startOfYear()->toDateString(); $yearEnds = $date->copy()->endOfYear()->toDateString(); $lastUser = User::whereBetween('tgl_bergabung', [$yearStarts, $yearEnds]) ->whereNotNull('nik') ->orderBy('id', 'desc') ->first(); $nextNumber = 1; if ($lastUser && preg_match('/-(\d{3})$/', $lastUser->nik, $matches)) { $nextNumber = intval($matches[1]) + 1; } $nomorUrut = str_pad($nextNumber, 3, '0', STR_PAD_LEFT); // Format: MP-202603-ITST-001 return "MP-{$yearMonth}-{$kodeTengah}-{$nomorUrut}"; } public function store(StorePegawaiRequest $request) { try { $data = $request->validated(); if ($request->hasFile('foto')) { $data['foto'] = $request->file('foto')->store('foto-profil', 'public'); } $tglBergabung = $data['tgl_bergabung'] ?? now()->toDateString(); $data['nik'] = $this->generateIdKaryawan($tglBergabung, $data['id_divisi'], $data['id_jabatan']); $existingNik = User::withTrashed()->where('nik', $data['nik'])->exists(); if ($existingNik) { \Illuminate\Support\Facades\Log::warning("NIK duplikat terdeteksi: {$data['nik']}"); return redirect()->back()->withInput()->with('error', 'Gagal generate NIK unik. Silakan coba lagi.'); } $data['password'] = Hash::make('Mpg123!'); $data['status_aktif'] = 1; $data['sisa_cuti'] = 12; $user = User::create($data); if ($request->filled('id_role')) { $user->roles()->attach($request->id_role); } \Illuminate\Support\Facades\Log::info("Pegawai baru berhasil dibuat: ID={$user->id}, NIK={$data['nik']}, Nama={$data['nama_lengkap']}"); return redirect()->route('pegawai.index')->with('success', 'Pegawai baru berhasil ditambahkan.'); } catch (\Exception $e) { \Illuminate\Support\Facades\Log::error("Gagal menambahkan pegawai: " . $e->getMessage()); return redirect()->back()->withInput()->with('error', 'Gagal menambahkan pegawai: ' . $e->getMessage()); } } public function update(UpdatePegawaiRequest $request, $id) { $pegawai = User::findOrFail($id); $data = $request->validated(); if ($request->hasFile('foto')) { if ($pegawai->foto) { Storage::disk('public')->delete($pegawai->foto); } $data['foto'] = $request->file('foto')->store('foto-profil', 'public'); } $pegawai->update($data); if ($request->filled('id_role')) { $pegawai->roles()->sync([$request->id_role]); } return redirect()->route('pegawai.index')->with('success', 'Data pegawai berhasil diperbarui.'); } public function create() { $divisi = Divisi::all(); $jabatan = Jabatan::all(); $kantor = Kantor::all(); $roles = Role::all(); return view('pegawai.create', compact('divisi', 'jabatan', 'kantor', 'roles')); } public function show($id) { $pegawai = User::with(['divisi', 'jabatan', 'kantor', 'roles'])->findOrFail($id); $authUser = auth()->user(); if (!$authUser->isGlobalAdmin()) { if ($pegawai->id_kantor != $authUser->id_kantor) { abort(403, 'Anda tidak berhak melihat detail karyawan dari kantor lain.'); } } $sisaPoin = \App\Models\PoinLembur::where('id_user', $id) ->where('is_fully_used', false) ->whereDate('expired_at', '>=', now()->toDateString()) ->sum('sisa_poin'); $historyTambah = \App\Models\PoinLembur::where('id_user', $id) ->select('id_poin as id', 'tanggal', 'jumlah_poin as jumlah', 'keterangan', \DB::raw("'penambahan' as tipe")) ->orderBy('tanggal', 'desc') ->take(10) ->get(); $historyKurang = \App\Models\PenggunaanPoin::where('id_user', $id) ->where('id_status', 1) ->select('id_penggunaan as id', 'tanggal_penggunaan as tanggal', 'jumlah_poin as jumlah', \DB::raw("'Penggunaan Poin' as keterangan"), \DB::raw("'pengurangan' as tipe")) ->orderBy('tanggal_penggunaan', 'desc') ->take(10) ->get(); $historyPoin = $historyTambah->concat($historyKurang)->sortByDesc('tanggal')->take(10); $riwayatPresensi = \App\Models\Presensi::with(['status']) ->where('id_user', $id) ->whereDate('tanggal', '>=', now()->subDays(30)->toDateString()) ->orderBy('tanggal', 'desc') ->get(); $jadwalKerja = \App\Models\JadwalKerja::with('shift') ->where('id_user', $id) ->whereIn('tanggal', $riwayatPresensi->pluck('tanggal')) ->get() ->keyBy('tanggal'); foreach ($riwayatPresensi as $presensi) { $presensi->setRelation('jadwal', $jadwalKerja->get($presensi->tanggal)); } $riwayatIzin = \App\Models\PengajuanIzin::with('jenisIzin') ->where('id_user', $id) ->whereDate('tanggal_mulai', '>=', now()->subDays(30)->toDateString()) ->orderBy('tanggal_mulai', 'desc') ->get(); return view('pegawai.show', compact('pegawai', 'sisaPoin', 'historyPoin', 'riwayatPresensi', 'riwayatIzin')); } public function edit($id) { $pegawai = User::findOrFail($id); $divisi = Divisi::all(); $jabatan = Jabatan::all(); $kantor = Kantor::all(); $roles = Role::all(); return view('pegawai.edit', compact('pegawai', 'divisi', 'jabatan', 'kantor', 'roles')); } public function destroy($id) { $pegawai = User::findOrFail($id); if ($pegawai->status_aktif == 0) { $pegawai->delete(); return redirect()->route('pegawai.index')->with('success', 'Data pegawai berhasil dihapus (Soft Delete).'); } $pegawai->update(['status_aktif' => 0]); return redirect()->route('pegawai.index')->with('success', 'Status pegawai telah diubah menjadi Non-Aktif (Resigned). Histori data tetap tersimpan.'); } public function resetPassword($id) { $pegawai = User::findOrFail($id); $defaultPassword = 'Mpg123!'; $pegawai->update([ 'password' => Hash::make($defaultPassword), ]); $pegawai->tokens()->delete(); return redirect()->route('pegawai.show', $id) ->with('success', "Password {$pegawai->nama_lengkap} berhasil direset ke default (Mpg123!)."); } }