fix registration enrollment of students
This commit is contained in:
@@ -380,6 +380,7 @@ class ParentController extends BaseController
|
|||||||
}
|
}
|
||||||
unset($student);
|
unset($student);
|
||||||
|
|
||||||
|
$this->ensureStudentYearStatusRows($students, $selectedYear);
|
||||||
service('studentYearStatus')->attachToStudents($students, $selectedYear);
|
service('studentYearStatus')->attachToStudents($students, $selectedYear);
|
||||||
foreach ($students as &$student) {
|
foreach ($students as &$student) {
|
||||||
$studentId = (int) ($student['id'] ?? 0);
|
$studentId = (int) ($student['id'] ?? 0);
|
||||||
@@ -528,7 +529,7 @@ class ParentController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$studentName = trim((string) ($studentInfo['firstname'] ?? '') . ' ' . (string) ($studentInfo['lastname'] ?? '')) ?: 'Student ID ' . $studentId;
|
$studentName = trim((string) ($studentInfo['firstname'] ?? '') . ' ' . (string) ($studentInfo['lastname'] ?? '')) ?: 'Student ID ' . $studentId;
|
||||||
if (empty($evaluation['can_enroll'])) {
|
if (empty($evaluation['can_enroll']) && empty($evaluation['parent_enrollment_allowed'])) {
|
||||||
$transitionService->logEnrollmentBlock($evaluation, 'parent_enroll_submit', (int) $parentId, (int) $parentId);
|
$transitionService->logEnrollmentBlock($evaluation, 'parent_enroll_submit', (int) $parentId, (int) $parentId);
|
||||||
$messages = array_values(array_filter(array_map('trim', array_map('strval', $evaluation['blockers'] ?? []))));
|
$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'] ?? []))));
|
$codes = array_values(array_filter(array_map('strval', array_merge($evaluation['blocking_rule_codes'] ?? [], $evaluation['review_rule_codes'] ?? []))));
|
||||||
@@ -1951,6 +1952,7 @@ class ParentController extends BaseController
|
|||||||
if ($this->hasSettledParentEnrollmentStatus($existingStatus, $existingAdmissionStatus)) {
|
if ($this->hasSettledParentEnrollmentStatus($existingStatus, $existingAdmissionStatus)) {
|
||||||
$payload[] = [
|
$payload[] = [
|
||||||
'student_id' => $studentId,
|
'student_id' => $studentId,
|
||||||
|
'student_name' => trim((string) ($student['firstname'] ?? '') . ' ' . (string) ($student['lastname'] ?? '')) ?: 'Student ID ' . $studentId,
|
||||||
'can_enroll' => false,
|
'can_enroll' => false,
|
||||||
'primary_block_reason' => 'ALREADY_ENROLLED',
|
'primary_block_reason' => 'ALREADY_ENROLLED',
|
||||||
'primary_parent_message' => EnrollmentEligibility::alreadyEnrolledMessage($existingStatus),
|
'primary_parent_message' => EnrollmentEligibility::alreadyEnrolledMessage($existingStatus),
|
||||||
@@ -1969,7 +1971,10 @@ class ParentController extends BaseController
|
|||||||
);
|
);
|
||||||
$payload[] = [
|
$payload[] = [
|
||||||
'student_id' => $studentId,
|
'student_id' => $studentId,
|
||||||
|
'student_name' => trim((string) ($student['firstname'] ?? '') . ' ' . (string) ($student['lastname'] ?? '')) ?: 'Student ID ' . $studentId,
|
||||||
'can_enroll' => (bool) ($evaluation['can_enroll'] ?? false),
|
'can_enroll' => (bool) ($evaluation['can_enroll'] ?? false),
|
||||||
|
'parent_enrollment_allowed' => (bool) ($evaluation['parent_enrollment_allowed'] ?? $evaluation['can_enroll'] ?? false),
|
||||||
|
'first_enrollment' => (bool) ($evaluation['first_enrollment'] ?? false),
|
||||||
'primary_block_reason' => $evaluation['primary_block_reason'] ?? null,
|
'primary_block_reason' => $evaluation['primary_block_reason'] ?? null,
|
||||||
'primary_parent_message' => $evaluation['primary_parent_message'] ?? null,
|
'primary_parent_message' => $evaluation['primary_parent_message'] ?? null,
|
||||||
'blocking_rule_codes' => array_values(array_map('strval', $evaluation['blocking_rule_codes'] ?? [])),
|
'blocking_rule_codes' => array_values(array_map('strval', $evaluation['blocking_rule_codes'] ?? [])),
|
||||||
@@ -2008,7 +2013,10 @@ class ParentController extends BaseController
|
|||||||
|
|
||||||
foreach ($students as $student) {
|
foreach ($students as $student) {
|
||||||
$evaluation = is_array($student['transition_evaluation'] ?? null) ? $student['transition_evaluation'] : [];
|
$evaluation = is_array($student['transition_evaluation'] ?? null) ? $student['transition_evaluation'] : [];
|
||||||
if (($evaluation['can_enroll'] ?? false) !== true) {
|
if (
|
||||||
|
($evaluation['can_enroll'] ?? false) !== true
|
||||||
|
&& ($evaluation['parent_enrollment_allowed'] ?? false) !== true
|
||||||
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2123,7 +2131,7 @@ class ParentController extends BaseController
|
|||||||
'parent'
|
'parent'
|
||||||
);
|
);
|
||||||
|
|
||||||
if (($evaluation['can_enroll'] ?? false) === true) {
|
if (($evaluation['can_enroll'] ?? false) === true || ($evaluation['parent_enrollment_allowed'] ?? false) === true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2800,6 +2808,7 @@ class ParentController extends BaseController
|
|||||||
}
|
}
|
||||||
unset($kid);
|
unset($kid);
|
||||||
|
|
||||||
|
$this->ensureStudentYearStatusRows($kids, $selectedSchoolYear);
|
||||||
service('studentYearStatus')->attachToStudents($kids, $selectedSchoolYear);
|
service('studentYearStatus')->attachToStudents($kids, $selectedSchoolYear);
|
||||||
|
|
||||||
foreach ($kids as &$kid) {
|
foreach ($kids as &$kid) {
|
||||||
@@ -2821,6 +2830,33 @@ class ParentController extends BaseController
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param list<array<string, mixed>> $students
|
||||||
|
*/
|
||||||
|
private function ensureStudentYearStatusRows(array $students, string $schoolYear): void
|
||||||
|
{
|
||||||
|
$schoolYear = trim($schoolYear);
|
||||||
|
if ($students === [] || ! preg_match('/^\d{4}-\d{4}$/', $schoolYear)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$studentYearStatus = service('studentYearStatus');
|
||||||
|
foreach ($students as $student) {
|
||||||
|
$studentId = (int) ($student['id'] ?? $student['student_id'] ?? 0);
|
||||||
|
if ($studentId <= 0 || $studentYearStatus->hasStatus($studentId, $schoolYear)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$isNew = (int) ($student['is_new'] ?? 1) === 1;
|
||||||
|
if (! $studentYearStatus->upsert($studentId, $schoolYear, $isNew)) {
|
||||||
|
log_message('error', 'Unable to repair student_year_status for student_id={studentId}, school_year={schoolYear}', [
|
||||||
|
'studentId' => $studentId,
|
||||||
|
'schoolYear' => $schoolYear,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function validateAndSaveOrUpdateStudent($idx, $parentId, $semester, $schoolYear, $schoolIdService, $isNew = null, $studentId = null)
|
private function validateAndSaveOrUpdateStudent($idx, $parentId, $semester, $schoolYear, $schoolIdService, $isNew = null, $studentId = null)
|
||||||
{
|
{
|
||||||
$firstName = $this->request->getPost('studentFirstName')[$idx] ?? null;
|
$firstName = $this->request->getPost('studentFirstName')[$idx] ?? null;
|
||||||
@@ -2883,8 +2919,10 @@ class ParentController extends BaseController
|
|||||||
'photo_consent' => $photoConsent,
|
'photo_consent' => $photoConsent,
|
||||||
'parent_id' => (int) $parentId,
|
'parent_id' => (int) $parentId,
|
||||||
'year_of_registration' => date('Y'),
|
'year_of_registration' => date('Y'),
|
||||||
'school_year' => $schoolYear,
|
|
||||||
];
|
];
|
||||||
|
if ($this->db->fieldExists('school_year', 'students')) {
|
||||||
|
$studentData['school_year'] = $schoolYear;
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_null($isNew)) {
|
if (!is_null($isNew)) {
|
||||||
$studentData['is_new'] = $isNew ? 1 : 0;
|
$studentData['is_new'] = $isNew ? 1 : 0;
|
||||||
@@ -2950,7 +2988,11 @@ class ParentController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! is_null($isNew) && (int) $studentId > 0) {
|
if (! is_null($isNew) && (int) $studentId > 0) {
|
||||||
service('studentYearStatus')->upsert((int) $studentId, (string) $schoolYear, (bool) $isNew);
|
$studentYearStatus = service('studentYearStatus');
|
||||||
|
$statusSaved = $studentYearStatus->upsert((int) $studentId, (string) $schoolYear, (bool) $isNew);
|
||||||
|
if (! $statusSaved || ! $studentYearStatus->hasStatus((int) $studentId, (string) $schoolYear)) {
|
||||||
|
throw new \RuntimeException('Student year status could not be saved for student ID ' . (int) $studentId . ' and school year ' . (string) $schoolYear . '.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- SAVE MEDICAL CONDITIONS ----------
|
// ---------- SAVE MEDICAL CONDITIONS ----------
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ class StudentModel extends Model
|
|||||||
'tuition_paid',
|
'tuition_paid',
|
||||||
'year_of_registration',
|
'year_of_registration',
|
||||||
'rfid_tag',
|
'rfid_tag',
|
||||||
'school_year',
|
|
||||||
'is_active'
|
'is_active'
|
||||||
];
|
];
|
||||||
protected $useTimestamps = false;
|
protected $useTimestamps = false;
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ final class EnrollmentRegistrationEmailService
|
|||||||
return 'KG students may complete registration now. ' . $name . ' is eligible for re-enrollment even though no final deliberation decision is recorded.' . $placementText;
|
return 'KG students may complete registration now. ' . $name . ' is eligible for re-enrollment even though no final deliberation decision is recorded.' . $placementText;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($evaluation['can_enroll'] ?? false) === false && ! empty($evaluation['primary_parent_message'])) {
|
if (! $this->canCompleteParentReEnrollment($evaluation) && ! empty($evaluation['primary_parent_message'])) {
|
||||||
return (string) $evaluation['primary_parent_message'];
|
return (string) $evaluation['primary_parent_message'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -655,7 +655,7 @@ final class EnrollmentRegistrationEmailService
|
|||||||
return $placement;
|
return $placement;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ($evaluation['can_enroll'] ?? false) === true ? 'Pending' : '';
|
return $this->canCompleteParentReEnrollment($evaluation) ? 'Pending' : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
private function requiredAction(array $evaluation, string $deadline, string $name = 'The student'): string
|
private function requiredAction(array $evaluation, string $deadline, string $name = 'The student'): string
|
||||||
|
|||||||
@@ -707,7 +707,35 @@ final class EnrollmentTransitionService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return trim((string) ($student['school_year'] ?? '')) === $targetSchoolYear;
|
if ($this->db->fieldExists('school_year', 'students')) {
|
||||||
|
return trim((string) ($student['school_year'] ?? '')) === $targetSchoolYear;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ! $this->studentHasPriorSchoolHistory($studentId, $targetSchoolYear);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function studentHasPriorSchoolHistory(int $studentId, string $targetSchoolYear): bool
|
||||||
|
{
|
||||||
|
if ($studentId <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (['student_class', 'enrollments', 'student_decisions'] as $table) {
|
||||||
|
if (! $this->db->tableExists($table) || ! $this->db->fieldExists('school_year', $table)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = $this->db->table($table)
|
||||||
|
->where('student_id', $studentId)
|
||||||
|
->where('school_year !=', $targetSchoolYear)
|
||||||
|
->countAllResults();
|
||||||
|
|
||||||
|
if ($count > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function schoolYearByName(string $schoolYear): ?array
|
private function schoolYearByName(string $schoolYear): ?array
|
||||||
@@ -2009,19 +2037,7 @@ final class EnrollmentTransitionService
|
|||||||
|
|
||||||
private function applyHouseholdLastNameRule(array &$evaluation, int $parentId, ?string $sourceSchoolYear = null): void
|
private function applyHouseholdLastNameRule(array &$evaluation, int $parentId, ?string $sourceSchoolYear = null): void
|
||||||
{
|
{
|
||||||
if (! empty($evaluation['first_enrollment'])) {
|
|
||||||
$evaluation['family_name_check_ok'] = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$students = $this->linkedStudentsForParent($parentId);
|
$students = $this->linkedStudentsForParent($parentId);
|
||||||
$sourceSchoolYear = trim((string) $sourceSchoolYear);
|
|
||||||
if ($sourceSchoolYear !== '') {
|
|
||||||
$students = array_values(array_filter(
|
|
||||||
$students,
|
|
||||||
fn (array $student): bool => $this->sourceAssignment((int) ($student['id'] ?? 0), $sourceSchoolYear) !== null
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($students) <= 1) {
|
if (count($students) <= 1) {
|
||||||
$evaluation['family_name_check_ok'] = true;
|
$evaluation['family_name_check_ok'] = true;
|
||||||
|
|||||||
@@ -40,15 +40,15 @@ class StudentYearStatusService
|
|||||||
return (int) ($row['is_new'] ?? 1) === 1;
|
return (int) ($row['is_new'] ?? 1) === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function upsert(int $studentId, string $schoolYear, bool $isNew): void
|
public function upsert(int $studentId, string $schoolYear, bool $isNew): bool
|
||||||
{
|
{
|
||||||
if ($studentId <= 0) {
|
if ($studentId <= 0) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$schoolYear = trim($schoolYear);
|
$schoolYear = trim($schoolYear);
|
||||||
if (! preg_match('/^\d{4}-\d{4}$/', $schoolYear) || ! $this->db->tableExists('student_year_status')) {
|
if (! preg_match('/^\d{4}-\d{4}$/', $schoolYear) || ! $this->db->tableExists('student_year_status')) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$flag = $isNew ? 1 : 0;
|
$flag = $isNew ? 1 : 0;
|
||||||
@@ -59,19 +59,35 @@ class StudentYearStatusService
|
|||||||
->first();
|
->first();
|
||||||
|
|
||||||
if (is_array($existing) && isset($existing['id'])) {
|
if (is_array($existing) && isset($existing['id'])) {
|
||||||
$this->yearStatusModel->update((int) $existing['id'], [
|
return (bool) $this->yearStatusModel->update((int) $existing['id'], [
|
||||||
'is_new' => $flag,
|
'is_new' => $flag,
|
||||||
]);
|
]);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->yearStatusModel->insert([
|
return (bool) $this->yearStatusModel->insert([
|
||||||
'student_id' => $studentId,
|
'student_id' => $studentId,
|
||||||
'school_year' => $schoolYear,
|
'school_year' => $schoolYear,
|
||||||
'is_new' => $flag,
|
'is_new' => $flag,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function hasStatus(int $studentId, string $schoolYear): bool
|
||||||
|
{
|
||||||
|
if ($studentId <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$schoolYear = trim($schoolYear);
|
||||||
|
if (! preg_match('/^\d{4}-\d{4}$/', $schoolYear) || ! $this->db->tableExists('student_year_status')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->yearStatusModel
|
||||||
|
->where('student_id', $studentId)
|
||||||
|
->where('school_year', $schoolYear)
|
||||||
|
->countAllResults() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark students who existed in a source school year as returning in the target year.
|
* Mark students who existed in a source school year as returning in the target year.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -281,7 +281,11 @@ $enrollableCount = 0;
|
|||||||
$withdrawableCount = 0;
|
$withdrawableCount = 0;
|
||||||
foreach (($students ?? []) as $student) {
|
foreach (($students ?? []) as $student) {
|
||||||
$evaluation = is_array($student['transition_evaluation'] ?? null) ? $student['transition_evaluation'] : [];
|
$evaluation = is_array($student['transition_evaluation'] ?? null) ? $student['transition_evaluation'] : [];
|
||||||
if (($evaluation['can_enroll'] ?? false) === true && !$deadlinePassed && $isEditable) {
|
if (
|
||||||
|
(($evaluation['can_enroll'] ?? false) === true || ($evaluation['parent_enrollment_allowed'] ?? false) === true)
|
||||||
|
&& !$deadlinePassed
|
||||||
|
&& $isEditable
|
||||||
|
) {
|
||||||
$enrollableCount++;
|
$enrollableCount++;
|
||||||
}
|
}
|
||||||
if (($student['enrollment_status'] ?? '') === 'enrolled' && $isEditable) {
|
if (($student['enrollment_status'] ?? '') === 'enrolled' && $isEditable) {
|
||||||
@@ -386,7 +390,7 @@ $studentCount = count($students ?? []);
|
|||||||
$evaluation = is_array($student['transition_evaluation'] ?? null) ? $student['transition_evaluation'] : [];
|
$evaluation = is_array($student['transition_evaluation'] ?? null) ? $student['transition_evaluation'] : [];
|
||||||
if ($hasSettledEnrollmentStatus($student['enrollment_status'] ?? '', $student['admission_status'] ?? '')) {
|
if ($hasSettledEnrollmentStatus($student['enrollment_status'] ?? '', $student['admission_status'] ?? '')) {
|
||||||
echo '<span class="text-muted small">' . esc($alreadyEnrolledMessage((string) ($student['enrollment_status'] ?? ''))) . '</span>';
|
echo '<span class="text-muted small">' . esc($alreadyEnrolledMessage((string) ($student['enrollment_status'] ?? ''))) . '</span>';
|
||||||
} elseif (($evaluation['can_enroll'] ?? false) === true) {
|
} elseif (($evaluation['can_enroll'] ?? false) === true || ($evaluation['parent_enrollment_allowed'] ?? false) === true) {
|
||||||
echo '<span class="text-success small">Eligible</span>';
|
echo '<span class="text-success small">Eligible</span>';
|
||||||
} elseif (! empty($evaluation['primary_parent_message'])) {
|
} elseif (! empty($evaluation['primary_parent_message'])) {
|
||||||
echo '<span class="text-danger small">' . esc($evaluation['primary_parent_message']) . '</span>';
|
echo '<span class="text-danger small">' . esc($evaluation['primary_parent_message']) . '</span>';
|
||||||
@@ -510,13 +514,20 @@ $studentCount = count($students ?? []);
|
|||||||
$evaluation = is_array($student['transition_evaluation'] ?? null) ? $student['transition_evaluation'] : [];
|
$evaluation = is_array($student['transition_evaluation'] ?? null) ? $student['transition_evaluation'] : [];
|
||||||
$studentName = trim((string) ($student['firstname'] ?? '') . ' ' . (string) ($student['lastname'] ?? ''));
|
$studentName = trim((string) ($student['firstname'] ?? '') . ' ' . (string) ($student['lastname'] ?? ''));
|
||||||
$studentName = $studentName !== '' ? $studentName : 'Student';
|
$studentName = $studentName !== '' ? $studentName : 'Student';
|
||||||
$canEnroll = ($evaluation['can_enroll'] ?? false) === true
|
$studentId = (int) ($student['id'] ?? 0);
|
||||||
|
$isPreselectedStudent = in_array($studentId, array_map('intval', $preselectedStudentIds ?? []), true);
|
||||||
|
$canEnroll = (
|
||||||
|
($evaluation['can_enroll'] ?? false) === true
|
||||||
|
|| ($evaluation['parent_enrollment_allowed'] ?? false) === true
|
||||||
|
)
|
||||||
&& !$deadlinePassed
|
&& !$deadlinePassed
|
||||||
&& $isEditable;
|
&& $isEditable;
|
||||||
$hasSettledEnrollment = $hasSettledEnrollmentStatus($student['enrollment_status'] ?? '', $student['admission_status'] ?? '');
|
$hasSettledEnrollment = $hasSettledEnrollmentStatus($student['enrollment_status'] ?? '', $student['admission_status'] ?? '');
|
||||||
$blockMessage = $hasSettledEnrollment
|
$blockMessage = $canEnroll
|
||||||
|
? ''
|
||||||
|
: ($hasSettledEnrollment
|
||||||
? $alreadyEnrolledMessage((string) ($student['enrollment_status'] ?? ''))
|
? $alreadyEnrolledMessage((string) ($student['enrollment_status'] ?? ''))
|
||||||
: (string) ($evaluation['primary_parent_message'] ?? $eligibilityMessage['message'] ?? '');
|
: (string) ($evaluation['primary_parent_message'] ?? $eligibilityMessage['message'] ?? ''));
|
||||||
$blockTitle = $hasSettledEnrollment
|
$blockTitle = $hasSettledEnrollment
|
||||||
? $alreadyEnrolledTitle((string) ($student['enrollment_status'] ?? ''))
|
? $alreadyEnrolledTitle((string) ($student['enrollment_status'] ?? ''))
|
||||||
: 'Enrollment Not Available';
|
: 'Enrollment Not Available';
|
||||||
@@ -547,6 +558,8 @@ $studentCount = count($students ?? []);
|
|||||||
<div class="student-select-card <?= $canEnroll ? '' : 'is-disabled' ?>"
|
<div class="student-select-card <?= $canEnroll ? '' : 'is-disabled' ?>"
|
||||||
data-student-card
|
data-student-card
|
||||||
data-student-id="<?= esc($student['id']) ?>"
|
data-student-id="<?= esc($student['id']) ?>"
|
||||||
|
data-student-name="<?= esc($studentName) ?>"
|
||||||
|
data-requested-student="<?= $isPreselectedStudent ? '1' : '0' ?>"
|
||||||
data-school-id="<?= esc($student['school_id'] ?? 'N/A') ?>"
|
data-school-id="<?= esc($student['school_id'] ?? 'N/A') ?>"
|
||||||
data-current-grade="<?= esc($gradeLabel) ?>"
|
data-current-grade="<?= esc($gradeLabel) ?>"
|
||||||
data-required-action="<?= esc($student['required_action_label'] ?? 'Contact administration') ?>"
|
data-required-action="<?= esc($student['required_action_label'] ?? 'Contact administration') ?>"
|
||||||
@@ -935,6 +948,11 @@ $studentCount = count($students ?? []);
|
|||||||
|
|
||||||
const selectedEnrollInputs = () => form ? Array.from(form.querySelectorAll("input[name='enroll[]']:checked")) : [];
|
const selectedEnrollInputs = () => form ? Array.from(form.querySelectorAll("input[name='enroll[]']:checked")) : [];
|
||||||
const selectedWithdrawInputs = () => form ? Array.from(form.querySelectorAll("input[name='withdraw[]']:checked")) : [];
|
const selectedWithdrawInputs = () => form ? Array.from(form.querySelectorAll("input[name='withdraw[]']:checked")) : [];
|
||||||
|
const studentCards = () => Array.from(document.querySelectorAll('[data-student-card]'));
|
||||||
|
const requestedStudentCards = () => {
|
||||||
|
const requested = studentCards().filter(card => card.dataset.requestedStudent === '1');
|
||||||
|
return requested.length ? requested : studentCards();
|
||||||
|
};
|
||||||
|
|
||||||
function setStep(step) {
|
function setStep(step) {
|
||||||
currentStep = Math.max(0, Math.min(finalStep, step));
|
currentStep = Math.max(0, Math.min(finalStep, step));
|
||||||
@@ -1214,7 +1232,8 @@ $studentCount = count($students ?? []);
|
|||||||
|
|
||||||
function selectStudentsForEnrollment(ids) {
|
function selectStudentsForEnrollment(ids) {
|
||||||
const wanted = Array.isArray(ids) ? ids.map(Number).filter(id => id > 0) : [];
|
const wanted = Array.isArray(ids) ? ids.map(Number).filter(id => id > 0) : [];
|
||||||
document.querySelectorAll('[data-student-card]').forEach(card => {
|
const cards = wanted.length ? requestedStudentCards() : studentCards();
|
||||||
|
cards.forEach(card => {
|
||||||
if (card.dataset.selectable !== '1') {
|
if (card.dataset.selectable !== '1') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1340,7 +1359,7 @@ $studentCount = count($students ?? []);
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelectorAll('[data-student-card]').forEach(card => {
|
studentCards().forEach(card => {
|
||||||
card.querySelectorAll('[data-health-group]').forEach(group => {
|
card.querySelectorAll('[data-health-group]').forEach(group => {
|
||||||
group.addEventListener('change', function(event) {
|
group.addEventListener('change', function(event) {
|
||||||
const target = event.target;
|
const target = event.target;
|
||||||
@@ -1372,17 +1391,41 @@ $studentCount = count($students ?? []);
|
|||||||
|
|
||||||
function showBlockModal(message, options = {}) {
|
function showBlockModal(message, options = {}) {
|
||||||
const alreadyEnrolled = options.alreadyEnrolled === true;
|
const alreadyEnrolled = options.alreadyEnrolled === true;
|
||||||
|
const warning = options.warning === true;
|
||||||
if (blockModalTitle) {
|
if (blockModalTitle) {
|
||||||
blockModalTitle.textContent = options.title || (alreadyEnrolled ? 'Already Enrolled' : 'Enrollment Not Available');
|
blockModalTitle.textContent = options.title || (alreadyEnrolled ? 'Already Enrolled' : 'Enrollment Not Available');
|
||||||
}
|
}
|
||||||
if (blockModalHeader) {
|
if (blockModalHeader) {
|
||||||
blockModalHeader.classList.toggle('bg-danger', !alreadyEnrolled);
|
blockModalHeader.classList.toggle('bg-danger', !alreadyEnrolled && !warning);
|
||||||
blockModalHeader.classList.toggle('bg-success', alreadyEnrolled);
|
blockModalHeader.classList.toggle('bg-success', alreadyEnrolled && !warning);
|
||||||
|
blockModalHeader.classList.toggle('bg-warning', warning);
|
||||||
|
blockModalHeader.classList.toggle('text-dark', warning);
|
||||||
|
blockModalHeader.classList.toggle('text-white', !warning);
|
||||||
}
|
}
|
||||||
if (blockModalBody) {
|
if (blockModalBody) {
|
||||||
blockModalBody.textContent = message || (alreadyEnrolled
|
const messages = Array.isArray(options.messages) ? options.messages.filter(Boolean) : [];
|
||||||
? 'This student is already enrolled for the selected school year.'
|
if (messages.length > 1) {
|
||||||
: 'Enrollment cannot continue at this time. Please contact school administration.');
|
const list = document.createElement('ul');
|
||||||
|
list.className = 'mb-0 ps-4';
|
||||||
|
messages.forEach(item => {
|
||||||
|
const li = document.createElement('li');
|
||||||
|
const separatorIndex = item.indexOf(': ');
|
||||||
|
if (separatorIndex > 0) {
|
||||||
|
const name = document.createElement('strong');
|
||||||
|
name.textContent = item.substring(0, separatorIndex);
|
||||||
|
li.appendChild(name);
|
||||||
|
li.appendChild(document.createTextNode(item.substring(separatorIndex)));
|
||||||
|
} else {
|
||||||
|
li.textContent = item;
|
||||||
|
}
|
||||||
|
list.appendChild(li);
|
||||||
|
});
|
||||||
|
blockModalBody.replaceChildren(list);
|
||||||
|
} else {
|
||||||
|
blockModalBody.textContent = messages[0] || message || (alreadyEnrolled
|
||||||
|
? 'This student is already enrolled for the selected school year.'
|
||||||
|
: 'Enrollment cannot continue at this time. Please contact school administration.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (blockModal) {
|
if (blockModal) {
|
||||||
blockModal.show();
|
blockModal.show();
|
||||||
@@ -1400,6 +1443,24 @@ $studentCount = count($students ?? []);
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function blockMessagesForCards(cards) {
|
||||||
|
return cards
|
||||||
|
.map(card => {
|
||||||
|
const studentId = String(card.dataset.studentId || '');
|
||||||
|
const row = latestEligibility[studentId] || {};
|
||||||
|
const message = row.primary_parent_message
|
||||||
|
|| (row.blocking_rule_codes || []).join(', ')
|
||||||
|
|| card.dataset.blockMessage
|
||||||
|
|| '';
|
||||||
|
if (!message) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const name = row.student_name || card.dataset.studentName || 'Student';
|
||||||
|
return name + ': ' + message;
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
async function refreshEligibility() {
|
async function refreshEligibility() {
|
||||||
const response = await fetch(eligibilityRefreshUrl, {
|
const response = await fetch(eligibilityRefreshUrl, {
|
||||||
headers: { 'X-Requested-With': 'XMLHttpRequest' },
|
headers: { 'X-Requested-With': 'XMLHttpRequest' },
|
||||||
@@ -1426,7 +1487,7 @@ $studentCount = count($students ?? []);
|
|||||||
function applyEligibilityToCards() {
|
function applyEligibilityToCards() {
|
||||||
let shouldReload = false;
|
let shouldReload = false;
|
||||||
|
|
||||||
document.querySelectorAll('[data-student-card]').forEach(card => {
|
studentCards().forEach(card => {
|
||||||
const studentId = String(card.dataset.studentId || '');
|
const studentId = String(card.dataset.studentId || '');
|
||||||
const row = latestEligibility[studentId];
|
const row = latestEligibility[studentId];
|
||||||
if (!row) {
|
if (!row) {
|
||||||
@@ -1434,7 +1495,7 @@ $studentCount = count($students ?? []);
|
|||||||
}
|
}
|
||||||
|
|
||||||
const wasBlocked = card.dataset.selectable !== '1';
|
const wasBlocked = card.dataset.selectable !== '1';
|
||||||
const canEnroll = row.can_enroll === true && !deadlinePassed;
|
const canEnroll = (row.can_enroll === true || row.parent_enrollment_allowed === true) && !deadlinePassed;
|
||||||
card.dataset.selectable = canEnroll ? '1' : '0';
|
card.dataset.selectable = canEnroll ? '1' : '0';
|
||||||
card.classList.toggle('is-disabled', !canEnroll);
|
card.classList.toggle('is-disabled', !canEnroll);
|
||||||
if (row.primary_parent_message) {
|
if (row.primary_parent_message) {
|
||||||
@@ -1468,19 +1529,29 @@ $studentCount = count($students ?? []);
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const eligibleCards = Array.from(document.querySelectorAll('[data-student-card]')).filter(card => {
|
const cardsToConsider = requestedStudentCards();
|
||||||
|
const eligibleCards = cardsToConsider.filter(card => {
|
||||||
const studentId = String(card.dataset.studentId || '');
|
const studentId = String(card.dataset.studentId || '');
|
||||||
return latestEligibility[studentId]?.can_enroll === true;
|
const row = latestEligibility[studentId] || {};
|
||||||
|
return row.can_enroll === true || row.parent_enrollment_allowed === true;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (eligibleCards.length === 0) {
|
if (eligibleCards.length === 0) {
|
||||||
const firstBlocked = Object.values(latestEligibility).find(row => row.primary_parent_message || (row.blocking_rule_codes || []).length > 0);
|
const otherBlockedCards = studentCards().filter(card => !cardsToConsider.includes(card));
|
||||||
|
const blockedMessages = blockMessagesForCards(cardsToConsider)
|
||||||
|
.concat(blockMessagesForCards(otherBlockedCards));
|
||||||
|
const firstBlocked = cardsToConsider
|
||||||
|
.map(card => latestEligibility[String(card.dataset.studentId || '')])
|
||||||
|
.find(row => row && (row.primary_parent_message || (row.blocking_rule_codes || []).length > 0))
|
||||||
|
|| Object.values(latestEligibility).find(row => row.primary_parent_message || (row.blocking_rule_codes || []).length > 0);
|
||||||
const alreadyEnrolled = firstBlocked?.decision === 'ALREADY_ENROLLED';
|
const alreadyEnrolled = firstBlocked?.decision === 'ALREADY_ENROLLED';
|
||||||
const blockReason = firstBlocked?.primary_parent_message
|
const blockReason = firstBlocked?.primary_parent_message
|
||||||
|| (firstBlocked?.blocking_rule_codes || []).join(', ')
|
|| (firstBlocked?.blocking_rule_codes || []).join(', ')
|
||||||
|| 'No students are currently eligible for enrollment.';
|
|| 'No students are currently eligible for enrollment.';
|
||||||
showBlockModal(blockReason, {
|
showBlockModal(blockReason, {
|
||||||
alreadyEnrolled,
|
alreadyEnrolled,
|
||||||
|
messages: blockedMessages,
|
||||||
|
warning: alreadyEnrolled && blockedMessages.length > 1,
|
||||||
title: firstBlocked?.block_title || (alreadyEnrolled ? 'Already Enrolled' : 'Enrollment Not Available'),
|
title: firstBlocked?.block_title || (alreadyEnrolled ? 'Already Enrolled' : 'Enrollment Not Available'),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -1491,7 +1562,7 @@ $studentCount = count($students ?? []);
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelectorAll('[data-student-card]').forEach(card => {
|
studentCards().forEach(card => {
|
||||||
card.addEventListener('click', async function(event) {
|
card.addEventListener('click', async function(event) {
|
||||||
if (event.target.closest('input, select, textarea, label')) {
|
if (event.target.closest('input, select, textarea, label')) {
|
||||||
return;
|
return;
|
||||||
@@ -1645,11 +1716,14 @@ $studentCount = count($students ?? []);
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (enrollmentStartStep >= 2 && startButton && !startButton.disabled && !<?= $flashError ? 'true' : 'false' ?>) {
|
refreshEligibility().then(() => {
|
||||||
openEnrollmentAtStep(enrollmentStartStep - 1);
|
if (enrollmentStartStep >= 2 && startButton && !startButton.disabled && !<?= $flashError ? 'true' : 'false' ?>) {
|
||||||
}
|
openEnrollmentAtStep(enrollmentStartStep - 1);
|
||||||
|
}
|
||||||
refreshEligibility().catch(() => {
|
}).catch(() => {
|
||||||
|
if (enrollmentStartStep >= 2 && startButton && !startButton.disabled && !<?= $flashError ? 'true' : 'false' ?>) {
|
||||||
|
openEnrollmentAtStep(enrollmentStartStep - 1);
|
||||||
|
}
|
||||||
// Keep server-rendered eligibility if refresh fails.
|
// Keep server-rendered eligibility if refresh fails.
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -100,14 +100,22 @@ $disableEmergencyBtn = count($emergencies) >= $maxEmergency;
|
|||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php
|
<?php
|
||||||
// Check if at least one student is not enrolled
|
|
||||||
$hasUnenrolled = false;
|
$hasUnenrolled = false;
|
||||||
|
$unenrolledStudentIds = [];
|
||||||
foreach ($existingKids as $kid) {
|
foreach ($existingKids as $kid) {
|
||||||
if ($kid['enrollment'] == 0) {
|
if ($kid['enrollment'] == 0) {
|
||||||
$hasUnenrolled = true;
|
$hasUnenrolled = true;
|
||||||
break;
|
$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),
|
||||||
|
]));
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php if ($hasUnenrolled): ?>
|
<?php if ($hasUnenrolled): ?>
|
||||||
@@ -118,7 +126,7 @@ $disableEmergencyBtn = count($emergencies) >= $maxEmergency;
|
|||||||
<p class="mb-3">
|
<p class="mb-3">
|
||||||
Please complete their enrollment using the button below to ensure they are able to attend classes.
|
Please complete their enrollment using the button below to ensure they are able to attend classes.
|
||||||
</p>
|
</p>
|
||||||
<a href="<?= base_url('/parent/enroll_classes') ?>"
|
<a href="<?= esc($enrollmentUrl) ?>"
|
||||||
class="btn btn-lg btn-success bi bi-pencil-square"
|
class="btn btn-lg btn-success bi bi-pencil-square"
|
||||||
data-bs-toggle="tooltip"
|
data-bs-toggle="tooltip"
|
||||||
data-bs-placement="bottom"
|
data-bs-placement="bottom"
|
||||||
|
|||||||
Reference in New Issue
Block a user