fixing bug di approval bertahap dokumen
This commit is contained in:
parent
f8c3816ca7
commit
ca4dbf0486
@ -12,6 +12,7 @@ use App\Models\MasterKlasifikasi;
|
||||
use App\Models\Notifkasi;
|
||||
use App\Models\SubUnitKerja;
|
||||
use App\Models\UnitKerja;
|
||||
use App\Models\DataUser;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@ -88,6 +89,41 @@ class PdfFpdiWithAlpha extends Fpdi
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
private function attachDeleteRecommendationMeta($items, $viewerPegawaiId)
|
||||
{
|
||||
$collection = collect($items);
|
||||
$recommenderIds = $collection->pluck('turt_by')
|
||||
->filter(fn ($id) => !empty($id))
|
||||
->map(fn ($id) => (int) $id)
|
||||
->unique()
|
||||
->values();
|
||||
|
||||
$recommenderNames = $recommenderIds->isEmpty()
|
||||
? collect()
|
||||
: DataUser::whereIn('id', $recommenderIds->all())->pluck('namalengkap', 'id');
|
||||
|
||||
return $collection->map(function ($item) use ($viewerPegawaiId, $recommenderNames) {
|
||||
$viewerId = $viewerPegawaiId ? (int) $viewerPegawaiId : null;
|
||||
$entryId = !empty($item->pegawai_id_entry) ? (int) $item->pegawai_id_entry : null;
|
||||
$recommenderId = !empty($item->turt_by) ? (int) $item->turt_by : null;
|
||||
|
||||
$canViewRecommendation = (bool) ($item->hapus_turt ?? false)
|
||||
&& !empty($item->note_hapus_turt)
|
||||
&& $viewerId !== null
|
||||
&& ($viewerId === $entryId || $viewerId === $recommenderId);
|
||||
|
||||
$item->delete_recommendation = $canViewRecommendation ? [
|
||||
'visible' => true,
|
||||
'note' => $item->note_hapus_turt,
|
||||
'actor_name' => $recommenderNames->get($recommenderId) ?? 'TURT',
|
||||
'actor_role' => 'TURT',
|
||||
'created_at' => $item->turt_at,
|
||||
] : null;
|
||||
|
||||
return $item;
|
||||
});
|
||||
}
|
||||
|
||||
// public function index(){
|
||||
// $katDok = MasterKategori::where('statusenabled', true)->select('master_kategori_directory_id', 'nama_kategori_directory')->get();
|
||||
// $klasifikasiDok = MasterKlasifikasi::where('statusenabled', true)->select('master_klasifikasi_directory_id', 'nama_klasifikasi_directory')->get();
|
||||
@ -131,9 +167,7 @@ class DashboardController extends Controller
|
||||
|
||||
public function index(){
|
||||
$katDok = MasterKategori::where('statusenabled', true)->select('master_kategori_directory_id', 'nama_kategori_directory')->get();
|
||||
$authMapping = auth()->user()?->dataUser?->mappingUnitKerjaPegawai()
|
||||
->where('isprimary', true)
|
||||
->first();
|
||||
$authMapping = auth()->user()?->dataUser?->mappingUnitKerjaPegawai()->where('isprimary', true)->first();
|
||||
// dd(auth()->user()?->dataUser);
|
||||
$authUnitKerja = $authMapping->objectunitkerjapegawaifk ?? null;
|
||||
$authSubUnitKerja = $authMapping->objectsubunitkerjapegawaifk ?? null;
|
||||
@ -287,6 +321,7 @@ class DashboardController extends Controller
|
||||
$item->nama_kategori = $item->kategori->nama_kategori_directory ?? $item->kategori_hukum ?? null;
|
||||
return $item;
|
||||
});
|
||||
$items = $this->attachDeleteRecommendationMeta($items, $pegawaiId);
|
||||
$kategoriList = (clone $baseQuery)->get()->map(function($item){
|
||||
if (!empty($item->kategori_hukum)) {
|
||||
return ['id' => 'hukum:' . $item->kategori_hukum, 'label' => $item->kategori_hukum];
|
||||
@ -1219,10 +1254,12 @@ class DashboardController extends Controller
|
||||
$data = $query->orderBy('entry_at', 'desc')
|
||||
->paginate($perPage);
|
||||
|
||||
$pegawaiId = auth()->user()?->dataUser?->id;
|
||||
$items = collect($data->items())->map(function($item){
|
||||
$item->nama_kategori = $item->kategori->nama_kategori_directory ?? $item->kategori_hukum ?? null;
|
||||
return $item;
|
||||
});
|
||||
$items = $this->attachDeleteRecommendationMeta($items, $pegawaiId);
|
||||
|
||||
$kategoriList = (clone $baseQuery)->get()->map(function($item){
|
||||
if (!empty($item->kategori_hukum)) {
|
||||
@ -1398,18 +1435,18 @@ class DashboardController extends Controller
|
||||
];
|
||||
$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
|
||||
]);
|
||||
@ -1933,14 +1970,14 @@ class DashboardController extends Controller
|
||||
$needTurt->whereNotNull('master_kategori_directory_id')
|
||||
->where(function ($pendingTurt) {
|
||||
$pendingTurt->whereNull('status_turt')
|
||||
->orWhere('status_turt', 'rejected');
|
||||
->orWhereIn('status_turt', ['rejected Turt', 'revised Turt']);
|
||||
});
|
||||
})
|
||||
->orWhere(function ($needMutu) {
|
||||
$needMutu->where('is_akre', true)
|
||||
->where(function ($pendingMutu) {
|
||||
$pendingMutu->whereNull('status_mutu')
|
||||
->orWhere('status_mutu', 'rejected');
|
||||
->orWhereIn('status_mutu', ['rejected Mutu', 'revised Mutu']);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1959,7 +1996,7 @@ class DashboardController extends Controller
|
||||
$sub->whereNotNull('master_kategori_directory_id')
|
||||
->where(function ($pendingTurt) {
|
||||
$pendingTurt->whereNull('status_turt')
|
||||
->orWhere('status_turt', 'rejected');
|
||||
->orWhereIn('status_turt', ['rejected Turt', 'revised Turt']);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -1969,7 +2006,7 @@ class DashboardController extends Controller
|
||||
$sub->where('is_akre', true)
|
||||
->where(function ($pendingMutu) {
|
||||
$pendingMutu->whereNull('status_mutu')
|
||||
->orWhere('status_mutu', 'rejected');
|
||||
->orWhereIn('status_mutu', ['rejected Mutu', 'revised Mutu']);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -2393,7 +2430,7 @@ class DashboardController extends Controller
|
||||
$sub->whereNotNull('master_kategori_directory_id')
|
||||
->where(function ($pendingTurt) {
|
||||
$pendingTurt->whereNull('status_turt')
|
||||
->orWhere('status_turt', 'rejected');
|
||||
->orWhereIn('status_turt', ['revised Turt']);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -2403,7 +2440,7 @@ class DashboardController extends Controller
|
||||
$sub->where('is_akre', true)
|
||||
->where(function ($pendingMutu) {
|
||||
$pendingMutu->whereNull('status_mutu')
|
||||
->orWhere('status_mutu', 'rejected');
|
||||
->orWhereIn('status_mutu', ['revised Mutu']);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -2846,7 +2883,7 @@ class DashboardController extends Controller
|
||||
$q->whereNotNull('master_kategori_directory_id')
|
||||
->where(function ($pendingTurt) {
|
||||
$pendingTurt->whereNull('status_turt')
|
||||
->orWhere('status_turt', 'rejected');
|
||||
->orWhereIn('status_turt', ['rejected Turt', 'revised Turt']);
|
||||
});
|
||||
}
|
||||
if ($isKomiteMutu) {
|
||||
@ -2855,7 +2892,7 @@ class DashboardController extends Controller
|
||||
$sub->where('is_akre', true)
|
||||
->where(function ($pendingMutu) {
|
||||
$pendingMutu->whereNull('status_mutu')
|
||||
->orWhere('status_mutu', 'rejected');
|
||||
->orWhereIn('status_mutu', ['rejected Mutu', 'revised Mutu']);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -2873,14 +2910,14 @@ class DashboardController extends Controller
|
||||
$needTurt->whereNotNull('master_kategori_directory_id')
|
||||
->where(function ($pendingTurt) {
|
||||
$pendingTurt->whereNull('status_turt')
|
||||
->orWhere('status_turt', 'rejected');
|
||||
->orWhereIn('status_turt', ['rejected Turt', 'revised Turt']);
|
||||
});
|
||||
})
|
||||
->orWhere(function ($needMutu) {
|
||||
$needMutu->where('is_akre', true)
|
||||
->where(function ($pendingMutu) {
|
||||
$pendingMutu->whereNull('status_mutu')
|
||||
->orWhere('status_mutu', 'rejected');
|
||||
->orWhereIn('status_mutu', ['rejected Mutu', 'revised Mutu']);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -2912,14 +2949,14 @@ class DashboardController extends Controller
|
||||
$needTurt->whereNotNull('master_kategori_directory_id')
|
||||
->where(function ($pendingTurt) {
|
||||
$pendingTurt->whereNull('status_turt')
|
||||
->orWhere('status_turt', 'rejected');
|
||||
->orWhere('status_turt', ['revised Turt', 'rejected Turt']);
|
||||
});
|
||||
})
|
||||
->orWhere(function ($needMutu) {
|
||||
$needMutu->where('is_akre', true)
|
||||
->where(function ($pendingMutu) {
|
||||
$pendingMutu->whereNull('status_mutu')
|
||||
->orWhere('status_mutu', 'rejected');
|
||||
->orWhereIn('status_mutu', ['revised Mutu', 'rejected Mutu']);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -3124,34 +3161,32 @@ class DashboardController extends Controller
|
||||
}
|
||||
}
|
||||
$targetRoleNotifications = [];
|
||||
$resetMutuApproval = $data->status_mutu === 'rejected';
|
||||
$resetTurtApproval = $data->status_turt === 'rejected';
|
||||
$resetMutuApproval = $data->status_mutu === 'rejected Mutu';
|
||||
$resetTurtApproval = $data->status_turt === 'rejected Turt';
|
||||
$resetAtasanApproval = $data->status_action === 'rejected';
|
||||
|
||||
// dd($resetTurtApproval, $resetMutuApproval);
|
||||
if ($resetMutuApproval) {
|
||||
$payload['status_mutu'] = 'revised Mutu';
|
||||
$payload['mutu_revision'] = null;
|
||||
// $payload['mutu_revision'] = null;
|
||||
$payload['action_mutu_at'] = null;
|
||||
$payload['action_mutu_by'] = null;
|
||||
$targetRoleNotifications[] = 51;
|
||||
}
|
||||
|
||||
if ($resetTurtApproval) {
|
||||
$payload['status_turt'] = 'revised TURT';
|
||||
$payload['turt_revision'] = null;
|
||||
$payload['status_turt'] = 'revised Turt';
|
||||
// $payload['turt_revision'] = null;
|
||||
$payload['action_turt_at'] = null;
|
||||
$payload['action_turt_by'] = null;
|
||||
$targetRoleNotifications[] = 22;
|
||||
}
|
||||
if($resetAtasanApproval){
|
||||
$payload['revision'] = null;
|
||||
// $payload['revision'] = null;
|
||||
$payload['status_action'] = 'revised';
|
||||
$payload['action_at'] = null;
|
||||
$payload['action_by'] = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!empty($payload)) {
|
||||
$data->update($payload);
|
||||
}
|
||||
@ -3940,14 +3975,11 @@ class DashboardController extends Controller
|
||||
], 422);
|
||||
}
|
||||
$data->update([
|
||||
'status_mutu' => 'rejected',
|
||||
'status_mutu' => 'rejected Mutu',
|
||||
'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,
|
||||
'revision' => 'Komite Mutu: ' . $revision
|
||||
]);
|
||||
|
||||
$parts = array_values(array_filter(explode('/', $data->file)));
|
||||
@ -4020,14 +4052,11 @@ class DashboardController extends Controller
|
||||
], 422);
|
||||
}
|
||||
$data->update([
|
||||
'status_turt' => 'rejected',
|
||||
'status_turt' => 'rejected Turt',
|
||||
'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)));
|
||||
|
||||
@ -66,30 +66,49 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
function approvalBadge(status, label){
|
||||
if (status === 'approved') return `<span class="badge bg-success">Approved ${label}</span>`;
|
||||
if (status === 'rejected') return `<span class="badge bg-danger">Rejected ${label}</span>`;
|
||||
const normalized = String(status || '').toLowerCase();
|
||||
if (normalized === 'approved') return `<span class="badge bg-success">Approved ${label}</span>`;
|
||||
if (normalized.startsWith('rejected')) return `<span class="badge bg-danger">Rejected ${label}</span>`;
|
||||
if (normalized.startsWith('revised')) return `<span class="badge bg-info">Revised ${label}</span>`;
|
||||
return `<span class="badge bg-warning text-dark">Pending ${label}</span>`;
|
||||
}
|
||||
|
||||
function getWorkflowStatusBadges(item){
|
||||
if (item?.status_mutu === 'rejected') return [`<span class="badge bg-danger">Rejected Mutu</span>`];
|
||||
if (item?.status_turt === 'rejected') return [`<span class="badge bg-danger">Rejected TURT</span>`];
|
||||
if (item?.status_action === 'rejected') return [`<span class="badge bg-danger">Rejected Atasan</span>`];
|
||||
if (item?.status_action === 'revised') return [`<span class="badge bg-info">Revised</span>`];
|
||||
const actionStatus = String(item?.status_action || '').toLowerCase();
|
||||
const mutuStatus = String(item?.status_mutu || '').toLowerCase();
|
||||
const turtStatus = String(item?.status_turt || '').toLowerCase();
|
||||
|
||||
if (item?.status_action !== 'approved') {
|
||||
if (actionStatus.startsWith('revised')) {
|
||||
return [`<span class="badge bg-info">Revised</span>`];
|
||||
}
|
||||
|
||||
if (actionStatus.startsWith('rejected')) {
|
||||
return [`<span class="badge bg-danger">Rejected Atasan</span>`];
|
||||
}
|
||||
|
||||
if (actionStatus !== 'approved') {
|
||||
return [`<span class="badge bg-warning text-dark">Pending Atasan</span>`];
|
||||
}
|
||||
|
||||
const statuses = [];
|
||||
if (item?.is_akre && item?.status_mutu !== 'approved') {
|
||||
statuses.push(`<span class="badge bg-warning text-dark">Pending Mutu</span>`);
|
||||
}
|
||||
if (item?.master_kategori_directory_id && item?.status_turt !== 'approved') {
|
||||
statuses.push(`<span class="badge bg-warning text-dark">Pending TURT</span>`);
|
||||
|
||||
if (item?.is_akre) {
|
||||
if (mutuStatus.startsWith('rejected')) {
|
||||
statuses.push(`<span class="badge bg-danger">Rejected Mutu</span>`);
|
||||
} else if (mutuStatus !== 'approved') {
|
||||
statuses.push(`<span class="badge bg-warning text-dark">Pending Mutu</span>`);
|
||||
}
|
||||
}
|
||||
|
||||
if (statuses.length) {
|
||||
if (item?.master_kategori_directory_id) {
|
||||
if (turtStatus.startsWith('rejected')) {
|
||||
statuses.push(`<span class="badge bg-danger">Rejected TURT</span>`);
|
||||
} else if (turtStatus !== 'approved') {
|
||||
statuses.push(`<span class="badge bg-warning text-dark">Pending TURT</span>`);
|
||||
}
|
||||
}
|
||||
|
||||
if (statuses.length > 0) {
|
||||
return statuses;
|
||||
}
|
||||
|
||||
@ -108,11 +127,18 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
function isRejected(item){
|
||||
return item?.status_action === 'rejected' || item?.status_mutu === 'rejected' || item?.status_turt === 'rejected';
|
||||
return String(item?.status_action || '').toLowerCase().startsWith('rejected')
|
||||
|| String(item?.status_mutu || '').toLowerCase().startsWith('rejected')
|
||||
|| String(item?.status_turt || '').toLowerCase().startsWith('rejected');
|
||||
}
|
||||
|
||||
function isAtasanApproved(item){
|
||||
return item?.status_action === 'approved';
|
||||
return String(item?.status_action || '').toLowerCase() === 'approved';
|
||||
}
|
||||
|
||||
function canProcessRoleStatus(status){
|
||||
const normalized = String(status || '').toLowerCase();
|
||||
return normalized === '' || normalized.startsWith('revised');
|
||||
}
|
||||
|
||||
function canApproveAsAtasan(item){
|
||||
@ -123,6 +149,62 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
return item?.can_edit_submission === true || item?.can_edit_submission === 1 || item?.can_edit_submission === '1';
|
||||
}
|
||||
|
||||
function hasRevisionInfo(item){
|
||||
return !!(item?.revision || item?.mutu_revision || item?.turt_revision);
|
||||
}
|
||||
|
||||
function collectRevisionNotes(item){
|
||||
const notes = [];
|
||||
const genericRevision = String(item?.revision || '').trim();
|
||||
const mutuRevision = String(item?.mutu_revision || '').trim();
|
||||
const turtRevision = String(item?.turt_revision || '').trim();
|
||||
|
||||
if (genericRevision) {
|
||||
const lowerGeneric = genericRevision.toLowerCase();
|
||||
if (!lowerGeneric.startsWith('komite mutu:') && !lowerGeneric.startsWith('turt:')) {
|
||||
notes.push({ label: 'Atasan', text: genericRevision });
|
||||
}
|
||||
}
|
||||
if (mutuRevision) {
|
||||
notes.push({ label: 'Komite Mutu', text: mutuRevision });
|
||||
}
|
||||
if (turtRevision) {
|
||||
notes.push({ label: 'TURT', text: turtRevision });
|
||||
}
|
||||
|
||||
return notes;
|
||||
}
|
||||
|
||||
function escapeHtml(value){
|
||||
return String(value ?? '')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function buildRevisionNotesHtml(notes){
|
||||
if (!notes.length) {
|
||||
return '<div class="text-muted">Tidak ada catatan revisi.</div>';
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="text-start" style="line-height:1.6;">
|
||||
${notes.map(note => `
|
||||
<div class="mb-2">
|
||||
<div><strong>${escapeHtml(note.label)}</strong></div>
|
||||
<div>${escapeHtml(note.text)}</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function getItemById(id){
|
||||
return (tableState.data || []).find((row) => String(row.file_directory_id) === String(id));
|
||||
}
|
||||
|
||||
function getSelectableIdsOnPage(){
|
||||
return (tableState.data || [])
|
||||
.filter((item) => !isRejected(item) && !isAtasanApproved(item) && canApproveAsAtasan(item))
|
||||
@ -169,6 +251,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const rejected = isRejected(item);
|
||||
const atasanApproved = isAtasanApproved(item);
|
||||
const canAtasanApprove = canApproveAsAtasan(item);
|
||||
const atasanRejected = String(item?.status_action || '').toLowerCase().startsWith('rejected');
|
||||
const canMutuAct = atasanApproved && isKomiteMutu && item.is_akre && canProcessRoleStatus(item.status_mutu);
|
||||
const canTurtAct = atasanApproved && isTurt && item.master_kategori_directory_id && canProcessRoleStatus(item.status_turt);
|
||||
const checked = selectedIds.has(id);
|
||||
const actions = [
|
||||
`<button class="btn btn-sm btn-primary" onclick="infoDok(this)"
|
||||
@ -187,20 +272,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
actions.push(`<button class="btn btn-sm btn-success" onclick="approvePending('${item.file_directory_id}', '${item.nama_dokumen || ''}')"><i class="fa-solid fa-check"></i></button>`);
|
||||
actions.push(`<button class="btn btn-sm btn-danger" onclick="rejectPending('${item.file_directory_id}', '${item.nama_dokumen || ''}')"><i class="fa-solid fa-xmark"></i></button>`);
|
||||
}
|
||||
if (atasanApproved && isKomiteMutu && item.is_akre && item.status_mutu !== 'approved') {
|
||||
if (canMutuAct) {
|
||||
actions.push(`<button class="btn btn-sm btn-success" onclick="approvePendingRole('mutu','${item.file_directory_id}','${item.nama_dokumen || ''}')"><i class="fa-solid fa-check"></i></button>`);
|
||||
actions.push(`<button class="btn btn-sm btn-danger" onclick="rejectPendingRole('mutu','${item.file_directory_id}','${item.nama_dokumen || ''}')"><i class="fa-solid fa-xmark"></i></button>`);
|
||||
}
|
||||
if (atasanApproved && isTurt && item.master_kategori_directory_id && item.status_turt !== 'approved') {
|
||||
actions.push(`<button class="btn btn-sm btn-success" onclick="approvePendingRole('turt','${item.file_directory_id}','${item.nama_dokumen || ''}')"><i class="fa-solid fa-check-double"></i></button>`);
|
||||
if (canTurtAct) {
|
||||
actions.push(`<button class="btn btn-sm btn-success" onclick="approvePendingRole('turt','${item.file_directory_id}','${item.nama_dokumen || ''}')"><i class="fa-solid fa-check"></i></button>`);
|
||||
actions.push(`<button class="btn btn-sm btn-danger" onclick="rejectPendingRole('turt','${item.file_directory_id}','${item.nama_dokumen || ''}')"><i class="fa-solid fa-ban"></i></button>`);
|
||||
}
|
||||
if (item.status_mutu === 'rejected' && item.mutu_revision) {
|
||||
actions.push(`<button class="btn btn-sm btn-info" onclick="infoRejectRole('Komite Mutu', ${JSON.stringify('' + (item.mutu_revision || ''))})"><i class="fa-solid fa-circle-info"></i></button>`);
|
||||
}
|
||||
if (item.status_turt === 'rejected' && item.turt_revision) {
|
||||
actions.push(`<button class="btn btn-sm btn-info" onclick="infoRejectRole('TURT', ${JSON.stringify('' + (item.turt_revision || ''))})"><i class="fa-solid fa-circle-info"></i></button>`);
|
||||
}
|
||||
} else {
|
||||
if (!atasanApproved) {
|
||||
actions.push(`<button class="btn btn-sm btn-success" onclick="approvePending('${item.file_directory_id}', '${item.nama_dokumen || ''}')"><i class="fa-solid fa-check"></i></button>`);
|
||||
@ -208,9 +287,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
}
|
||||
|
||||
if (rejected) {
|
||||
if (rejected && atasanRejected && !canMutuAct && !canTurtAct) {
|
||||
actions.length = 1;
|
||||
actions.push(`<button class="btn btn-sm btn-info" onclick="infoRejectPending('${item.file_directory_id}')"><i class="fa-solid fa-circle-info"></i></button>`);
|
||||
}
|
||||
|
||||
if (rejected) {
|
||||
if (hasRevisionInfo(item)) {
|
||||
actions.push(`<button class="btn btn-sm btn-info" onclick="infoRejectPending('${item.file_directory_id}')"><i class="fa-solid fa-circle-info"></i></button>`);
|
||||
}
|
||||
if (canEditSubmission(item)) {
|
||||
actions.push(`<button class="btn btn-sm btn-primary" onclick="editRejectedFromPending('${item.file_directory_id}')"><i class="fa-solid fa-pen-to-square"></i></button>`);
|
||||
}
|
||||
@ -546,31 +630,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
}
|
||||
|
||||
window.infoRejectRole = function(label, revision){
|
||||
Swal.fire({
|
||||
title: `Catatan ${label}`,
|
||||
text: revision || 'Tidak ada catatan revisi.',
|
||||
icon: 'info',
|
||||
confirmButtonText: 'Tutup'
|
||||
});
|
||||
}
|
||||
|
||||
window.infoRejectPending = function(id){
|
||||
const item = getItemById(id);
|
||||
const notes = [];
|
||||
if (item?.revision) {
|
||||
notes.push(`Atasan: ${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)}`);
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
title: 'Catatan Revisi',
|
||||
text: notes.length ? notes.join('\n\n') : 'Tidak ada catatan revisi.',
|
||||
html: buildRevisionNotesHtml(collectRevisionNotes(item)),
|
||||
icon: 'info',
|
||||
confirmButtonText: 'Tutup'
|
||||
});
|
||||
|
||||
@ -19,7 +19,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const selectedCountEl = document.getElementById('selectedCount');
|
||||
const bulkActionsEl = document.getElementById('pengajuanBulkActions');
|
||||
const deleteDataEl = document.getElementById('deleteData');
|
||||
const pendingPersetujuanTabBadge = document.getElementById('pendingPersetujuanTabBadge');
|
||||
const pendingPersetujuanNotice = document.getElementById('pendingPersetujuanNotice');
|
||||
const pendingPersetujuanNoticeCount = document.getElementById('pendingPersetujuanNoticeCount');
|
||||
const formCreate = document.getElementById('formFile');
|
||||
@ -111,55 +110,137 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
function approvalBadge(status, label){
|
||||
if (status === 'approved') return `<span class="badge bg-success">Approved ${label}</span>`;
|
||||
if (status === 'rejected') return `<span class="badge bg-danger">Rejected ${label}</span>`;
|
||||
const normalized = String(status || '').toLowerCase();
|
||||
if (normalized === 'approved') return `<span class="badge bg-success">Approved ${label}</span>`;
|
||||
if (normalized.startsWith('rejected')) return `<span class="badge bg-danger">Rejected ${label}</span>`;
|
||||
if (normalized.startsWith('revised')) return `<span class="badge bg-info">Revised ${label}</span>`;
|
||||
return `<span class="badge bg-warning text-dark">Pending ${label}</span>`;
|
||||
}
|
||||
|
||||
function getPengajuanStatusBadge(item){
|
||||
if (item?.status_mutu === 'rejected') {
|
||||
return `<span class="badge bg-danger">Rejected Mutu</span>`;
|
||||
function hasRevisionInfo(item){
|
||||
return !!(item?.revision || item?.mutu_revision || item?.turt_revision);
|
||||
}
|
||||
|
||||
function collectRevisionNotes(item){
|
||||
const notes = [];
|
||||
const genericRevision = String(item?.revision || '').trim();
|
||||
const mutuRevision = String(item?.mutu_revision || '').trim();
|
||||
const turtRevision = String(item?.turt_revision || '').trim();
|
||||
|
||||
if (genericRevision) {
|
||||
const lowerGeneric = genericRevision.toLowerCase();
|
||||
if (!lowerGeneric.startsWith('komite mutu:') && !lowerGeneric.startsWith('turt:')) {
|
||||
notes.push({ label: 'Atasan/Bagian Terkait', text: genericRevision });
|
||||
}
|
||||
}
|
||||
if (item?.status_turt === 'rejected') {
|
||||
return `<span class="badge bg-danger">Rejected TURT</span>`;
|
||||
if (mutuRevision) {
|
||||
notes.push({ label: 'Komite Mutu', text: mutuRevision });
|
||||
}
|
||||
if (item?.status_action === 'rejected') {
|
||||
return `<span class="badge bg-danger">Rejected Atasan</span>`;
|
||||
if (turtRevision) {
|
||||
notes.push({ label: 'TURT', text: turtRevision });
|
||||
}
|
||||
if (item?.status_action === 'revised') {
|
||||
|
||||
return notes;
|
||||
}
|
||||
|
||||
function escapeHtml(value){
|
||||
return String(value ?? '')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function buildRevisionNotesHtml(notes){
|
||||
if (!notes.length) {
|
||||
return '<div class="text-muted">Tidak ada catatan revisi.</div>';
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="text-start" style="line-height:1.6;">
|
||||
${notes.map(note => `
|
||||
<div class="mb-2">
|
||||
<div><strong>${escapeHtml(note.label)}</strong></div>
|
||||
<div>${escapeHtml(note.text)}</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function isRejectedStatus(item){
|
||||
return String(item?.status_action || '').toLowerCase().startsWith('rejected')
|
||||
|| String(item?.status_mutu || '').toLowerCase().startsWith('rejected')
|
||||
|| String(item?.status_turt || '').toLowerCase().startsWith('rejected');
|
||||
}
|
||||
|
||||
function isApprovedStatus(status){
|
||||
return String(status || '').toLowerCase() === 'approved';
|
||||
}
|
||||
|
||||
function canProcessRoleStatus(status){
|
||||
const normalized = String(status || '').toLowerCase();
|
||||
return normalized === '' || normalized.startsWith('revised');
|
||||
}
|
||||
|
||||
function getPengajuanStatusBadges(item){
|
||||
const actionStatus = String(item?.status_action || '').toLowerCase();
|
||||
const mutuStatus = String(item?.status_mutu || '').toLowerCase();
|
||||
const turtStatus = String(item?.status_turt || '').toLowerCase();
|
||||
|
||||
if (actionStatus.startsWith('revised')) {
|
||||
return `<span class="badge bg-info">Revised</span>`;
|
||||
}
|
||||
|
||||
if (item?.status_action !== 'approved') {
|
||||
if (actionStatus.startsWith('rejected')) {
|
||||
return `<span class="badge bg-danger">Rejected Atasan</span>`;
|
||||
}
|
||||
|
||||
if (actionStatus !== 'approved') {
|
||||
return `<span class="badge bg-warning text-dark">Pending Atasan</span>`;
|
||||
}
|
||||
|
||||
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');
|
||||
const statuses = [];
|
||||
if (item?.is_akre) {
|
||||
if (mutuStatus.startsWith('rejected mutu')) {
|
||||
statuses.push(`<span class="badge bg-danger">Rejected Mutu</span>`);
|
||||
} else if (mutuStatus === 'revised mutu') {
|
||||
statuses.push(`<span class="badge bg-info text-white">Revisi Mutu</span>`);
|
||||
} else if(mutuStatus === 'approved'){
|
||||
statuses.push(`<span class="badge bg-success text-white">Approved Mutu</span>`);
|
||||
}else{
|
||||
statuses.push(`<span class="badge bg-warning text-dark">Pending Mutu</span>`);
|
||||
}
|
||||
}
|
||||
|
||||
if (pendingApprovals.length) {
|
||||
return pendingApprovals.map((label) => `<span class="badge bg-warning text-dark">${label}</span>`).join(' ');
|
||||
}
|
||||
if (item?.status_action === 'approved') {
|
||||
return `<span class="badge bg-success">Approved</span>`;
|
||||
if (item?.master_kategori_directory_id) {
|
||||
if (turtStatus.startsWith('rejected turt')) {
|
||||
statuses.push(`<span class="badge bg-danger">Rejected TURT</span>`);
|
||||
} else if (turtStatus === 'revised turt') {
|
||||
statuses.push(`<span class="badge bg-info text-white">Revisi TURT</span>`);
|
||||
} else if(turtStatus === 'approved'){
|
||||
statuses.push(`<span class="badge bg-success text-white">Approved TURT</span>`);
|
||||
} else{
|
||||
statuses.push(`<span class="badge bg-warning text-dark">Pending TURT</span>`);
|
||||
}
|
||||
}
|
||||
|
||||
return `<span class="badge bg-warning text-dark">Pending Atasan</span>`;
|
||||
if (statuses.length > 0) {
|
||||
return statuses.join(' ');
|
||||
}
|
||||
|
||||
return `<span class="badge bg-success">Approved</span>`;
|
||||
}
|
||||
|
||||
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' || item?.status_mutu === 'rejected' || item?.status_turt === 'rejected';
|
||||
const showEdit = !isApproved || isRejected;
|
||||
const showInfo = isRejected;
|
||||
const isApproved = isApprovedStatus(item?.status_action);
|
||||
const isRejected = isRejectedStatus(item);
|
||||
const showEdit = isRejected;
|
||||
const showInfo = isRejected && hasRevisionInfo(item);
|
||||
const id = String(item.file_directory_id);
|
||||
const checked = selectedIds.has(id);
|
||||
const aksi = `
|
||||
@ -195,7 +276,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
</td>
|
||||
<td>${aksi}</td>
|
||||
<td>${item.no_dokumen || '-'}</td>
|
||||
<td>${getPengajuanStatusBadge(item)}</td>
|
||||
<td><div class="d-flex gap-1 flex-wrap">${getPengajuanStatusBadges(item)}</div></td>
|
||||
<td>${aksesBadge(item?.permission_file)}</td>
|
||||
<td><a href="#" class="file-link"
|
||||
data-file="${item.file}"
|
||||
@ -234,19 +315,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
data-permission_file="${item.permission_file || '-'}"><i class="fa-solid fa-eye"></i></button>`
|
||||
];
|
||||
|
||||
if (showMutu && item.status_mutu !== 'approved') {
|
||||
if (showMutu && canProcessRoleStatus(item.status_mutu)) {
|
||||
actions.push(`<button class="btn btn-sm btn-success" onclick="approvePersetujuan('mutu','${item.file_directory_id}','${item.nama_dokumen || ''}')"><i class="fa-solid fa-check"></i></button>`);
|
||||
actions.push(`<button class="btn btn-sm btn-danger" onclick="rejectPersetujuan('mutu','${item.file_directory_id}','${item.nama_dokumen || ''}')"><i class="fa-solid fa-xmark"></i></button>`);
|
||||
}
|
||||
if (showTurt && item.status_turt !== 'approved') {
|
||||
actions.push(`<button class="btn btn-sm btn-success" onclick="approvePersetujuan('turt','${item.file_directory_id}','${item.nama_dokumen || ''}')"><i class="fa-solid fa-check-double"></i></button>`);
|
||||
if (showTurt && canProcessRoleStatus(item.status_turt)) {
|
||||
actions.push(`<button class="btn btn-sm btn-success" onclick="approvePersetujuan('turt','${item.file_directory_id}','${item.nama_dokumen || ''}')"><i class="fa-solid fa-check"></i></button>`);
|
||||
actions.push(`<button class="btn btn-sm btn-danger" onclick="rejectPersetujuan('turt','${item.file_directory_id}','${item.nama_dokumen || ''}')"><i class="fa-solid fa-ban"></i></button>`);
|
||||
}
|
||||
if (item.status_mutu === 'rejected' && item.mutu_revision) {
|
||||
actions.push(`<button class="btn btn-sm btn-info" onclick="infoRejectPersetujuan('Komite Mutu', ${JSON.stringify('' + (item.mutu_revision || ''))})"><i class="fa-solid fa-circle-info"></i></button>`);
|
||||
}
|
||||
if (item.status_turt === 'rejected' && item.turt_revision) {
|
||||
actions.push(`<button class="btn btn-sm btn-info" onclick="infoRejectPersetujuan('TURT', ${JSON.stringify('' + (item.turt_revision || ''))})"><i class="fa-solid fa-circle-info"></i></button>`);
|
||||
if (hasRevisionInfo(item)) {
|
||||
actions.push(`<button class="btn btn-sm btn-info" onclick="infoReject('${item.file_directory_id}')"><i class="fa-solid fa-circle-info"></i></button>`);
|
||||
}
|
||||
|
||||
const statusParts = [];
|
||||
@ -499,10 +577,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
function updatePendingPersetujuanIndicators(total){
|
||||
const count = Number(total || 0);
|
||||
if (pendingPersetujuanTabBadge) {
|
||||
pendingPersetujuanTabBadge.textContent = String(count);
|
||||
pendingPersetujuanTabBadge.classList.toggle('d-none', count <= 0);
|
||||
}
|
||||
console.log(pendingPersetujuanNoticeCount);
|
||||
|
||||
if (pendingPersetujuanNotice && pendingPersetujuanNoticeCount) {
|
||||
pendingPersetujuanNoticeCount.textContent = String(count);
|
||||
pendingPersetujuanNotice.classList.toggle('d-none', count <= 0);
|
||||
@ -513,19 +589,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
function fetchPendingPersetujuanCount(){
|
||||
if (!(isKomiteMutu || isTurt || isAtasan)) return;
|
||||
|
||||
const params = new URLSearchParams({
|
||||
page: 1,
|
||||
per_page: 1,
|
||||
keyword: '',
|
||||
start_date: '',
|
||||
end_date: '',
|
||||
mode: 'persetujuan'
|
||||
});
|
||||
|
||||
fetch(`/datatable/pengajuan-file?${params.toString()}`)
|
||||
fetch('/data/count-pending', {
|
||||
headers: {
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
updatePendingPersetujuanIndicators(data?.pagination?.total || 0);
|
||||
updatePendingPersetujuanIndicators(data?.count || 0);
|
||||
})
|
||||
.catch(() => {
|
||||
updatePendingPersetujuanIndicators(0);
|
||||
@ -633,29 +704,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
window.infoReject = function(id){
|
||||
const item = getItemById(id);
|
||||
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,
|
||||
icon: 'info',
|
||||
confirmButtonText: 'Tutup'
|
||||
});
|
||||
}
|
||||
|
||||
window.infoRejectPersetujuan = function(label, revision){
|
||||
Swal.fire({
|
||||
title: `Catatan ${label}`,
|
||||
text: revision || 'Tidak ada catatan revisi.',
|
||||
html: buildRevisionNotesHtml(collectRevisionNotes(item)),
|
||||
icon: 'info',
|
||||
confirmButtonText: 'Tutup'
|
||||
});
|
||||
|
||||
@ -660,6 +660,7 @@
|
||||
|
||||
function renderDeleteRecommendation(item){
|
||||
const recommendation = item?.delete_recommendation;
|
||||
|
||||
if (!recommendation?.visible || !recommendation?.note) return '';
|
||||
|
||||
const actorRole = recommendation.actor_role || 'TURT';
|
||||
@ -1255,7 +1256,7 @@
|
||||
data-input-target="expiredInput_${colCount}"
|
||||
data-base-target="dateActive_${colCount}"
|
||||
data-preview-target="expiredPreview_${colCount}">
|
||||
<option value="">Tidak ada</option>
|
||||
<option value="">Selamanya</option>
|
||||
<option value="1">1 Tahun</option>
|
||||
<option value="2">2 Tahun</option>
|
||||
<option value="3">3 Tahun</option>
|
||||
|
||||
@ -57,7 +57,7 @@
|
||||
data-input-target="expiredInput_0"
|
||||
data-base-target="dateActive_0"
|
||||
data-preview-target="expiredPreview_0">
|
||||
<option value="">Tidak ada</option>
|
||||
<option value="">Selamanya</option>
|
||||
<option value="1">1 Tahun</option>
|
||||
<option value="2">2 Tahun</option>
|
||||
<option value="3">3 Tahun</option>
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
<div class="small text-muted ms-md-auto" id="tableSummary"></div>
|
||||
</div>
|
||||
<div id="tabPengajuan">
|
||||
<div class="table-responsive" style="max-height: 55vh; overflow-y:auto; overflow-x:auto;">
|
||||
<div class="table-responsive" style="max-height: 75vh; overflow-y:auto; overflow-x:auto;">
|
||||
<table class="table table-sm table-hover table-striped align-middle mb-0 pending-table" id="lastUpdatedTable">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@ -135,7 +135,7 @@
|
||||
<div class="d-flex flex-column flex-md-row align-items-md-center justify-content-between gap-2 mt-3" id="paginationPengajuan"></div>
|
||||
</div>
|
||||
<div id="tabHistory" class="d-none">
|
||||
<div class="table-responsive" style="max-height: 55vh; overflow-y:auto;">
|
||||
<div class="table-responsive" style="max-height: 75vh; overflow-y:auto;">
|
||||
<table class="table table-sm table-hover align-middle mb-0" id="tableHistory">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -145,8 +145,6 @@
|
||||
<th>Kategori</th>
|
||||
<th>Unit</th>
|
||||
<th>Aksi</th>
|
||||
<th>Tanggal Terbit</th>
|
||||
<th>Tanggal Kedaluwarsa Dokumen</th>
|
||||
<th>Tanggal Upload</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@ -56,7 +56,7 @@
|
||||
data-input-target="edit_tgl_expired"
|
||||
data-base-target="edit_tanggal_terbit"
|
||||
data-preview-target="edit_expired_preview">
|
||||
<option value="">Tidak ada</option>
|
||||
<option value="">Selamanya</option>
|
||||
<option value="1">1 Tahun</option>
|
||||
<option value="2">2 Tahun</option>
|
||||
<option value="3">3 Tahun</option>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user