fix enrollment, invoice, payment and financila aid
This commit is contained in:
@@ -116,15 +116,31 @@ final class EnrollmentRegistrationEmailService
|
||||
foreach ($this->recipientFamilies($schoolYear, null) as $family) {
|
||||
$message = $this->buildMessage($schoolYear, $family);
|
||||
$latest = $this->latestEmailRecord($schoolYearName, (int) $family['parent_user_id']);
|
||||
$previousYear = $this->previousSchoolYearName($schoolYearName);
|
||||
$studentSummaries = [];
|
||||
|
||||
foreach ($family['students'] as $student) {
|
||||
$studentId = (int) ($student['id'] ?? 0);
|
||||
$evaluation = $studentId > 0 && $previousYear !== null
|
||||
? $this->transitionService->evaluateForParent(
|
||||
(int) $family['parent_user_id'],
|
||||
$studentId,
|
||||
$previousYear,
|
||||
$schoolYearName
|
||||
)
|
||||
: [];
|
||||
$studentSummaries[] = [
|
||||
'name' => trim((string) ($student['firstname'] ?? '') . ' ' . (string) ($student['lastname'] ?? '')) ?: 'Student #' . $studentId,
|
||||
'adult_student' => ! empty($evaluation['adult_student']),
|
||||
];
|
||||
}
|
||||
|
||||
$examples[] = [
|
||||
'parent_user_id' => (int) $family['parent_user_id'],
|
||||
'parent_name' => (string) $family['name'],
|
||||
'recipients' => $message['recipients'],
|
||||
'student_names' => array_map(
|
||||
static fn (array $student): string => trim((string) ($student['firstname'] ?? '') . ' ' . (string) ($student['lastname'] ?? '')) ?: 'Student #' . (int) ($student['id'] ?? 0),
|
||||
$family['students']
|
||||
),
|
||||
'students' => $studentSummaries,
|
||||
'student_names' => array_column($studentSummaries, 'name'),
|
||||
'subject' => (string) $message['subject'],
|
||||
'delivery_status' => (string) ($latest['delivery_status'] ?? 'not sent'),
|
||||
'sent_at' => $latest['sent_at'] ?? null,
|
||||
@@ -161,10 +177,15 @@ final class EnrollmentRegistrationEmailService
|
||||
continue;
|
||||
}
|
||||
|
||||
$evaluation = $this->transitionService->evaluate($studentId, $previousYear, $schoolYearName, 'parent');
|
||||
$evaluation = $this->transitionService->evaluateForParent(
|
||||
(int) $family['parent_user_id'],
|
||||
$studentId,
|
||||
$previousYear,
|
||||
$schoolYearName
|
||||
);
|
||||
$studentRows[] = $this->studentRow($student, $evaluation, $opens, $deadline, $schoolYear);
|
||||
$studentIds[] = $studentId;
|
||||
$hasReEnrollmentEligibleStudent = $hasReEnrollmentEligibleStudent || $this->canCompleteParentReEnrollment($evaluation);
|
||||
$hasReEnrollmentEligibleStudent = $hasReEnrollmentEligibleStudent || (bool) ($evaluation['can_enroll'] ?? false);
|
||||
}
|
||||
|
||||
$financial = $this->financialSection((int) $family['parent_user_id'], $schoolYear, $previousYear);
|
||||
@@ -192,7 +213,7 @@ final class EnrollmentRegistrationEmailService
|
||||
|
||||
private function canCompleteParentReEnrollment(array $evaluation): bool
|
||||
{
|
||||
return (bool) ($evaluation['parent_enrollment_allowed'] ?? false);
|
||||
return (bool) ($evaluation['can_enroll'] ?? false);
|
||||
}
|
||||
|
||||
private function registrationStepsSection(string $opens, string $deadline, bool $include): string
|
||||
@@ -227,7 +248,7 @@ final class EnrollmentRegistrationEmailService
|
||||
$requiredAction = $this->requiredAction($evaluation, $deadline, $name);
|
||||
$message = $this->decisionMessage($name, $evaluation, $opens, $deadline, $schoolYear);
|
||||
$nextStepHtml = $this->decisionMessageHtml($message, (string) ($evaluation['deliberation_decision'] ?? ''));
|
||||
if ($requiredAction !== '') {
|
||||
if ($this->shouldAppendRequiredAction($message, $requiredAction)) {
|
||||
$nextStepHtml .= '<br><strong>' . esc($requiredAction) . '</strong>';
|
||||
}
|
||||
|
||||
@@ -239,7 +260,7 @@ final class EnrollmentRegistrationEmailService
|
||||
. '</td>'
|
||||
. '</tr>'
|
||||
. $this->studentDetailRow('Decision', esc($decision ?: 'Pending'))
|
||||
. $this->studentDetailRow('Registration Status', '<strong>' . esc($status) . '</strong><br>' . esc($placement))
|
||||
. $this->studentDetailRow('Registration Status', '<strong>' . esc($status) . '</strong>' . ($placement !== '' ? '<br>' . esc($placement) : ''))
|
||||
. $this->studentDetailRow('Next Step', $nextStepHtml)
|
||||
. '</tbody></table>';
|
||||
}
|
||||
@@ -272,14 +293,15 @@ final class EnrollmentRegistrationEmailService
|
||||
|
||||
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);
|
||||
|
||||
return $name . ' has successfully passed ' . $grade . '.';
|
||||
if (($evaluation['can_enroll'] ?? false) === false && ! empty($evaluation['primary_parent_message'])) {
|
||||
return (string) $evaluation['primary_parent_message'];
|
||||
}
|
||||
|
||||
if (($evaluation['blockers'] ?? []) !== []) {
|
||||
return implode(' ', array_map('strval', $evaluation['blockers']));
|
||||
return implode(' ', array_values(array_unique(array_filter(array_map(
|
||||
static fn ($blocker): string => trim((string) $blocker),
|
||||
$evaluation['blockers']
|
||||
)))));
|
||||
}
|
||||
|
||||
return match ((string) ($evaluation['deliberation_decision'] ?? '')) {
|
||||
@@ -318,11 +340,13 @@ final class EnrollmentRegistrationEmailService
|
||||
|
||||
private function financialSection(int $parentId, array $schoolYear, ?string $previousYear): string
|
||||
{
|
||||
$carry = $previousYear !== null ? $this->invoiceBalance($parentId, $previousYear) : 0.0;
|
||||
$registrationFee = (float) ($schoolYear['registration_fee'] ?? 0);
|
||||
$tuition = (float) ($schoolYear['tuition_due_at_registration'] ?? 0);
|
||||
$mandatory = (float) ($schoolYear['mandatory_fees'] ?? 0);
|
||||
$total = max(0, $carry) + $registrationFee + $tuition + $mandatory;
|
||||
$schoolYearName = (string) ($schoolYear['name'] ?? '');
|
||||
$summary = $this->transitionService->getEnrollmentFinancialSummary(
|
||||
$parentId,
|
||||
$previousYear ?? '',
|
||||
$schoolYearName
|
||||
);
|
||||
$total = (float) ($summary['total_enrollment_due'] ?? $summary['amount_due'] ?? 0);
|
||||
if ($total <= 0.0) {
|
||||
return '';
|
||||
}
|
||||
@@ -333,7 +357,7 @@ final class EnrollmentRegistrationEmailService
|
||||
}
|
||||
|
||||
return '<h3>Family Account Information</h3>'
|
||||
. '<p><strong>Carry-over balance:</strong> $' . number_format($carry, 2) . '<br>'
|
||||
. '<p><strong>Carry-over balance:</strong> $' . number_format((float) ($summary['carry_forward_balance'] ?? 0), 2) . '<br>'
|
||||
. '<strong>Total currently due:</strong> $' . number_format($total, 2) . '</p>'
|
||||
. '<p>' . esc($message) . '</p>';
|
||||
}
|
||||
@@ -488,40 +512,73 @@ final class EnrollmentRegistrationEmailService
|
||||
|
||||
private function registrationStatus(array $evaluation): string
|
||||
{
|
||||
if ((string) ($evaluation['deliberation_decision'] ?? '') === DeliberationDecision::PASSED) {
|
||||
return 'Eligible';
|
||||
if (($evaluation['can_enroll'] ?? false) === true) {
|
||||
return ($evaluation['deliberation_decision'] ?? '') === DeliberationDecision::MAKE_UP_EXAM
|
||||
? 'Eligible with pending placement'
|
||||
: 'Eligible';
|
||||
}
|
||||
|
||||
if (! empty($evaluation['adult_student'])) {
|
||||
return 'Not Eligible';
|
||||
}
|
||||
|
||||
if (($evaluation['blockers'] ?? []) !== []) {
|
||||
return ($evaluation['adult_student'] ?? false) ? 'Student Action Required' : 'Not Eligible';
|
||||
return 'Not Eligible';
|
||||
}
|
||||
return ($evaluation['deliberation_decision'] ?? '') === DeliberationDecision::MAKE_UP_EXAM ? 'Eligible with pending placement' : 'Eligible';
|
||||
|
||||
return 'Not Eligible';
|
||||
}
|
||||
|
||||
private function placementText(array $evaluation): string
|
||||
{
|
||||
return match ((string) ($evaluation['placement_status'] ?? '')) {
|
||||
$placement = match ((string) ($evaluation['placement_status'] ?? '')) {
|
||||
'automatic_distribution_pending' => $this->assignedGradeText($evaluation),
|
||||
'same_class_assigned' => 'Same grade and class',
|
||||
'temporary_same_grade' => 'Same grade initially',
|
||||
'manual_class_required' => 'Same grade',
|
||||
'exit_required' => 'Completion or exit process required',
|
||||
default => 'Pending',
|
||||
default => '',
|
||||
};
|
||||
|
||||
if ($placement !== '') {
|
||||
return $placement;
|
||||
}
|
||||
|
||||
return ($evaluation['can_enroll'] ?? false) === true ? 'Pending' : '';
|
||||
}
|
||||
|
||||
private function requiredAction(array $evaluation, string $deadline, string $name = 'The student'): string
|
||||
{
|
||||
if ((string) ($evaluation['deliberation_decision'] ?? '') === DeliberationDecision::PASSED) {
|
||||
return 'Complete re-enrollment before ' . $deadline . '.';
|
||||
if (($evaluation['can_enroll'] ?? false) === true) {
|
||||
return ($evaluation['deliberation_decision'] ?? '') === DeliberationDecision::MAKE_UP_EXAM
|
||||
? ''
|
||||
: 'Complete re-enrollment before ' . $deadline . '.';
|
||||
}
|
||||
|
||||
if (($evaluation['blockers'] ?? []) !== []) {
|
||||
return ($evaluation['adult_student'] ?? false) ? 'Student must complete the authorized adult-student process or contact administration.' : 'Contact the school administration.';
|
||||
if (! empty($evaluation['primary_parent_message'])) {
|
||||
return (string) $evaluation['primary_parent_message'];
|
||||
}
|
||||
return ($evaluation['deliberation_decision'] ?? '') === DeliberationDecision::MAKE_UP_EXAM
|
||||
? ''
|
||||
: 'Complete re-enrollment before ' . $deadline . '.';
|
||||
|
||||
return 'Contact the school administration.';
|
||||
}
|
||||
|
||||
private function shouldAppendRequiredAction(string $message, string $requiredAction): bool
|
||||
{
|
||||
$message = trim($message);
|
||||
$requiredAction = trim($requiredAction);
|
||||
if ($requiredAction === '') {
|
||||
return false;
|
||||
}
|
||||
if ($message === '') {
|
||||
return true;
|
||||
}
|
||||
|
||||
$normalizedMessage = preg_replace('/\s+/', ' ', strtolower($message)) ?? $message;
|
||||
$normalizedAction = preg_replace('/\s+/', ' ', strtolower($requiredAction)) ?? $requiredAction;
|
||||
|
||||
return $normalizedMessage !== $normalizedAction
|
||||
&& ! str_contains($normalizedMessage, $normalizedAction)
|
||||
&& ! str_contains($normalizedAction, $normalizedMessage);
|
||||
}
|
||||
|
||||
private function previousSchoolYearName(string $schoolYear): ?string
|
||||
|
||||
Reference in New Issue
Block a user