fix enrollment logic, add financial aid, fix class distribution
Tests / PHPUnit (push) Failing after 1m6s
Tests / PHPUnit (push) Failing after 1m6s
This commit is contained in:
@@ -92,15 +92,6 @@ class ParentController extends BaseController
|
||||
$this->maxEmergency = (int) $this->configModel->getConfig('max_emergency') ?? 0;
|
||||
|
||||
helper(['url', 'form']);
|
||||
|
||||
if (!session()->get('is_logged_in')) {
|
||||
return redirect()->to('/login');
|
||||
}
|
||||
|
||||
// Add more role-specific checks if needed
|
||||
if (session()->get('role') !== 'parent') {
|
||||
return redirect()->to('/access_denied');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
@@ -252,9 +243,6 @@ class ParentController extends BaseController
|
||||
public function enrollClasses()
|
||||
{
|
||||
try {
|
||||
// Log session data for debugging
|
||||
log_message('info', 'Session Data: ' . print_r(session()->get(), true));
|
||||
|
||||
// Get deadlines and school year from config
|
||||
if (!$this->schoolYear) {
|
||||
log_message('error', 'Current school year not found in configuration.');
|
||||
@@ -373,7 +361,7 @@ class ParentController extends BaseController
|
||||
|
||||
if ($isEditable) {
|
||||
$student['transition_evaluation'] = $previousSchoolYear !== null
|
||||
? $this->transitionEvaluationForStudent((int) $studentId, $previousSchoolYear, $selectedYear)
|
||||
? $this->transitionEvaluationForStudent((int) $parentId, (int) $studentId, $previousSchoolYear, $selectedYear)
|
||||
: null;
|
||||
$student['enrollment_eligibility_message'] = $this->eligibilityMessageFromTransition(
|
||||
$student,
|
||||
@@ -382,11 +370,13 @@ class ParentController extends BaseController
|
||||
);
|
||||
$student['expected_placement_label'] = $this->expectedPlacementLabel($student['transition_evaluation']);
|
||||
$student['required_action_label'] = $this->requiredActionLabel($student['transition_evaluation']);
|
||||
$student['parent_enrollment_state'] = $this->parentEnrollmentState($student);
|
||||
} else {
|
||||
$student['transition_evaluation'] = $this->readonlyEnrollmentEvaluation($student['previous_year_decision']);
|
||||
$student['enrollment_eligibility_message'] = ['message' => '', 'blocking' => false, 'level' => 'info'];
|
||||
$student['expected_placement_label'] = (string) ($student['class_section'] ?? 'Class not Assigned');
|
||||
$student['required_action_label'] = 'Read-only closed school year.';
|
||||
$student['parent_enrollment_state'] = $this->parentEnrollmentState($student);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,8 +406,6 @@ class ParentController extends BaseController
|
||||
|
||||
public function enrollClassesHandler()
|
||||
{
|
||||
// Call enrollClasses() function at the start of this method
|
||||
$this->enrollClasses();
|
||||
$refundService = new FeeCalculationService();
|
||||
|
||||
// Retrieve enrollment and withdrawal data from the POST request
|
||||
@@ -460,25 +448,70 @@ class ParentController extends BaseController
|
||||
|
||||
if (!empty($enroll)) {
|
||||
$selectedYear = $this->currentSchoolYearName((string) ($this->schoolYear ?? ''));
|
||||
$blockingDecisionMessages = $this->blockedEnrollmentDecisionMessages(array_map('intval', (array) $enroll), $selectedYear);
|
||||
if ($blockingDecisionMessages !== []) {
|
||||
return redirect()->back()->withInput()->with('error', implode(' ', $blockingDecisionMessages));
|
||||
$previousSchoolYear = $this->previousSchoolYearName($selectedYear);
|
||||
if ($previousSchoolYear === null) {
|
||||
return redirect()->back()->withInput()->with('error', 'Enrollment cannot be submitted because the closing school year could not be determined.');
|
||||
}
|
||||
|
||||
$financialBlockers = $this->financialSubmissionBlockers((int) $parentId, $selectedYear);
|
||||
if ($financialBlockers !== []) {
|
||||
return redirect()->back()->withInput()->with('error', implode(' ', $financialBlockers));
|
||||
$parent = $this->userModel->find((int) $parentId);
|
||||
if (! is_array($parent) || ($parent['user_type'] ?? '') !== 'primary') {
|
||||
return redirect()->back()->withInput()->with('error', 'Only primary parents can enroll students.');
|
||||
}
|
||||
|
||||
$transitionService = service('enrollmentTransition');
|
||||
$submittedStudentIds = array_values(array_unique(array_filter(array_map('intval', (array) $enroll), static fn (int $id): bool => $id > 0)));
|
||||
$evaluations = [];
|
||||
$errors = [];
|
||||
|
||||
foreach ($submittedStudentIds as $studentId) {
|
||||
try {
|
||||
$evaluation = $transitionService->evaluateForParent((int) $parentId, $studentId, $previousSchoolYear, $selectedYear, 'parent');
|
||||
} catch (Throwable $e) {
|
||||
log_message('error', 'Parent enrollment eligibility evaluation failed for student {studentId}: {message}', [
|
||||
'studentId' => $studentId,
|
||||
'message' => $e->getMessage(),
|
||||
]);
|
||||
$errors[] = 'Student ID ' . $studentId . ': enrollment eligibility could not be evaluated. Please contact administration.';
|
||||
continue;
|
||||
}
|
||||
|
||||
$studentInfo = $this->studentModel->find($studentId);
|
||||
if (! is_array($studentInfo)) {
|
||||
$errors[] = 'Student ID ' . $studentId . ': student record was not found.';
|
||||
continue;
|
||||
}
|
||||
|
||||
$studentName = trim((string) ($studentInfo['firstname'] ?? '') . ' ' . (string) ($studentInfo['lastname'] ?? '')) ?: 'Student ID ' . $studentId;
|
||||
if (empty($evaluation['can_enroll'])) {
|
||||
$messages = array_values(array_filter(array_map('trim', array_map('strval', $evaluation['blockers'] ?? []))));
|
||||
$codes = array_values(array_filter(array_map('strval', array_merge($evaluation['blocking_rule_codes'] ?? [], $evaluation['review_rule_codes'] ?? []))));
|
||||
$errors[] = $studentName . ': ' . ($messages !== [] ? implode(' ', $messages) : 'Enrollment is not currently allowed' . ($codes !== [] ? ' (' . implode(', ', $codes) . ')' : '') . '.');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $this->studentModel->getStudentSchoolIdByStudentId($studentId)) {
|
||||
$errors[] = $studentName . ': Student school ID not found.';
|
||||
continue;
|
||||
}
|
||||
|
||||
$evaluations[$studentId] = $evaluation;
|
||||
}
|
||||
|
||||
if ($errors !== []) {
|
||||
return redirect()->back()->withInput()->with('error', implode(' ', $errors));
|
||||
}
|
||||
|
||||
$this->db->transStart();
|
||||
foreach ($enroll as $studentId) {
|
||||
$studentId = (int) $studentId;
|
||||
if (! isset($evaluations[$studentId])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$evaluation = $evaluations[$studentId];
|
||||
// Get student full name (supports both string return or array with firstname/lastname)
|
||||
$studentInfo = $this->studentModel->getFullNameById($studentId);
|
||||
|
||||
if (empty($studentName)) {
|
||||
$studentName = "Student ID $studentId";
|
||||
log_message('warning', "Name for student ID $studentId not found in students table.");
|
||||
}
|
||||
|
||||
// Save student info into $studentData
|
||||
$studentData[$studentId] = $studentInfo; // raw return from getFullName()
|
||||
|
||||
@@ -490,49 +523,57 @@ class ParentController extends BaseController
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
$studentSchoolId = $this->studentModel->getStudentSchoolIdByStudentId($studentId);
|
||||
if (!$studentSchoolId) {
|
||||
return redirect()->back()->with('error', "{$studentData[$studentId]['firstname']} {$studentData[$studentId]['lastname']}: Student school ID not found.");
|
||||
}
|
||||
$studentName = trim((string) ($studentData[$studentId]['firstname'] ?? '') . ' ' . (string) ($studentData[$studentId]['lastname'] ?? '')) ?: 'Student ID ' . $studentId;
|
||||
if ($existingEnrollment) {
|
||||
$isReturningReEnrollment = $this->isReturningReEnrollmentStudent((int)$studentId, $selectedYear);
|
||||
$targetEnrollmentStatus = $isReturningReEnrollment ? 'payment pending' : 'admission under review';
|
||||
$targetAdmissionStatus = $isReturningReEnrollment ? 'accepted' : 'pending';
|
||||
|
||||
$update = $this->enrollmentPayloadFromEvaluation($evaluation, [
|
||||
'is_withdrawn' => 0,
|
||||
'withdrawal_date' => null,
|
||||
'enrollment_status' => $targetEnrollmentStatus,
|
||||
'admission_status' => $targetAdmissionStatus,
|
||||
'updated_at' => utc_now(),
|
||||
]);
|
||||
|
||||
if ($existingEnrollment['is_withdrawn'] == 1) {
|
||||
// Reactivate the enrollment if the student was previously withdrawn
|
||||
$this->enrollmentModel->where('id', $existingEnrollment['id'])->update([
|
||||
'is_withdrawn' => 0,
|
||||
'withdrawal_date' => null,
|
||||
'enrollment_status' => $targetEnrollmentStatus,
|
||||
'admission_status' => $targetAdmissionStatus,
|
||||
'updated_at' => utc_now()
|
||||
]);
|
||||
$this->enrollmentModel->where('id', $existingEnrollment['id'])->update($update);
|
||||
log_message('info', "{$studentData[$studentId]['firstname']} {$studentData[$studentId]['lastname']} (ID $studentId) has been re-enrolled in enrollment ID {$existingEnrollment['id']}.");
|
||||
// Apply promotion-based class placement for the upcoming year
|
||||
$this->applyPromotionAssignment((int)$studentId, $selectedYear, $isReturningReEnrollment);
|
||||
} else {
|
||||
$currentStatus = (string) ($existingEnrollment['enrollment_status'] ?? '');
|
||||
$update = [
|
||||
'updated_at' => utc_now(),
|
||||
];
|
||||
if ($currentStatus === 'enrolled') {
|
||||
$update['admission_status'] = 'accepted';
|
||||
} else {
|
||||
$update['enrollment_status'] = $targetEnrollmentStatus;
|
||||
$update['admission_status'] = $targetAdmissionStatus;
|
||||
}
|
||||
$this->enrollmentModel->where('id', $existingEnrollment['id'])->update($update);
|
||||
log_message('info', "{$studentData[$studentId]['firstname']} {$studentData[$studentId]['lastname']} (ID $studentId) is already actively enrolled.");
|
||||
$this->applyPromotionAssignment((int)$studentId, $selectedYear, $isReturningReEnrollment);
|
||||
}
|
||||
|
||||
$enrollmentId = (int) $existingEnrollment['id'];
|
||||
if (! empty($evaluation['admin_exception']['id'])) {
|
||||
$transitionService->markExceptionUsed((int) $evaluation['admin_exception']['id'], $enrollmentId);
|
||||
}
|
||||
$transitionService->auditEnrollmentDecision(
|
||||
$studentId,
|
||||
$selectedYear,
|
||||
$previousSchoolYear,
|
||||
! empty($evaluation['admin_exception']) ? 'parent_enrollment_submitted_with_exception' : 'parent_enrollment_submitted',
|
||||
(int) $parentId,
|
||||
$existingEnrollment,
|
||||
$this->enrollmentAuditPayload($update, $evaluation),
|
||||
implode(' ', array_map('strval', $evaluation['rule_codes'] ?? []))
|
||||
);
|
||||
} else {
|
||||
$isReturningReEnrollment = $this->isReturningReEnrollmentStudent((int)$studentId, $selectedYear);
|
||||
$targetEnrollmentStatus = $isReturningReEnrollment ? 'payment pending' : 'admission under review';
|
||||
$targetAdmissionStatus = $isReturningReEnrollment ? 'accepted' : 'pending';
|
||||
|
||||
// If no enrollment record exists, insert a new enrollment record
|
||||
$result = $this->enrollmentModel->insert([
|
||||
$payload = $this->enrollmentPayloadFromEvaluation($evaluation, [
|
||||
'student_id' => $studentId,
|
||||
'parent_id' => $parentId,
|
||||
'school_year' => $selectedYear,
|
||||
@@ -543,16 +584,38 @@ class ParentController extends BaseController
|
||||
'admission_status' => $targetAdmissionStatus,
|
||||
'created_at' => utc_now()
|
||||
]);
|
||||
$result = $this->enrollmentModel->insert($payload, true);
|
||||
|
||||
if (!$result) {
|
||||
dd($this->enrollmentModel->errors());
|
||||
$this->db->transRollback();
|
||||
return redirect()->back()->withInput()->with('error', $studentName . ': Unable to save enrollment.');
|
||||
} else {
|
||||
log_message('info', "{$studentData[$studentId]['firstname']} {$studentData[$studentId]['lastname']} (ID $studentId) has been newly enrolled.");
|
||||
// Apply promotion-based class placement for the upcoming year
|
||||
$this->applyPromotionAssignment((int)$studentId, $selectedYear, $isReturningReEnrollment);
|
||||
}
|
||||
|
||||
$enrollmentId = (int) $result;
|
||||
if (! empty($evaluation['admin_exception']['id'])) {
|
||||
$transitionService->markExceptionUsed((int) $evaluation['admin_exception']['id'], $enrollmentId);
|
||||
}
|
||||
$transitionService->auditEnrollmentDecision(
|
||||
$studentId,
|
||||
$selectedYear,
|
||||
$previousSchoolYear,
|
||||
! empty($evaluation['admin_exception']) ? 'parent_enrollment_submitted_with_exception' : 'parent_enrollment_submitted',
|
||||
(int) $parentId,
|
||||
null,
|
||||
$this->enrollmentAuditPayload($payload, $evaluation),
|
||||
implode(' ', array_map('strval', $evaluation['rule_codes'] ?? []))
|
||||
);
|
||||
}
|
||||
}
|
||||
$this->db->transComplete();
|
||||
|
||||
if (! $this->db->transStatus()) {
|
||||
return redirect()->back()->withInput()->with('error', 'A database error occurred while submitting enrollment.');
|
||||
}
|
||||
}
|
||||
|
||||
// $studentData now holds info for all students processed
|
||||
@@ -652,6 +715,74 @@ class ParentController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
private function enrollmentPayloadFromEvaluation(array $evaluation, array $base): array
|
||||
{
|
||||
$payload = array_merge($base, [
|
||||
'source_school_year' => $evaluation['source_school_year'] ?? null,
|
||||
'deliberation_decision' => $evaluation['deliberation_decision'] ?? null,
|
||||
'source_grade_id' => $evaluation['source_grade_id'] ?? null,
|
||||
'assigned_grade_id' => $evaluation['assigned_grade_id'] ?? null,
|
||||
'source_class_section_id' => $evaluation['source_class_section_id'] ?? null,
|
||||
'assigned_class_section_id' => $evaluation['assigned_class_section_id'] ?? null,
|
||||
'class_section_id' => $evaluation['assigned_class_section_id'] ?? ($base['class_section_id'] ?? null),
|
||||
'placement_status' => $evaluation['placement_status'] ?? null,
|
||||
'age_reference_date' => $evaluation['age_reference_date'] ?? null,
|
||||
'age_on_reference_date' => $evaluation['age_on_reference_date'] ?? null,
|
||||
'adult_student' => ! empty($evaluation['adult_student']) ? 1 : 0,
|
||||
'parent_enrollment_allowed' => ! empty($evaluation['parent_enrollment_allowed']) ? 1 : 0,
|
||||
'student_self_enrollment_allowed' => ! empty($evaluation['student_self_enrollment_allowed']) ? 1 : 0,
|
||||
'exception_required' => ! empty($evaluation['admin_exception']) || ! empty($evaluation['flags']) ? 1 : 0,
|
||||
'exception_reason' => $this->exceptionReasonFromEvaluation($evaluation),
|
||||
'registration_submitted_at' => utc_now(),
|
||||
]);
|
||||
|
||||
return $this->filterEnrollmentPayloadByColumns($payload);
|
||||
}
|
||||
|
||||
private function exceptionReasonFromEvaluation(array $evaluation): ?string
|
||||
{
|
||||
if (! empty($evaluation['admin_exception'])) {
|
||||
return 'Admin exception: ' . (string) ($evaluation['admin_exception']['reason_code'] ?? 'approved');
|
||||
}
|
||||
|
||||
$codes = array_values(array_filter(array_map('strval', array_merge(
|
||||
$evaluation['blocking_rule_codes'] ?? [],
|
||||
$evaluation['review_rule_codes'] ?? [],
|
||||
$evaluation['warning_rule_codes'] ?? []
|
||||
))));
|
||||
|
||||
return $codes !== [] ? implode(', ', array_unique($codes)) : null;
|
||||
}
|
||||
|
||||
private function enrollmentAuditPayload(array $payload, array $evaluation): array
|
||||
{
|
||||
return [
|
||||
'enrollment' => $payload,
|
||||
'eligibility' => [
|
||||
'decision' => $evaluation['decision'] ?? null,
|
||||
'can_enroll' => ! empty($evaluation['can_enroll']),
|
||||
'rule_codes' => $evaluation['rule_codes'] ?? [],
|
||||
'blocking_rule_codes' => $evaluation['blocking_rule_codes'] ?? [],
|
||||
'review_rule_codes' => $evaluation['review_rule_codes'] ?? [],
|
||||
'warning_rule_codes' => $evaluation['warning_rule_codes'] ?? [],
|
||||
'admin_exception' => $evaluation['admin_exception'] ?? null,
|
||||
'financial_summary' => $evaluation['financial_summary'] ?? null,
|
||||
'last_name_exception_carry_forward' => $evaluation['last_name_exception_carry_forward'] ?? null,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function filterEnrollmentPayloadByColumns(array $payload): array
|
||||
{
|
||||
foreach (array_keys($payload) as $column) {
|
||||
if (! $this->db->fieldExists($column, 'enrollments')) {
|
||||
unset($payload[$column]);
|
||||
}
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
private function hasAcceptedPolicyForYear(int $parentId, string $schoolYear): bool
|
||||
{
|
||||
if ($parentId <= 0 || $schoolYear === '') {
|
||||
@@ -1243,7 +1374,8 @@ class ParentController extends BaseController
|
||||
|
||||
try {
|
||||
$studentName = $this->studentNameForEnrollmentMessage($studentId);
|
||||
$evaluation = service('enrollmentTransition')->evaluate($studentId, $previousSchoolYear, $targetSchoolYear, 'parent');
|
||||
$parentId = (int) session()->get('user_id');
|
||||
$evaluation = service('enrollmentTransition')->evaluateForParent($parentId, $studentId, $previousSchoolYear, $targetSchoolYear, 'parent');
|
||||
foreach ($evaluation['blockers'] ?? [] as $blocker) {
|
||||
$blocker = trim((string) $blocker);
|
||||
if ($blocker !== '') {
|
||||
@@ -1268,10 +1400,10 @@ class ParentController extends BaseController
|
||||
return EnrollmentEligibility::parentDecisionMessage($student, $decisionRow, $targetSchoolYear, $fallMakeupExamOn);
|
||||
}
|
||||
|
||||
private function transitionEvaluationForStudent(int $studentId, string $previousSchoolYear, string $selectedYear): ?array
|
||||
private function transitionEvaluationForStudent(int $parentId, int $studentId, string $previousSchoolYear, string $selectedYear): ?array
|
||||
{
|
||||
try {
|
||||
return service('enrollmentTransition')->evaluate($studentId, $previousSchoolYear, $selectedYear, 'parent');
|
||||
return service('enrollmentTransition')->evaluateForParent($parentId, $studentId, $previousSchoolYear, $selectedYear, 'parent');
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'Enrollment transition evaluation failed for student ' . $studentId . ': ' . $e->getMessage());
|
||||
|
||||
@@ -1317,6 +1449,14 @@ class ParentController extends BaseController
|
||||
);
|
||||
}
|
||||
|
||||
if (! empty($evaluation['can_enroll']) && ! empty($evaluation['admin_exception'])) {
|
||||
return [
|
||||
'message' => 'Enrollment has been authorized by administration.',
|
||||
'blocking' => false,
|
||||
'level' => 'info',
|
||||
];
|
||||
}
|
||||
|
||||
$blockers = array_values(array_filter(array_map('trim', array_map('strval', $evaluation['blockers'] ?? []))));
|
||||
if ($blockers !== []) {
|
||||
$name = $this->studentNameFromRow($student);
|
||||
@@ -1409,31 +1549,80 @@ class ParentController extends BaseController
|
||||
private function requiredActionLabel(?array $evaluation): string
|
||||
{
|
||||
if ($evaluation === null) {
|
||||
return 'Complete re-enrollment before the registration deadline.';
|
||||
return 'Contact administration';
|
||||
}
|
||||
|
||||
if (($evaluation['blockers'] ?? []) !== []) {
|
||||
if (($evaluation['adult_student'] ?? false) && ! ($evaluation['parent_enrollment_allowed'] ?? false)) {
|
||||
return 'Student must complete the authorized adult-student process or contact administration.';
|
||||
$state = $this->parentEnrollmentStateFromEvaluation($evaluation, null);
|
||||
return match ($state) {
|
||||
'Enroll' => 'Complete re-enrollment before the registration deadline.',
|
||||
'Eligible with follow-up' => 'Complete re-enrollment and follow the listed next step.',
|
||||
'Already submitted' => 'Already submitted',
|
||||
'Action needed' => 'Action needed: pay the previous-year balance or contact administration.',
|
||||
'Under review' => 'Under review. Contact the school administration.',
|
||||
default => 'Contact administration',
|
||||
};
|
||||
}
|
||||
|
||||
private function parentEnrollmentState(array $student): string
|
||||
{
|
||||
$status = strtolower(trim((string) ($student['enrollment_status'] ?? '')));
|
||||
if (in_array($status, [
|
||||
'admission under review',
|
||||
'review & decision',
|
||||
'payment pending',
|
||||
'enrolled',
|
||||
'waitlist',
|
||||
'withdraw under review',
|
||||
], true)) {
|
||||
return 'Already submitted';
|
||||
}
|
||||
|
||||
return $this->parentEnrollmentStateFromEvaluation(
|
||||
is_array($student['transition_evaluation'] ?? null) ? $student['transition_evaluation'] : null,
|
||||
$status
|
||||
);
|
||||
}
|
||||
|
||||
private function parentEnrollmentStateFromEvaluation(?array $evaluation, ?string $enrollmentStatus): string
|
||||
{
|
||||
if ($evaluation === null) {
|
||||
return 'Contact administration';
|
||||
}
|
||||
|
||||
$decision = (string) ($evaluation['decision'] ?? '');
|
||||
$codes = array_map('strval', $evaluation['blocking_rule_codes'] ?? []);
|
||||
|
||||
if ($decision === 'ALREADY_ENROLLED' || $enrollmentStatus === 'already enrolled') {
|
||||
return 'Already submitted';
|
||||
}
|
||||
|
||||
if (! empty($evaluation['can_enroll']) || $decision === 'EXCEPTION_ELIGIBLE' || $decision === 'ELIGIBLE') {
|
||||
if ($decision === 'ELIGIBLE_WITH_WARNING' || ($evaluation['warning_rule_codes'] ?? []) !== []) {
|
||||
return 'Eligible with follow-up';
|
||||
}
|
||||
|
||||
$decision = (string) ($evaluation['deliberation_decision'] ?? '');
|
||||
if (in_array($decision, [
|
||||
DeliberationDecision::EXPELLED,
|
||||
DeliberationDecision::WITHDRAWN,
|
||||
DeliberationDecision::DEFERRED_DECISION,
|
||||
], true)) {
|
||||
return 'Contact the school administration.';
|
||||
}
|
||||
|
||||
return 'Review the eligibility message above.';
|
||||
return 'Enroll';
|
||||
}
|
||||
|
||||
if (($evaluation['deliberation_decision'] ?? '') === DeliberationDecision::MAKE_UP_EXAM) {
|
||||
return 'Complete re-enrollment and follow make-up exam instructions.';
|
||||
if ($decision === 'ELIGIBLE_WITH_WARNING') {
|
||||
return 'Eligible with follow-up';
|
||||
}
|
||||
|
||||
return 'Complete re-enrollment before the registration deadline.';
|
||||
if (in_array('OUTSTANDING_BALANCE_BLOCKED', $codes, true)
|
||||
|| in_array('FINANCE_APPROVAL_REQUIRED', $codes, true)
|
||||
|| in_array('SIBLING_LAST_NAME_MISMATCH', $codes, true)
|
||||
) {
|
||||
return 'Action needed';
|
||||
}
|
||||
|
||||
if ($decision === 'REVIEW_REQUIRED' || in_array((string) ($evaluation['deliberation_decision'] ?? ''), [
|
||||
DeliberationDecision::EXPELLED,
|
||||
DeliberationDecision::WITHDRAWN,
|
||||
DeliberationDecision::DEFERRED_DECISION,
|
||||
], true)) {
|
||||
return 'Under review';
|
||||
}
|
||||
|
||||
return 'Contact administration';
|
||||
}
|
||||
|
||||
private function familyFinancialSummary(int $parentId, ?string $previousSchoolYear, string $selectedYear): array
|
||||
@@ -1444,7 +1633,7 @@ class ParentController extends BaseController
|
||||
$registrationFee = round((float) ($schoolYearConfig['registration_fee'] ?? 0), 2);
|
||||
$tuitionDue = round((float) ($schoolYearConfig['tuition_due_at_registration'] ?? 0), 2);
|
||||
$mandatoryFees = round((float) ($schoolYearConfig['mandatory_fees'] ?? 0), 2);
|
||||
$behavior = (string) ($schoolYearConfig['carry_over_balance_behavior'] ?? 'information_only');
|
||||
$behavior = (string) ($schoolYearConfig['carry_over_balance_behavior'] ?? 'submission_blocked_until_payment');
|
||||
$amountDue = max(0.0, $carryOver) + $registrationFee + $tuitionDue + $mandatoryFees;
|
||||
|
||||
return [
|
||||
@@ -1461,21 +1650,6 @@ class ParentController extends BaseController
|
||||
];
|
||||
}
|
||||
|
||||
private function financialSubmissionBlockers(int $parentId, string $selectedYear): array
|
||||
{
|
||||
$previousSchoolYear = $this->previousSchoolYearName($selectedYear);
|
||||
$summary = $this->familyFinancialSummary($parentId, $previousSchoolYear, $selectedYear);
|
||||
if (($summary['carry_over_balance'] ?? 0.0) <= 0.0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return match ((string) ($summary['balance_behavior'] ?? 'information_only')) {
|
||||
'submission_blocked_until_payment' => ['Registration cannot be submitted until the previous-year balance is paid.'],
|
||||
'admin_approval_required' => ['Registration requires administrative financial approval because there is a previous-year balance.'],
|
||||
default => [],
|
||||
};
|
||||
}
|
||||
|
||||
private function financialPolicyMessage(string $behavior, string $configured): string
|
||||
{
|
||||
$configured = trim($configured);
|
||||
@@ -1488,7 +1662,7 @@ class ParentController extends BaseController
|
||||
'submission_allowed_confirmation_blocked' => 'Registration may be submitted, but it will not be confirmed until the balance is settled.',
|
||||
'submission_blocked_until_payment' => 'The balance must be paid before registration can be submitted.',
|
||||
'admin_approval_required' => 'Please contact the finance office to arrange an approved exception.',
|
||||
default => 'The balance is shown for information and does not currently block registration.',
|
||||
default => 'The previous-year balance must be paid before registration can be submitted.',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1784,6 +1958,10 @@ class ParentController extends BaseController
|
||||
|
||||
public function profile($id)
|
||||
{
|
||||
if (! $this->canAccessUserRecord((int) $id)) {
|
||||
return redirect()->to('/access_denied');
|
||||
}
|
||||
|
||||
// Fetch the user's data based on the given ID
|
||||
$user = $this->userModel->find($id);
|
||||
|
||||
@@ -1798,6 +1976,10 @@ class ParentController extends BaseController
|
||||
|
||||
public function updateProfile($id)
|
||||
{
|
||||
if (! $this->canAccessUserRecord((int) $id)) {
|
||||
return redirect()->to('/access_denied');
|
||||
}
|
||||
|
||||
$user = $this->userModel->find($id);
|
||||
|
||||
// Step 1: Check if user exists
|
||||
@@ -2937,4 +3119,22 @@ $existing = $this->studentModel
|
||||
|
||||
return redirect()->back()->with('success', 'Participation updated');
|
||||
}
|
||||
|
||||
private function canAccessUserRecord(int $id): bool
|
||||
{
|
||||
$userId = (int) (session()->get('user_id') ?? 0);
|
||||
if ($userId <= 0 || $id <= 0) {
|
||||
return false;
|
||||
}
|
||||
if ($userId === $id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$roles = array_map(
|
||||
static fn ($role): string => strtolower(trim((string) $role)),
|
||||
array_filter(array_merge((array) session()->get('roles'), [session()->get('role')]))
|
||||
);
|
||||
|
||||
return (bool) array_intersect($roles, ['administrator', 'administrative staff', 'principal', 'admin']);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user