fix enrollment and email send to parent
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 49s
Tests / PHPUnit (push) Failing after 1m20s

This commit is contained in:
root
2026-08-27 12:39:08 -04:00
parent 7b86cf5218
commit 0ae9993d82
19 changed files with 37831 additions and 1313 deletions
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
+66 -1
View File
@@ -514,6 +514,8 @@ class DiscountController extends BaseController
$affected = count($rowsToUpdate);
$db->transCommit();
$this->triggerStudentEnrolledNotification($parentId, $rowsToUpdate);
log_message(
'info',
'Enrollment status -> enrolled for {n} row(s). parent={p}, year={y}, sem={s}, ids=[{ids}]',
@@ -534,10 +536,60 @@ class DiscountController extends BaseController
}
}
private function triggerStudentEnrolledNotification(int $parentId, array $enrollmentRows): void
{
if ($parentId <= 0 || $enrollmentRows === []) {
return;
}
try {
$parent = $this->userModel->find($parentId) ?? [];
$studentIds = array_values(array_unique(array_filter(
array_map(static fn (array $row): int => (int) ($row['student_id'] ?? 0), $enrollmentRows),
static fn (int $studentId): bool => $studentId > 0
)));
if ($studentIds === []) {
return;
}
$students = [];
foreach ($this->db->table('students')->whereIn('id', $studentIds)->get()->getResultArray() as $student) {
$studentId = (int) ($student['id'] ?? 0);
if ($studentId <= 0) {
continue;
}
$students[] = [
'student_id' => $studentId,
'name' => trim((string) ($student['firstname'] ?? '') . ' ' . (string) ($student['lastname'] ?? '')) ?: 'Student #' . $studentId,
];
}
if ($students === []) {
return;
}
Events::trigger('studentEnrolled', [
'user_id' => $parent['id'] ?? $parentId,
'email' => $parent['email'] ?? null,
'firstname' => $parent['firstname'] ?? '',
'lastname' => $parent['lastname'] ?? '',
'school_year' => (string) $this->schoolYear,
'portalLink' => base_url('/login'),
], $students);
} catch (\Throwable $e) {
log_message('error', 'Enrollment confirmation notification after discount failed for parent {parent_id}: {error}', [
'parent_id' => $parentId,
'error' => $e->getMessage(),
]);
}
}
public function listVouchers()
{
$this->schoolYear = $this->activeSchoolYearName();
$this->schoolYear = $this->currentSchoolYearName();
$vouchers = $this->voucherModel
->where('school_year', $this->schoolYear)
@@ -684,6 +736,19 @@ class DiscountController extends BaseController
}
}
protected function currentSchoolYearName(?string $fallback = null): string
{
try {
return service('schoolYearContext')->resolve($this->request)->yearName();
} catch (\Throwable) {
if ($fallback !== null && $fallback !== '') {
return $fallback;
}
return (string) ($this->configModel->getConfig('school_year') ?? '');
}
}
/**
* 🔄 Helper: Current invoice balance (school-year scoped) = total - payments - discounts - refundsPaid
*/
+28 -11
View File
@@ -2010,8 +2010,14 @@ class ParentController extends BaseController
private function enrollmentTuitionDue(array $students): float
{
$tuitionStudents = [];
$existingTuitionStudentCount = 0;
foreach ($students as $student) {
if ($this->countsTowardCurrentYearTuition($student)) {
$existingTuitionStudentCount++;
continue;
}
$evaluation = is_array($student['transition_evaluation'] ?? null) ? $student['transition_evaluation'] : [];
if (
($evaluation['can_enroll'] ?? false) !== true
@@ -2034,9 +2040,29 @@ class ParentController extends BaseController
return 0.0;
}
if ($existingTuitionStudentCount > 0) {
$additionalStudentFee = (float) ($this->configModel->getConfig('second_student_fee') ?? 280);
return round(count($tuitionStudents) * $additionalStudentFee, 2);
}
return (new FeeCalculationService())->calculateEnrollmentTuition($tuitionStudents);
}
private function countsTowardCurrentYearTuition(array $student): bool
{
$status = strtolower(trim((string) ($student['enrollment_status'] ?? '')));
if (in_array($status, ['withdrawn', 'withdraw under review', 'refund pending', 'denied', 'not enrolled'], true)) {
return false;
}
if (in_array($status, ['admission under review', 'review & decision', 'payment pending', 'enrolled', 'waitlist'], true)) {
return true;
}
return strtolower(trim((string) ($student['admission_status'] ?? ''))) === 'accepted';
}
private function enrollmentFeeSchedule(string $selectedYear): array
{
$schoolYearConfig = $this->schoolYearConfig($selectedYear);
@@ -2673,7 +2699,6 @@ class ParentController extends BaseController
$this->db->transStart();
$studentAdded = false;
$registeredStudentIds = [];
// Gather all POST data for last year flags
$rawPost = $this->request->getPost();
@@ -2700,9 +2725,6 @@ class ParentController extends BaseController
if ($result) {
$studentAdded = true;
if (is_numeric($result) && (int) $result > 0) {
$registeredStudentIds[] = (int) $result;
}
}
}
}
@@ -2724,13 +2746,8 @@ class ParentController extends BaseController
}
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/enroll_classes?' . http_build_query(['start' => 1])))
->with('success', 'Registration successful! Continue enrollment by selecting all students you want to enroll.');
}
return redirect()->to(base_url('/parent/child_register'))->with('success', 'Registration successful!');
+1 -1
View File
@@ -332,7 +332,7 @@ class PaymentController extends ResourceController
// Read the search term (email or phone)
$searchTerm = trim((string) $this->request->getGet('search_term'));
$manualPaySchoolYear = $this->activeSchoolYearName();
$manualPaySchoolYear = $this->currentSchoolYearName();
// --- Installment end date comes ONLY from config ---
$installmentDateRaw = (string) ($this->installmentDate ?? '');
+155 -38
View File
@@ -14,6 +14,7 @@ use App\Models\StudentSectionDistributionDraftModel;
use App\Models\StudentAllergyModel;
use App\Models\StudentMedicalConditionModel;
use App\Support\Enrollment\DeliberationDecision;
use CodeIgniter\Events\Events;
use CodeIgniter\Database\Exceptions\DataException;
use Throwable;
@@ -129,11 +130,21 @@ class StudentController extends BaseController
$existing = $this->studentClassModel
->where('student_id', $studentId)
->where('school_year', (string)$this->schoolYear)
->orderBy('id', 'DESC')
->findAll();
$existingBySection = [];
$scPk = 'id';
foreach ($existing as $row) {
$existingBySection[(int)($row['class_section_id'] ?? 0)] = $row;
$rowEventFlag = (int)($row['is_event_only'] ?? 0);
if ($rowEventFlag !== $isEventOnly) {
continue;
}
$sectionKey = (int)($row['class_section_id'] ?? 0);
if ($sectionKey > 0 && !isset($existingBySection[$sectionKey])) {
$existingBySection[$sectionKey] = $row;
}
}
$displayNames = [];
@@ -184,8 +195,6 @@ class StudentController extends BaseController
try {
// Upsert student_class entries per selection
$scPk = $this->studentClassModel->primaryKey ?? 'id';
foreach ($classSectionIds as $cid) {
$eventFlag = $isEventOnly ? 1 : 0;
if (isset($existingBySection[$cid])) {
@@ -215,6 +224,7 @@ class StudentController extends BaseController
$attnStats = [];
$scoreStats = [];
$invoiceParentId = 0;
$paymentPendingNotification = null;
if (!$isEventOnly) {
// Update enrollment for current term (if exists)
$enroll = \Config\Services::enrollmentStatus(false)
@@ -258,6 +268,16 @@ class StudentController extends BaseController
if ((int) ($result['id'] ?? 0) <= 0) {
throw new \RuntimeException('Failed to update enrollment.');
}
$oldEnrollmentStatus = strtolower(trim(str_replace("\xc2\xa0", ' ', (string) ($result['old_status'] ?? $enroll['enrollment_status'] ?? ''))));
$oldEnrollmentStatus = preg_replace('/\s+/', ' ', $oldEnrollmentStatus) ?? $oldEnrollmentStatus;
if (in_array($oldEnrollmentStatus, ['admission under review', 'review & decision'], true)) {
$paymentPendingNotification = [
'parent_id' => $invoiceParentId,
'student_id' => $studentId,
'student_name' => trim((string) ($student['firstname'] ?? '') . ' ' . (string) ($student['lastname'] ?? '')) ?: 'Student #' . $studentId,
];
}
}
// 🔄 Re-tag attendance rows for this student in the current term (section + class)
@@ -301,6 +321,10 @@ class StudentController extends BaseController
}
}
if ($paymentPendingNotification !== null) {
$this->triggerPaymentPendingNotification($paymentPendingNotification);
}
$resp = [
'ok' => true,
'student_id' => $studentId,
@@ -323,6 +347,51 @@ class StudentController extends BaseController
}
}
private function triggerPaymentPendingNotification(array $notification): void
{
$parentId = (int) ($notification['parent_id'] ?? 0);
$studentId = (int) ($notification['student_id'] ?? 0);
if ($parentId <= 0 || $studentId <= 0) {
return;
}
try {
$parent = $this->userModel->find($parentId) ?? [];
$invoice = $this->db->table('invoices')
->where('parent_id', $parentId)
->where('school_year', (string) $this->schoolYear)
->orderBy('created_at', 'DESC')
->orderBy('id', 'DESC')
->limit(1)
->get()
->getRowArray();
$parentData = [
'user_id' => $parent['id'] ?? $parentId,
'email' => $parent['email'] ?? null,
'firstname' => $parent['firstname'] ?? '',
'lastname' => $parent['lastname'] ?? '',
'school_year' => (string) $this->schoolYear,
'portalLink' => base_url('/login'),
];
if ($invoice) {
$parentData['amount'] = (float) ($invoice['balance'] ?? $invoice['amount_due'] ?? $invoice['total_amount'] ?? 0);
$parentData['due_date'] = $invoice['due_date'] ?? null;
}
Events::trigger('paymentPending', $parentData, [[
'student_id' => $studentId,
'name' => (string) ($notification['student_name'] ?? ('Student #' . $studentId)),
]]);
} catch (\Throwable $e) {
log_message('error', 'Payment pending notification after class assignment failed for parent {parent_id}: {error}', [
'parent_id' => $parentId,
'error' => $e->getMessage(),
]);
}
}
/**
* Remove a student-class assignment for the current term.
*/
@@ -1116,6 +1185,7 @@ class StudentController extends BaseController
}
$rows = [];
$activeEnrollmentStatuses = $this->distributionActiveEnrollmentStatuses();
if ($this->db->tableExists('student_class')) {
$builder = $this->db->table('student_class sc')
@@ -1141,16 +1211,16 @@ class StudentController extends BaseController
}
if ($this->db->tableExists('enrollments')) {
$classIdExpression = $this->distributionEnrollmentClassIdExpression();
$sectionIdExpression = $this->distributionEnrollmentSectionIdExpression();
$builder = $this->db->table('enrollments e')
->select('0 AS promotion_queue_id, e.student_id, e.school_year AS school_year_from, cs.class_id AS source_class_id, cs.class_section_name AS source_class_name, students.firstname, students.lastname, students.gender, students.age, students.dob, students.registration_grade', false)
->select('0 AS promotion_queue_id, e.student_id, e.school_year AS school_year_from, ' . $classIdExpression . ' AS source_class_id, cs.class_section_name AS source_class_name, students.firstname, students.lastname, students.gender, students.age, students.dob, students.registration_grade', false)
->join('students', 'students.id = e.student_id', 'inner')
->join('classSection cs', 'cs.class_section_id = e.class_section_id AND cs.school_year = ' . $this->db->escape($year), 'left', false)
->join('classSection cs', 'cs.class_section_id = ' . $sectionIdExpression . ' AND cs.school_year = ' . $this->db->escape($year), 'left', false)
->where('e.school_year', $year)
->whereIn('e.enrollment_status', ['admission under review', 'payment pending', 'enrolled'])
->groupStart()
->where('e.is_withdrawn', 0)
->orWhere('e.is_withdrawn', null)
->groupEnd();
->whereIn('e.enrollment_status', $activeEnrollmentStatuses);
$this->applyEnrollmentNotWithdrawnFilter($builder);
if ($this->db->fieldExists('is_active', 'students')) {
$builder->where('students.is_active', 1);
@@ -1272,21 +1342,22 @@ class StudentController extends BaseController
return [];
}
$classIdExpression = $this->distributionEnrollmentClassIdExpression();
$sectionIdExpression = $this->distributionEnrollmentSectionIdExpression();
$builder = $this->db->table('enrollments e')
->select('0 AS promotion_queue_id, e.student_id, e.school_year AS school_year_from, cs.class_id AS source_class_id, cs.class_section_name AS source_class_name, students.firstname, students.lastname, students.gender, students.age, students.dob, students.registration_grade', false)
->select('0 AS promotion_queue_id, e.student_id, e.school_year AS school_year_from, ' . $classIdExpression . ' AS source_class_id, cs.class_section_name AS source_class_name, students.firstname, students.lastname, students.gender, students.age, students.dob, students.registration_grade', false)
->join('students', 'students.id = e.student_id', 'inner')
->join('classSection cs', 'cs.class_section_id = e.class_section_id AND cs.school_year = ' . $this->db->escape($year), 'left', false)
->join('classSection cs', 'cs.class_section_id = ' . $sectionIdExpression . ' AND cs.school_year = ' . $this->db->escape($year), 'left', false)
->where('e.school_year', $year)
->whereIn('e.enrollment_status', ['admission under review', 'payment pending', 'enrolled'])
->groupStart()
->where('e.is_withdrawn', 0)
->orWhere('e.is_withdrawn', null)
->groupEnd()
->whereIn('e.enrollment_status', $this->distributionActiveEnrollmentStatuses())
->groupStart()
->where('cs.class_id', $classId)
->orWhereIn('UPPER(students.registration_grade)', ['KG', 'K', 'KINDERGARTEN'])
->groupEnd();
$this->applyEnrollmentNotWithdrawnFilter($builder);
if ($this->db->fieldExists('is_active', 'students')) {
$builder->where('students.is_active', 1);
}
@@ -1459,19 +1530,17 @@ class StudentController extends BaseController
}
if ($this->db->tableExists('enrollments')) {
$rows = $this->db->table('enrollments e')
$sectionIdExpression = $this->distributionEnrollmentSectionIdExpression();
$builder = $this->db->table('enrollments e')
->select('cs.class_section_name')
->join('classSection cs', 'cs.class_section_id = e.class_section_id AND cs.school_year = ' . $this->db->escape($previousYear), 'left', false)
->join('classSection cs', 'cs.class_section_id = ' . $sectionIdExpression . ' AND cs.school_year = ' . $this->db->escape($previousYear), 'left', false)
->where('e.student_id', $studentId)
->where('e.school_year', $previousYear)
->where('e.class_section_id IS NOT NULL', null, false)
->whereIn('e.enrollment_status', ['admission under review', 'payment pending', 'enrolled'])
->groupStart()
->where('e.is_withdrawn', 0)
->orWhere('e.is_withdrawn', null)
->groupEnd()
->get()
->getResultArray();
->where($sectionIdExpression . ' IS NOT NULL', null, false)
->whereIn('e.enrollment_status', $this->distributionActiveEnrollmentStatuses());
$this->applyEnrollmentNotWithdrawnFilter($builder);
$rows = $builder->get()->getResultArray();
foreach ($rows as $row) {
$baseName = $this->baseClassNameForDistribution((string)($row['class_section_name'] ?? ''));
@@ -1901,20 +1970,18 @@ class StudentController extends BaseController
}
if (empty($names) && $this->db->tableExists('enrollments')) {
$rows = $this->db->table('enrollments e')
$sectionIdExpression = $this->distributionEnrollmentSectionIdExpression();
$builder = $this->db->table('enrollments e')
->select('cs.class_section_name')
->join('classSection cs', 'cs.class_section_id = e.class_section_id AND cs.school_year = ' . $this->db->escape($previousYear), 'left', false)
->join('classSection cs', 'cs.class_section_id = ' . $sectionIdExpression . ' AND cs.school_year = ' . $this->db->escape($previousYear), 'left', false)
->where('e.student_id', $studentId)
->where('e.school_year', $previousYear)
->where('e.class_section_id IS NOT NULL', null, false)
->whereIn('e.enrollment_status', ['payment pending', 'enrolled'])
->groupStart()
->where('e.is_withdrawn', 0)
->orWhere('e.is_withdrawn', null)
->groupEnd()
->orderBy('cs.class_section_name', 'ASC')
->get()
->getResultArray();
->where($sectionIdExpression . ' IS NOT NULL', null, false)
->whereIn('e.enrollment_status', $this->distributionActiveEnrollmentStatuses())
->orderBy('cs.class_section_name', 'ASC');
$this->applyEnrollmentNotWithdrawnFilter($builder);
$rows = $builder->get()->getResultArray();
foreach ($rows as $row) {
$name = trim((string)($row['class_section_name'] ?? ''));
if ($name !== '') {
@@ -2399,6 +2466,56 @@ class StudentController extends BaseController
return $this->distributionBaseClassIdCache[$cacheKey];
}
private function distributionActiveEnrollmentStatuses(): array
{
return [
'admission under review',
'review & decision',
'payment pending',
'enrolled',
];
}
private function applyEnrollmentNotWithdrawnFilter($builder): void
{
if (! $this->db->fieldExists('is_withdrawn', 'enrollments')) {
return;
}
$builder->groupStart()
->where('e.is_withdrawn', 0)
->orWhere('e.is_withdrawn', null)
->groupEnd();
}
private function distributionEnrollmentClassIdExpression(): string
{
$parts = [];
foreach (['assigned_grade_id', 'source_grade_id'] as $field) {
if ($this->db->fieldExists($field, 'enrollments')) {
$parts[] = 'e.' . $field;
}
}
$parts[] = 'cs.class_id';
return count($parts) === 1 ? $parts[0] : 'COALESCE(' . implode(', ', $parts) . ')';
}
private function distributionEnrollmentSectionIdExpression(): string
{
$parts = [];
foreach (['assigned_class_section_id', 'class_section_id', 'source_class_section_id'] as $field) {
if ($this->db->fieldExists($field, 'enrollments')) {
$parts[] = 'e.' . $field;
}
}
if (empty($parts)) {
return 'NULL';
}
return count($parts) === 1 ? $parts[0] : 'COALESCE(' . implode(', ', $parts) . ')';
}
private function pendingDistributionDraftClassIds(string $year): array
{
if ($year === '' || ! $this->db->tableExists('student_section_distribution_drafts')) {
@@ -901,6 +901,19 @@ private function applyDistributionDraftToStudentClass(int $studentId, string $ye
return;
}
$enrollment = $this->db->table('enrollments')
->select('class_section_id')
->where('student_id', $studentId)
->where('school_year', $year)
->orderBy('updated_at', 'DESC')
->orderBy('id', 'DESC')
->limit(1)
->get()
->getRowArray();
if ((int)($enrollment['class_section_id'] ?? 0) > 0) {
return;
}
$targetSectionId = (int)($draft['class_section_id'] ?? 0);
if ($targetSectionId <= 0) {
return;
@@ -9,7 +9,7 @@ final class EnrollmentEligibility
public const DEFERRED_MESSAGE = 'Re-enrollment cannot currently be completed because the final deliberation decision is deferred. Please contact the school administration for the next required step.';
public const KG_MISSING_DECISION_ELIGIBLE_MESSAGE = 'KG students may complete registration now. Their new-year grade placement will be based on the school age-placement rule.';
public const MISSING_DECISION_MESSAGE = 'Re-enrollment cannot currently be completed because no final deliberation decision is recorded for the student. Registration will become available after the school records a final decision.';
public const ADULT_STUDENT_MESSAGE = 'This student will be 18 years old or older on September 1 of the selected school year. A parent or guardian cannot complete registration for this student. Please contact school administration.';
public const ADULT_STUDENT_MESSAGE = 'This student will be 18 years old or older on September 1 of the selected school year. This student can no longer enroll with the school';
public const ADULT_STUDENT_PARENT_PORTAL_MESSAGE = self::ADULT_STUDENT_MESSAGE;
public const WITHDRAWN_PORTAL_MESSAGE = 'This student is currently marked as Withdrawn and cannot be enrolled at this time. Please contact school administration.';
public const SIBLING_PORTAL_MESSAGE = 'Enrollment cannot continue because the family record requires administrative review. Please contact school administration.';
+20 -5
View File
@@ -279,7 +279,20 @@ $hasSettledEnrollmentStatus = static function (?string $status, ?string $admissi
};
$enrollableCount = 0;
$withdrawableCount = 0;
$currentYearTuitionStudentCount = 0;
foreach (($students ?? []) as $student) {
$studentStatus = strtolower(trim((string) ($student['enrollment_status'] ?? '')));
$studentAdmissionStatus = strtolower(trim((string) ($student['admission_status'] ?? '')));
if (
! in_array($studentStatus, ['withdrawn', 'withdraw under review', 'refund pending', 'denied', 'not enrolled'], true)
&& (
in_array($studentStatus, ['admission under review', 'review & decision', 'payment pending', 'enrolled', 'waitlist'], true)
|| $studentAdmissionStatus === 'accepted'
)
) {
$currentYearTuitionStudentCount++;
}
$evaluation = is_array($student['transition_evaluation'] ?? null) ? $student['transition_evaluation'] : [];
if (
(($evaluation['can_enroll'] ?? false) === true || ($evaluation['parent_enrollment_allowed'] ?? false) === true)
@@ -942,6 +955,7 @@ $studentCount = count($students ?? []);
'carryOverBalance' => (float) ($familyFinancialSummary['carry_forward_balance'] ?? $familyFinancialSummary['carry_over_balance'] ?? 0),
'currentBalance' => (float) ($familyFinancialSummary['current_year_balance'] ?? $familyFinancialSummary['current_balance'] ?? 0),
'amountDue' => (float) ($familyFinancialSummary['total_enrollment_due'] ?? $familyFinancialSummary['amount_due'] ?? 0),
'currentYearTuitionStudentCount' => (int) ($currentYearTuitionStudentCount ?? 0),
], JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) ?>;
let currentStep = 0;
let hasAcceptedSchoolPolicy = <?= $hasAcceptedSchoolPolicy ? 'true' : 'false' ?>;
@@ -975,7 +989,8 @@ $studentCount = count($students ?? []);
function calculateSelectedTuition() {
return selectedEnrollInputs().reduce((total, input, index) => {
return total + (index === 0 ? Number(feeSchedule.firstStudentFee || 0) : Number(feeSchedule.secondStudentFee || 0));
const familyPosition = Number(familyFinancial.currentYearTuitionStudentCount || 0) + index;
return total + (familyPosition === 0 ? Number(feeSchedule.firstStudentFee || 0) : Number(feeSchedule.secondStudentFee || 0));
}, 0);
}
@@ -1037,8 +1052,8 @@ $studentCount = count($students ?? []);
}
feeReviewList.innerHTML = cards.map((student, index) => {
const tuitionFee = index === 0 ? feeSchedule.firstStudentFee : feeSchedule.secondStudentFee;
const tier = index === 0 ? 'First student tuition tier' : 'Additional student tuition tier';
const familyPosition = Number(familyFinancial.currentYearTuitionStudentCount || 0) + index;
const tuitionFee = familyPosition === 0 ? feeSchedule.firstStudentFee : feeSchedule.secondStudentFee;
const lines = [
['Student', student.name],
['School ID', student.schoolId || 'N/A'],
@@ -1717,11 +1732,11 @@ $studentCount = count($students ?? []);
});
refreshEligibility().then(() => {
if (enrollmentStartStep >= 2 && startButton && !startButton.disabled && !<?= $flashError ? 'true' : 'false' ?>) {
if (enrollmentStartStep >= 1 && startButton && !startButton.disabled && !<?= $flashError ? 'true' : 'false' ?>) {
openEnrollmentAtStep(enrollmentStartStep - 1);
}
}).catch(() => {
if (enrollmentStartStep >= 2 && startButton && !startButton.disabled && !<?= $flashError ? 'true' : 'false' ?>) {
if (enrollmentStartStep >= 1 && startButton && !startButton.disabled && !<?= $flashError ? 'true' : 'false' ?>) {
openEnrollmentAtStep(enrollmentStartStep - 1);
}
// Keep server-rendered eligibility if refresh fails.
+1 -8
View File
@@ -101,20 +101,13 @@ $disableEmergencyBtn = count($emergencies) >= $maxEmergency;
<?php endif; ?>
<?php
$hasUnenrolled = false;
$unenrolledStudentIds = [];
foreach ($existingKids as $kid) {
if ($kid['enrollment'] == 0) {
$hasUnenrolled = true;
$studentId = (int) ($kid['id'] ?? 0);
if ($studentId > 0) {
$unenrolledStudentIds[] = $studentId;
}
}
}
usort($unenrolledStudentIds, static fn (int $a, int $b): int => $b <=> $a);
$enrollmentUrl = base_url('/parent/enroll_classes?' . http_build_query([
'start' => 2,
'students' => implode(',', $unenrolledStudentIds),
'start' => 1,
]));
?>
@@ -8,7 +8,6 @@
'administrator/sections/auto-distribute',
'admin/enrollment/new-students',
'payment/unpaid-parents',
'discounts/list',
'expenses/index',
'reimbursements/index',
];