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 = ` -