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

406 lines
16 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Penugasan;
use App\Models\Teknisi;
use App\Models\TarifPekerjaan;
use App\Models\TimTeknisiPenugasan;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Carbon\Carbon;
class PenugasanController extends Controller
{
public function index(Request $request)
{
$query = Penugasan::with(['teknisi', 'tarif', 'timTeknisi.teknisi']);
if ($request->filled('status')) {
if ($request->status === 'garansi_aktif') {
$query->garansiAktif();
} else {
$query->where('status_pekerjaan', $request->status);
}
}
if ($request->filled('jenis_pekerjaan')) {
$query->where('jenis_pekerjaan', $request->jenis_pekerjaan);
}
if ($request->filled('search')) {
$search = $request->search;
$query->where(function($q) use ($search) {
$q->where('catatan_admin', 'LIKE', "%{$search}%")
->orWhere('detail_pekerjaan', 'LIKE', "%{$search}%")
->orWhereHas('teknisi', function($tq) use ($search) {
$tq->where('nama', 'LIKE', "%{$search}%");
});
});
}
if ($request->filled('id_teknisi')) {
$teknisiId = $request->id_teknisi;
$query->where(function($q) use ($teknisiId) {
$q->where('id_teknisi', $teknisiId)
->orWhereHas('timTeknisi', function($tq) use ($teknisiId) {
$tq->where('id_teknisi', $teknisiId);
});
});
}
if ($request->filled('start_date') && $request->filled('end_date')) {
$query->whereBetween('tanggal_diberikan', [$request->start_date, $request->end_date]);
} elseif ($request->filled('start_date')) {
$query->where('tanggal_diberikan', '>=', $request->start_date);
} elseif ($request->filled('end_date')) {
$query->where('tanggal_diberikan', '<=', $request->end_date);
}
$penugasan = $query->orderBy('created_at', 'desc')->paginate(10);
$totalPenugasan = Penugasan::count();
$belumMulai = Penugasan::where('status_pekerjaan', 'belum_mulai')->count();
$dalamProses = Penugasan::where('status_pekerjaan', 'dalam_proses')->count();
$selesai = Penugasan::where('status_pekerjaan', 'selesai')->count();
$dibatalkan = Penugasan::where('status_pekerjaan', 'dibatalkan')->count();
$garansiAktif = Penugasan::garansiAktif()->count();
$today = Carbon::today()->toDateString();
$absentTechIds = \App\Models\Absensi::where('tanggal', $today)
->whereIn('status', ['izin', 'sakit'])
->pluck('id_teknisi')
->toArray();
$abandonedTasks = collect();
if (!empty($absentTechIds)) {
$abandonedTasks = Penugasan::whereIn('status_pekerjaan', ['belum_mulai', 'dalam_proses'])
->where(function($q) use ($absentTechIds) {
$q->whereIn('id_teknisi', $absentTechIds)
->orWhereHas('timTeknisi', function($tq) use ($absentTechIds) {
$tq->whereIn('id_teknisi', $absentTechIds);
});
})
->with('teknisi')
->get();
}
$teknisis = Teknisi::where('status', 'aktif')->orderBy('nama')->get();
$teknisiList = $teknisis; // Use same data for the new dropdown
return view('Admin.KelolaPekerjaan.Penugasan', compact(
'penugasan', 'totalPenugasan', 'belumMulai', 'dalamProses',
'selesai', 'dibatalkan', 'garansiAktif', 'teknisis', 'teknisiList', 'abandonedTasks'
));
}
public function store(Request $request)
{
try {
$validated = $request->validate([
'id_teknisi' => 'required|array',
'id_teknisi.*' => 'exists:teknisis,id_teknisi',
'tanggal_diberikan' => 'required|date',
'foto_surat' => 'nullable|image|mimes:jpeg,png,jpg,webp|max:5120',
'catatan_admin' => 'nullable|string',
'jenis_pekerjaan' => 'required|string',
'alamat_lokasi' => 'required|string',
'nama_pelanggan' => 'nullable|string',
'no_sambungan' => 'nullable|string',
]);
DB::beginTransaction();
$path = null;
if ($request->hasFile('foto_surat')) {
$path = $request->file('foto_surat')->store('penugasan/surat', 'public');
}
$penugasan = Penugasan::create([
'id_teknisi' => $validated['id_teknisi'][0],
'foto_surat' => $path,
'tanggal_diberikan' => $validated['tanggal_diberikan'],
'catatan_admin' => $validated['catatan_admin'] ?? null,
'jenis_pekerjaan' => $validated['jenis_pekerjaan'],
'alamat_lokasi' => $validated['alamat_lokasi'],
'nama_pelanggan' => $validated['nama_pelanggan'] ?? null,
'no_sambungan' => $validated['no_sambungan'] ?? null,
'status_pekerjaan' => 'belum_mulai',
]);
$techIds = array_unique($validated['id_teknisi']);
foreach ($techIds as $techId) {
TimTeknisiPenugasan::create([
'id_penugasan' => $penugasan->id_penugasan,
'id_teknisi' => $techId,
'status_kehadiran' => 'hadir',
]);
}
DB::commit();
return redirect()->route('pekerjaan.penugasan.index')
->with('success', 'Penugasan berhasil dibuat! Teknisi akan melengkapi detail via mobile.');
} catch (\Exception $e) {
DB::rollBack();
return redirect()->back()
->with('error', 'Gagal menambahkan data: ' . $e->getMessage())
->withInput();
}
}
/**
* ✅ FIX: Tambah field garansi lengkap di response show()
* - is_garansi_aktif → true/false apakah garansi masih aktif
* - sisa_hari_garansi → berapa hari tersisa
* - tanggal_garansi_mulai → sudah ikut dari toArray()
* - tanggal_garansi_selesai → sudah ikut dari toArray()
*
* Sebelumnya field-field ini tidak di-append sehingga
* badge garansi di modal detail tidak pernah muncul
* meski datanya sudah ada di database
*/
public function show($id)
{
try {
$penugasan = Penugasan::with(['teknisi', 'tarif', 'timTeknisi.teknisi', 'items.tarif'])
->findOrFail($id);
$data = $penugasan->toArray();
$data['foto_surat_url'] = $penugasan->foto_surat_url;
$data['foto_sebelum_url'] = $penugasan->foto_sebelum_url;
$data['foto_sesudah_url'] = $penugasan->foto_sesudah_url;
$data['label_jenis_pekerjaan'] = $penugasan->label_jenis_pekerjaan;
// ✅ FIX: Info garansi — dibutuhkan oleh blade untuk tampilkan badge
$data['is_garansi_aktif'] = $penugasan->isGaransiAktif();
$data['sisa_hari_garansi'] = $penugasan->getSisaHariGaransi();
return response()->json(['success' => true, 'data' => $data]);
} catch (\Exception $e) {
return response()->json(['success' => false, 'message' => 'Data tidak ditemukan'], 404);
}
}
public function edit($id)
{
try {
$penugasan = Penugasan::with(['teknisi', 'timTeknisi.teknisi'])->findOrFail($id);
$data = $penugasan->toArray();
$data['foto_surat_url'] = $penugasan->foto_surat_url;
return response()->json(['success' => true, 'data' => $data]);
} catch (\Exception $e) {
return response()->json(['success' => false, 'message' => 'Data tidak ditemukan'], 404);
}
}
public function update(Request $request, $id)
{
try {
$penugasan = Penugasan::findOrFail($id);
$validated = $request->validate([
'id_teknisi' => 'required|array',
'id_teknisi.*' => 'exists:teknisis,id_teknisi',
'tanggal_diberikan' => 'required|date',
'foto_surat' => 'nullable|image|mimes:jpeg,png,jpg,webp|max:5120',
'catatan_admin' => 'nullable|string',
'jenis_pekerjaan' => 'required|string',
'alamat_lokasi' => 'required|string',
'nama_pelanggan' => 'nullable|string',
'no_sambungan' => 'nullable|string',
]);
DB::beginTransaction();
$updateData = [
'id_teknisi' => $validated['id_teknisi'][0],
'tanggal_diberikan' => $validated['tanggal_diberikan'],
'catatan_admin' => $validated['catatan_admin'] ?? null,
'jenis_pekerjaan' => $validated['jenis_pekerjaan'],
'alamat_lokasi' => $validated['alamat_lokasi'],
'nama_pelanggan' => $validated['nama_pelanggan'] ?? null,
'no_sambungan' => $validated['no_sambungan'] ?? null,
];
if ($request->hasFile('foto_surat')) {
if ($penugasan->foto_surat) {
Storage::disk('public')->delete($penugasan->foto_surat);
}
$updateData['foto_surat'] = $request->file('foto_surat')->store('penugasan/surat', 'public');
}
$penugasan->update($updateData);
TimTeknisiPenugasan::where('id_penugasan', $penugasan->id_penugasan)->delete();
$techIds = array_unique($validated['id_teknisi']);
foreach ($techIds as $techId) {
TimTeknisiPenugasan::create([
'id_penugasan' => $penugasan->id_penugasan,
'id_teknisi' => $techId,
'status_kehadiran' => 'hadir',
]);
}
DB::commit();
return response()->json(['success' => true, 'message' => 'Data berhasil diupdate!']);
} catch (\Exception $e) {
DB::rollBack();
return response()->json(['success' => false, 'message' => 'Gagal update: ' . $e->getMessage()], 500);
}
}
public function destroy($id)
{
try {
DB::beginTransaction();
$penugasan = Penugasan::findOrFail($id);
if ($penugasan->foto_surat) {
Storage::disk('public')->delete($penugasan->foto_surat);
}
$penugasan->delete();
DB::commit();
return response()->json(['success' => true, 'message' => 'Data berhasil dihapus!']);
} catch (\Exception $e) {
DB::rollBack();
return response()->json(['success' => false, 'message' => 'Gagal menghapus: ' . $e->getMessage()], 500);
}
}
public function getTarifByJenis(Request $request)
{
try {
$tarifs = TarifPekerjaan::where('jenis_pekerjaan', $request->jenis_pekerjaan)
->where('is_active', true)
->get();
return response()->json(['success' => true, 'data' => $tarifs]);
} catch (\Exception $e) {
return response()->json(['success' => false, 'message' => 'Gagal mengambil tarif'], 500);
}
}
public function getTeknisiByDate(Request $request)
{
try {
// Selalu tampilkan seluruh teknisi aktif agar fleksibel secara operasional
$teknisis = Teknisi::where('status', 'aktif')
->orderBy('nama')
->get();
return response()->json(['success' => true, 'data' => $teknisis]);
} catch (\Exception $e) {
return response()->json(['success' => false, 'message' => 'Gagal mengambil data teknisi: ' . $e->getMessage()], 500);
}
}
/**
* ✅ FIX: Filter tanggal monitoring pakai tanggal_diselesaikan
* bukan updated_at agar hasil filter akurat
*/
public function monitoring(Request $request)
{
$query = Penugasan::with(['teknisi', 'timTeknisi.teknisi']);
if ($request->filled('status')) {
$query->where('status_pekerjaan', $request->status);
}
if ($request->filled('teknisi_id')) {
$teknisiId = $request->teknisi_id;
$query->where(function($q) use ($teknisiId) {
$q->where('id_teknisi', $teknisiId)
->orWhereHas('timTeknisi', function($tq) use ($teknisiId) {
$tq->where('id_teknisi', $teknisiId);
});
});
}
if ($request->filled('start_date') && $request->filled('end_date')) {
$start = $request->start_date . ' 00:00:00';
$end = $request->end_date . ' 23:59:59';
$query->where(function($q) use ($start, $end) {
$q->where(function($q2) use ($start, $end) {
$q2->whereNotNull('tanggal_diselesaikan')
->whereBetween('tanggal_diselesaikan', [$start, $end]);
})->orWhere(function($q2) use ($start, $end) {
$q2->whereNull('tanggal_diselesaikan')
->whereBetween('updated_at', [$start, $end]);
});
});
} elseif ($request->filled('start_date')) {
$start = $request->start_date . ' 00:00:00';
$query->where(function($q) use ($start) {
$q->where(function($q2) use ($start) {
$q2->whereNotNull('tanggal_diselesaikan')
->where('tanggal_diselesaikan', '>=', $start);
})->orWhere(function($q2) use ($start) {
$q2->whereNull('tanggal_diselesaikan')
->where('updated_at', '>=', $start);
});
});
} elseif ($request->filled('end_date')) {
$end = $request->end_date . ' 23:59:59';
$query->where(function($q) use ($end) {
$q->where(function($q2) use ($end) {
$q2->whereNotNull('tanggal_diselesaikan')
->where('tanggal_diselesaikan', '<=', $end);
})->orWhere(function($q2) use ($end) {
$q2->whereNull('tanggal_diselesaikan')
->where('updated_at', '<=', $end);
});
});
}
$progresKerja = $query->orderBy('updated_at', 'desc')->paginate(12);
$progresKerja->getCollection()->transform(function ($item) {
$item->persentase_pekerjaan = match($item->status_pekerjaan) {
'selesai' => 100,
'dalam_proses' => 50,
default => 0,
};
$item->is_garansi_aktif = $item->isGaransiAktif();
$item->sisa_hari_garansi = $item->getSisaHariGaransi();
return $item;
});
$statistics = [
'total' => Penugasan::count(),
'dalam_progres' => Penugasan::where('status_pekerjaan', 'dalam_proses')->count(),
'selesai' => Penugasan::where('status_pekerjaan', 'selesai')->count(),
'belum_mulai' => Penugasan::where('status_pekerjaan', 'belum_mulai')->count(),
'garansi_aktif' => Penugasan::garansiAktif()->count(),
];
$statusList = [
'belum_mulai' => 'Belum Mulai',
'dalam_proses' => 'Dalam Proses',
'selesai' => 'Selesai',
];
$teknisiList = Teknisi::orderBy('nama')->get();
return view('Admin.KelolaPekerjaan.ProgresKerja', compact(
'progresKerja', 'statistics', 'statusList', 'teknisiList'
));
}
}