464 lines
15 KiB
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
|
|
]);
|
|
}
|
|
} |