fix enrollment, invoice, payment and financila aid
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 47s
Tests / PHPUnit (push) Failing after 1m19s

This commit is contained in:
root
2026-08-24 21:20:58 -04:00
parent 576da3bd78
commit 608aca79b8
30 changed files with 3327 additions and 774 deletions
+73 -12
View File
@@ -214,22 +214,41 @@ class StudentController extends BaseController
$attnStats = [];
$scoreStats = [];
$invoiceParentId = 0;
if (!$isEventOnly) {
// Update enrollment for current term (if exists)
$enroll = $this->enrollmentModel
->where('student_id', $studentId)
->where('school_year', (string)$this->schoolYear)
->where('semester', (string)$this->semester)
->first();
$enroll = \Config\Services::enrollmentStatus(false)
->controllingEnrollment($studentId, (string) $this->schoolYear);
if ($enroll) {
$invoiceParentId = (int) ($enroll['parent_id'] ?? $student['parent_id'] ?? 0);
$parentId = $invoiceParentId;
if ($parentId > 0) {
$advance = service('enrollmentTransition')->evaluateEnrollmentAdvance(
$parentId,
$studentId,
(string) $this->schoolYear,
'admin'
);
if (! service('enrollmentTransition')->adminMayAdvanceEnrollment($advance)) {
service('enrollmentTransition')->logEnrollmentBlock(
$advance,
'assign_class_student',
$parentId,
$userId > 0 ? $userId : null
);
$msg = (string) ($advance['primary_parent_message'] ?? 'Enrollment eligibility check failed.');
throw new \RuntimeException($msg);
}
}
$enPk = $this->enrollmentModel->primaryKey ?? 'id';
$result = \Config\Services::enrollmentStatus(false)->upsertStatus([
'id' => (int) $enroll[$enPk],
'student_id' => $studentId,
'parent_id' => (int) ($enroll['parent_id'] ?? 0),
'school_year' => (string) $this->schoolYear,
'semester' => (string) $this->semester,
'semester' => (string) ($enroll['semester'] ?? $this->semester),
'class_section_id' => $primarySectionId,
'enrollment_status' => 'payment pending',
// Ensure admission is marked accepted once moved out of review
@@ -267,6 +286,21 @@ class StudentController extends BaseController
$this->db->transCommit();
if (! $isEventOnly && $invoiceParentId > 0) {
try {
(new InvoiceController())->generateInvoice(
(string) $invoiceParentId,
(string) $this->schoolYear,
(string) $this->semester
);
} catch (\Throwable $e) {
log_message('error', 'Invoice refresh after class assignment failed for parent {parent_id}: {error}', [
'parent_id' => $invoiceParentId,
'error' => $e->getMessage(),
]);
}
}
$resp = [
'ok' => true,
'student_id' => $studentId,
@@ -680,7 +714,7 @@ class StudentController extends BaseController
$cands = $this->distributionCandidates($classId, $year);
if (empty($cands)) {
$msg = 'No promoted students found to distribute for selected class/year.';
$msg = 'No students found to distribute for the selected class/year.';
return $isAjax ? $json(['ok' => false, 'message' => $msg], 200) : redirect()->back()->with('info', $msg);
}
@@ -1592,6 +1626,9 @@ class StudentController extends BaseController
$scoreField = $this->studentDecisionScoreField();
$select = 'sd.id AS decision_id, sd.student_id, sd.class_section_name, sd.decision, students.firstname, students.lastname, students.gender, students.age, students.dob';
if ($this->db->fieldExists('deliberation_decision_standard', 'student_decisions')) {
$select .= ', sd.deliberation_decision_standard';
}
if ($scoreField !== null) {
$select .= ', sd.' . $scoreField . ' AS year_score';
}
@@ -1616,13 +1653,15 @@ class StudentController extends BaseController
continue;
}
$seen[$studentId] = true;
if (DeliberationDecision::normalize($row['decision'] ?? null) !== DeliberationDecision::PASSED) {
$normalizedDecision = $this->normalizedDecisionFromRow($row);
if ($normalizedDecision !== DeliberationDecision::PASSED
&& $normalizedDecision !== DeliberationDecision::REPEAT_CLASS) {
continue;
}
$targetClassId = $this->targetClassIdFromDecision(
(string)($row['class_section_name'] ?? ''),
(string)($row['decision'] ?? ''),
$normalizedDecision ?? (string)($row['decision'] ?? ''),
$targetSchoolYear
);
$ageAtReference = $this->distributionAgeAtReference($row['dob'] ?? null, $targetSchoolYear);
@@ -1760,8 +1799,13 @@ class StudentController extends BaseController
return $this->distributionExcludedDecisionCache[$previousSchoolYear];
}
$select = 'student_id, decision';
if ($this->db->fieldExists('deliberation_decision_standard', 'student_decisions')) {
$select .= ', deliberation_decision_standard';
}
$rows = $this->db->table('student_decisions')
->select('student_id, decision')
->select($select)
->where('school_year', $previousSchoolYear)
->orderBy('updated_at', 'DESC')
->orderBy('id', 'DESC')
@@ -1777,7 +1821,8 @@ class StudentController extends BaseController
}
$seen[$studentId] = true;
if ($this->isDistributionExcludedDecision((string)($row['decision'] ?? ''))) {
$normalizedDecision = $this->normalizedDecisionFromRow($row);
if ($normalizedDecision !== null && $this->isDistributionExcludedDecision($normalizedDecision)) {
$excluded[$studentId] = true;
}
}
@@ -1787,9 +1832,25 @@ class StudentController extends BaseController
return $excluded;
}
private function normalizedDecisionFromRow(array $row): ?string
{
return DeliberationDecision::normalize($row['deliberation_decision_standard'] ?? null)
?? DeliberationDecision::normalize($row['decision'] ?? null);
}
private function isDistributionExcludedDecision(string $decision): bool
{
return DeliberationDecision::normalize($decision) !== DeliberationDecision::PASSED;
$normalized = DeliberationDecision::normalize($decision);
if ($normalized === null) {
return true;
}
return in_array($normalized, [
DeliberationDecision::EXPELLED,
DeliberationDecision::WITHDRAWN,
DeliberationDecision::DEFERRED_DECISION,
DeliberationDecision::MAKE_UP_EXAM,
], true);
}
private function distributionPreviousClassSectionName(int $studentId, string $targetSchoolYear, ?string $sourceSchoolYear = null): string