SIPDAM/samooapk/app/Http/Controllers/Api/DashboardApiController.php

243 lines
9.4 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Penugasan;
use App\Models\Penggajian;
use App\Models\Kasbon;
use App\Models\Teknisi;
use App\Models\Absensi;
use App\Models\TarifPekerjaan;
use Illuminate\Http\Request;
use Exception;
use Carbon\Carbon;
class DashboardApiController extends Controller
{
/**
* GET - Data dashboard mobile teknisi
*/
public function index(Request $request)
{
try {
$idTeknisi = $request->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);
}
}