Detailing fungsi semua modul dari bugs error

This commit is contained in:
Iwit
2026-06-05 13:39:13 +07:00
parent 1089f60a3d
commit 6a79bc3464
31 changed files with 1927 additions and 228 deletions
@@ -9,32 +9,159 @@ use App\Models\Sop;
use App\Models\ExamResult;
use Illuminate\View\View;
use Illuminate\Support\Facades\DB;
use App\Models\Department;
use Carbon\Carbon;
class DashboardController extends Controller
{
/**
* 1. Fungsi Dashboard Utama Admin
*/
public function index(Request $request): View
public function index(Request $request)
{
$statistics = [
// PENTING: Menggunakan whereHas() untuk mengecek relasi Role di tabel pivot
'total_karyawan' => User::whereHas('roles', function ($query) {
$query->where('name', 'trainee'); // Atau 'karyawan', sesuaikan dengan nama role di database Anda
})->count(),
// 1. FILTER TAHUN & BULAN
$selectedYear = $request->input('year', Carbon::now()->year);
$selectedMonth = $request->input('month', Carbon::now()->month);
'total_trainer' => User::whereHas('roles', function ($query) {
// Menghitung admin dan trainer
$query->whereIn('name', ['trainer', 'admin']);
})->count(),
// 2. STATISTIK OVERDUE (Training Terlewat)
// Mengambil penugasan yang deadlinenya sudah lewat dan belum lulus
$overdueTrainings = DB::table('exam_assignments')
->join('users', 'exam_assignments.user_id', '=', 'users.id')
->join('exams', 'exam_assignments.exam_id', '=', 'exams.id')
->join('departments', 'users.department_id', '=', 'departments.id')
->whereMonth('exam_assignments.deadline_date', $selectedMonth)
->whereYear('exam_assignments.deadline_date', $selectedYear)
->where('exam_assignments.deadline_date', '<', Carbon::now())
->where('exam_assignments.status', '!=', 'passed')
->select('users.first_name', 'users.last_name', 'exams.title', 'departments.name as dept_name', 'exam_assignments.deadline_date')
->orderBy('exam_assignments.deadline_date', 'asc')
->take(5) // Ambil 5 teratas untuk list ringkas
->get();
'total_sop' => Sop::where('status', 'Active')->count(),
$totalOverdue = DB::table('exam_assignments')
->whereMonth('deadline_date', $selectedMonth)
->whereYear('deadline_date', $selectedYear)
->where('deadline_date', '<', Carbon::now())
->where('status', '!=', 'passed')
->count();
// 3. PERSENTASE PEMENUHAN TRAINING PER DEPARTEMEN
// Menghitung (Total Lulus / Total Ditugaskan) * 100 per departemen
$departments = Department::all();
$deptFulfillment = [];
foreach ($departments as $dept) {
$totalAssigned = DB::table('exam_assignments')
->join('users', 'exam_assignments.user_id', '=', 'users.id')
->where('users.department_id', $dept->id)
->whereMonth('exam_assignments.created_at', $selectedMonth)
->whereYear('exam_assignments.created_at', $selectedYear)
->count();
$totalPassed = DB::table('exam_assignments')
->join('users', 'exam_assignments.user_id', '=', 'users.id')
->where('users.department_id', $dept->id)
->where('exam_assignments.status', 'passed')
->whereMonth('exam_assignments.created_at', $selectedMonth)
->whereYear('exam_assignments.created_at', $selectedYear)
->count();
$percentage = $totalAssigned > 0 ? round(($totalPassed / $totalAssigned) * 100) : 0;
'lulus_ujian' => ExamResult::where('is_passed', true)->count(),
];
$deptFulfillment[] = [
'id' => $dept->id,
'name' => $dept->name,
'assigned' => $totalAssigned,
'passed' => $totalPassed,
'percentage' => $percentage
];
}
// Pastikan path view ini benar-benar ada di resources/views/pages/admin/dashboard/dashboard.blade.php
return view('pages.admin.dashboard.dashboard', compact('statistics'));
// Urutkan dari persentase terkecil (yang butuh perhatian) ke terbesar
usort($deptFulfillment, function($a, $b) {
return $a['percentage'] <=> $b['percentage'];
});
// 4. DATA ACTIVE / ONGOING EXAM (Untuk injeksi awal Realtime)
// Kita tarik data awal, selanjutnya Alpine.js akan melakukan polling AJAX
$activeExamsCount = DB::table('exam_attempts')->where('status', 'ongoing')->count();
// -------------------------------------------------------------------
// 5. DATA UNTUK KALENDER TRAINING (Berdasarkan Role)
// -------------------------------------------------------------------
$user = \Illuminate\Support\Facades\Auth::user();
$calendarQuery = DB::table('exam_assignments')
->join('users', 'exam_assignments.user_id', '=', 'users.id')
->join('exams', 'exam_assignments.exam_id', '=', 'exams.id')
->select(
'exam_assignments.id',
'exams.title as exam_title',
'users.first_name',
'exam_assignments.created_at',
'exam_assignments.deadline_date',
'exam_assignments.status'
);
// LOGIKA ROLE: Jika BUKAN superadmin, batasi hanya melihat departemennya sendiri
if (!$user->hasRole('superadmin')) {
$calendarQuery->where('users.department_id', $user->department_id);
}
$calendarData = $calendarQuery->get()->map(function($assign) {
// Menentukan warna event di kalender berdasarkan status
$color = '#f59e0b'; // Amber (Pending)
if ($assign->status === 'passed') $color = '#10b981'; // Emerald (Lulus)
if ($assign->status === 'ongoing') $color = '#3b82f6'; // Blue (Sedang dikerjakan)
if ($assign->status != 'passed' && Carbon::parse($assign->deadline_date)->isPast()) {
$color = '#ef4444'; // Red (Overdue)
}
return [
'id' => $assign->id,
'title' => $assign->first_name . ' - ' . $assign->exam_title,
'start' => Carbon::parse($assign->created_at)->format('Y-m-d'), // Tanggal ditugaskan
'end' => Carbon::parse($assign->deadline_date)->addDay()->format('Y-m-d'), // Tanggal deadline (+1 agar FullCalendar merender sampai hari H penuh)
'color' => $color,
'allDay'=> true
];
});
return view('pages.admin.dashboard.dashboard', compact(
'selectedYear', 'selectedMonth', 'overdueTrainings', 'totalOverdue', 'deptFulfillment', 'activeExamsCount', 'calendarData' // <--- Tambahkan ini
));
}
// ==========================================================
// FUNGSI API UNTUK REAL-TIME MONITORING (AJAX Polling)
// ==========================================================
public function getLiveExams()
{
$liveExams = DB::table('exam_attempts')
->join('exam_assignments', 'exam_attempts.exam_assignment_id', '=', 'exam_assignments.id')
->join('users', 'exam_assignments.user_id', '=', 'users.id')
->join('exams', 'exam_assignments.exam_id', '=', 'exams.id')
->join('departments', 'users.department_id', '=', 'departments.id')
->where('exam_attempts.status', 'ongoing')
->select(
'exam_attempts.id as attempt_id',
'users.first_name',
'users.last_name',
'departments.name as dept_name',
'exams.title as exam_title',
'exam_attempts.started_at',
'exams.duration_minutes'
)
->get()
->map(function ($exam) {
// Kalkulasi sisa waktu secara server-side
$started = Carbon::parse($exam->started_at);
$endsAt = $started->copy()->addMinutes($exam->duration_minutes);
$exam->time_left_seconds = Carbon::now()->diffInSeconds($endsAt, false); // Minus jika kelebihan
return $exam;
});
return response()->json($liveExams);
}
/**
@@ -234,4 +361,31 @@ class DashboardController extends Controller
return response()->stream($callback, 200, $headers);
}
// ==========================================================
// FUNGSI UNTUK HALAMAN DETAIL PEMENUHAN DEPARTEMEN
// ==========================================================
public function departmentFulfillment($id, Request $request)
{
$department = Department::findOrFail($id);
$selectedMonth = $request->input('month', Carbon::now()->month);
$selectedYear = $request->input('year', Carbon::now()->year);
// Ambil detail penugasan ujian khusus departemen ini di bulan/tahun yang dipilih
$assignments = DB::table('exam_assignments')
->join('users', 'exam_assignments.user_id', '=', 'users.id')
->join('exams', 'exam_assignments.exam_id', '=', 'exams.id')
->where('users.department_id', $id)
->whereMonth('exam_assignments.created_at', $selectedMonth)
->whereYear('exam_assignments.created_at', $selectedYear)
->select(
'users.first_name', 'users.last_name', 'users.nik',
'exams.title', 'exam_assignments.status',
'exam_assignments.deadline_date', 'exam_assignments.created_at'
)
->orderBy('exam_assignments.created_at', 'desc')
->paginate(20);
return view('pages.admin.dashboard.department-detail', compact('department', 'assignments', 'selectedMonth', 'selectedYear'));
}
}
@@ -49,9 +49,11 @@ class DepartmentController extends Controller
->with('success', 'Departemen baru berhasil ditambahkan.');
}
public function show(Department $department)
public function show($id)
{
// Hanya melempar object $department ke view tanpa load relasi positions
// Pastikan kita me-load relasi 'users' (Karyawan) beserta 'position' (Jabatan) mereka
$department = \App\Models\Department::with(['users.position'])->findOrFail($id);
return view('pages.admin.departments.show', compact('department'));
}
@@ -9,110 +9,331 @@ use App\Models\Position;
use App\Models\Subject;
use App\Models\User;
use App\Models\QuestionBank;
use App\Models\Exam;
class ExamManagementController extends Controller
{
public function questionBank(Request $request)
// ==============================================================================
// 1. AREA MANAJEMEN UJIAN (CBT)
// ==============================================================================
public function index(Request $request)
{
// 1. Ambil ID unik siapa saja yang PERNAH membuat soal di tabel question_banks
$creatorIds = \App\Models\QuestionBank::whereNotNull('created_by')
->distinct()
->pluck('created_by');
$query = Exam::with('subject');
// 2. Tarik data User HANYA berdasarkan ID pembuat soal tersebut
$creators = \App\Models\User::whereIn('id', $creatorIds)
->orderBy('first_name', 'asc')
->get();
// 3. Tarik data pendukung lainnya untuk filter & dropdown
$subjects = \App\Models\Subject::orderBy('name', 'asc')->get();
$departments = \App\Models\Department::orderBy('name', 'asc')->get();
$positions = \App\Models\Position::orderBy('name', 'asc')->get();
// 4. Hitung Total Soal Keseluruhan (TANPA FILTER) untuk Badge di View
$totalQuestions = \App\Models\QuestionBank::count(); // <--- TAMBAHKAN BARIS INI
// 5. Query utama Bank Soal (dengan fitur pencarian/filter)
$query = \App\Models\QuestionBank::with(['subject', 'department', 'creator', 'position']);
// Filter berdasarkan pembuat soal
if ($request->filled('creator_id')) {
$query->where('created_by', $request->creator_id);
if ($request->filled('search')) {
$query->where('title', 'LIKE', '%' . $request->search . '%');
}
$exams = $query->latest()->paginate(20);
return view('pages.admin.exams.index', compact('exams'));
}
public function create()
{
// Tarik data materi untuk Select2 Modul
$subjects = Subject::orderBy('name', 'asc')->get();
// Filter berdasarkan subject/materi
if ($request->filled('subject_id')) {
$query->where('subject_id', $request->subject_id);
// Tarik data karyawan untuk Select2 Peserta (Bisa pilih banyak)
$employees = User::orderBy('first_name', 'asc')->get();
return view('pages.admin.exams.create', compact('subjects', 'employees'));
}
public function store(Request $request)
{
$request->validate([
'training_type' => 'required|in:matrix_plant,general,external',
'is_random_order' => 'nullable|boolean',
]);
if ($request->training_type === 'external') {
return back()->with('info', 'Fitur External Training dengan database HR sedang dalam tahap pengembangan.');
}
// Filter berdasarkan departemen
if ($request->filled('department_id')) {
$query->where('department_id', $request->department_id);
// Validasi Tambahan: Peserta, Deadline, dan Array Ujian
$request->validate([
'employee_ids' => 'required|array|min:1', // Wajib pilih minimal 1 peserta
'employee_ids.*' => 'exists:users,id',
'deadline_date' => 'required|date|after_or_equal:today', // Deadline tidak boleh masa lalu
'exams' => 'required|array|min:1',
'exams.*.subject_id' => 'required|exists:subjects,id',
'exams.*.title' => 'nullable|string|max:255',
'exams.*.duration_minutes' => 'required|integer|min:1',
'exams.*.passing_grade' => 'required|integer|min:1|max:100',
'exams.*.max_retakes' => 'required|integer|min:0',
]);
$isRandom = $request->has('is_random_order');
$trainingType = $request->training_type === 'general' ? 'product' : 'matrix_plant';
// 1. Simpan setiap modul sebagai sesi ujian tersendiri
foreach ($request->exams as $examData) {
$exam = Exam::create([
'title' => $examData['title'] ?: Subject::find($examData['subject_id'])->name,
'subject_id' => $examData['subject_id'],
'training_type' => $trainingType,
'duration_minutes' => $examData['duration_minutes'],
'passing_grade' => $examData['passing_grade'],
'max_retakes' => $examData['max_retakes'],
'is_random_order' => $isRandom,
'is_active' => true,
]);
// 2. Tugaskan (Assign) ujian yang baru dibuat ini ke SEMUA karyawan yang dipilih
$assignments = [];
foreach ($request->employee_ids as $userId) {
$assignments[] = [
'user_id' => $userId,
'exam_id' => $exam->id,
'deadline_date' => $request->deadline_date,
'status' => 'pending',
'created_at' => now(),
'updated_at' => now(),
];
}
// Insert massal ke database agar prosesnya secepat kilat
\Illuminate\Support\Facades\DB::table('exam_assignments')->insert($assignments);
}
// Filter berdasarkan posisi/jabatan
if ($request->filled('position_id')) {
$query->where('position_id', $request->position_id);
return redirect()->route('admin.exams.index')
->with('success', count($request->exams) . ' Modul Ujian berhasil dibuat dan ditugaskan ke ' . count($request->employee_ids) . ' Karyawan!');
}
// ==============================================================================
// 2. AREA MANAJEMEN BANK SOAL
// ==============================================================================
public function questionBank(Request $request)
{
$creatorIds = QuestionBank::whereNotNull('created_by')->distinct()->pluck('created_by');
$creators = User::whereIn('id', $creatorIds)->orderBy('first_name', 'asc')->get();
$subjects = Subject::orderBy('name', 'asc')->get();
$departments = Department::orderBy('name', 'asc')->get();
$positions = Position::orderBy('name', 'asc')->get();
$totalQuestions = QuestionBank::count();
// Query utama dengan relasi
$query = QuestionBank::with(['subject', 'department', 'creator', 'position']);
// 1. FILTER GLOBAL SEARCH (Mencari di semua kolom & relasi)
if ($request->filled('search')) {
$search = $request->search;
$query->where(function($q) use ($search) {
// Cari di ID atau Teks Soal
$q->where('id', 'LIKE', "%{$search}%")
->orWhere('question_text', 'LIKE', "%{$search}%")
->orWhere('question_type', 'LIKE', "%{$search}%")
->orWhere('question_level', 'LIKE', "%{$search}%")
// Cari di Nama Materi
->orWhereHas('subject', function($sub) use ($search) {
$sub->where('name', 'LIKE', "%{$search}%");
})
// Cari di Nama Departemen
->orWhereHas('department', function($dep) use ($search) {
$dep->where('name', 'LIKE', "%{$search}%");
})
// Cari di Nama Jabatan
->orWhereHas('position', function($pos) use ($search) {
$pos->where('name', 'LIKE', "%{$search}%");
})
// Cari di Nama Pembuat Soal
->orWhereHas('creator', function($usr) use ($search) {
$usr->where('first_name', 'LIKE', "%{$search}%")
->orWhere('last_name', 'LIKE', "%{$search}%");
});
});
}
// Pagination
// 2. FILTER DROPDOWN SPESIFIK
if ($request->filled('creator_id')) { $query->where('created_by', $request->creator_id); }
if ($request->filled('subject_id')) { $query->where('subject_id', $request->subject_id); }
if ($request->filled('department_id')) { $query->where('department_id', $request->department_id); }
if ($request->filled('position_id')) { $query->where('position_id', $request->position_id); }
if ($request->filled('question_type')) { $query->where('question_type', $request->question_type); }
if ($request->filled('question_level')) { $query->where('question_level', $request->question_level); }
// ==============================================================================
// 3. INTERCEPTOR UNTUK EXPORT (Excel & PDF)
// ==============================================================================
if ($request->action === 'export_excel' || $request->action === 'export_pdf') {
$exportData = $query->latest()->get();
$exporterName = auth()->user()->first_name . ' ' . auth()->user()->last_name;
$exportTime = now()->format('d F Y, H:i:s');
// LOGIKA EXPORT EXCEL (Download Paksa)
if ($request->action === 'export_excel') {
$fileName = 'Data_Bank_Soal_' . now()->format('Ymd_His') . '.xls';
return response()->streamDownload(function () use ($exportData, $exporterName, $exportTime, $request) {
echo view('pages.admin.question-banks.export-report', compact('exportData', 'exporterName', 'exportTime', 'request'))->render();
}, $fileName, [
'Content-Type' => 'application/vnd.ms-excel',
'Content-Disposition' => 'attachment; filename="'.$fileName.'"',
]);
}
// LOGIKA EXPORT PDF (Menggunakan Facade DomPDF)
if ($request->action === 'export_pdf') {
$fileName = 'Data_Bank_Soal_' . now()->format('Ymd_His') . '.pdf';
// Gunakan library PDF yang sudah ada di project Anda
$pdf = \Barryvdh\DomPDF\Facade\Pdf::loadView('pages.admin.question-banks.export-report', compact('exportData', 'exporterName', 'exportTime', 'request'))
->setPaper('a4', 'landscape'); // Format landscape agar tabel muat
return $pdf->download($fileName);
}
}
// 4. JIKA BUKAN EXPORT, LANJUTKAN KE TAMPILAN TABEL NORMAL DENGAN PAGINATION
$questions = $query->latest()->paginate(20);
// Pastikan $totalQuestions ikut dikirim ke compact
return view('pages.admin.question-banks.question-bank', compact('questions', 'creators', 'subjects', 'departments', 'positions', 'totalQuestions'));
}
// Fungsi untuk menampilkan halaman Tambah Soal
public function create()
// Nama diubah agar tidak bentrok dengan create() ujian
public function createQuestion()
{
$departments = Department::orderBy('name', 'asc')->get();
$positions = Position::orderBy('name', 'asc')->get();
$subjects = Subject::orderBy('name', 'asc')->get(); // Kirim Subject ke form
$subjects = Subject::orderBy('name', 'asc')->get();
return view('pages.admin.question-banks.create', compact('departments', 'positions', 'subjects'));
}
// Fungsi untuk menampilkan halaman Edit Soal
public function edit($id)
// Nama diubah agar spesifik untuk soal
public function editQuestion($id)
{
$question = QuestionBank::findOrFail($id);
$departments = Department::orderBy('name', 'asc')->get();
$positions = Position::orderBy('name', 'asc')->get();
$subjects = Subject::orderBy('name', 'asc')->get(); // Kirim Subject ke form
$subjects = Subject::orderBy('name', 'asc')->get();
return view('pages.admin.question-banks.edit', compact('question', 'departments', 'positions', 'subjects'));
}
// Fungsi Show untuk Detail Soal
public function show($id)
// Nama diubah agar spesifik untuk soal
public function showQuestion($id)
{
$question = QuestionBank::with(['subject', 'department', 'position', 'creator'])->findOrFail($id);
return view('pages.admin.question-banks.show', compact('question'));
}
/**
* Menghapus banyak soal sekaligus (Bulk Delete)
*/
public function bulkDelete(Request $request)
{
$request->validate([
'question_ids' => 'required|array',
'question_ids.*' => 'exists:questions,id'
'question_ids.*' => 'exists:question_banks,id' // Diperbaiki dari tabel questions ke question_banks
]);
try {
Question::whereIn('id', $request->question_ids)->delete();
// Diperbaiki dari model Question ke QuestionBank
QuestionBank::whereIn('id', $request->question_ids)->delete();
return back()->with('success', count($request->question_ids) . ' Soal berhasil dihapus secara massal.');
} catch (\Exception $e) {
return back()->with('error', 'Gagal menghapus soal: ' . $e->getMessage());
}
}
/**
* Menampilkan Halaman Import Soal
*/
public function importView()
{
return view('pages.admin.exams.questions.import');
}
// ==============================================================================
// FUNGSI PROSES SIMPAN, EDIT, DAN HAPUS BANK SOAL
// ==============================================================================
public function storeQuestion(Request $request)
{
$request->validate([
'subject_id' => 'required|exists:subjects,id',
'department_id' => 'nullable|exists:departments,id',
'position_id' => 'nullable|exists:positions,id',
// VALIDASI INI SUDAH DISAMAKAN DENGAN FORM UI
'question_type' => 'required|in:single,multiple,true_false,descriptive',
'question_text' => 'required|string',
'score_weight' => 'required|numeric|min:1',
'duration' => 'nullable|numeric',
'passing_grade' => 'nullable|numeric',
]);
$data = $request->all();
$data['created_by'] = auth()->id(); // Rekam siapa yang membuat soal
// Bersihkan data yang tidak relevan berdasarkan jenis soal
if ($request->question_type === 'descriptive') {
$data['option_a'] = null;
$data['option_b'] = null;
$data['option_c'] = null;
$data['option_d'] = null;
$data['option_e'] = null;
$data['correct_answer'] = null;
} else {
$data['essay_keywords'] = null;
}
// Jika tipe soal adalah Multiple (bisa centang lebih dari 1), ubah array menjadi JSON
// if (isset($request->correct_answer) && is_array($request->correct_answer)) {
// $data['correct_answer'] = json_encode($request->correct_answer);
// }
QuestionBank::create($data);
return redirect()->route('admin.question-bank.index')->with('success', 'Soal baru berhasil ditambahkan ke Bank Soal!');
}
public function updateQuestion(Request $request, $id)
{
$request->validate([
'subject_id' => 'required|exists:subjects,id',
'department_id' => 'nullable|exists:departments,id',
'position_id' => 'nullable|exists:positions,id',
'question_type' => 'required|in:single,multiple,true_false,descriptive',
'question_text' => 'required|string',
'score_weight' => 'required|numeric|min:1',
'duration' => 'nullable|numeric',
'passing_grade' => 'nullable|numeric',
]);
$question = QuestionBank::findOrFail($id);
$data = $request->all();
// 1. Bersihkan data yang tidak relevan berdasarkan jenis soal
if ($request->question_type === 'descriptive') {
$data['option_a'] = null;
$data['option_b'] = null;
$data['option_c'] = null;
$data['option_d'] = null;
$data['option_e'] = null;
$data['correct_answer'] = null;
} else {
$data['essay_keywords'] = null;
}
// 2. Jika tipe soal adalah Multiple (bisa centang lebih dari 1), ubah array menjadi JSON
// if (is_array($request->correct_answer)) {
// $data['correct_answer'] = json_encode($request->correct_answer);
// }
// 3. Simpan pembaruan
$question->update($data);
return redirect()->route('admin.question-bank.index')->with('success', 'Perubahan soal berhasil disimpan!');
}
public function destroyQuestion($id)
{
try {
$question = QuestionBank::findOrFail($id);
$question->delete();
return back()->with('success', 'Soal berhasil dihapus.');
} catch (\Exception $e) {
return back()->with('error', 'Gagal menghapus soal: ' . $e->getMessage());
}
}
}
+14 -6
View File
@@ -2,20 +2,28 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Exam extends Model
{
use HasFactory;
protected $fillable = [
'old_id',
'title',
'duration',
'passing_percentage'
'description',
'training_type',
'subject_id',
'duration_minutes',
'passing_grade',
'max_retakes',
'is_random_order',
'is_active'
];
public function results(): HasMany
// Relasi: Setiap Ujian pasti milik satu Materi (Subject)
public function subject()
{
return $this->hasMany(ExamResult::class);
return $this->belongsTo(Subject::class);
}
}
+4 -19
View File
@@ -10,25 +10,10 @@ class QuestionBank extends Model
protected $table = 'question_banks';
protected $fillable = [
// Atribut Soal dari desain Anda
'old_id',
'subject_id',
'question_type',
'question_level',
'passing_grade',
'duration',
'question_text',
'option_a',
'option_b',
'option_c',
'option_d',
'option_e',
'correct_answer',
// PENTING: Atribut Relasi yang dibutuhkan form Create/Edit & Filter Index
'department_id',
'position_id',
'training_matrix_id',
'subject_id', 'department_id', 'position_id', 'question_type',
'question_level', 'question_text', 'option_a', 'option_b',
'option_c', 'option_d', 'option_e', 'correct_answer',
'essay_keywords', 'score_weight', 'passing_grade', 'duration',
'created_by'
];
+8
View File
@@ -19,4 +19,12 @@ class Subject extends Model
{
return $this->hasMany(QuestionBank::class, 'subject_id');
}
public function users() // atau employees()
{
// Paksa pencarian menggunakan 'user_id'
return $this->belongsToMany(User::class, 'employee_subject', 'subject_id', 'user_id')
->withPivot('status')
->withTimestamps();
}
}
+10 -2
View File
@@ -73,10 +73,18 @@ class User extends Authenticatable
return $this->belongsTo(Position::class, 'position_id');
}
public function subjects()
{
// Parameter ke-3 'user_id' akan memaksa Laravel mengabaikan pencarian 'employee_id'
return $this->belongsToMany(\App\Models\Subject::class, 'employee_subject', 'user_id', 'subject_id')
->withPivot('status')
->withTimestamps();
}
public function trainings()
{
// Ubah 'user_id' menjadi 'employee_id' agar sesuai dengan database Anda saat ini
return $this->belongsToMany(Subject::class, 'employee_subject', 'employee_id', 'subject_id')
// Karena ini Model User, foreign key-nya harus 'user_id'
return $this->belongsToMany(Subject::class, 'employee_subject', 'user_id', 'subject_id')
->withPivot('status')
->withTimestamps();
}