fix enrollment and registration email send
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-28 16:16:59 -04:00
parent 3133b3c584
commit d2cb159451
6 changed files with 118 additions and 73 deletions
@@ -11,6 +11,7 @@ use DateTimeInterface;
final class EnrollmentRegistrationEmailService
{
public const TEMPLATE_VERSION = 'phase5_consolidated_v3';
private const SEND_DELAY_SECONDS = 2;
public function __construct(
private readonly BaseConnection $db,
@@ -50,7 +51,7 @@ final class EnrollmentRegistrationEmailService
return $summary;
}
public function sendForSchoolYear(array $schoolYear, ?string $testEmail = null, bool $dryRun = false, bool $force = false): array
public function sendForSchoolYear(array $schoolYear, ?string $testEmail = null, bool $dryRun = false, bool $force = false, bool $failedOnly = false): array
{
$summary = ['recipients' => 0, 'sent' => 0, 'failed' => 0, 'skipped' => 0, 'messages' => []];
if (! $dryRun && empty($schoolYear['registration_launch_approved_at'])) {
@@ -65,12 +66,28 @@ final class EnrollmentRegistrationEmailService
return $summary;
}
$failedParentIds = $failedOnly ? $this->failedParentIdsForSchoolYear((string) $schoolYear['name']) : null;
if ($failedOnly && $failedParentIds === []) {
$summary['messages'][] = 'No failed registration emails found for ' . (string) ($schoolYear['name'] ?? '') . '.';
return $summary;
}
$sentAttempted = false;
foreach ($families as $family) {
if ($testEmail === null && ! $force && $this->alreadySent((string) $schoolYear['name'], (int) $family['parent_user_id'])) {
if ($failedParentIds !== null && ! in_array((int) $family['parent_user_id'], $failedParentIds, true)) {
$summary['skipped']++;
continue;
}
if ($failedParentIds === null && $testEmail === null && ! $force && $this->alreadySent((string) $schoolYear['name'], (int) $family['parent_user_id'])) {
$summary['skipped']++;
continue;
}
if ($sentAttempted && ! $dryRun) {
sleep(self::SEND_DELAY_SECONDS);
}
$message = $this->buildMessage($schoolYear, $family);
if ($testEmail !== null) {
$message['subject'] = '[TEST] ' . $message['subject'];
@@ -85,6 +102,8 @@ final class EnrollmentRegistrationEmailService
if (! $dryRun && $recordId !== null) {
$this->recordDelivery($recordId, $sent, $sent ? null : 'Email send failed');
}
$sentAttempted = true;
}
return $summary;
@@ -153,14 +172,14 @@ final class EnrollmentRegistrationEmailService
return $examples;
}
public function sendForSchoolYearName(string $schoolYearName, bool $force = false): array
public function sendForSchoolYearName(string $schoolYearName, bool $force = false, bool $failedOnly = false): array
{
$schoolYear = $this->schoolYearByName($schoolYearName);
if ($schoolYear === null) {
return ['recipients' => 0, 'sent' => 0, 'failed' => 0, 'skipped' => 1, 'messages' => ['School year was not found.']];
}
return $this->sendForSchoolYear($schoolYear, null, false, $force);
return $this->sendForSchoolYear($schoolYear, null, false, $force, $failedOnly);
}
private function buildMessage(array $schoolYear, array $family): array
@@ -478,6 +497,39 @@ final class EnrollmentRegistrationEmailService
->countAllResults() > 0;
}
/**
* @return list<int>
*/
private function failedParentIdsForSchoolYear(string $schoolYear): array
{
if (! $this->db->tableExists('enrollment_email_records')) {
return [];
}
$rows = $this->db->table('enrollment_email_records')
->select('parent_user_id, delivery_status')
->where('school_year', $schoolYear)
->orderBy('created_at', 'DESC')
->orderBy('id', 'DESC')
->get()
->getResultArray();
$latestByParent = [];
foreach ($rows as $row) {
$parentId = (int) ($row['parent_user_id'] ?? 0);
if ($parentId <= 0 || array_key_exists($parentId, $latestByParent)) {
continue;
}
$latestByParent[$parentId] = (string) ($row['delivery_status'] ?? '');
}
return array_values(array_map(
'intval',
array_keys(array_filter($latestByParent, static fn (string $status): bool => $status === 'failed'))
));
}
private function latestEmailRecord(string $schoolYear, int $parentId): ?array
{
if (! $this->db->tableExists('enrollment_email_records')) {