fix is_new issue with enrollment fixes
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 48s
Tests / PHPUnit (push) Failing after 1m22s

This commit is contained in:
root
2026-08-20 19:57:25 -04:00
parent 127098b87c
commit 889c037660
29 changed files with 77306 additions and 293 deletions
+212 -15
View File
@@ -83,7 +83,8 @@ class ParentController extends BaseController
$this->ageDateRefernce = $this->configModel->getConfig('date_age_reference');
$this->lastDayOfRegistration = $this->configModel->getConfig('enrollment_deadline');
$this->schoolStartDate = $this->configModel->getConfig('fall_semester_start');
$this->schoolStartDate = $this->configModel->getConfig('first_day_of_school')
?: $this->configModel->getConfig('fall_semester_start');
$this->withdrawalDeadline = $this->configModel->getConfig('refund_deadline');
$this->schoolYear = $this->configModel->getConfig('school_year');
$this->semester = getSemester();
@@ -263,7 +264,7 @@ class ParentController extends BaseController
// Verify user type is "parent" from the `users` table
$userData = $this->db->table('users')
->select('user_type, accept_school_policy')
->select('user_type, accept_school_policy, firstname, lastname, cellphone, address_street, apt, city, state, zip')
->where('id', $parentId)
->get()
->getRowArray();
@@ -385,6 +386,30 @@ class ParentController extends BaseController
$student['parent_enrollment_state'] = $this->parentEnrollmentState($student);
}
}
unset($student);
service('studentYearStatus')->attachToStudents($students, $selectedYear);
foreach ($students as &$student) {
$studentId = (int) ($student['id'] ?? 0);
if ($studentId > 0 && $this->isReturningReEnrollmentStudent($studentId, $selectedYear)) {
$student['is_new'] = 0;
}
}
unset($student);
$enrollmentStartStep = (int) $this->request->getGet('start');
if ($enrollmentStartStep < 1 || $enrollmentStartStep > 5) {
$enrollmentStartStep = 0;
}
$preselectedStudentIds = [];
$studentsParam = trim((string) $this->request->getGet('students'));
if ($studentsParam !== '') {
$preselectedStudentIds = array_values(array_unique(array_filter(
array_map('intval', explode(',', $studentsParam)),
static fn (int $id): bool => $id > 0
)));
}
// Render view
return view('/parent/enroll_classes', [
@@ -399,6 +424,9 @@ class ParentController extends BaseController
'hasAcceptedSchoolPolicy' => $this->hasAcceptedPolicyForYear((int) $parentId, $selectedYear),
'familyFinancialSummary' => $this->familyFinancialSummary((int) $parentId, $previousSchoolYear, $selectedYear, $students),
'enrollmentFeeSchedule' => $this->enrollmentFeeSchedule($selectedYear),
'parentContact' => $this->parentContactForEnrollment($userData),
'enrollmentStartStep' => $enrollmentStartStep,
'preselectedStudentIds' => $preselectedStudentIds,
]);
} catch (Exception $e) {
log_message('error', 'An error occurred in enrollClasses: ' . $e->getMessage());
@@ -452,6 +480,7 @@ class ParentController extends BaseController
// Handle enrollments
$studentData = [];
$enrollmentResultMessages = [];
if (!empty($enroll)) {
$selectedYear = $this->currentSchoolYearName((string) ($this->schoolYear ?? ''));
@@ -476,6 +505,11 @@ class ParentController extends BaseController
return redirect()->back()->withInput()->with('error', implode(' ', $studentInfoErrors));
}
$parentContactErrors = $this->updateEnrollmentParentContact((int) $parentId);
if ($parentContactErrors !== []) {
return redirect()->back()->withInput()->with('error', implode(' ', $parentContactErrors));
}
foreach ($submittedStudentIds as $studentId) {
try {
$evaluation = $transitionService->evaluateForParent((int) $parentId, $studentId, $previousSchoolYear, $selectedYear, 'parent');
@@ -539,12 +573,13 @@ class ParentController extends BaseController
$studentName = trim((string) ($studentData[$studentId]['firstname'] ?? '') . ' ' . (string) ($studentData[$studentId]['lastname'] ?? '')) ?: 'Student ID ' . $studentId;
$isReturningReEnrollment = $this->isReturningReEnrollmentStudent((int)$studentId, $selectedYear);
$submittedEnrollmentContexts[$studentId] = $isReturningReEnrollment ? 're_enrollment' : 'first_enrollment';
$isNewForSelectedYear = ! $isReturningReEnrollment
&& service('studentYearStatus')->isNew($studentId, $selectedYear);
$submittedEnrollmentContexts[$studentId] = $isNewForSelectedYear ? 'first_enrollment' : 're_enrollment';
$targetEnrollmentStatus = $isNewForSelectedYear ? 'admission under review' : 'payment pending';
$targetAdmissionStatus = $isNewForSelectedYear ? 'pending' : 'accepted';
if ($existingEnrollment) {
$targetEnrollmentStatus = $isReturningReEnrollment ? 'payment pending' : 'admission under review';
$targetAdmissionStatus = $isReturningReEnrollment ? 'accepted' : 'pending';
$update = $this->enrollmentPayloadFromEvaluation($evaluation, [
'is_withdrawn' => 0,
'withdrawal_date' => null,
@@ -595,10 +630,8 @@ class ParentController extends BaseController
$this->enrollmentAuditPayload($update, $evaluation),
implode(' ', array_map('strval', $evaluation['rule_codes'] ?? []))
);
$enrollmentResultMessages[] = $studentName . ': ' . $targetEnrollmentStatus;
} else {
$targetEnrollmentStatus = $isReturningReEnrollment ? 'payment pending' : 'admission under review';
$targetAdmissionStatus = $isReturningReEnrollment ? 'accepted' : 'pending';
// If no enrollment record exists, insert a new enrollment record
$payload = $this->enrollmentPayloadFromEvaluation($evaluation, [
'student_id' => $studentId,
@@ -636,6 +669,7 @@ class ParentController extends BaseController
$this->enrollmentAuditPayload($payload, $evaluation),
implode(' ', array_map('strval', $evaluation['rule_codes'] ?? []))
);
$enrollmentResultMessages[] = $studentName . ': ' . $targetEnrollmentStatus;
}
}
$this->db->transComplete();
@@ -649,8 +683,11 @@ class ParentController extends BaseController
// $studentData now holds info for all students processed
// Handle withdrawals
$withdrawalResultMessages = [];
$withdrawalErrors = [];
if (!empty($withdraw)) {
foreach ($withdraw as $studentId) {
$studentId = (int) $studentId;
$enrollment = $this->enrollmentModel
->where('student_id', $studentId)
->where('school_year', $this->schoolYear)
@@ -673,6 +710,7 @@ class ParentController extends BaseController
'updated_at' => utc_now()
], (int) $parentId, 'parent_withdrawal_requested');
log_message('info', "Student ID $studentId has been withdrawn from enrollment ID {$enrollment['id']}.");
$withdrawalResultMessages[] = 'Student ID ' . $studentId . ': withdraw under review';
// === Trigger refund process ===
// Find the related invoice (you may need to adjust this based on your DB structure)
@@ -752,6 +790,7 @@ class ParentController extends BaseController
}
} else {
log_message('error', "No active enrollment found for student ID $studentId.");
$withdrawalErrors[] = 'Student ID ' . $studentId . ': no active enrollment was found.';
}
}
}
@@ -761,13 +800,32 @@ class ParentController extends BaseController
// Redirect to the success page after processing enrollment and withdrawal
if (!empty($withdraw)) {
// Redirect to withdrawal success page if there are withdrawals //parent/enroll_classes
return redirect()->to('/parent/enroll_classes');
$redirect = redirect()->to('/parent/enroll_classes');
if ($withdrawalResultMessages !== []) {
$redirect = $redirect->with('success', 'Withdrawal request submitted. ' . implode(' ', $withdrawalResultMessages));
}
if ($withdrawalErrors !== []) {
$redirect = $redirect->with('error', 'Some withdrawal requests failed. ' . implode(' ', $withdrawalErrors));
}
return $redirect;
} else {
// Redirect to enrollment success page if there are enrollments
$contextValues = array_values(array_unique($submittedEnrollmentContexts ?? []));
$parentData['enrollment_context'] = count($contextValues) === 1 ? $contextValues[0] : 'mixed';
Events::trigger('admissionUnderReview', $parentData, $studentData); //send notification for enrolled student
return redirect()->to('/parent/enroll_classes');
try {
Events::trigger('admissionUnderReview', $parentData, $studentData);
} catch (Throwable $e) {
log_message('error', 'Enrollment notification failed after successful submission: {message}', [
'message' => $e->getMessage(),
]);
}
$successMessage = 'Enrollment submitted successfully.';
if ($enrollmentResultMessages !== []) {
$successMessage .= ' ' . implode(' ', $enrollmentResultMessages);
}
return redirect()->to('/parent/enroll_success')->with('success', $successMessage);
}
}
@@ -887,6 +945,107 @@ class ParentController extends BaseController
return $errors;
}
/**
* @param array<string, mixed> $user
* @return array<string, string>
*/
private function parentContactForEnrollment(array $user): array
{
$posted = old('parent_contact');
$posted = is_array($posted) ? $posted : [];
$phoneDigits = preg_replace('/\D/', '', (string) ($posted['cellphone'] ?? $user['cellphone'] ?? '')) ?? '';
$phoneDisplay = strlen($phoneDigits) === 10
? substr($phoneDigits, 0, 3) . '-' . substr($phoneDigits, 3, 3) . '-' . substr($phoneDigits, 6)
: trim((string) ($posted['cellphone'] ?? $user['cellphone'] ?? ''));
return [
'firstname' => trim((string) ($user['firstname'] ?? '')),
'lastname' => trim((string) ($user['lastname'] ?? '')),
'cellphone' => $phoneDisplay,
'address_street' => trim((string) ($posted['address_street'] ?? $user['address_street'] ?? '')),
'apt' => trim((string) ($posted['apt'] ?? $user['apt'] ?? '')),
'city' => trim((string) ($posted['city'] ?? $user['city'] ?? '')),
'state' => strtoupper(trim((string) ($posted['state'] ?? $user['state'] ?? ''))),
'zip' => trim((string) ($posted['zip'] ?? $user['zip'] ?? '')),
];
}
/**
* @return list<string>
*/
private function updateEnrollmentParentContact(int $parentId): array
{
$fields = $this->request->getPost('parent_contact');
$normalized = $this->normalizeEnrollmentParentContact(is_array($fields) ? $fields : []);
if ($normalized['errors'] !== []) {
return $normalized['errors'];
}
if (! $this->userModel->update($parentId, $normalized['data'])) {
return ['Parent contact information could not be updated.'];
}
return [];
}
/**
* @param array<string, mixed> $fields
* @return array{errors: list<string>, data: array<string, string>}
*/
private function normalizeEnrollmentParentContact(array $fields): array
{
$phoneDigits = preg_replace('/\D/', '', (string) ($fields['cellphone'] ?? '')) ?? '';
$street = trim((string) ($fields['address_street'] ?? ''));
$apt = trim((string) ($fields['apt'] ?? ''));
$city = trim((string) ($fields['city'] ?? ''));
$state = strtoupper(trim((string) ($fields['state'] ?? '')));
$zip = trim((string) ($fields['zip'] ?? ''));
$errors = [];
if (strlen($phoneDigits) !== 10) {
$errors[] = 'A valid 10-digit home/cell phone number is required.';
}
if (strlen($street) < 5 || strlen($street) > 255) {
$errors[] = 'Home street address is required.';
}
if ($apt !== '' && strlen($apt) > 15) {
$errors[] = 'Apartment or unit must be 15 characters or fewer.';
}
if (strlen($city) < 2 || strlen($city) > 100) {
$errors[] = 'City is required.';
}
if (! preg_match('/^[A-Z]{2}$/', $state)) {
$errors[] = 'State is required.';
}
if (! preg_match('/^\d{5}$/', $zip)) {
$errors[] = 'A valid 5-digit ZIP code is required.';
}
if ($errors !== []) {
return ['errors' => $errors, 'data' => []];
}
$formattedPhone = (new PhoneFormatterService())->formatPhoneNumber($phoneDigits);
return [
'errors' => [],
'data' => [
'cellphone' => $formattedPhone ?: $phoneDigits,
'address_street' => $street,
'apt' => $apt,
'city' => ucfirst(strtolower($city)),
'state' => $state,
'zip' => $zip,
'updated_at' => utc_now(),
],
];
}
/**
* @param mixed $selected
* @return list<string>
@@ -1968,6 +2127,11 @@ class ParentController extends BaseController
return ((int) $matches[1] - 1) . '-' . ((int) $matches[2] - 1);
}
public function enrollSuccess()
{
return view('/parent/enroll_success');
}
public function enrollFailure()
{
echo view('/parent/enroll_failure');
@@ -2446,6 +2610,7 @@ class ParentController extends BaseController
$this->db->transStart();
$studentAdded = false;
$registeredStudentIds = [];
// Gather all POST data for last year flags
$rawPost = $this->request->getPost();
@@ -2472,6 +2637,9 @@ class ParentController extends BaseController
if ($result) {
$studentAdded = true;
if (is_numeric($result) && (int) $result > 0) {
$registeredStudentIds[] = (int) $result;
}
}
}
}
@@ -2492,6 +2660,16 @@ class ParentController extends BaseController
throw new \Exception('DB transaction failed.');
}
if ($studentAdded) {
$enrollmentQuery = ['start' => 2];
if ($registeredStudentIds !== []) {
$enrollmentQuery['students'] = implode(',', array_values(array_unique($registeredStudentIds)));
}
return redirect()->to(base_url('/parent/enroll_classes?' . http_build_query($enrollmentQuery)))
->with('success', 'Registration successful! Continue enrollment by confirming your home address and phone number.');
}
return redirect()->to(base_url('/parent/child_register'))->with('success', 'Registration successful!');
} catch (\Throwable $e) {
log_message('error', $e->getMessage());
@@ -2564,8 +2742,15 @@ class ParentController extends BaseController
->findColumn('condition_name') ?? [];
$kid['enrollment'] = isset($enrollmentMap[$studentId]['id']) && !empty($enrollmentMap[$studentId]['id']) ? 1 : 0;
}
unset($kid);
service('studentYearStatus')->attachToStudents($kids, $selectedSchoolYear);
foreach ($kids as &$kid) {
$kid['can_delete'] = $this->canParentDeleteStudent($kid, $parentId);
}
unset($kid);
$emergencies = $this->emergencyContactModel->where('parent_id', $parentId)->findAll();
@@ -2693,6 +2878,10 @@ $existing = $this->studentModel
}
}
if (! is_null($isNew) && (int) $studentId > 0) {
service('studentYearStatus')->upsert((int) $studentId, (string) $schoolYear, (bool) $isNew);
}
// ---------- SAVE MEDICAL CONDITIONS ----------
$this->medicalConditionModel->where('student_id', $studentId)->delete();
foreach ((array) $conditions as $c) {
@@ -2710,14 +2899,14 @@ $existing = $this->studentModel
foreach ((array) $allergies as $a) {
$a = trim($a);
if ($a !== '') {
$this->allergyModel->insert([
$this->allergyModel->insert([
'student_id' => $studentId,
'allergy' => $a,
]);
}
}
return true;
return (int) $studentId > 0 ? (int) $studentId : true;
}
@@ -3099,7 +3288,15 @@ $existing = $this->studentModel
return false;
}
if ((string) ($student['is_new'] ?? '1') === '0') {
$statusYear = trim((string) ($student['school_year'] ?? ''));
if ($statusYear === '') {
$statusYear = (string) (service('studentYearStatus')->activeSchoolYear() ?? '');
}
$isNew = $statusYear !== ''
? service('studentYearStatus')->isNew($studentId, $statusYear)
: ((string) ($student['is_new'] ?? '1') === '1');
if (! $isNew) {
return false;
}