diff --git a/app/Services/EnrollmentRegistrationEmailService.php b/app/Services/EnrollmentRegistrationEmailService.php
index a3467f6..feb16dd 100644
--- a/app/Services/EnrollmentRegistrationEmailService.php
+++ b/app/Services/EnrollmentRegistrationEmailService.php
@@ -162,7 +162,7 @@ final class EnrollmentRegistrationEmailService
}
$evaluation = $this->transitionService->evaluate($studentId, $previousYear, $schoolYearName, 'parent');
- $studentRows[] = $this->studentRow($student, $evaluation, $opens, $deadline);
+ $studentRows[] = $this->studentRow($student, $evaluation, $opens, $deadline, $schoolYear);
$studentIds[] = $studentId;
$hasReEnrollmentEligibleStudent = $hasReEnrollmentEligibleStudent || $this->canCompleteParentReEnrollment($evaluation);
}
@@ -218,14 +218,14 @@ final class EnrollmentRegistrationEmailService
. '';
}
- private function studentRow(array $student, array $evaluation, string $opens, string $deadline): string
+ private function studentRow(array $student, array $evaluation, string $opens, string $deadline, array $schoolYear = []): string
{
$name = trim((string) ($student['firstname'] ?? '') . ' ' . (string) ($student['lastname'] ?? '')) ?: 'Student';
$decision = DeliberationDecision::display((string) ($evaluation['deliberation_decision'] ?? ''));
$status = $this->registrationStatus($evaluation);
$placement = $this->placementText($evaluation);
$requiredAction = $this->requiredAction($evaluation, $deadline, $name);
- $message = $this->decisionMessage($name, $evaluation, $opens, $deadline);
+ $message = $this->decisionMessage($name, $evaluation, $opens, $deadline, $schoolYear);
$nextStepHtml = $this->decisionMessageHtml($message, (string) ($evaluation['deliberation_decision'] ?? ''));
if ($requiredAction !== '') {
$nextStepHtml .= '
' . esc($requiredAction) . '';
@@ -270,7 +270,7 @@ final class EnrollmentRegistrationEmailService
return implode('
', $lines);
}
- private function decisionMessage(string $name, array $evaluation, string $opens, string $deadline): string
+ private function decisionMessage(string $name, array $evaluation, string $opens, string $deadline, array $schoolYear = []): string
{
if ((string) ($evaluation['deliberation_decision'] ?? '') === DeliberationDecision::PASSED) {
$grade = $this->currentGradeText($evaluation);
@@ -284,16 +284,26 @@ final class EnrollmentRegistrationEmailService
return match ((string) ($evaluation['deliberation_decision'] ?? '')) {
DeliberationDecision::REPEAT_CLASS => 'The deliberation decision for ' . $name . ' is to repeat the current grade. After re-enrollment is completed, the student will remain in the same grade.',
- DeliberationDecision::MAKE_UP_EXAM => 'The final academic decision for ' . $name . ' is currently pending the result of a make-up exam. This exam is scheduled for ' . $this->makeupExamDateText() . ' from 9:30 AM to 11:00 AM at ISGL.'
+ DeliberationDecision::MAKE_UP_EXAM => 'The final academic decision for ' . $name . ' is currently pending the result of a make-up exam. This exam is scheduled for ' . $this->makeupExamDateText($schoolYear) . ' from 9:30 AM to 11:00 AM at ISGL.'
. "\n" . 'The exam result will determine whether the student advances to the next grade or repeats the current class. Failure to attend the make-up exam will automatically result in the student repeating the class, as no further retake opportunities will be available.'
. "\n" . 'You must re-enroll ' . $name . ' before the make-up exam can be taken.',
default => 'Please review the registration portal for the current enrollment status.',
};
}
- private function makeupExamDateText(): string
+ private function makeupExamDateText(array $schoolYear = []): string
{
- $raw = trim((string) (($this->configurationModel ?? new ConfigurationModel())->getConfig('make-up-exam') ?? ''));
+ $raw = trim((string) ($schoolYear['fall_makeup_exam_on'] ?? ''));
+ if ($raw === '') {
+ $configModel = $this->configurationModel ?? new ConfigurationModel();
+ foreach (['make-up-exam', 'make_up_exam', 'makeup_exam_day'] as $key) {
+ $raw = trim((string) ($configModel->getConfig($key) ?? ''));
+ if ($raw !== '') {
+ break;
+ }
+ }
+ }
+
if ($raw === '') {
return 'a date to be announced';
}
diff --git a/tests/app/Services/EnrollmentRegistrationEmailServiceTest.php b/tests/app/Services/EnrollmentRegistrationEmailServiceTest.php
index ba6895c..8453727 100644
--- a/tests/app/Services/EnrollmentRegistrationEmailServiceTest.php
+++ b/tests/app/Services/EnrollmentRegistrationEmailServiceTest.php
@@ -85,6 +85,44 @@ final class EnrollmentRegistrationEmailServiceTest extends TestCase
$this->assertSame('', $action);
}
+ public function testMakeupExamDecisionMessageUsesSchoolYearDateBeforeConfig(): void
+ {
+ $configModel = $this->createMock(ConfigurationModel::class);
+ $configModel->expects($this->never())->method('getConfig');
+
+ $service = $this->service(configModel: $configModel);
+
+ $message = $this->invoke($service, 'decisionMessage', ['Student Name', [
+ 'deliberation_decision' => DeliberationDecision::MAKE_UP_EXAM,
+ 'blockers' => [],
+ ], 'August 1, 2026', 'August 31, 2026', [
+ 'fall_makeup_exam_on' => '2026-09-13',
+ ]]);
+
+ $this->assertStringContainsString('This exam is scheduled for 09-13-2026 from 9:30 AM to 11:00 AM at ISGL.', $message);
+ $this->assertStringNotContainsString('a date to be announced', $message);
+ }
+
+ public function testMakeupExamDecisionMessageFallsBackToSyncedConfigKeys(): void
+ {
+ $configModel = $this->createMock(ConfigurationModel::class);
+ $configModel->expects($this->exactly(2))
+ ->method('getConfig')
+ ->willReturnMap([
+ ['make-up-exam', ''],
+ ['make_up_exam', '2026-09-13'],
+ ]);
+
+ $service = $this->service(configModel: $configModel);
+
+ $message = $this->invoke($service, 'decisionMessage', ['Student Name', [
+ 'deliberation_decision' => DeliberationDecision::MAKE_UP_EXAM,
+ 'blockers' => [],
+ ], 'August 1, 2026', 'August 31, 2026']);
+
+ $this->assertStringContainsString('This exam is scheduled for 09-13-2026 from 9:30 AM to 11:00 AM at ISGL.', $message);
+ }
+
public function testMakeupExamStudentRowRendersMessageLineBreaks(): void
{
$configModel = $this->createMock(ConfigurationModel::class);