diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index ea82162..156d526 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -17,6 +17,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; +use Mockery\Matcher\Not; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Xlsx; use setasign\Fpdi\Fpdi; @@ -1330,20 +1331,36 @@ class DashboardController extends Controller $isAtasan = MappingUnitKerjaPegawai::where('statusenabled', true)->where(function($q){ $q->where('objectatasanlangsungfk', auth()->user()?->dataUser?->id)->orWhere('objectpejabatpenilaifk', auth()->user()->objectpegawaifk); })->exists(); + + $objectUnit = MappingUnitKerjaPegawai::query() + ->where('statusenabled', true) + ->where('objectpegawaifk', auth()->user()->objectpegawaifk) + ->pluck('objectunitkerjapegawaifk') + ->unique() + ->values() + ->all(); + $isKomiteMutu = in_array(51, $objectUnit); + $isTurt = in_array(22, $objectUnit); foreach ($datas as $index => $data) { - list($id_unit_kerja, $nama_unit_kerja) = explode('/', $data['id_unit_kerja'],2); + if(isset(explode('/', $data['id_unit_kerja'],2)[1])){ + list($id_unit_kerja, $nama_unit_kerja) = explode('/', $data['id_unit_kerja'],2); + }else{ + $nama_unit_kerja = UnitKerja::where('id', $data['id_unit_kerja'])->first()->name; + $id_unit_kerja = $data['id_unit_kerja']; + } list($id_sub_unit_kerja, $nama_sub_unit_kerja) = explode('/', $data['id_sub_unit_kerja'],2); + if($data['master_kategori_directory_id']){ + list($master_kategori_directory_id, $nama_kategori) = explode('/', $data['master_kategori_directory_id'],2); + } if(isset($data['akre'])){ $path = $data['akre']; }else{ if(isset($data['master_kategori_directory_id'])){ - list($master_kategori_directory_id, $nama_kategori) = explode('/', $data['master_kategori_directory_id'],2); $path = "{$nama_unit_kerja}/{$nama_sub_unit_kerja}/{$nama_kategori}"; }else{ $path = "{$nama_unit_kerja}/{$nama_sub_unit_kerja}"; } } - $uploadedFile = request()->file("data.$index.file"); if(!$uploadedFile){ throw new \RuntimeException('File wajib diunggah pada segment ke-' . ($index+1)); @@ -1351,8 +1368,14 @@ class DashboardController extends Controller if (!$uploadedFile->isValid()) { throw new \RuntimeException('Upload file gagal pada segment ke-' . ($index+1)); } - $status = $isAtasan ? 'approved' : null; - dd($data); + $requiresMutuApproval = isset($data['akre']); + $requiresTurtApproval = !empty($master_kategori_directory_id); + $mutuStatus = $isKomiteMutu && $requiresMutuApproval ? 'approved' : null; + $turtStatus = $isTurt && $requiresTurtApproval ? 'approved' : null; + $finalApproved = $isAtasan + && (!$requiresMutuApproval || $mutuStatus === 'approved') + && (!$requiresTurtApproval || $turtStatus === 'approved'); + $status = $finalApproved ? 'approved' : null; $payload = [ 'id_unit_kerja' => $id_unit_kerja, 'id_sub_unit_kerja' => $id_sub_unit_kerja, @@ -1368,28 +1391,34 @@ class DashboardController extends Controller 'action_by' => $status && $status === "approved" ? auth()->user()->objectpegawaifk : null, 'action_at' => $status && $status === "approved" ? now() : null, 'is_akre' => isset($data['akre']), - 'kategori_hukum' => isset($data['kategori_hukum']) ? $data['kategori_hukum'] : null + 'kategori_hukum' => isset($data['kategori_hukum']) ? $data['kategori_hukum'] : null, + 'status_mutu' => $mutuStatus, + 'action_mutu_at' => $mutuStatus === 'approved' ? now() : null, + 'action_mutu_by' => $mutuStatus === 'approved' ? auth()->user()->objectpegawaifk : null, + 'status_turt' => $turtStatus, + 'action_turt_at' => $turtStatus === 'approved' ? now() : null, + 'action_turt_by' => $turtStatus === 'approved' ? auth()->user()->objectpegawaifk : null, ]; $fd = FileDirectory::create($payload); - $disk = Storage::disk('s3'); + // $disk = Storage::disk('s3'); $imageName = $this->buildStoredFileName( $fd->nama_dokumen ?? null, $fd->file_directory_id, $uploadedFile->getClientOriginalExtension() ); - $disk->putFileAs( - $path, - $uploadedFile, - $imageName, - ['visibility' => 'private'] - ); + // $disk->putFileAs( + // $path, + // $uploadedFile, + // $imageName, + // ['visibility' => 'private'] + // ); $fd->update([ 'file' => $path . '/' . $imageName ]); + $docNumber = $fd->no_dokumen ? 'nomor '. $fd->no_dokumen : $data['nama_dokumen']; if(!$isAtasan){ $uploaderName = auth()->user()?->dataUser?->namalengkap ?? 'Pengguna'; - $docNumber = $fd->no_dokumen ? 'nomor '. $fd->no_dokumen : $imageName; $payloadNotification = [ 'created_at' => now(), 'text_notifikasi' => "Dokumen {$docNumber} memerlukan persetujuan. Diunggah oleh {$uploaderName}.", @@ -1412,15 +1441,40 @@ class DashboardController extends Controller } } + if($isAtasan){ + if($fd->is_akre && $fd->status_mutu !== 'approved'){ + $payloadNotificationMutu = [ + 'created_at' => now(), + 'text_notifikasi' => "Dokumen {$docNumber} memerlukan persetujuan. Diunggah oleh " . auth()->user()->dataUser->namalengkap, + 'url' => '/pengajuan-file', + 'is_read' => false, + 'unit_id' => 51, + ]; + + Notifkasi::create($payloadNotificationMutu); + } + if($fd->master_kategori_directory_id && $fd->status_turt !== 'approved'){ + $payloadNotificationTurt = [ + 'created_at' => now(), + 'text_notifikasi' => "Dokumen {$docNumber} memerlukan persetujuan. Diunggah oleh " . auth()->user()->dataUser->namalengkap, + 'url' => '/pengajuan-file', + 'is_read' => false, + 'unit_id' => 22, + ]; + + Notifkasi::create($payloadNotificationTurt); + } + } } + DB::connection('dbDirectory')->commit(); return response()->json([ 'status' => true, 'message' => 'Data berhasil disimpan', - 'status_action' => $isAtasan ? 'approved' : null + 'status_action' => $status ], 200); } catch (\Throwable $th) { - // dd($th); + dd($th); DB::connection('dbDirectory')->rollback(); return response()->json([ 'status' => false, @@ -1822,7 +1876,19 @@ class DashboardController extends Controller } public function pendingFile(){ - return view('pendingFile.index', ['title' => 'Data Persetujuan']); + $objectUnit = MappingUnitKerjaPegawai::query() + ->where('statusenabled', true) + ->where('objectpegawaifk', auth()->user()->objectpegawaifk) + ->pluck('objectunitkerjapegawaifk') + ->unique() + ->values() + ->all(); + + return view('pendingFile.index', [ + 'title' => 'Data Persetujuan', + 'isKomiteMutu' => in_array(51, $objectUnit), + 'isTurt' => in_array(22, $objectUnit), + ]); } public function dataPendingFile(){ @@ -1840,18 +1906,80 @@ class DashboardController extends Controller ->unique() ->values() ->all(); + $objectUnit = MappingUnitKerjaPegawai::query() + ->where('statusenabled', true) + ->where('objectpegawaifk', auth()->user()->objectpegawaifk) + ->pluck('objectunitkerjapegawaifk') + ->unique() + ->values() + ->all(); $keyword = request('keyword'); - $query = FileDirectory::where('statusenabled', true) - ->where(function($qsa){ - $qsa->where('status_action', '!=', 'approved')->orWhereNull('status_action'); - }) - ->whereIn('pegawai_id_entry', $objectpegawaifk) - ->when($keyword, function ($q) use ($keyword) { + $isKomiteMutu = in_array(51, $objectUnit); + $isTurt = in_array(22, $objectUnit); + // 51 / Komite Mutu + // 22 / turt + $query = FileDirectory::where('statusenabled', true); + + if ($isKomiteMutu || $isTurt) { + $query->where('status_action', 'approved') + ->where(function ($q) use ($isKomiteMutu, $isTurt) { + if ($isTurt) { + $q->where(function ($sub) { + $sub->whereNotNull('master_kategori_directory_id') + ->where(function ($pendingTurt) { + $pendingTurt->whereNull('status_turt') + ->orWhere('status_turt', 'rejected'); + }); + }); + } + if ($isKomiteMutu) { + $method = $isTurt ? 'orWhere' : 'where'; + $q->{$method}(function ($sub) { + $sub->where('is_akre', true) + ->where(function ($pendingMutu) { + $pendingMutu->whereNull('status_mutu') + ->orWhere('status_mutu', 'rejected'); + }); + }); + } + }); + } else { + $query->where(function ($qsa) { + $qsa->where('status_action', '!=', 'approved') + ->orWhereNull('status_action') + ->orWhere(function ($approvedButPending) { + $approvedButPending->where('status_action', 'approved') + ->where(function ($needFurtherApproval) { + $needFurtherApproval + ->where(function ($needTurt) { + $needTurt->whereNotNull('master_kategori_directory_id') + ->where(function ($pendingTurt) { + $pendingTurt->whereNull('status_turt') + ->orWhere('status_turt', 'rejected'); + }); + }) + ->orWhere(function ($needMutu) { + $needMutu->where('is_akre', true) + ->where(function ($pendingMutu) { + $pendingMutu->whereNull('status_mutu') + ->orWhere('status_mutu', 'rejected'); + }); + }); + }); + }); + }); + } + $query->when($keyword, function ($q) use ($keyword) { $q->where(function ($sub) use ($keyword) { $sub->where('nama_dokumen', 'ILIKE', "%{$keyword}%") ->orWhere('no_dokumen', 'ILIKE', "%{$keyword}%"); }); }); + if(!empty($objectpegawaifk) && !$isKomiteMutu && !$isTurt){ + $query->whereIn('pegawai_id_entry', $objectpegawaifk); + } + + if($start){ $query->whereDate('entry_at','>=',$start); @@ -1877,9 +2005,14 @@ class DashboardController extends Controller 'tanggal_terbit' => $item->tanggal_terbit, 'permission_file' => $item->permission_file, 'status_action' => $item->status_action, + 'status_mutu' => $item->status_mutu, + 'status_turt' => $item->status_turt, + 'mutu_revision' => $item->mutu_revision, + 'turt_revision' => $item->turt_revision, 'id_unit_kerja' => $item->id_unit_kerja, 'id_sub_unit_kerja' => $item->id_sub_unit_kerja, - 'master_kategori_directory_id' => $item->master_kategori_directory_id + 'master_kategori_directory_id' => $item->master_kategori_directory_id, + 'is_akre' => $item->is_akre, ]; }); return response()->json([ @@ -1942,6 +2075,29 @@ class DashboardController extends Controller 'action_type' => 'Approved Dokumen', ]; LogActivity::create($payloadLog); + if($data->is_akre){ + $payloadNotificationMutu = [ + 'created_at' => now(), + 'text_notifikasi' => "Dokumen {$docNumber} memerlukan persetujuan. Diunggah oleh {$data->pegawai_nama_entry}.", + 'url' => '/pending-file', + 'is_read' => false, + 'unit_id' => 51, + ]; + + Notifkasi::create($payloadNotificationMutu); + } + if($data->master_kategori_directory_id){ + $payloadNotificationTurt = [ + 'created_at' => now(), + 'text_notifikasi' => "Dokumen {$docNumber} memerlukan persetujuan. Diunggah oleh {$data->pegawai_nama_entry}.", + 'url' => '/pending-file', + 'is_read' => false, + 'unit_id' => 22, + ]; + + Notifkasi::create($payloadNotificationTurt); + } + DB::connection('dbDirectory')->commit(); return response()->json([ 'status' => true, @@ -2224,7 +2380,16 @@ class DashboardController extends Controller ]); } - $pegawaiId = auth()->user()?->dataUser?->id; + $pegawaiId = auth()->user()?->objectpegawaifk; + $objectUnit = MappingUnitKerjaPegawai::query() + ->where('statusenabled', true) + ->where('objectpegawaifk', auth()->user()->objectpegawaifk) + ->pluck('objectunitkerjapegawaifk') + ->unique() + ->values() + ->all(); + $isKomiteMutu = in_array(51, $objectUnit); + $isTurt = in_array(22, $objectUnit); if (!$pegawaiId) { return response()->json([ 'status' => false, @@ -2233,8 +2398,16 @@ class DashboardController extends Controller 'unread' => 0 ], 404); } - - $query = Notifkasi::where('pegawai_id', $pegawaiId); + $query = Notifkasi::query(); + $query->where(function($q) use($pegawaiId, $objectUnit, $isKomiteMutu, $isTurt){ + if($isKomiteMutu || $isTurt){ + $q->orWhere(function($sub) use($objectUnit){ + $sub->whereNull('pegawai_id')->whereIn('unit_id', $objectUnit); + }); + }else{ + $q->where('pegawai_id', $pegawaiId); + } + }); $unread = (clone $query)->where('is_read', false)->count(); $items = $query->orderBy('created_at', 'desc') ->limit(20) @@ -2266,6 +2439,15 @@ class DashboardController extends Controller } $pegawaiId = auth()->user()?->dataUser?->id; + $objectUnit = MappingUnitKerjaPegawai::query() + ->where('statusenabled', true) + ->where('objectpegawaifk', auth()->user()->objectpegawaifk) + ->pluck('objectunitkerjapegawaifk') + ->unique() + ->values() + ->all(); + $isKomiteMutu = in_array(51, $objectUnit); + $isTurt = in_array(22, $objectUnit); if (!$pegawaiId) { return response()->json([ 'status' => false, @@ -2273,9 +2455,17 @@ class DashboardController extends Controller ], 404); } - Notifkasi::where('pegawai_id', $pegawaiId) - ->where('is_read', false) - ->update(['is_read' => true]); + $query = Notifkasi::query(); + $query->where(function($q) use($pegawaiId, $isKomiteMutu, $isTurt, $objectUnit){ + if($isKomiteMutu || $isTurt){ + $q->orWhere(function($sub) use($objectUnit){ + $sub->whereNull('pegawai_id')->whereIn('unit_id', $objectUnit); + }); + }else{ + $q->where('pegawai_id', $pegawaiId); + } + })->where('is_read', false) + ->update(['is_read' => true]); return response()->json([ 'status' => true, @@ -2515,9 +2705,20 @@ class DashboardController extends Controller $katDok = MasterKategori::where('statusenabled', true) ->select('master_kategori_directory_id', 'nama_kategori_directory') ->get(); + $objectUnit = MappingUnitKerjaPegawai::query() + ->where('statusenabled', true) + ->where('objectpegawaifk', auth()->user()->objectpegawaifk) + ->pluck('objectunitkerjapegawaifk') + ->unique() + ->values() + ->all(); + $isKomiteMutu = in_array(51, $objectUnit); + $isTurt = in_array(22, $objectUnit); return view('pengajuanFile.index', [ 'title' => 'Data Persetujuan', - 'katDok' => $katDok + 'katDok' => $katDok, + 'isKomiteMutu' => $isKomiteMutu, + 'isTurt' => $isTurt ]); } @@ -2527,21 +2728,87 @@ class DashboardController extends Controller $start = request('start_date'); $end = request('end_date'); $isHistory = filter_var(request('history'), FILTER_VALIDATE_BOOLEAN); - $query = FileDirectory::with('kategori')->where('statusenabled', true) - ->where('pegawai_id_entry', auth()->user()->objectpegawaifk) - ->when($isHistory, function($q){ - $q->where('status_action', 'approved'); - }, function($q){ - $q->where(function($sub){ - $sub->where('status_action', '!=', 'approved') - ->orWhereNull('status_action'); + $mode = (string) request('mode', 'pengajuan'); + $pegawaiId = auth()->user()->objectpegawaifk; + $objectUnit = MappingUnitKerjaPegawai::query() + ->where('statusenabled', true) + ->where('objectpegawaifk', $pegawaiId) + ->pluck('objectunitkerjapegawaifk') + ->unique() + ->values() + ->all(); + $isKomiteMutu = in_array(51, $objectUnit); + $isTurt = in_array(22, $objectUnit); + + $query = FileDirectory::with('kategori')->where('statusenabled', true); + + if ($mode === 'persetujuan' && ($isKomiteMutu || $isTurt)) { + $query->where(function ($q) use ($isKomiteMutu, $isTurt) { + if ($isTurt) { + $q->whereNotNull('master_kategori_directory_id') + ->where(function ($pendingTurt) { + $pendingTurt->whereNull('status_turt') + ->orWhere('status_turt', 'rejected'); + }); + } + if ($isKomiteMutu) { + $method = $isTurt ? 'orWhere' : 'where'; + $q->{$method}(function ($sub) { + $sub->where('is_akre', true) + ->where(function ($pendingMutu) { + $pendingMutu->whereNull('status_mutu') + ->orWhere('status_mutu', 'rejected'); + }); + }); + } + })->where('status_action', 'approved'); + } else { + $query->where('pegawai_id_entry', $pegawaiId) + ->when($isHistory, function($q){ + $q->where('status_action', 'approved') + ->where(function ($sub) { + $sub->whereNull('master_kategori_directory_id') + ->orWhere('status_turt', 'approved'); + }) + ->where(function ($sub) { + $sub->where('is_akre', '!=', true) + ->orWhereNull('is_akre') + ->orWhere('status_mutu', 'approved'); + }); + }, function($q){ + $q->where(function($sub){ + $sub->where('status_action', '!=', 'approved') + ->orWhereNull('status_action') + ->orWhere(function ($approvedButPending) { + $approvedButPending->where('status_action', 'approved') + ->where(function ($needFurtherApproval) { + $needFurtherApproval + ->where(function ($needTurt) { + $needTurt->whereNotNull('master_kategori_directory_id') + ->where(function ($pendingTurt) { + $pendingTurt->whereNull('status_turt') + ->orWhere('status_turt', 'rejected'); + }); + }) + ->orWhere(function ($needMutu) { + $needMutu->where('is_akre', true) + ->where(function ($pendingMutu) { + $pendingMutu->whereNull('status_mutu') + ->orWhere('status_mutu', 'rejected'); + }); + }); + }); + }); + }); }); - }) - ->orderBy('entry_at','desc'); + } + + $query->orderBy('entry_at','desc'); if($keyword){ $query->where(function($q) use ($keyword){ $q->where('file', 'ILIKE', "%{$keyword}%") - ->orWhere('no_dokumen', 'ILIKE', "%{$keyword}%"); + ->orWhere('no_dokumen', 'ILIKE', "%{$keyword}%") + ->orWhere('nama_dokumen', 'ILIKE', "%{$keyword}%"); }); } if($start){ @@ -2568,6 +2835,10 @@ class DashboardController extends Controller 'permission_file' => $item->permission_file, 'status_action' => $item->status_action, 'revision' => $item->revision, + 'status_mutu' => $item->status_mutu, + 'status_turt' => $item->status_turt, + 'mutu_revision' => $item->mutu_revision, + 'turt_revision' => $item->turt_revision, 'id_unit_kerja' => $item->id_unit_kerja, 'id_sub_unit_kerja' => $item->id_sub_unit_kerja, 'master_kategori_directory_id' => $item->master_kategori_directory_id, @@ -2727,39 +2998,70 @@ class DashboardController extends Controller } } } - $payload['status_action'] = 'revised'; + $targetRoleNotifications = []; + $resetMutuApproval = $data->status_mutu === 'rejected'; + $resetTurtApproval = $data->status_turt === 'rejected'; + + if ($resetMutuApproval) { + $payload['status_mutu'] = null; + $payload['mutu_revision'] = null; + $payload['action_mutu_at'] = null; + $payload['action_mutu_by'] = null; + $targetRoleNotifications[] = 51; + } + + if ($resetTurtApproval) { + $payload['status_turt'] = null; + $payload['turt_revision'] = null; + $payload['action_turt_at'] = null; + $payload['action_turt_by'] = null; + $targetRoleNotifications[] = 22; + } + + $payload['revision'] = null; + $payload['status_action'] = 'revised'; + $payload['action_at'] = null; + $payload['action_by'] = null; if (!empty($payload)) { $data->update($payload); } + $data->refresh(); $mapping = MappingUnitKerjaPegawai::where('statusenabled', true) ->where('objectpegawaifk', auth()->user()?->dataUser?->id) ->first(); $parts = array_values(array_filter(explode('/', $data->file))); $uploaderName = auth()->user()?->dataUser?->namalengkap ?? 'Pengguna'; $docNumber = $data->no_dokumen ? 'nomor '. $data->no_dokumen : end($parts);; - $payloadNotification = [ - 'created_at' => now(), - 'text_notifikasi' => "Dokumen {$docNumber} telah direvisi dan memerlukan persetujuan ulang. ". "Direvisi oleh {$uploaderName}.", - 'url' => '/pending-file', - 'is_read' => false, - 'pegawai_id' => $mapping?->objectatasanlangsungfk, - ]; + $notifText = "Dokumen {$docNumber} telah direvisi dan memerlukan persetujuan ulang. Direvisi oleh {$uploaderName}."; + $targetRoleNotifications = array_values(array_unique($targetRoleNotifications)); - - Notifkasi::create($payloadNotification); - - if($mapping->objectpejabatpenilaifk){ - $payloadNotification = [ + if (!empty($targetRoleNotifications)) { + foreach ($targetRoleNotifications as $unitId) { + Notifkasi::create([ 'created_at' => now(), - 'text_notifikasi' => "Dokumen {$docNumber} telah direvisi dan memerlukan persetujuan ulang. ". "Direvisi oleh {$uploaderName}.", + 'text_notifikasi' => $notifText, + 'url' => '/pengajuan-file', + 'is_read' => false, + 'unit_id' => $unitId, + ]); + } + } else { + $pegawaiTargets = array_filter([ + $mapping?->objectatasanlangsungfk, + $mapping?->objectpejabatpenilaifk, + ]); + + foreach (array_unique($pegawaiTargets) as $pegawaiId) { + Notifkasi::create([ + 'created_at' => now(), + 'text_notifikasi' => $notifText, 'url' => '/pending-file', 'is_read' => false, - 'pegawai_id' => $mapping?->objectpejabatpenilaifk, - ]; - - Notifkasi::create($payloadNotification); + 'pegawai_id' => $pegawaiId, + ]); + } } $payloadLog = [ @@ -2771,7 +3073,7 @@ class DashboardController extends Controller 'statusenabled' => true, 'nama_dokumen' => $data->nama_dokumen ?? null, 'no_dokumen' => $data->no_dokumen ?? null, - 'mod_change' => null, + 'mod_change' => 'Reset approval: ' . (!empty($targetRoleNotifications) ? implode(',', $targetRoleNotifications) : 'atasan'), 'id_unit_kerja' => $data ? $data->id_unit_kerja : null, 'id_sub_unit_kerja' => $data ? $data->id_sub_unit_kerja : null, 'action_type' => 'Revisi Dokumen', @@ -3230,4 +3532,340 @@ class DashboardController extends Controller return $result; } + public function approvePendingFileMutu(string $id){ + try { + DB::connection('dbDirectory')->beginTransaction(); + if (!$this->hasApprovalRole(51)) { + return response()->json([ + 'status' => false, + 'message' => 'Anda tidak memiliki akses approval Komite Mutu' + ], 403); + } + $data = FileDirectory::where('file_directory_id', $id)->first(); + if(!$data){ + return response()->json([ + 'status' => false, + 'message' => 'Data tidak ditemukan' + ], 404); + } + if ($data->status_action !== 'approved') { + return response()->json([ + 'status' => false, + 'message' => 'Dokumen belum disetujui atasan.' + ], 422); + } + $data->update([ + 'status_mutu' => 'approved', + 'action_mutu_at' => now(), + 'action_mutu_by' => auth()->user()->objectpegawaifk, + ]); + $this->syncFinalApprovalStatus($data->fresh()); + + $parts = array_values(array_filter(explode('/', $data->file))); + $actionName = auth()->user()?->dataUser?->namalengkap ?? 'Pengguna'; + $docNumber = $data->no_dokumen ? 'nomor '. $data->no_dokumen : end($parts); + $payloadNotification = [ + 'created_at' => now(), + 'text_notifikasi' => "Dokumen {$docNumber} telah disetujui oleh {$actionName} Komite Mutu.", + 'url' => '/', + 'is_read' => false, + 'pegawai_id' => $data->pegawai_id_entry, + ]; + + Notifkasi::create($payloadNotification); + + $payloadLog = [ + 'file_directory_id' => $data->file_directory_id, + 'pegawai_id_entry' => $data->pegawai_id_entry, + 'pegawai_nama_entry' => $data->pegawai_nama_entry, + 'entry_at' => now(), + 'file' => $data->file, + 'statusenabled' => true, + 'nama_dokumen' => $data->nama_dokumen ?? null, + 'no_dokumen' => $data->no_dokumen ?? null, + 'mod_change' => null, + 'id_unit_kerja' => $data ? $data->id_unit_kerja : null, + 'id_sub_unit_kerja' => $data ? $data->id_sub_unit_kerja : null, + 'action_type' => 'Approved Dokumen Mutu', + ]; + LogActivity::create($payloadLog); + + DB::connection('dbDirectory')->commit(); + return response()->json([ + 'status' => true, + 'message' => 'File berhasil di-approve' + ], 200); + } catch (\Throwable $th) { + DB::connection('dbDirectory')->rollBack(); + return response()->json([ + 'status' => false, + 'message' => $th->getMessage() + ], 500); + } + } + + public function approvePendingFileTurt(string $id){ + try { + DB::connection('dbDirectory')->beginTransaction(); + if (!$this->hasApprovalRole(22)) { + return response()->json([ + 'status' => false, + 'message' => 'Anda tidak memiliki akses approval TURT' + ], 403); + } + $data = FileDirectory::where('file_directory_id', $id)->first(); + if(!$data){ + return response()->json([ + 'status' => false, + 'message' => 'Data tidak ditemukan' + ], 404); + } + if ($data->status_action !== 'approved') { + return response()->json([ + 'status' => false, + 'message' => 'Dokumen belum disetujui atasan.' + ], 422); + } + $data->update([ + 'status_turt' => 'approved', + 'action_turt_at' => now(), + 'action_turt_by' => auth()->user()->objectpegawaifk, + ]); + $this->syncFinalApprovalStatus($data->fresh()); + + $parts = array_values(array_filter(explode('/', $data->file))); + $actionName = auth()->user()?->dataUser?->namalengkap ?? 'Pengguna'; + $docNumber = $data->no_dokumen ? 'nomor '. $data->no_dokumen : end($parts); + $payloadNotification = [ + 'created_at' => now(), + 'text_notifikasi' => "Dokumen {$docNumber} telah disetujui oleh {$actionName}, Tim Kerja Tata Usaha dan Rumah Tangga.", + 'url' => '/', + 'is_read' => false, + 'pegawai_id' => $data->pegawai_id_entry, + ]; + + Notifkasi::create($payloadNotification); + + $payloadLog = [ + 'file_directory_id' => $data->file_directory_id, + 'pegawai_id_entry' => $data->pegawai_id_entry, + 'pegawai_nama_entry' => $data->pegawai_nama_entry, + 'entry_at' => now(), + 'file' => $data->file, + 'statusenabled' => true, + 'nama_dokumen' => $data->nama_dokumen ?? null, + 'no_dokumen' => $data->no_dokumen ?? null, + 'mod_change' => null, + 'id_unit_kerja' => $data ? $data->id_unit_kerja : null, + 'id_sub_unit_kerja' => $data ? $data->id_sub_unit_kerja : null, + 'action_type' => 'Approved Dokumen Turt', + ]; + LogActivity::create($payloadLog); + + DB::connection('dbDirectory')->commit(); + return response()->json([ + 'status' => true, + 'message' => 'File berhasil di-approve' + ], 200); + } catch (\Throwable $th) { + DB::connection('dbDirectory')->rollBack(); + return response()->json([ + 'status' => false, + 'message' => $th->getMessage() + ], 500); + } + } + + public function rejectPendingFileMutu(Request $request, string $id){ + try { + DB::connection('dbDirectory')->beginTransaction(); + if (!$this->hasApprovalRole(51)) { + return response()->json([ + 'status' => false, + 'message' => 'Anda tidak memiliki akses approval Komite Mutu' + ], 403); + } + $data = FileDirectory::where('file_directory_id', $id)->first(); + if(!$data){ + return response()->json([ + 'status' => false, + 'message' => 'Data tidak ditemukan' + ], 404); + } + if ($data->status_action !== 'approved') { + return response()->json([ + 'status' => false, + 'message' => 'Dokumen belum disetujui atasan.' + ], 422); + } + $revision = trim((string) $request->input('revision', '')); + if ($revision === '') { + return response()->json([ + 'status' => false, + 'message' => 'Catatan revisi wajib diisi' + ], 422); + } + $data->update([ + 'status_mutu' => 'rejected', + 'action_mutu_at' => now(), + 'action_mutu_by' => auth()->user()->dataUser->id, + 'mutu_revision' => $revision, + 'revision' => 'Komite Mutu: ' . $revision, + 'status_action' => 'rejected', + 'action_at' => now(), + 'action_by' => auth()->user()->objectpegawaifk, + ]); + + $parts = array_values(array_filter(explode('/', $data->file))); + $actionName = auth()->user()?->dataUser?->namalengkap ?? 'Pengguna'; + $docNumber = $data->no_dokumen ? 'nomor '. $data->no_dokumen : end($parts); + $payloadNotification = [ + 'created_at' => now(), + 'text_notifikasi' => "Dokumen {$docNumber} telah ditolak oleh {$actionName}, Komite Mutu. ". "Silakan periksa dokumen untuk melakukan perbaikan.", + 'url' => '/pengajuan-file', + 'is_read' => false, + // 'pegawai_id' => $mapping?->objectatasanlangsungfk, + 'pegawai_id' => $data->pegawai_id_entry, + ]; + + Notifkasi::create($payloadNotification); + $payloadLog = [ + 'file_directory_id' => $data->file_directory_id, + 'pegawai_id_entry' => $data->pegawai_id_entry, + 'pegawai_nama_entry' => $data->pegawai_nama_entry, + 'entry_at' => now(), + 'file' => $data->file, + 'statusenabled' => true, + 'nama_dokumen' => $data->nama_dokumen ?? null, + 'no_dokumen' => $data->no_dokumen ?? null, + 'id_unit_kerja' => $data ? $data->id_unit_kerja : null, + 'id_sub_unit_kerja' => $data ? $data->id_sub_unit_kerja : null, + 'action_type' => 'Rejected Dokumen Mutu', + ]; + LogActivity::create($payloadLog); + DB::connection('dbDirectory')->commit(); + return response()->json([ + 'status' => true, + 'message' => 'File berhasil di-reject' + ], 200); + } catch (\Throwable $th) { + DB::connection('dbDirectory')->rollBack(); + return response()->json([ + 'status' => false, + 'message' => $th->getMessage() + ], 500); + } + } + public function rejectPendingFileTurt(Request $request, string $id){ + try { + DB::connection('dbDirectory')->beginTransaction(); + if (!$this->hasApprovalRole(22)) { + return response()->json([ + 'status' => false, + 'message' => 'Anda tidak memiliki akses approval TURT' + ], 403); + } + $data = FileDirectory::where('file_directory_id', $id)->first(); + if(!$data){ + return response()->json([ + 'status' => false, + 'message' => 'Data tidak ditemukan' + ], 404); + } + if ($data->status_action !== 'approved') { + return response()->json([ + 'status' => false, + 'message' => 'Dokumen belum disetujui atasan.' + ], 422); + } + $revision = trim((string) $request->input('revision', '')); + if ($revision === '') { + return response()->json([ + 'status' => false, + 'message' => 'Catatan revisi wajib diisi' + ], 422); + } + $data->update([ + 'status_turt' => 'rejected', + 'action_turt_at' => now(), + 'action_turt_by' => auth()->user()->dataUser->id, + 'turt_revision' => $revision, + 'revision' => 'TURT: ' . $revision, + 'status_action' => 'rejected', + 'action_at' => now(), + 'action_by' => auth()->user()->objectpegawaifk, + ]); + + $parts = array_values(array_filter(explode('/', $data->file))); + $actionName = auth()->user()?->dataUser?->namalengkap ?? 'Pengguna'; + $docNumber = $data->no_dokumen ? 'nomor '. $data->no_dokumen : end($parts); + $payloadNotification = [ + 'created_at' => now(), + 'text_notifikasi' => "Dokumen {$docNumber} telah ditolak oleh {$actionName}, Tim Kerja Tata Usaha dan Rumah Tangga. ". "Silakan periksa dokumen untuk melakukan perbaikan.", + 'url' => '/pengajuan-file', + 'is_read' => false, + // 'pegawai_id' => $mapping?->objectatasanlangsungfk, + 'pegawai_id' => $data->pegawai_id_entry, + ]; + + Notifkasi::create($payloadNotification); + $payloadLog = [ + 'file_directory_id' => $data->file_directory_id, + 'pegawai_id_entry' => $data->pegawai_id_entry, + 'pegawai_nama_entry' => $data->pegawai_nama_entry, + 'entry_at' => now(), + 'file' => $data->file, + 'statusenabled' => true, + 'nama_dokumen' => $data->nama_dokumen ?? null, + 'no_dokumen' => $data->no_dokumen ?? null, + 'mod_change' => $revision, + 'id_unit_kerja' => $data ? $data->id_unit_kerja : null, + 'id_sub_unit_kerja' => $data ? $data->id_sub_unit_kerja : null, + 'action_type' => 'Rejected Dokumen Turt', + ]; + LogActivity::create($payloadLog); + DB::connection('dbDirectory')->commit(); + return response()->json([ + 'status' => true, + 'message' => 'File berhasil di-reject' + ], 200); + } catch (\Throwable $th) { + DB::connection('dbDirectory')->rollBack(); + return response()->json([ + 'status' => false, + 'message' => $th->getMessage() + ], 500); + } + } + + private function syncFinalApprovalStatus(FileDirectory $data): void + { + $mustApproveMutu = (bool) $data->is_akre; + $mustApproveTurt = !empty($data->master_kategori_directory_id); + + if ($data->status_action !== 'approved') { + return; + } + + $mutuApproved = !$mustApproveMutu || $data->status_mutu === 'approved'; + $turtApproved = !$mustApproveTurt || $data->status_turt === 'approved'; + + if ($mutuApproved && $turtApproved) { + $data->update([ + 'status_action' => 'approved', + 'action_at' => now(), + 'action_by' => auth()->user()->objectpegawaifk, + ]); + } + } + + private function hasApprovalRole(int $unitId): bool + { + return MappingUnitKerjaPegawai::query() + ->where('statusenabled', true) + ->where('objectpegawaifk', auth()->user()->objectpegawaifk) + ->where('objectunitkerjapegawaifk', $unitId) + ->exists(); + } + } diff --git a/app/Models/User.php b/app/Models/User.php index 9a0e454..a62c864 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -45,7 +45,7 @@ class User extends Authenticatable 'katasandi' => 'hashed', ]; } - protected $with = ['dataUser', 'masterPersetujuan', 'akses']; + protected $with = ['dataUser']; public function dataUser(){ return $this->belongsTo(DataUser::class, 'objectpegawaifk', 'id')->select('id', 'namalengkap'); } diff --git a/public/assets/css/styles.min.css b/public/assets/css/styles.min.css index da87999..db728db 100644 --- a/public/assets/css/styles.min.css +++ b/public/assets/css/styles.min.css @@ -15904,14 +15904,14 @@ body { border-radius: 20px; } .body-wrapper .body-wrapper-inner { - min-height: calc(100vh - 110px); + min-height: calc(130vh - 180px); } .body-wrapper .container-fluid, .body-wrapper .container-sm, .body-wrapper .container-md, .body-wrapper .container-lg, .body-wrapper .container-xl, .body-wrapper .container-xxl { - max-width: 1300px; + max-width: 1600px; margin: 0 auto; - padding: 24px; + padding: 10px; transition: 0.2s ease-in; - padding-top: 120px; + padding-top: 90px; } @media (max-width: 991.98px) { .body-wrapper .container-fluid, .body-wrapper .container-sm, .body-wrapper .container-md, .body-wrapper .container-lg, .body-wrapper .container-xl, .body-wrapper .container-xxl { diff --git a/public/js/pendingFile/index.js b/public/js/pendingFile/index.js index f15d17d..b4cabc0 100644 --- a/public/js/pendingFile/index.js +++ b/public/js/pendingFile/index.js @@ -19,6 +19,8 @@ document.addEventListener('DOMContentLoaded', () => { const titleEl = document.getElementById('pendingTitle'); const tabPendingEl = document.getElementById('tabPengajuan'); const tabHistoryEl = document.getElementById('tabHistory'); + const isKomiteMutu = !!window.isKomiteMutu; + const isTurt = !!window.isTurt; const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); const selectedIds = new Set(); @@ -63,10 +65,35 @@ document.addEventListener('DOMContentLoaded', () => { }); } - function statusBadge(status){ - if (status === 'rejected') return 'Rejected'; - if (status === 'revised') return 'Revised'; - return 'Pending'; + function approvalBadge(status, label){ + if (status === 'approved') return `Approved ${label}`; + if (status === 'rejected') return `Rejected ${label}`; + return `Pending ${label}`; + } + + function getWorkflowStatusBadges(item){ + if (item?.status_mutu === 'rejected') return [`Rejected Mutu`]; + if (item?.status_turt === 'rejected') return [`Rejected TURT`]; + if (item?.status_action === 'rejected') return [`Rejected Atasan`]; + if (item?.status_action === 'revised') return [`Revised`]; + + if (item?.status_action !== 'approved') { + return [`Pending Atasan`]; + } + + const statuses = []; + if (item?.is_akre && item?.status_mutu !== 'approved') { + statuses.push(`Pending Mutu`); + } + if (item?.master_kategori_directory_id && item?.status_turt !== 'approved') { + statuses.push(`Pending TURT`); + } + + if (statuses.length) { + return statuses; + } + + return [`Approved`]; } function aksesBadge(akses){ @@ -81,18 +108,22 @@ document.addEventListener('DOMContentLoaded', () => { } function isRejected(item){ - return item?.status_action === 'rejected'; + return item?.status_action === 'rejected' || item?.status_mutu === 'rejected' || item?.status_turt === 'rejected'; + } + + function isAtasanApproved(item){ + return item?.status_action === 'approved'; } function getSelectableIdsOnPage(){ return (tableState.data || []) - .filter((item) => !isRejected(item)) + .filter((item) => !isRejected(item) && !isAtasanApproved(item)) .map((item) => String(item.file_directory_id)); } function updateSelectAllState(){ if (!selectAllCheckbox) return; - if (tableState.mode === 'history') { + if (tableState.mode === 'history' || isKomiteMutu || isTurt) { selectAllCheckbox.checked = false; selectAllCheckbox.indeterminate = false; selectAllCheckbox.disabled = true; @@ -115,8 +146,8 @@ document.addEventListener('DOMContentLoaded', () => { function updateSelectionUI(){ const count = selectedIds.size; if (selectedCountEl) selectedCountEl.textContent = String(count); - if (bulkApproveBtn) bulkApproveBtn.disabled = count === 0 || tableState.mode === 'history'; - if (clearSelectionBtn) clearSelectionBtn.disabled = count === 0 || tableState.mode === 'history'; + if (bulkApproveBtn) bulkApproveBtn.disabled = count === 0 || tableState.mode === 'history' || isKomiteMutu || isTurt; + if (clearSelectionBtn) clearSelectionBtn.disabled = count === 0 || tableState.mode === 'history' || isKomiteMutu || isTurt; updateSelectAllState(); } @@ -126,26 +157,45 @@ document.addEventListener('DOMContentLoaded', () => { const tanggalTerbit = item.tanggal_terbit ? formatTanggal(item.tanggal_terbit) : '-'; const id = String(item.file_directory_id); const rejected = isRejected(item); + const atasanApproved = isAtasanApproved(item); const checked = selectedIds.has(id); - const aksi = ` -
- - - -
- `; + const actions = [ + `` + ]; + + if (isKomiteMutu || isTurt) { + if (isKomiteMutu && item.is_akre && item.status_mutu !== 'approved') { + actions.push(``); + actions.push(``); + } + if (isTurt && item.status_turt !== 'approved') { + actions.push(``); + actions.push(``); + } + if (item.status_mutu === 'rejected' && item.mutu_revision) { + actions.push(``); + } + if (item.status_turt === 'rejected' && item.turt_revision) { + actions.push(``); + } + } else { + if (!atasanApproved) { + actions.push(``); + actions.push(``); + } + } + + const statusContent = (isKomiteMutu || isTurt) + ? getWorkflowStatusBadges(item).join(' ') + : getWorkflowStatusBadges(item).join(' '); return ` @@ -153,11 +203,11 @@ document.addEventListener('DOMContentLoaded', () => { class="form-check-input row-select" data-id="${id}" ${checked ? 'checked' : ''} - ${rejected ? 'disabled' : ''}> + ${(rejected || atasanApproved || isKomiteMutu || isTurt) ? 'disabled' : ''}> - ${rejected ? '' : aksi} + ${rejected ? '' : `
${actions.join('')}
`} ${safeText(item.no_dokumen)} - ${statusBadge(item?.status_action)} + ${statusContent} ${aksesBadge(item?.permission_file)} { tabHistoryEl.classList.toggle('d-none', tableState.mode !== 'history'); } if (pendingBulkActionsEl) { - pendingBulkActionsEl.classList.toggle('d-none', tableState.mode === 'history'); + pendingBulkActionsEl.classList.toggle('d-none', tableState.mode === 'history' || isKomiteMutu || isTurt); } updateSelectionUI(); } @@ -473,6 +523,117 @@ document.addEventListener('DOMContentLoaded', () => { }); } + window.infoRejectRole = function(label, revision){ + Swal.fire({ + title: `Catatan ${label}`, + text: revision || 'Tidak ada catatan revisi.', + icon: 'info', + confirmButtonText: 'Tutup' + }); + } + + window.approvePendingRole = function(type, id, fileName){ + const endpoint = type === 'mutu' + ? `/pending-file/${id}/approve-mutu` + : `/pending-file/${id}/approve-turt`; + const label = type === 'mutu' ? 'Komite Mutu' : 'TURT'; + + Swal.fire({ + title: `Approve ${label}?`, + text: fileName || 'Dokumen akan disetujui.', + icon: 'question', + showCancelButton: true, + confirmButtonText: 'Approve', + cancelButtonText: 'Batal', + }).then((result) => { + if (!result.isConfirmed) return; + fetch(endpoint, { + method: 'POST', + headers: { + 'X-CSRF-TOKEN': csrfToken, + 'Content-Type': 'application/json' + }, + }).then(async(res) => { + const data = await res.json(); + if (!res.ok || !data?.status) { + throw new Error(data?.message || 'Gagal approve.'); + } + Swal.fire({ + icon: 'success', + title: 'Berhasil', + text: data.message || 'Dokumen disetujui.', + timer: 1500, + showConfirmButton: false + }); + fetchData(); + }).catch((err) => { + Swal.fire({ + icon: 'error', + title: 'Gagal', + text: err.message || 'Terjadi kesalahan.' + }); + }); + }); + } + + window.rejectPendingRole = function(type, id, fileName){ + const endpoint = type === 'mutu' + ? `/pending-file/${id}/reject-mutu` + : `/pending-file/${id}/reject-turt`; + const label = type === 'mutu' ? 'Komite Mutu' : 'TURT'; + + Swal.fire({ + title: `Reject ${label}?`, + text: fileName || 'Dokumen akan ditolak.', + icon: 'warning', + showCancelButton: true, + confirmButtonText: 'Reject', + cancelButtonText: 'Batal', + input: 'textarea', + inputLabel: 'Catatan', + inputPlaceholder: 'Tulis alasan atau catatan revisi...', + inputAttributes: { + 'aria-label': 'Catatan' + }, + preConfirm: (value) => { + const revision = (value || '').trim(); + if (!revision) { + Swal.showValidationMessage('Catatan revisi wajib diisi.'); + } + return revision; + } + }).then((result) => { + if (!result.isConfirmed) return; + fetch(endpoint, { + method: 'POST', + headers: { + 'X-CSRF-TOKEN': csrfToken, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ revision: result.value }) + }).then(async(res) => { + const data = await res.json(); + if (!res.ok || !data?.status) { + throw new Error(data?.message || 'Gagal reject.'); + } + Swal.fire({ + icon: 'success', + title: 'Berhasil', + text: data.message || 'Dokumen ditolak.', + timer: 1500, + showConfirmButton: false + }); + fetchData(); + }).catch((err) => { + Swal.fire({ + icon: 'error', + title: 'Gagal', + text: err.message || 'Terjadi kesalahan.' + }); + }); + }); + } + window.infoDok = function(e){ let fileUrl =$(e).data('file'); let noDokumen = $(e).data('no_dokumen'); diff --git a/public/js/pengajuanFile/index.js b/public/js/pengajuanFile/index.js index 9068738..98b3b44 100644 --- a/public/js/pengajuanFile/index.js +++ b/public/js/pengajuanFile/index.js @@ -27,6 +27,8 @@ document.addEventListener('DOMContentLoaded', () => { const editUnitSelect = $('#edit_id_unit_kerja'); const editSubUnitSelect = $('#edit_id_sub_unit_kerja'); const selectedIds = new Set(); + const isKomiteMutu = !!window.isKomiteMutu; + const isTurt = !!window.isTurt; if (pageSizeSelect) { const initialSize = parseInt(pageSizeSelect.value); @@ -74,7 +76,7 @@ document.addEventListener('DOMContentLoaded', () => { function updateSelectAllState(){ if (!selectAllCheckbox) return; - if (tableState.mode === 'history') { + if (tableState.mode === 'history' || tableState.mode === 'persetujuan') { selectAllCheckbox.checked = false; selectAllCheckbox.indeterminate = false; selectAllCheckbox.disabled = true; @@ -98,18 +100,60 @@ document.addEventListener('DOMContentLoaded', () => { function updateSelectionUI(){ const count = selectedIds.size; if (selectedCountEl) selectedCountEl.textContent = String(count); - if (bulkDeleteBtn) bulkDeleteBtn.disabled = count === 0 || tableState.mode === 'history'; - if (clearSelectionBtn) clearSelectionBtn.disabled = count === 0 || tableState.mode === 'history'; + if (bulkDeleteBtn) bulkDeleteBtn.disabled = count === 0 || tableState.mode === 'history' || tableState.mode === 'persetujuan'; + if (clearSelectionBtn) clearSelectionBtn.disabled = count === 0 || tableState.mode === 'history' || tableState.mode === 'persetujuan'; updateSelectAllState(); } + function approvalBadge(status, label){ + if (status === 'approved') return `Approved ${label}`; + if (status === 'rejected') return `Rejected ${label}`; + return `Pending ${label}`; + } + + function getPengajuanStatusBadge(item){ + if (item?.status_mutu === 'rejected') { + return `Rejected Mutu`; + } + if (item?.status_turt === 'rejected') { + return `Rejected TURT`; + } + if (item?.status_action === 'rejected') { + return `Rejected Atasan`; + } + if (item?.status_action === 'revised') { + return `Revised`; + } + + if (item?.status_action !== 'approved') { + return `Pending Atasan`; + } + + const pendingApprovals = []; + if (item?.is_akre && item?.status_mutu !== 'approved') { + pendingApprovals.push('Pending Mutu'); + } + if (item?.master_kategori_directory_id && item?.status_turt !== 'approved') { + pendingApprovals.push('Pending TURT'); + } + + if (pendingApprovals.length) { + return pendingApprovals.map((label) => `${label}`).join(' '); + } + if (item?.status_action === 'approved') { + return `Approved`; + } + + return `Pending Atasan`; + } + function buildRow(item){ let tanggal = item.entry_at ? formatTanggal(item.entry_at) : '-'; let tanggalExp = item.tgl_expired ? formatTanggal(item.tgl_expired) : '-'; let tanggalTerbit = item.tanggal_terbit ? formatTanggal(item.tanggal_terbit) : '-'; const isApproved = item?.status_action === 'approved'; - const isRejected = item?.status_action === 'rejected'; - const showEdit = !isApproved; + const isRejected = item?.status_action === 'rejected' || item?.status_mutu === 'rejected' || item?.status_turt === 'rejected'; + const showEdit = !isApproved || isRejected; const showInfo = isRejected; const id = String(item.file_directory_id); const checked = selectedIds.has(id); @@ -146,18 +190,7 @@ document.addEventListener('DOMContentLoaded', () => { ${aksi} ${item.no_dokumen || '-'} - - - + ${getPengajuanStatusBadge(item)} ${aksesBadge(item?.permission_file)} { `; } + function buildRowPersetujuan(item){ + const tanggal = item.entry_at ? formatTanggal(item.entry_at) : '-'; + const tanggalExp = item.tgl_expired ? formatTanggal(item.tgl_expired) : '-'; + const tanggalTerbit = item.tanggal_terbit ? formatTanggal(item.tanggal_terbit) : '-'; + const showMutu = isKomiteMutu && !!item.is_akre; + const showTurt = isTurt; + const actions = [ + `` + ]; + + if (showMutu && item.status_mutu !== 'approved') { + actions.push(``); + actions.push(``); + } + if (showTurt && item.status_turt !== 'approved') { + actions.push(``); + actions.push(``); + } + if (item.status_mutu === 'rejected' && item.mutu_revision) { + actions.push(``); + } + if (item.status_turt === 'rejected' && item.turt_revision) { + actions.push(``); + } + + const statusParts = []; + if (item.is_akre) { + statusParts.push(approvalBadge(item.status_mutu, 'Mutu')); + } + if (item.master_kategori_directory_id) { + statusParts.push(approvalBadge(item.status_turt, 'TURT')); + } + + return ` + + - +
${actions.join('')}
+ ${item.no_dokumen || '-'} +
${statusParts.join('')}
+ ${aksesBadge(item?.permission_file)} +
${item.nama_dokumen} + ${item.is_akre ? `Dokumen akreditasi` : `${item.name_kategori || '-'}${item.name_unit || '-'}`} + ${tanggalTerbit} + ${tanggalExp} + ${tanggal} + + `; + } + function buildHistoryRow(item){ const tanggal = item.entry_at ? formatTanggal(item.entry_at) : '-'; const tanggalExp = item.tgl_expired ? formatTanggal(item.tgl_expired) : '-'; @@ -300,11 +394,14 @@ document.addEventListener('DOMContentLoaded', () => { function renderTable(){ const isHistoryMode = tableState.mode === 'history'; + const isPersetujuan = tableState.mode === 'persetujuan'; + const activeState = isHistoryMode ? historyState : tableState; + const pageData = activeState.data || []; const targetBody = isHistoryMode ? tbodyHistory : tbodyPengajuan; const colSpan = isHistoryMode ? 9 : 11; - const rowBuilder = isHistoryMode ? buildHistoryRow : buildRow; + const rowBuilder = isHistoryMode ? buildHistoryRow : (isPersetujuan ? buildRowPersetujuan : buildRow); if (pageData.length === 0) { targetBody.innerHTML = ` @@ -363,17 +460,20 @@ document.addEventListener('DOMContentLoaded', () => { }); } if (titleEl) { - titleEl.textContent = tableState.mode === 'history' ? 'Log History' : 'Data Pengajuan'; + titleEl.textContent = tableState.mode === 'history' + ? 'Log History' + : (tableState.mode === 'persetujuan' ? 'Data Persetujuan' : 'Data Pengajuan'); } document.body.dataset.pengajuanMode = tableState.mode; + if (tabPengajuanEl && tabHistoryEl) { tabPengajuanEl.classList.toggle('d-none', tableState.mode === 'history'); tabHistoryEl.classList.toggle('d-none', tableState.mode !== 'history'); } if (bulkActionsEl) { - bulkActionsEl.classList.toggle('d-none', tableState.mode === 'history'); + bulkActionsEl.classList.toggle('d-none', tableState.mode === 'history' || tableState.mode === 'persetujuan'); } - if (deleteDataEl && tableState.mode === 'history') { + if (deleteDataEl && (tableState.mode === 'history' || tableState.mode === 'persetujuan')) { deleteDataEl.classList.add('d-none'); } updateSelectionUI(); @@ -457,7 +557,8 @@ document.addEventListener('DOMContentLoaded', () => { per_page: activeState.pageSize, keyword: activeState.search || '', start_date: activeState.startDate || '', - end_date: activeState.endDate || '' + end_date: activeState.endDate || '', + mode: tableState.mode }); const endpoint = tableState.mode === 'history' ? `/data/log-dokumen?${params.toString()}` @@ -478,7 +579,17 @@ document.addEventListener('DOMContentLoaded', () => { window.infoReject = function(id){ const item = getItemById(id); - const revision = item?.revision ? String(item.revision) : 'Tidak ada catatan revisi.'; + const notes = []; + if (item?.revision) { + notes.push(`Atasan/Bagian Terkait: ${String(item.revision)}`); + } + if (item?.mutu_revision) { + notes.push(`Komite Mutu: ${String(item.mutu_revision)}`); + } + if (item?.turt_revision) { + notes.push(`TURT: ${String(item.turt_revision)}`); + } + const revision = notes.length ? notes.join('\n\n') : 'Tidak ada catatan revisi.'; Swal.fire({ title: 'Catatan Revisi', text: revision, @@ -486,6 +597,119 @@ document.addEventListener('DOMContentLoaded', () => { confirmButtonText: 'Tutup' }); } + + window.infoRejectPersetujuan = function(label, revision){ + Swal.fire({ + title: `Catatan ${label}`, + text: revision || 'Tidak ada catatan revisi.', + icon: 'info', + confirmButtonText: 'Tutup' + }); + } + + window.approvePersetujuan = function(type, id, fileName){ + const endpoint = type === 'mutu' + ? `/pengajuan-file/${id}/approve-mutu` + : `/pengajuan-file/${id}/approve-turt`; + const label = type === 'mutu' ? 'Komite Mutu' : 'TURT'; + + Swal.fire({ + title: `Approve ${label}?`, + text: fileName || 'Dokumen akan disetujui.', + icon: 'question', + showCancelButton: true, + confirmButtonText: 'Approve', + cancelButtonText: 'Batal', + }).then((result) => { + if (!result.isConfirmed) return; + fetch(endpoint, { + method: 'POST', + headers: { + 'X-CSRF-TOKEN': csrfToken, + 'Content-Type': 'application/json' + }, + }).then(async(res) => { + const data = await res.json(); + if (!res.ok || !data?.status) { + throw new Error(data?.message || 'Gagal approve.'); + } + Swal.fire({ + icon: 'success', + title: 'Berhasil', + text: data.message || 'Dokumen disetujui.', + timer: 1500, + showConfirmButton: false + }); + fetchData(); + }).catch((err) => { + Swal.fire({ + icon: 'error', + title: 'Gagal', + text: err.message || 'Terjadi kesalahan.' + }); + }); + }); + } + + window.rejectPersetujuan = function(type, id, fileName){ + const endpoint = type === 'mutu' + ? `/pengajuan-file/${id}/reject-mutu` + : `/pengajuan-file/${id}/reject-turt`; + const label = type === 'mutu' ? 'Komite Mutu' : 'TURT'; + + Swal.fire({ + title: `Reject ${label}?`, + text: fileName || 'Dokumen akan ditolak.', + icon: 'warning', + showCancelButton: true, + confirmButtonText: 'Reject', + cancelButtonText: 'Batal', + input: 'textarea', + inputLabel: 'Catatan', + inputPlaceholder: 'Tulis alasan atau catatan revisi...', + inputAttributes: { + 'aria-label': 'Catatan' + }, + preConfirm: (value) => { + const revision = (value || '').trim(); + if (!revision) { + Swal.showValidationMessage('Catatan revisi wajib diisi.'); + } + return revision; + } + }).then((result) => { + if (!result.isConfirmed) return; + fetch(endpoint, { + method: 'POST', + headers: { + 'X-CSRF-TOKEN': csrfToken, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + revision: result.value + }) + }).then(async(res) => { + const data = await res.json(); + if (!res.ok || !data?.status) { + throw new Error(data?.message || 'Gagal reject.'); + } + Swal.fire({ + icon: 'success', + title: 'Berhasil', + text: data.message || 'Dokumen ditolak.', + timer: 1500, + showConfirmButton: false + }); + fetchData(); + }).catch((err) => { + Swal.fire({ + icon: 'error', + title: 'Gagal', + text: err.message || 'Terjadi kesalahan.' + }); + }); + }); + } window.infoDok = function(e){ let fileUrl = $(e).data('file'); let noDokumen = $(e).data('no_dokumen') diff --git a/resources/views/dataUmum/index.blade.php b/resources/views/dataUmum/index.blade.php index af60d84..c19a141 100644 --- a/resources/views/dataUmum/index.blade.php +++ b/resources/views/dataUmum/index.blade.php @@ -200,8 +200,8 @@ Tampilkan diff --git a/resources/views/dataUnit/index.blade.php b/resources/views/dataUnit/index.blade.php index ea9f234..196cb25 100644 --- a/resources/views/dataUnit/index.blade.php +++ b/resources/views/dataUnit/index.blade.php @@ -198,8 +198,8 @@ Tampilkan diff --git a/resources/views/pendingFile/index.blade.php b/resources/views/pendingFile/index.blade.php index b8a4f93..c427e7f 100644 --- a/resources/views/pendingFile/index.blade.php +++ b/resources/views/pendingFile/index.blade.php @@ -114,5 +114,9 @@ @include('pendingFile.modal.view') + @endsection diff --git a/resources/views/pengajuanFile/index.blade.php b/resources/views/pengajuanFile/index.blade.php index 431d810..80eba99 100644 --- a/resources/views/pengajuanFile/index.blade.php +++ b/resources/views/pengajuanFile/index.blade.php @@ -46,6 +46,11 @@ + @if($isKomiteMutu || $isTurt) + + @endif @@ -151,6 +156,8 @@ @include('dataUnit.modal.create') @endsection diff --git a/routes/web.php b/routes/web.php index 9b89713..eb79ea2 100644 --- a/routes/web.php +++ b/routes/web.php @@ -71,6 +71,10 @@ Route::middleware(['auth:admin,web'])->group(function(){ Route::get('/pengajuan-file', [DashboardController::class, 'pengajuanFile']); Route::get('/datatable/pengajuan-file', [DashboardController::class, 'dataPengajuanFile']); Route::post('/pengajuan-file/{id}/update', [DashboardController::class, 'updatePengajuanFile']); + Route::post('/pengajuan-file/{id}/approve-mutu', [DashboardController::class, 'approvePendingFileMutu']); + Route::post('/pengajuan-file/{id}/approve-turt', [DashboardController::class, 'approvePendingFileTurt']); + Route::post('/pengajuan-file/{id}/reject-mutu', [DashboardController::class, 'rejectPendingFileMutu']); + Route::post('/pengajuan-file/{id}/reject-turt', [DashboardController::class, 'rejectPendingFileTurt']); // Route::middleware(['master.persetujuan'])->group(function () { Route::get('/pending-file', [DashboardController::class, 'pendingFile']); @@ -78,6 +82,10 @@ Route::middleware(['auth:admin,web'])->group(function(){ Route::post('/pending-file/{id}/approve', [DashboardController::class, 'approvePendingFile']); Route::post('/pending-file/approve-multiple', [DashboardController::class, 'approvePendingFileMultiple']); Route::post('/pending-file/{id}/reject', [DashboardController::class, 'rejectPendingFile']); + Route::post('/pending-file/{id}/approve-mutu', [DashboardController::class, 'approvePendingFileMutu']); + Route::post('/pending-file/{id}/approve-turt', [DashboardController::class, 'approvePendingFileTurt']); + Route::post('/pending-file/{id}/reject-mutu', [DashboardController::class, 'rejectPendingFileMutu']); + Route::post('/pending-file/{id}/reject-turt', [DashboardController::class, 'rejectPendingFileTurt']); Route::get('/data/count-pending', [DashboardController::class, 'countDataPending']); Route::get('/data/count-rejected', [DashboardController::class, 'countRejectedPengajuan']); // });