Files
root e0dfc3ec82
API CI/CD / Validate (composer + pint) (push) Successful in 3m15s
API CI/CD / Test (PHPUnit) (push) Failing after 5m4s
API CI/CD / Build frontend assets (push) Successful in 1m3s
API CI/CD / Security audit (push) Failing after 49s
API CI/CD / Deploy to shared hosting (PHP) (push) Has been skipped
Fixed many feature failures around preferences, route coverage, administrator enrollment, assignment section names, attendance tracking controller access, finance PDF generation, and finance notification logging.
2026-07-07 21:26:47 -04:00

186 lines
6.1 KiB
PHP

<?php
namespace App\Services\AttendanceTracking;
use App\Http\Controllers\Api\AttendanceTracking\AttendanceTrackingController;
use App\Models\Configuration;
use Carbon\Carbon;
use Illuminate\Support\Facades\Validator;
/**
* Facade used by {@see AttendanceTrackingController}.
*/
class AttendanceTrackingService
{
protected AttendancePendingViolationService $pendingViolationService;
protected AttendanceCaseQueryService $caseQueryService;
protected AttendanceNotificationWorkflowService $workflowService;
protected AttendanceCommunicationSupportService $communicationSupportService;
public function __construct(
?AttendancePendingViolationService $pendingViolationService = null,
?AttendanceCaseQueryService $caseQueryService = null,
?AttendanceNotificationWorkflowService $workflowService = null,
?AttendanceCommunicationSupportService $communicationSupportService = null,
) {
$this->pendingViolationService = $pendingViolationService ?? app(AttendancePendingViolationService::class);
$this->caseQueryService = $caseQueryService ?? app(AttendanceCaseQueryService::class);
$this->workflowService = $workflowService ?? app(AttendanceNotificationWorkflowService::class);
$this->communicationSupportService = $communicationSupportService ?? app(AttendanceCommunicationSupportService::class);
}
protected function defaultSchoolYear(): string
{
return (string) (Configuration::getConfig('school_year') ?? '');
}
protected function defaultSemester(): string
{
return (string) (Configuration::getConfig('semester') ?? '');
}
public function getPendingViolations(?string $schoolYearParam, ?string $semesterParam): array
{
return $this->pendingViolationService->getPendingViolations(
$this->defaultSchoolYear(),
$schoolYearParam,
$semesterParam
);
}
public function getNotifiedViolations(?string $schoolYearParam, ?string $semesterParam): array
{
return $this->caseQueryService->getNotifiedViolations(
$schoolYearParam,
$semesterParam,
$this->defaultSchoolYear(),
$this->defaultSemester()
);
}
public function getStudentCase(
int $studentId,
?string $codeParam,
?string $incidentDate,
bool $includeNotified,
bool $pendingOnly,
?string $schoolYearFilter,
?string $semesterFilter,
): array {
return $this->caseQueryService->getStudentCase(
$studentId,
$codeParam,
$incidentDate,
$includeNotified,
$pendingOnly,
$schoolYearFilter,
$semesterFilter,
$this->defaultSchoolYear(),
$this->defaultSemester()
);
}
public function record(array $data): array
{
return $this->workflowService->record($data);
}
/**
* legacy POST attendance/send-auto-emails — runs auto_email actions on current pending violations.
*/
public function sendAutoEmails(mixed $variantInput): array
{
$variant = is_string($variantInput) ? $variantInput : null;
$pending = $this->getPendingViolations(null, null);
$violations = $pending['students'] ?? [];
return $this->workflowService->sendAutoEmails($violations, $variant);
}
public function compose(int $studentId, string $code, string $variant, ?string $incidentDate): array
{
return $this->communicationSupportService->compose($studentId, $code, $variant, $incidentDate);
}
public function parentsInfo(int $studentId): array
{
return $this->communicationSupportService->parentsInfo($studentId);
}
public function sendEmailManual(array $data): array
{
$studentId = (int) ($data['student_id'] ?? 0);
$code = (string) ($data['code'] ?? '');
$incidentRaw = $data['incident_date'] ?? null;
$incidentDate = $incidentRaw !== null && $incidentRaw !== ''
? substr((string) $incidentRaw, 0, 10)
: null;
$violationDates = $this->communicationSupportService->getViolationDatesForStudent(
$studentId,
$code,
$incidentDate
);
return $this->workflowService->sendEmailManual($data, $violationDates);
}
public function saveNotificationNote(array $data): array
{
return $this->workflowService->saveNotificationNote($data);
}
/**
* legacy route referenced {@see View\AttendanceTrackingController::notify_parent} was never implemented in legacy;
* this matches the attendance notification modal (student_id, to, subject, message, subject_type, date).
*/
public function notifyParent(array $input): array
{
$validator = Validator::make($input, [
'student_id' => ['required', 'integer', 'min:1'],
'to' => ['required', 'email'],
'subject' => ['required', 'string'],
'message' => ['required', 'string'],
'subject_type' => ['nullable', 'string'],
'date' => ['nullable', 'date'],
]);
if ($validator->fails()) {
return [
'success' => false,
'message' => 'Validation failed.',
'errors' => $validator->errors(),
'status' => 422,
];
}
$data = $validator->validated();
$subjectType = strtolower((string) ($data['subject_type'] ?? 'absent'));
$code = str_contains($subjectType, 'late') ? 'LATE_1' : 'ABS_1';
$ymd = null;
if (! empty($data['date'])) {
try {
$ymd = Carbon::parse((string) $data['date'])->format('Y-m-d');
} catch (\Throwable) {
$ymd = null;
}
}
return $this->sendEmailManual([
'student_id' => (int) $data['student_id'],
'to' => (string) $data['to'],
'subject' => (string) $data['subject'],
'body_html' => (string) $data['message'],
'code' => $code,
'variant' => 'default',
'incident_date' => $ymd,
]);
}
}