SIPDAM/samooapk/laravel/app/Http/Controllers/AbsensiController.php

252 lines
9.6 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Absensi;
use App\Models\Teknisi;
use Illuminate\Http\Request;
use Carbon\Carbon;
use Illuminate\Support\Facades\Storage;
class AbsensiController extends Controller
{
/**
* Menampilkan daftar data absensi dengan fitur filter.
*/
public function index(Request $request)
{
$teknisis = Teknisi::orderBy('nama', 'asc')->get();
// Query dasar untuk data utama
$query = Absensi::with('teknisi');
// Filter Rentang Tanggal
if ($request->filled('start_date') && $request->filled('end_date')) {
$query->whereBetween('tanggal', [$request->start_date, $request->end_date]);
} elseif ($request->filled('start_date')) {
$query->whereDate('tanggal', '>=', $request->start_date);
} elseif ($request->filled('end_date')) {
$query->whereDate('tanggal', '<=', $request->end_date);
}
// Filter Teknisi
if ($request->filled('teknisi')) {
$query->where('id_teknisi', $request->teknisi);
}
// Hitung statistik berdasarkan filter di atas (sebelum filter status)
$counts = [
'total' => (clone $query)->count(),
'hadir' => (clone $query)->where('status', 'hadir')->count(),
'izin' => (clone $query)->whereIn('status', ['izin', 'sakit'])->count(),
];
// Apply filter status untuk tabel
if ($request->query('status') === 'izin') {
$query->whereIn('status', ['izin', 'sakit']);
} else {
$query->filterByStatus($request->query('status'));
}
$absensis = $query->orderBy('tanggal', 'desc')
->orderBy('jam_masuk', 'desc')
->paginate(15);
return view('Admin.KelolaTeknisi.Absensi', compact('absensis', 'teknisis', 'counts'));
}
/**
* Menampilkan detail data absensi spesifik.
*/
public function show($id)
{
$absensi = Absensi::with('teknisi')->where('id_absensi', $id)->first();
if (!$absensi) {
return response()->json([
'error' => 'Data absensi tidak ditemukan.'
], 404);
}
// Debug log
\Log::info('=== DEBUG ABSENSI SHOW ===');
\Log::info('Absensi ID: ' . $absensi->id_absensi);
\Log::info('Foto Masuk Path: ' . ($absensi->foto_absen_masuk ?? 'NULL'));
\Log::info('Foto Keluar Path: ' . ($absensi->foto_absen_keluar ?? 'NULL'));
// Cek apakah file benar-benar ada
if ($absensi->foto_absen_masuk) {
$exists = Storage::disk('public')->exists($absensi->foto_absen_masuk);
\Log::info('Foto Masuk Exists: ' . ($exists ? 'YES' : 'NO'));
\Log::info('Full Path: ' . Storage::disk('public')->path($absensi->foto_absen_masuk));
}
if ($absensi->foto_absen_keluar) {
$exists = Storage::disk('public')->exists($absensi->foto_absen_keluar);
\Log::info('Foto Keluar Exists: ' . ($exists ? 'YES' : 'NO'));
\Log::info('Full Path: ' . Storage::disk('public')->path($absensi->foto_absen_keluar));
}
// Generate URL yang benar
$fotoMasukUrl = null;
$fotoKeluarUrl = null;
if ($absensi->foto_absen_masuk && Storage::disk('public')->exists($absensi->foto_absen_masuk)) {
$fotoMasukUrl = Storage::url($absensi->foto_absen_masuk);
\Log::info('Generated Foto Masuk URL: ' . $fotoMasukUrl);
}
if ($absensi->foto_absen_keluar && Storage::disk('public')->exists($absensi->foto_absen_keluar)) {
$fotoKeluarUrl = Storage::url($absensi->foto_absen_keluar);
\Log::info('Generated Foto Keluar URL: ' . $fotoKeluarUrl);
}
$data = [
'id' => $absensi->id_absensi,
'tanggal' => $absensi->tanggal instanceof \Carbon\Carbon
? $absensi->tanggal->format('d/m/Y')
: Carbon::parse($absensi->tanggal)->format('d/m/Y'),
'tanggal_full' => $absensi->tanggal instanceof \Carbon\Carbon
? $absensi->tanggal->isoFormat('dddd, D MMMM YYYY')
: Carbon::parse($absensi->tanggal)->isoFormat('dddd, D MMMM YYYY'),
'jam_masuk' => $absensi->jam_masuk
? Carbon::parse($absensi->jam_masuk)->format('H:i')
: '-',
'jam_keluar' => $absensi->jam_keluar
? Carbon::parse($absensi->jam_keluar)->format('H:i')
: '-',
'durasi_kerja' => $absensi->durasi_kerja_formatted ?? '00:00',
'status' => $absensi->status,
'status_formatted' => ucfirst($absensi->status),
'status_badge_class' => $absensi->status_badge_class ?? 'badge-secondary',
'is_terlambat' => $absensi->is_terlambat ?? false,
'keterangan' => $absensi->keterangan ?? '-',
'teknisi' => [
'id' => $absensi->teknisi ? $absensi->teknisi->id_teknisi : null,
'nama' => $absensi->teknisi ? $absensi->teknisi->nama : 'Teknisi tidak ditemukan',
'email' => ($absensi->teknisi && $absensi->teknisi->email)
? $absensi->teknisi->email
: 'Email tidak tersedia',
],
'foto_masuk_url' => $fotoMasukUrl,
'foto_keluar_url' => $fotoKeluarUrl,
'kategori_kerja' => $absensi->kategori_kerja,
'latitude' => $absensi->latitude ?? '0',
'longitude' => $absensi->longitude ?? '0',
];
\Log::info('Response Data: ' . json_encode($data));
\Log::info('=== END DEBUG ===');
return response()->json([
'success' => true,
'data' => $data
]);
}
/**
* Mendapatkan statistik absensi
*/
public function getStatistik(Request $request)
{
$id_teknisi = $request->id_teknisi;
$start = $request->start_date;
$end = $request->end_date;
// Ambil data mentah pakai Query Builder agar lebih pasti
$data = \DB::table('absensis')
->whereBetween('tanggal', [$start . ' 00:00:00', $end . ' 23:59:59'])
->get();
$stats = ['hadir' => 0, 'terlambat' => 0, 'izin' => 0, 'sakit' => 0];
$trendGroups = [];
$rankGroups = [];
$weekly = ['Sen'=>0, 'Sel'=>0, 'Rab'=>0, 'Kam'=>0, 'Jum'=>0];
$dayMap = [1=>'Min', 2=>'Sen', 3=>'Sel', 4=>'Rab', 5=>'Kam', 6=>'Jum', 7=>'Sab'];
foreach ($data as $d) {
$status = strtolower($d->status);
$tgl = \Carbon\Carbon::parse($d->tanggal);
// 1. Filter Teknisi untuk Statistik Utama
if (!$id_teknisi || $d->id_teknisi == $id_teknisi) {
if (isset($stats[$status])) $stats[$status]++;
$jam = $d->jam_masuk ? \Carbon\Carbon::parse($d->jam_masuk)->format('H:i') : '';
if ($jam && ($jam < '07:00' || $jam > '18:00')) $stats['terlambat']++;
}
// 2. Trend Bulanan (Gunakan semua data biar grafiknya penuh)
$week = 'Minggu ' . ceil($tgl->day / 7);
if (!isset($trendGroups[$week])) {
$trendGroups[$week] = ['label' => $week, 'hadir' => 0, 'urgent' => 0];
}
if ($status == 'hadir') $trendGroups[$week]['hadir']++;
// 3. Ranking Data (Group by Teknisi)
if (!isset($rankGroups[$d->id_teknisi])) {
$tek = \DB::table('teknisis')->where('id_teknisi', $d->id_teknisi)->first();
$rankGroups[$d->id_teknisi] = [
'name' => $tek ? $tek->nama : 'Unknown',
'init' => $tek ? strtoupper(substr($tek->nama, 0, 2)) : '??',
'total' => 0, 'hadir' => 0
];
}
$rankGroups[$d->id_teknisi]['total']++;
if ($status == 'hadir') $rankGroups[$d->id_teknisi]['hadir']++;
// 4. Weekly Data
$dayName = $dayMap[$tgl->dayOfWeek + 1] ?? '';
if (isset($weekly[$dayName]) && $status == 'hadir') $weekly[$dayName]++;
}
// Finalisasi Ranking
$rankings = collect($rankGroups)->map(function($r) {
$r['pct'] = $r['total'] > 0 ? round(($r['hadir'] / $r['total']) * 100) : 0;
return $r;
})->sortByDesc('pct')->values()->take(5);
// Finalisasi Trend (Urutkan Minggu 1, 2, dst)
ksort($trendGroups);
$trend = array_values($trendGroups);
return response()->json([
'success' => true,
'data' => array_merge($stats, [
'trend' => $trend,
'rankings' => $rankings,
'weekly' => $weekly
])
]);
}
/**
* Memperbarui data absensi (digunakan oleh Admin).
*/
public function update(Request $request, $id)
{
$request->validate([
'jam_masuk' => 'nullable',
'jam_keluar' => 'nullable',
'status' => 'required|in:hadir,izin,sakit',
'keterangan' => 'nullable|string'
]);
$absensi = Absensi::findOrFail($id);
$tgl = \Carbon\Carbon::parse($absensi->tanggal)->format('Y-m-d');
// Update fields
$absensi->jam_masuk = $request->jam_masuk ? $tgl . ' ' . $request->jam_masuk : null;
$absensi->jam_keluar = $request->jam_keluar ? $tgl . ' ' . $request->jam_keluar : null;
$absensi->status = $request->status;
$absensi->keterangan = $request->keterangan;
$absensi->save();
return response()->json([
'success' => true,
'message' => 'Data absensi berhasil diperbarui.'
]);
}
}