input('id_teknisi'); if (!$idTeknisi) { return response()->json([ 'success' => false, 'message' => 'ID Teknisi tidak ditemukan' ], 401); } $teknisi = Teknisi::findOrFail($idTeknisi); // 1. Tugas Hari Ini / Aktif $tugasAktif = Penugasan::where(function ($q) use ($idTeknisi) { $q->where('id_teknisi', $idTeknisi) ->orWhereHas('timTeknisi', function ($sq) use ($idTeknisi) { $sq->where('id_teknisi', $idTeknisi); }); }) ->whereIn('status_pekerjaan', ['belum_mulai', 'dalam_proses']) ->count(); // 2. Gaji Bulan Berjalan (Estimasi Ongkos Kerja) $now = Carbon::now(); // Cari semua penugasan yang melibatkan teknisi ini di bulan berjalan (eager loaded untuk performa) $penugasans = Penugasan::where(function ($q) use ($idTeknisi) { // (a) Teknisi utama penugasan $q->where('id_teknisi', $idTeknisi) // (b) Anggota tim yang hadir ->orWhereHas('timTeknisi', function ($sq) use ($idTeknisi) { $sq->where('id_teknisi', $idTeknisi) ->where('status_kehadiran', 'hadir'); }); }) ->where('status_pekerjaan', 'selesai') ->where(function ($q) use ($now) { // Filter berdasarkan bulan selesai (Prioritas: tanggal_diselesaikan, fallback ke updated_at) $q->where(function ($q2) use ($now) { $q2->whereNotNull('tanggal_diselesaikan') ->whereMonth('tanggal_diselesaikan', $now->month) ->whereYear('tanggal_diselesaikan', $now->year); })->orWhere(function ($q2) use ($now) { $q2->whereNull('tanggal_diselesaikan') ->whereMonth('updated_at', $now->month) ->whereYear('updated_at', $now->year); }); }) ->with(['items.tarif', 'timTeknisi']) ->get(); $estimasiGaji = 0; $tugasSelesaiBulanIni = 0; foreach ($penugasans as $penugasan) { $tugasSelesaiBulanIni++; // Hitung jumlah anggota tim yang hadir $jumlahHadir = $penugasan->countTimHadir(); if ($jumlahHadir === 0) { $jumlahHadir = 1; } // Hitung total ongkos dari penugasan_items $totalOngkosTugas = 0; if ($penugasan->items->count() > 0) { foreach ($penugasan->items as $item) { $itemTotal = (float) $item->total_nilai_pekerjaan; if ($itemTotal <= 0) { $itemTotal = $this->calculatePenugasanItemValue($item); } $totalOngkosTugas += $itemTotal; } } // Fallback: ambil dari total_nilai_pekerjaan penugasan induk atau tarif if ($totalOngkosTugas <= 0) { $totalOngkosTugas = $this->calculatePenugasanValue($penugasan); } if ($totalOngkosTugas <= 0) { continue; } // Bagian ongkos = total ongkos dibagi jumlah anggota tim yang hadir $bagianOngkos = $totalOngkosTugas / $jumlahHadir; $estimasiGaji += $bagianOngkos; } // 3. Total Kasbon Aktif $totalKasbon = Kasbon::where('id_teknisi', $idTeknisi) ->where('status', 'belum_lunas') ->sum('jumlah_kasbon'); // 4. Gaji Terakhir Diterima $gajiTerakhir = Penggajian::where('id_teknisi', $idTeknisi) ->where('status_pembayaran', 'sudah_bayar') ->orderBy('periode_tahun', 'desc') ->orderBy('periode_bulan', 'desc') ->first(); // 5. Statistik Absensi Bulan Ini $absensiBulanIni = Absensi::where('id_teknisi', $idTeknisi) ->whereMonth('tanggal', $now->month) ->whereYear('tanggal', $now->year) ->get(); $hadir = $absensiBulanIni->where('status', 'hadir')->count(); $totalAbsen = $absensiBulanIni->count(); $kehadiran = $totalAbsen > 0 ? round(($hadir / $totalAbsen) * 100) : 0; // Rata-rata jam kerja (dalam jam) $totalDurasiMenit = $absensiBulanIni->where('status', 'hadir')->sum(function($a) { return $a->durasi_kerja; }); $jamKerja = round($totalDurasiMenit / 60, 1); // Efisiensi $poolTugas = $tugasAktif + $tugasSelesaiBulanIni; $efisiensi = $poolTugas > 0 ? round(($tugasSelesaiBulanIni / $poolTugas) * 100) : 0; return response()->json([ 'success' => true, 'message' => 'Data dashboard berhasil diambil', 'data' => [ 'teknisi' => [ 'nama' => $teknisi->nama, 'spesialisasi' => $teknisi->spesialisasi, 'foto' => $teknisi->foto_url ], 'statistik' => [ 'tugas_aktif' => $tugasAktif, 'tugas_selesai' => $tugasSelesaiBulanIni, 'estimasi_gaji' => (float) $estimasiGaji, 'total_kasbon' => (float) $totalKasbon, 'gaji_terakhir' => $gajiTerakhir ? (float) $gajiTerakhir->gaji_bersih : 0, 'periode_terakhir' => $gajiTerakhir ? Penggajian::getNamaBulan($gajiTerakhir->periode_bulan) . ' ' . $gajiTerakhir->periode_tahun : '-', 'kehadiran' => $kehadiran, 'jam_kerja' => $jamKerja, 'efisiensi' => $efisiensi, ] ] ]); } catch (Exception $e) { return response()->json([ 'success' => false, 'message' => 'Gagal mengambil data dashboard: ' . $e->getMessage() ], 500); } } /** * Calculate nilai penugasan dengan fallback ke tarif */ private function calculatePenugasanValue($penugasan): float { if ($penugasan->total_nilai_pekerjaan > 0) { return (float) $penugasan->total_nilai_pekerjaan; } $tarif = $penugasan->tarif; if (!$tarif) { $query = TarifPekerjaan::where('jenis_pekerjaan', $penugasan->jenis_pekerjaan) ->where('is_active', true); if ($penugasan->dimensi_pipa) { $query->where('dimensi_pipa', $penugasan->dimensi_pipa); } $tarif = $query->first(); } if (!$tarif) return 0; if ($penugasan->jarak_meter > 0 && $tarif->tarif_per_meter) { return (float) $tarif->tarif_per_meter * (float) $penugasan->jarak_meter; } if ($penugasan->jumlah_unit > 0 && $tarif->tarif_per_unit) { return (float) $tarif->tarif_per_unit * (int) $penugasan->jumlah_unit; } if ($penugasan->jumlah_titik > 0 && $tarif->tarif_per_unit) { return (float) $tarif->tarif_per_unit * (int) $penugasan->jumlah_titik; } return (float) ($tarif->tarif_per_unit ?? $tarif->tarif_per_meter ?? 0); } /** * Calculate nilai untuk setiap PenugasanItem */ private function calculatePenugasanItemValue($item): float { if ($item->total_nilai_pekerjaan > 0) { return (float) $item->total_nilai_pekerjaan; } $tarif = $item->tarif; if (!$tarif) { $query = TarifPekerjaan::where('jenis_pekerjaan', $item->jenis_pekerjaan) ->where('is_active', true); if ($item->dimensi_pipa) { $query->where('dimensi_pipa', $item->dimensi_pipa); } $tarif = $query->first(); } if (!$tarif) return 0; if ($item->jarak_meter > 0 && $tarif->tarif_per_meter) { return (float) $tarif->tarif_per_meter * (float) $item->jarak_meter; } if ($item->jumlah_unit > 0 && $tarif->tarif_per_unit) { return (float) $tarif->tarif_per_unit * (int) $item->jumlah_unit; } if ($item->jumlah_titik > 0 && $tarif->tarif_per_unit) { return (float) $tarif->tarif_per_unit * (int) $item->jumlah_titik; } return (float) ($tarif->tarif_per_unit ?? $tarif->tarif_per_meter ?? 0); } }