currentFlag = model(CurrentFlag::class); $this->flag = model(Flag::class); $this->student = model(Student::class); $this->classSection = model(ClassSection::class); $this->studentClass = model(StudentClass::class); $this->config = model(Configuration::class); } public function index() { $page = max(1, (int) ($this->request->getGet('page') ?? 1)); $perPage = min(100, max(1, (int) ($this->request->getGet('per_page') ?? 20))); $studentId = $this->request->getGet('student_id'); $flagType = $this->request->getGet('flag_type') ?? $this->request->getGet('flag'); $state = $this->request->getGet('state') ?? $this->request->getGet('flag_state'); $query = $this->currentFlag->newQuery()->orderBy('created_at', 'DESC'); if ($studentId) { $query->where('student_id', $studentId); } if ($flagType) { $query->where('flag', $flagType); } if ($state) { $query->where('flag_state', $state); } $result = $this->paginate($query, $page, $perPage); // Also return class sections (grades) for UI $classSections = $this->classSection->findAll(); $grades = []; foreach ($classSections as $section) { $grades[] = [ 'id' => $section['class_section_id'] ?? $section['id'] ?? null, 'name' => $section['class_section_name'] ?? $section['name'] ?? '', ]; } $result['grades'] = $grades; return $this->success($result, 'Flags retrieved successfully'); } public function show($id = null) { $flag = $this->currentFlag->find($id); if (!$flag) { return $this->respondError('Flag not found', Response::HTTP_NOT_FOUND); } return $this->success($flag, 'Flag retrieved successfully'); } public function create() { return $this->addFlag(); } /** * Add or update a flag for a student * If a flag of the same type exists, it updates it; otherwise creates a new one */ public function addFlag() { $user = $this->getCurrentUser(); $data = $this->payloadData(); if (empty($data)) { return $this->respondError('Invalid request data', Response::HTTP_BAD_REQUEST); } $studentId = $data['student_id'] ?? $data['student'] ?? null; $flagType = $data['flag'] ?? $data['flag_type'] ?? null; $description = $data['description'] ?? $data['open_description'] ?? null; $flagState = $data['flag_state'] ?? 'Open'; $stateDescription = $data['state_description'] ?? null; $grade = $data['grade'] ?? null; if (!$studentId || !$flagType || !$description) { return $this->respondError('Missing required fields: student_id, flag, description', Response::HTTP_BAD_REQUEST); } try { // Retrieve student information $student = $this->student->find($studentId); if (!$student) { return $this->respondError('Student not found', Response::HTTP_NOT_FOUND); } $userId = $user->id ?? null; $semester = $this->config->getConfig('semester'); $schoolYear = $this->config->getConfig('school_year'); $currentDateTime = date('Y-m-d H:i:s'); // Check if a flag of the same type already exists for this student $existingFlag = $this->currentFlag ->where('student_id', $studentId) ->where('flag', $flagType) ->first(); if ($existingFlag) { // Update existing flag $updateData = [ 'flag_datetime' => $currentDateTime, 'updated_by_open' => $userId, ]; // Append description based on flag state if ($flagState === 'Closed') { $updateData['flag_state'] = 'Closed'; $existingCloseDesc = $existingFlag['close_description'] ?? ''; $updateData['close_description'] = $existingCloseDesc ? $existingCloseDesc . PHP_EOL . $stateDescription : $stateDescription; } elseif ($flagState === 'Canceled') { $updateData['flag_state'] = 'Canceled'; $existingCancelDesc = $existingFlag['cancel_description'] ?? ''; $updateData['cancel_description'] = $existingCancelDesc ? $existingCancelDesc . PHP_EOL . $stateDescription : $stateDescription; } else { $existingOpenDesc = $existingFlag['open_description'] ?? ''; $updateData['open_description'] = $existingOpenDesc ? $existingOpenDesc . PHP_EOL . $description : $description; } $this->currentFlag->update($existingFlag['id'], $updateData); $flag = $this->currentFlag->find($existingFlag['id']); return $this->success($flag, 'Flag updated successfully'); } else { // Create new flag $flagData = [ 'student_id' => $student['id'], 'student_name' => trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')), 'grade' => $grade, 'flag' => $flagType, 'flag_datetime' => $currentDateTime, 'flag_state' => 'Open', 'updated_by_open' => $userId, 'open_description' => $description, 'semester' => $semester, 'school_year' => $schoolYear, ]; $flag = $this->currentFlag->create($flagData); return $this->success($flag, 'New flag added successfully', Response::HTTP_CREATED); } } catch (\Throwable $e) { log_message('error', 'Add flag error: ' . $e->getMessage()); return $this->respondError('Failed to add flag', Response::HTTP_INTERNAL_SERVER_ERROR); } } public function updateState($id = null) { $flag = $this->currentFlag->find($id); if (!$flag) { return $this->respondError('Flag not found', Response::HTTP_NOT_FOUND); } $data = $this->payloadData(); if (empty($data)) { return $this->respondError('Invalid request data', Response::HTTP_BAD_REQUEST); } $newState = $data['flag_state'] ?? null; if (!$newState) { return $this->respondError('Flag state is required', Response::HTTP_BAD_REQUEST); } try { $updateData = ['flag_state' => $newState]; // Update appropriate description field based on state if (isset($data['state_description'])) { if ($newState === 'Closed') { $updateData['close_description'] = $data['state_description']; } elseif ($newState === 'Canceled') { $updateData['cancel_description'] = $data['state_description']; } else { $updateData['open_description'] = $data['state_description']; } } $this->currentFlag->update($id, $updateData); $flag = $this->currentFlag->find($id); return $this->success($flag, 'Flag state updated successfully'); } catch (\Throwable $e) { log_message('error', 'Update flag state error: ' . $e->getMessage()); return $this->respondError('Failed to update flag state', Response::HTTP_INTERNAL_SERVER_ERROR); } } public function close($id = null) { return $this->closeFlag($id); } public function cancel($id = null) { return $this->cancelFlag($id); } /** * Close a flag and move it to history */ public function closeFlag($flagId = null) { $flagId = $flagId ?? $this->request->getPost('id') ?? $this->request->getGet('id'); if (!$flagId) { return $this->respondError('Flag ID is required', Response::HTTP_BAD_REQUEST); } try { $user = $this->getCurrentUser(); $userId = $user->id ?? null; // Get the current flag data $flagData = $this->currentFlag->find($flagId); if (!$flagData) { return $this->respondError('Flag not found', Response::HTTP_NOT_FOUND); } // Check if flag is already closed if ($flagData['flag_state'] === 'Closed') { return $this->respondError('Flag is already closed', Response::HTTP_BAD_REQUEST); } // Get close description from request $data = $this->payloadData(); $closeDescription = $data['state_description'] ?? $data['close_description'] ?? null; if (empty($closeDescription)) { return $this->respondError('Close description is required', Response::HTTP_BAD_REQUEST); } // Update the flag state to Closed $this->currentFlag->update($flagId, [ 'flag_state' => 'Closed', 'updated_by_closed' => $userId, 'close_description' => $closeDescription, ]); // Retrieve updated flag data $flagData = $this->currentFlag->find($flagId); // Move to history return $this->moveToHistory($flagData); } catch (\Throwable $e) { log_message('error', 'Close flag error: ' . $e->getMessage()); return $this->respondError('Failed to close flag', Response::HTTP_INTERNAL_SERVER_ERROR); } } /** * Cancel a flag and move it to history */ public function cancelFlag($flagId = null) { $flagId = $flagId ?? $this->request->getPost('id') ?? $this->request->getGet('id'); if (!$flagId) { return $this->respondError('Flag ID is required', Response::HTTP_BAD_REQUEST); } try { $user = $this->getCurrentUser(); $userId = $user->id ?? null; // Get the current flag data $flagData = $this->currentFlag->find($flagId); if (!$flagData) { return $this->respondError('Flag not found', Response::HTTP_NOT_FOUND); } // Check if flag is already canceled if ($flagData['flag_state'] === 'Canceled') { return $this->respondError('Flag is already canceled', Response::HTTP_BAD_REQUEST); } // Get cancel description from request $data = $this->payloadData(); $cancelDescription = $data['state_description'] ?? $data['cancel_description'] ?? null; if (empty($cancelDescription)) { return $this->respondError('Cancel description is required', Response::HTTP_BAD_REQUEST); } // Update the flag state to Canceled $this->currentFlag->update($flagId, [ 'flag_state' => 'Canceled', 'updated_by_canceled' => $userId, 'cancel_description' => $cancelDescription, ]); // Retrieve updated flag data $flagData = $this->currentFlag->find($flagId); // Move to history return $this->moveToHistory($flagData); } catch (\Throwable $e) { log_message('error', 'Cancel flag error: ' . $e->getMessage()); return $this->respondError('Failed to cancel flag', Response::HTTP_INTERNAL_SERVER_ERROR); } } /** * Move flag to history table and delete from current_flag table */ protected function moveToHistory($flagData) { try { // Prepare data for the flag table $dataToInsert = [ 'student_id' => $flagData['student_id'] ?? null, 'student_name' => $flagData['student_name'] ?? null, 'grade' => $flagData['grade'] ?? null, 'flag' => $flagData['flag'] ?? null, 'flag_datetime' => $flagData['flag_datetime'] ?? null, 'flag_state' => $flagData['flag_state'] ?? null, 'updated_by_open' => $flagData['updated_by_open'] ?? null, 'open_description' => $flagData['open_description'] ?? null, 'updated_by_closed' => $flagData['updated_by_closed'] ?? null, 'close_description' => $flagData['close_description'] ?? null, 'updated_by_canceled' => $flagData['updated_by_canceled'] ?? null, 'cancel_description' => $flagData['cancel_description'] ?? null, 'semester' => $flagData['semester'] ?? null, 'school_year' => $flagData['school_year'] ?? null, 'created_at' => $flagData['created_at'] ?? date('Y-m-d H:i:s'), 'updated_at' => $flagData['updated_at'] ?? date('Y-m-d H:i:s'), ]; // Insert data into the flag table $this->flag->insert($dataToInsert); // Delete the entry from the current_flag table $this->currentFlag->delete($flagData['id']); return $this->success(['moved_to_history' => true], 'Flag has been moved to history'); } catch (\Throwable $e) { log_message('error', 'Move to history error: ' . $e->getMessage()); return $this->respondError('Failed to move flag to history', Response::HTTP_INTERNAL_SERVER_ERROR); } } public function getStudentsByGrade($gradeId = null) { try { $studentIds = $this->studentClass->newQuery() ->where('class_section_id', $gradeId) ->pluck('student_id') ->toArray(); if (empty($studentIds)) { return $this->success([], 'No students found for this grade'); } $students = $this->student->newQuery() ->whereIn('id', $studentIds) ->get() ->map(fn($student) => [ 'id' => $student->id, 'name' => trim(($student->firstname ?? '') . ' ' . ($student->lastname ?? '')), ]) ->values() ->toArray(); return $this->success($students, 'Students retrieved successfully'); } catch (\Throwable $e) { log_message('error', 'Get students by grade error: ' . $e->getMessage()); return $this->respondError('Failed to retrieve students', Response::HTTP_INTERNAL_SERVER_ERROR); } } }