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

464 lines
15 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\ProgresKerja;
use App\Models\Penugasan;
use App\Models\Teknisi;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Carbon\Carbon;
class ProgresKerjaController extends Controller
{
/**
* Display a listing of the progress kerja.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$query = ProgresKerja::with(['teknisi', 'penugasan']);
// Filter by status
if ($request->filled('status')) {
$query->byStatus($request->status);
}
// Filter by teknisi
if ($request->filled('teknisi_id')) {
$query->byTeknisi($request->teknisi_id);
}
// Filter by date range
if ($request->filled('start_date') || $request->filled('end_date')) {
$query->byDateRange($request->start_date, $request->end_date);
}
// Search functionality
if ($request->filled('search')) {
$search = $request->search;
$query->where(function($q) use ($search) {
$q->where('tugas', 'like', "%{$search}%")
->orWhere('deskripsi_progres', 'like', "%{$search}%")
->orWhereHas('teknisi', function($teknisiQuery) use ($search) {
$teknisiQuery->where('nama', 'like', "%{$search}%");
});
});
}
$progresKerja = $query->latest()->paginate(10);
// Get filter options
$teknisiList = Teknisi::orderBy('nama')->get();
$statusList = ProgresKerja::$statusProgres;
// Get statistics
$statistics = ProgresKerja::getStatistics();
return view('Admin.KelolaPekerjaan.ProgresKerja', compact(
'progresKerja',
'teknisiList',
'statusList',
'statistics'
));
}
/**
* Show the form for creating a new progress kerja.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
$penugasanList = Penugasan::with('pelanggan')->orderBy('created_at', 'desc')->get();
$teknisiList = Teknisi::orderBy('nama')->get();
$statusList = ProgresKerja::$statusProgres;
return view('Admin.KelolaPekerjaan.ProgresKerjaForm', compact(
'penugasanList',
'teknisiList',
'statusList'
));
}
/**
* Store a newly created progress kerja in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'id_penugasan' => 'required|exists:penugasan,id_penugasan',
'id_teknisi' => 'required|exists:teknisi,id_teknisi',
'tugas' => 'required|string|max:255',
'deskripsi_progres' => 'nullable|string',
'status_progres' => 'required|in:' . implode(',', array_keys(ProgresKerja::$statusProgres)),
'persentase_pekerjaan' => 'required|integer|min:0|max:100',
'foto_progress' => 'nullable|image|mimes:jpeg,png,jpg|max:2048',
]);
if ($validator->fails()) {
return redirect()->back()
->withErrors($validator)
->withInput();
}
$data = $request->only([
'id_penugasan',
'id_teknisi',
'tugas',
'deskripsi_progres',
'status_progres',
'persentase_pekerjaan'
]);
// Handle foto progress upload
if ($request->hasFile('foto_progress')) {
$file = $request->file('foto_progress');
$fileName = time() . '_' . Str::random(10) . '.' . $file->getClientOriginalExtension();
// Store in public/storage/progress_photos
$file->storeAs('progress_photos', $fileName, 'public');
$data['foto_progress'] = $fileName;
}
$progresKerja = ProgresKerja::create($data);
// Auto update status based on percentage
$progresKerja->autoUpdateStatus();
return redirect()->route('progres-kerja.index')
->with('success', 'Progress kerja berhasil ditambahkan.');
}
/**
* Display the specified progress kerja.
*
* @param \App\Models\ProgresKerja $progresKerja
* @return \Illuminate\Http\Response
*/
public function show(ProgresKerja $progresKerja)
{
$progresKerja->load(['teknisi', 'penugasan.pelanggan']);
return view('Admin.KelolaPekerjaan.ProgresKerjaDetail', compact('progresKerja'));
}
/**
* Show the form for editing the specified progress kerja.
*
* @param \App\Models\ProgresKerja $progresKerja
* @return \Illuminate\Http\Response
*/
public function edit(ProgresKerja $progresKerja)
{
$penugasanList = Penugasan::with('pelanggan')->orderBy('created_at', 'desc')->get();
$teknisiList = Teknisi::orderBy('nama')->get();
$statusList = ProgresKerja::$statusProgres;
return view('Admin.KelolaPekerjaan.ProgresKerjaForm', compact(
'progresKerja',
'penugasanList',
'teknisiList',
'statusList'
));
}
/**
* Update the specified progress kerja in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\ProgresKerja $progresKerja
* @return \Illuminate\Http\Response
*/
public function update(Request $request, ProgresKerja $progresKerja)
{
$validator = Validator::make($request->all(), [
'id_penugasan' => 'required|exists:penugasan,id_penugasan',
'id_teknisi' => 'required|exists:teknisi,id_teknisi',
'tugas' => 'required|string|max:255',
'deskripsi_progres' => 'nullable|string',
'status_progres' => 'required|in:' . implode(',', array_keys(ProgresKerja::$statusProgres)),
'persentase_pekerjaan' => 'required|integer|min:0|max:100',
'foto_progress' => 'nullable|image|mimes:jpeg,png,jpg|max:2048',
]);
if ($validator->fails()) {
return redirect()->back()
->withErrors($validator)
->withInput();
}
$data = $request->only([
'id_penugasan',
'id_teknisi',
'tugas',
'deskripsi_progres',
'status_progres',
'persentase_pekerjaan'
]);
// Handle foto progress upload
if ($request->hasFile('foto_progress')) {
// Delete old photo if exists
if ($progresKerja->foto_progress) {
Storage::disk('public')->delete('progress_photos/' . $progresKerja->foto_progress);
}
$file = $request->file('foto_progress');
$fileName = time() . '_' . Str::random(10) . '.' . $file->getClientOriginalExtension();
$file->storeAs('progress_photos', $fileName, 'public');
$data['foto_progress'] = $fileName;
}
$progresKerja->update($data);
// Auto update status based on percentage
$progresKerja->autoUpdateStatus();
return redirect()->route('progres-kerja.index')
->with('success', 'Progress kerja berhasil diperbarui.');
}
/**
* Remove the specified progress kerja from storage.
*
* @param \App\Models\ProgresKerja $progresKerja
* @return \Illuminate\Http\Response
*/
public function destroy(ProgresKerja $progresKerja)
{
// Delete photo if exists
if ($progresKerja->foto_progress) {
Storage::disk('public')->delete('progress_photos/' . $progresKerja->foto_progress);
}
$progresKerja->delete();
return redirect()->route('progres-kerja.index')
->with('success', 'Progress kerja berhasil dihapus.');
}
/**
* Quick update progress status
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\ProgresKerja $progresKerja
* @return \Illuminate\Http\JsonResponse
*/
public function updateStatus(Request $request, ProgresKerja $progresKerja)
{
$validator = Validator::make($request->all(), [
'status' => 'required|in:' . implode(',', array_keys(ProgresKerja::$statusProgres)),
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'message' => 'Status tidak valid.'
], 400);
}
// Check if transition is valid
if (!$progresKerja->canTransitionTo($request->status)) {
return response()->json([
'success' => false,
'message' => 'Transisi status tidak valid.'
], 400);
}
$progresKerja->update(['status_progres' => $request->status]);
return response()->json([
'success' => true,
'message' => 'Status berhasil diperbarui.',
'new_status' => $progresKerja->status_formatted,
'badge_class' => $progresKerja->status_badge_class
]);
}
/**
* Update progress percentage
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\ProgresKerja $progresKerja
* @return \Illuminate\Http\JsonResponse
*/
public function updatePercentage(Request $request, ProgresKerja $progresKerja)
{
$validator = Validator::make($request->all(), [
'percentage' => 'required|integer|min:0|max:100',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'message' => 'Persentase tidak valid.'
], 400);
}
$progresKerja->update(['persentase_pekerjaan' => $request->percentage]);
$progresKerja->autoUpdateStatus();
return response()->json([
'success' => true,
'message' => 'Persentase berhasil diperbarui.',
'new_percentage' => $progresKerja->persentase_pekerjaan,
'new_status' => $progresKerja->status_formatted,
'badge_class' => $progresKerja->status_badge_class
]);
}
/**
* Get progress by teknisi (AJAX)
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function getByTeknisi(Request $request)
{
$teknisiId = $request->get('teknisi_id');
if (!$teknisiId) {
return response()->json([
'success' => false,
'message' => 'Teknisi ID diperlukan.'
], 400);
}
$progresKerja = ProgresKerja::getByTeknisi($teknisiId);
return response()->json([
'success' => true,
'data' => $progresKerja->map(function($item) {
return [
'id' => $item->id_progres,
'tugas' => $item->tugas,
'status' => $item->status_formatted,
'persentase' => $item->persentase_pekerjaan,
'tanggal_update' => $item->tanggal_update_formatted,
'penugasan' => $item->penugasan->nama_pekerjaan ?? 'N/A'
];
})
]);
}
/**
* Export progress data
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function export(Request $request)
{
$query = ProgresKerja::with(['teknisi', 'penugasan']);
// Apply same filters as index
if ($request->filled('status')) {
$query->byStatus($request->status);
}
if ($request->filled('teknisi_id')) {
$query->byTeknisi($request->teknisi_id);
}
if ($request->filled('start_date') || $request->filled('end_date')) {
$query->byDateRange($request->start_date, $request->end_date);
}
$progresKerja = $query->latest()->get();
$filename = 'progress_kerja_' . date('Y-m-d') . '.csv';
$headers = [
'Content-Type' => 'text/csv',
'Content-Disposition' => 'attachment; filename="' . $filename . '"',
];
$callback = function() use ($progresKerja) {
$file = fopen('php://output', 'w');
// Add BOM for UTF-8
fwrite($file, "\xEF\xBB\xBF");
// Header row
fputcsv($file, [
'ID',
'Penugasan',
'Teknisi',
'Tugas',
'Deskripsi Progress',
'Status',
'Persentase (%)',
'Tanggal Update',
'Foto Progress'
]);
// Data rows
foreach ($progresKerja as $item) {
fputcsv($file, [
$item->id_progres,
$item->penugasan->nama_pekerjaan ?? 'N/A',
$item->teknisi->nama ?? 'N/A',
$item->tugas,
$item->deskripsi_progres,
$item->status_formatted,
$item->persentase_pekerjaan,
$item->tanggal_update_formatted,
$item->has_foto ? 'Ya' : 'Tidak'
]);
}
fclose($file);
};
return response()->stream($callback, 200, $headers);
}
/**
* Get recent updates for dashboard
*
* @return \Illuminate\Http\JsonResponse
*/
public function getRecentUpdates()
{
$recentUpdates = ProgresKerja::getRecentUpdates(5);
return response()->json([
'success' => true,
'data' => $recentUpdates->map(function($item) {
return [
'id' => $item->id_progres,
'tugas' => $item->tugas,
'teknisi' => $item->teknisi->nama ?? 'N/A',
'status' => $item->status_formatted,
'persentase' => $item->persentase_pekerjaan,
'tanggal_update' => $item->tanggal_update_formatted,
'days_since_update' => $item->days_since_update
];
})
]);
}
/**
* Get statistics for dashboard
*
* @return \Illuminate\Http\JsonResponse
*/
public function getStatistics()
{
$statistics = ProgresKerja::getStatistics();
return response()->json([
'success' => true,
'data' => $statistics
]);
}
}