all()); $request->validate([ 'status' => 'required', 'keterangan' => 'required', 'photo' => 'required_if:status,Hadir,Masuk', 'latitude' => 'required_if:status,Hadir,Masuk', 'longitude' => 'required_if:status,Hadir,Masuk', 'clock_type' => 'required|in:in,out' ]); $user = Auth::user(); $now = Carbon::now(); // Cek apakah sudah presensi hari ini untuk clock type yang sama $existingPresensi = Presensi::where('user_id', $user->id) ->whereDate('created_at', $now->toDateString()) ->where('clock_type', $request->clock_type) ->first(); if ($existingPresensi) { return response()->json([ 'success' => false, 'message' => 'Anda sudah melakukan presensi ' . ($request->clock_type == 'in' ? 'masuk' : 'keluar') . ' hari ini' ], 400); } // Set status terlambat jika clock in setelah jam 8 pagi $status = $request->status; // Konversi status 'Masuk' menjadi 'Hadir' if ($status == 'Masuk') { $status = 'Hadir'; } if ($request->clock_type == 'in' && $status == 'Hadir') { $batasWaktu = Carbon::createFromTime(8, 0, 0); // 08:00:00 if ($now->greaterThan($batasWaktu)) { $status = 'Terlambat'; } } $data = [ 'user_id' => $user->id, 'status' => $status, 'keterangan' => $request->keterangan, 'clock_type' => $request->clock_type, 'file_pdf' => null // Pastikan file_pdf kosong untuk presensi biasa ]; // Jika status Hadir atau Masuk, simpan foto dan lokasi if ($request->status == 'Hadir' || $request->status == 'Masuk') { if ($request->hasFile('photo')) { Log::info('Photo file received', ['filename' => $request->file('photo')->getClientOriginalName()]); $photo = $request->file('photo'); $filename = 'presensi_' . time() . '_' . $user->id . '.' . $photo->getClientOriginalExtension(); $path = $photo->storeAs('public/presensi', $filename); $data['foto'] = $filename; } else { Log::warning('No photo file received for status: ' . $request->status); } $data['latitude'] = $request->latitude; $data['longitude'] = $request->longitude; } Log::info('Saving presensi data:', $data); $presensi = Presensi::create($data); return response()->json([ 'success' => true, 'message' => 'Presensi berhasil disimpan', 'data' => $presensi ]); } catch (\Exception $e) { Log::error('Error in presensi store: ' . $e->getMessage()); Log::error('Stack trace: ' . $e->getTraceAsString()); return response()->json([ 'success' => false, 'message' => 'Error: ' . $e->getMessage() ], 500); } } public function getPresensi(Request $request) { try { $user = auth()->user(); if (!$user) { return response()->json([ 'success' => false, 'message' => 'Unauthorized' ], 401); } $query = Presensi::where('user_id', $user->id); // Filter by date if ($request->has('date')) { $query->whereDate('created_at', $request->date); } // Filter by status if ($request->has('status')) { $query->where('status', $request->status); } // Filter by clock_type if ($request->has('clock_type')) { $query->where('clock_type', $request->clock_type); } // Sort by latest first $presensi = $query->orderBy('created_at', 'desc')->get(); return response()->json([ 'success' => true, 'message' => 'Data presensi berhasil diambil', 'data' => $presensi ], 200); } catch (\Exception $e) { return response()->json([ 'success' => false, 'message' => 'Error: ' . $e->getMessage() ], 500); } } public function getDashboardStats() { try { $user = Auth::user(); $currentMonth = Carbon::now()->month; $currentYear = Carbon::now()->year; // Hitung jumlah kehadiran bulan ini // Hanya menghitung status 'Hadir' dan 'Terlambat', tidak termasuk 'Izin' dan 'Sakit' $attendanceCount = Presensi::where('user_id', $user->id) ->whereMonth('created_at', $currentMonth) ->whereYear('created_at', $currentYear) ->whereIn('status', ['Hadir', 'Terlambat']) ->where('clock_type', 'in') ->count(); // Hitung sisa cuti $totalLeaveTaken = Cuti::where('user_id', $user->id) ->where('status', 'Disetujui') ->whereYear('tanggal_mulai', $currentYear) ->count(); // Asumsi total cuti per tahun adalah 12 hari $remainingLeave = 12 - $totalLeaveTaken; $remainingLeave = max(0, $remainingLeave); // Pastikan tidak negatif return response()->json([ 'success' => true, 'data' => [ 'total_presensi' => $attendanceCount, 'remaining_leave' => $remainingLeave, 'total_cuti' => $totalLeaveTaken ] ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'message' => 'Gagal mengambil data statistik: ' . $e->getMessage() ], 500); } } public function getMonthlyTotal() { try { $user = Auth::user(); if (!$user) { return response()->json([ 'success' => false, 'message' => 'Unauthorized' ], 401); } $total = Presensi::where('user_id', $user->id) ->whereMonth('created_at', Carbon::now()->month) ->whereYear('created_at', Carbon::now()->year) ->whereIn('status', ['Hadir', 'Terlambat']) ->where('clock_type', 'in') ->count(); return response()->json([ 'success' => true, 'data' => [ 'total' => $total ] ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'message' => 'Error: ' . $e->getMessage() ], 500); } } public function getStats() { try { $user = auth()->user(); if (!$user) { return response()->json([ 'success' => false, 'message' => 'Unauthorized' ], 401); } // Hitung total presensi bulan ini untuk user yang login // Hanya menghitung kehadiran (Hadir/Terlambat), tidak termasuk Izin dan Sakit $totalPresensi = Presensi::where('user_id', $user->id) ->whereMonth('created_at', now()->month) ->whereYear('created_at', now()->year) ->whereIn('status', ['Hadir', 'Terlambat']) ->where('clock_type', 'in') // Hanya hitung clock in ->count(); Log::info('Presensi stats for user ' . $user->id . ':', ['total' => $totalPresensi]); return response()->json([ 'success' => true, 'message' => 'Data statistik presensi berhasil diambil', 'data' => [ 'total_presensi' => $totalPresensi ] ], 200); } catch (\Exception $e) { Log::error('Error getting presensi stats: ' . $e->getMessage()); return response()->json([ 'success' => false, 'message' => 'Error: ' . $e->getMessage() ], 500); } } public function storeIzin(Request $request) { try { $request->validate([ 'status' => 'required|in:Izin,Sakit', 'keterangan' => 'required', 'file' => 'required|mimes:pdf,jpg,jpeg,png|max:5120', // Max 5MB ]); $user = Auth::user(); $now = Carbon::now(); // Check if user already has an Izin or Sakit entry for today $existingLeave = Presensi::where('user_id', $user->id) ->whereDate('created_at', $now->toDateString()) ->whereIn('status', ['Izin', 'Sakit']) ->first(); if ($existingLeave) { return response()->json([ 'success' => false, 'message' => 'Anda sudah mengajukan ' . $existingLeave->status . ' untuk hari ini' ], 400); } // Check if user already has a regular attendance for today $existingAttendance = Presensi::where('user_id', $user->id) ->whereDate('created_at', $now->toDateString()) ->whereIn('status', ['Hadir', 'Terlambat']) ->first(); if ($existingAttendance) { return response()->json([ 'success' => false, 'message' => 'Anda sudah melakukan presensi hari ini, tidak dapat mengajukan ' . $request->status ], 400); } $data = [ 'user_id' => $user->id, 'status' => $request->status, 'keterangan' => $request->keterangan, 'clock_type' => null, // Izin tidak perlu clock type 'latitude' => null, 'longitude' => null, 'foto' => null // Pastikan foto kosong untuk pengajuan izin ]; // Upload dan simpan file if ($request->hasFile('file')) { $file = $request->file('file'); $extension = $file->getClientOriginalExtension(); $filename = 'izin_' . time() . '_' . $user->id . '.' . $extension; // Simpan file ke storage $path = $file->storeAs('public/presensi', $filename); // Simpan semua jenis file di kolom file_pdf untuk pengajuan izin $data['file_pdf'] = $filename; } $presensi = Presensi::create($data); return response()->json([ 'success' => true, 'message' => 'Pengajuan ' . $request->status . ' berhasil disimpan', 'data' => $presensi ]); } catch (\Exception $e) { Log::error('Error izin: ' . $e->getMessage()); return response()->json([ 'success' => false, 'message' => 'Error: ' . $e->getMessage() ], 500); } } }