group(function(){ Route::get('/pitstop/progress-detail', [PitStopController::class, 'progressDetail']); Route::get('/list-karyawan', [KaryawanController::class, 'listData']); Route::get('/list-karyawan-luar', [KaryawanController::class, 'listDataKaryawanLuar']); Route::get('/pitstop', [PitStopController::class, 'pitstop']); // Progress by unit (DataTables) Route::get('/', [PitStopController::class, 'progressUnit']); Route::get('/monitoring-pra-akreditasi/pdf', [PitStopController::class, 'monitoringPdf']); Route::get('/monitoring-pra-akreditasi/pdf-external', [PitStopController::class, 'monitoringPdfExternal']); Route::get('/monitoring-pra-akreditasi/excel', [PitStopController::class, 'monitoringExcel']); Route::get('/monitoring-pra-akreditasi/excel-external', [PitStopController::class, 'monitoringExcelExternal']); Route::get('/pitstop/progress-unit/{unit_id}', [PitStopController::class, 'progressUnitDetail']); // Use query param (?tipe=...) to safely handle values containing "/" (encoded slashes may break route params) Route::get('/pitstop/progress-external', [PitStopController::class, 'progressExternalDetail']); Route::get('/pitstop/progress-external/{tipe}', [PitStopController::class, 'progressExternalDetail']); Route::get('/data/progress-Internal', [PitStopController::class, 'dataProgress']); Route::get('/data/progress-Internal/{unit_id}', [PitStopController::class, 'dataProgressUnit']); Route::get('/data/progress-external/by-tipe', [PitStopController::class, 'dataProgressExternalByTipe']); Route::get('/data/progress-external/{tipe}', [PitStopController::class, 'dataProgressExternalByTipe']); Route::get('/data/progress-all-karyawan', [PitStopController::class, 'dataProgressAllKaryawan']); Route::get('/data/progress-external', [PitStopController::class, 'dataProgressExternal']); Route::get('/data/progress-external/detail', [PitStopController::class, 'dataProgressExternalDetail']); // Master PitStop (CRUD) Route::get('/master-pitstop', [MasterPitStopController::class, 'index']); Route::get('/master-pitstop/data', [MasterPitStopController::class, 'data']); Route::post('/master-pitstop', [MasterPitStopController::class, 'store']); Route::put('/master-pitstop/{id}', [MasterPitStopController::class, 'update']); Route::patch('/master-pitstop/{id}/toggle', [MasterPitStopController::class, 'toggle']); Route::get('/pitstop/pegawai-steps', [PitStopController::class, 'pegawaiSteps']); Route::get('/pitstop/pegawai-steps-external', [PitStopController::class, 'pegawaiStepsExternal']); Route::post('/pitstop/submit', [PitStopController::class, 'submit']); Route::get('/pitstop/progress-detail-external', [PitStopController::class, 'progressDetailExternal']); Route::post('/logout', [AuthController::class, 'logout']); }); Route::get('/login', [AuthController::class, 'login'])->name('login'); Route::post('/login', [AuthController::class, 'submitLogin']); Route::get('/data/progress-all-karyawan-ghost', [PitStopController::class, 'dataProgressAllKaryawanGhost']); Route::get('/pitstop/progress-detail-ghost', [PitStopController::class, 'progressDetailGhost']); Route::get('/pitstop/progress-detail-external-ghost', [PitStopController::class, 'progressDetailExternal']); // Route::get('/outsorching', function(){ // $data = DB::connection('pgsql')->select(" // SELECT // pl.nama AS nama_external, // pl.tipe, // pg.namalengkap AS nama_internal, // ukp.name AS unit, // similarity(LOWER(pl.nama), LOWER(pg.namalengkap)) as score, // 'MATCH' as status_data // FROM public.pegawai_luar_pl pl // JOIN public.pegawai_m pg // ON similarity(LOWER(pl.nama), LOWER(pg.namalengkap)) > 0.6 // LEFT JOIN public.mappegawaijabatantounitkerja_m mp // ON pg.id = mp.objectpegawaifk // AND mp.statusenabled = true // AND mp.isprimary = true // LEFT JOIN public.unitkerjapegawai_m ukp // ON ukp.id = mp.objectunitkerjapegawaifk // WHERE // pl.tipe ILIKE '%OUTSORCHING%' // AND pg.statusenabled = true // AND pg.kategorypegawai = '11' // AND pg.kedudukanfk = 1 // UNION ALL // SELECT // NULL AS nama_external, // NULL AS tipe, // pg.namalengkap AS nama_internal, // ukp.name AS unit, // NULL AS score, // 'HANYA DI INTERNAL' as status_data // FROM public.pegawai_m pg // LEFT JOIN public.mappegawaijabatantounitkerja_m mp // ON pg.id = mp.objectpegawaifk // AND mp.statusenabled = true // AND mp.isprimary = true // LEFT JOIN public.unitkerjapegawai_m ukp // ON ukp.id = mp.objectunitkerjapegawaifk // WHERE // pg.statusenabled = true // AND pg.kategorypegawai = '11' // AND pg.kedudukanfk = 1 // AND NOT EXISTS ( // SELECT 1 FROM public.pegawai_luar_pl pl // WHERE pl.tipe ILIKE '%OUTSORCHING%' // AND similarity(LOWER(pl.nama), LOWER(pg.namalengkap)) > 0.6 // ) // ORDER BY status_data // "); // $collection = collect($data); // return [ // 'summary' => [ // 'total' => $collection->count(), // 'match' => $collection->where('status_data', 'MATCH')->count(), // 'external_only' => $collection->where('status_data', 'HANYA DI EXTERNAL')->count(), // 'internal_only' => $collection->where('status_data', 'HANYA DI INTERNAL')->count(), // ], // 'data' => $data // ]; // }); // Route::get('/outsorching', function(){ // $data = DB::connection('pgsql')->select(" // -- ========================= // -- 🔥 1. MATCH (FUZZY) // -- ========================= // SELECT // COALESCE(pl.nama, '-') AS nama_external, // pl.tipe, // pg.id as pegawai_id, // pg.namalengkap AS nama_internal, // ukp.name AS unit, // ROUND(similarity(LOWER(pl.nama), LOWER(pg.namalengkap))::numeric, 2) as score, // true as is_match, // 'MATCH' as status_data, // COUNT(pr.id) as total_praakre, // COUNT(*) FILTER (WHERE pr.status = 'LULUS') as jumlah_lulus, // COUNT(*) FILTER (WHERE pr.status = 'TIDAK LULUS') as jumlah_tidak_lulus, // COALESCE( // json_agg( // json_build_object( // 'id', pr.id, // 'unit_id', pr.unit_id, // 'masterpitstop_id', pr.masterpitstop_id, // 'masterpitstop_nama', mpit.nama, // 'nilai', pr.nilai, // 'action_at', pm.namalengkap, // 'created_at', pr.created_at, // 'type_karyawan', pr.tipe_karyawan // ) // ORDER BY NULLIF(pr.masterpitstop_id, '')::int // ) FILTER (WHERE pr.id IS NOT NULL), // '[]'::json // ) as praakre_data // FROM public.pegawai_luar_pl pl // JOIN public.pegawai_m pg // ON similarity(LOWER(pl.nama), LOWER(pg.namalengkap)) > 0.6 // LEFT JOIN public.mappegawaijabatantounitkerja_m mp // ON pg.id = mp.objectpegawaifk // AND mp.statusenabled = true // AND mp.isprimary = true // LEFT JOIN public.unitkerjapegawai_m ukp // ON ukp.id = mp.objectunitkerjapegawaifk // -- 🔥 PRAAKRE INTERNAL + LUAR // LEFT JOIN public.praakre pr // ON ( // (pr.tipe_karyawan = 'internal' AND pr.pegawai_id::int = pg.id) // OR // (pr.tipe_karyawan = 'luar' AND pr.pegawai_id::int = pl.id) // ) // LEFT JOIN public.masterpitstop mpit // ON mpit.id = NULLIF(pr.masterpitstop_id, '')::int // LEFT JOIN public.pegawai_m pm // ON pm.id = NULLIF(pr.action_at, '')::int // WHERE // pl.tipe ILIKE '%OUTSORCHING%' // AND pg.statusenabled = true // AND pg.kategorypegawai = '11' // AND pg.kedudukanfk = 1 // GROUP BY // pl.nama, pl.tipe, pg.id, pg.namalengkap, ukp.name // UNION ALL // -- ========================= // -- 🔥 2. HANYA DI INTERNAL // -- ========================= // SELECT // '-' AS nama_external, // NULL AS tipe, // pg.id as pegawai_id, // pg.namalengkap AS nama_internal, // ukp.name AS unit, // NULL as score, // false as is_match, // 'HANYA DI INTERNAL' as status_data, // COUNT(pr.id) as total_praakre, // COALESCE( // json_agg( // json_build_object( // 'id', pr.id, // 'masterpitstop_id', pr.masterpitstop_id, // 'masterpitstop_nama', mpit.nama, // 'nilai', pr.nilai, // 'action_at', pm.namalengkap, // 'created_at', pr.created_at, // 'type_karyawan', pr.tipe_karyawan // ) // ORDER BY NULLIF(pr.masterpitstop_id, '')::int // ) FILTER (WHERE pr.id IS NOT NULL), // '[]'::json // ) as praakre_data // FROM public.pegawai_m pg // LEFT JOIN public.mappegawaijabatantounitkerja_m mp // ON pg.id = mp.objectpegawaifk // AND mp.statusenabled = true // AND mp.isprimary = true // LEFT JOIN public.unitkerjapegawai_m ukp // ON ukp.id = mp.objectunitkerjapegawaifk // -- 🔥 PRAAKRE INTERNAL SAJA // LEFT JOIN public.praakre pr // ON pr.tipe_karyawan = 'internal' // AND pr.pegawai_id::int = pg.id // LEFT JOIN public.masterpitstop mpit // ON mpit.id = NULLIF(pr.masterpitstop_id, '')::int // LEFT JOIN public.pegawai_m pm // ON pm.id = NULLIF(pr.action_at, '')::int // WHERE // pg.statusenabled = true // AND pg.kategorypegawai = '11' // AND pg.kedudukanfk = 1 // AND NOT EXISTS ( // SELECT 1 FROM public.pegawai_luar_pl pl // WHERE pl.tipe ILIKE '%OUTSORCHING%' // AND similarity(LOWER(pl.nama), LOWER(pg.namalengkap)) > 0.6 // ) // GROUP BY // pg.id, pg.namalengkap, ukp.name // ORDER BY status_data, nama_internal // "); // // 🔥 FIX: pastikan JSON jadi array beneran di Laravel // $data = collect($data)->map(function($item){ // $item->praakre_data = is_string($item->praakre_data) // ? json_decode($item->praakre_data, true) // : $item->praakre_data; // return $item; // }); // return [ // 'summary' => [ // 'total' => $data->count(), // 'match' => $data->where('status_data', 'MATCH')->count(), // 'internal_only' => $data->where('status_data', 'HANYA DI INTERNAL')->count(), // 'total_lulus' => $data->sum('jumlah_lulus'), // 'total_tidak_lulus' => $data->sum('jumlah_tidak_lulus'), // ], // 'data' => $data // ]; // });