Files
alrahma_sunday_school_api/app/Services/Incidents/CurrentIncidentService.php
T
2026-06-11 11:46:12 -04:00

232 lines
8.0 KiB
PHP

<?php
namespace App\Services\Incidents;
use App\Models\Configuration;
use App\Models\CurrentIncident;
use App\Models\Incident;
use App\Models\Student;
use App\Models\StudentClass;
use Illuminate\Support\Facades\DB;
class CurrentIncidentService
{
public function __construct(private IncidentLookupService $lookup) {}
public function listCurrent(): array
{
$incidents = CurrentIncident::query()->get()->map(fn ($row) => $row->toArray())->all();
$schoolYear = Configuration::getConfig('school_year');
$updaterIds = [];
foreach ($incidents as $incident) {
foreach (['updated_by_open', 'updated_by_closed', 'updated_by_canceled'] as $key) {
if (! empty($incident[$key])) {
$updaterIds[] = (int) $incident[$key];
}
}
}
$updaterMap = $this->lookup->updaterNameMap($updaterIds);
foreach ($incidents as &$incident) {
foreach (['updated_by_open', 'updated_by_closed', 'updated_by_canceled'] as $key) {
$id = (int) ($incident[$key] ?? 0);
$incident[$key.'_name'] = $id > 0 ? ($updaterMap[$id] ?? null) : null;
}
}
unset($incident);
return [
'incidents' => $incidents,
'grades' => $this->lookup->gradeOptionsWithActiveStudents($schoolYear),
];
}
public function studentsByGrade(int $gradeId): array
{
$studentIds = StudentClass::query()
->active()
->where('student_class.class_section_id', $gradeId)
->pluck('student_id')
->all();
if (empty($studentIds)) {
return [];
}
return Student::query()
->whereIn('id', $studentIds)
->where('is_active', 1)
->get()
->map(fn ($student) => [
'id' => (int) $student->id,
'name' => trim((string) $student->firstname.' '.(string) $student->lastname),
])
->all();
}
public function addIncident(array $payload, int $userId): array
{
$studentId = (int) $payload['student_id'];
$incidentType = (string) $payload['incident'];
$description = (string) ($payload['description'] ?? '');
$incidentState = (string) ($payload['incident_state'] ?? 'Open');
$stateDescription = (string) ($payload['state_description'] ?? '');
$grade = (string) $payload['grade'];
$student = Student::query()->find($studentId);
if (! $student) {
return [
'ok' => false,
'message' => 'Student not found.',
];
}
$semester = Configuration::getConfig('semester');
$schoolYear = Configuration::getConfig('school_year');
$currentDateTime = function_exists('utc_now') ? utc_now() : now('UTC')->toDateTimeString();
$existingIncident = CurrentIncident::query()
->where('student_id', $studentId)
->where('incident', $incidentType)
->first();
if ($existingIncident) {
$data = [
'incident_datetime' => $currentDateTime,
'updated_by_open' => $userId,
];
if ($incidentState === 'Closed') {
$data['incident_state'] = 'Closed';
$data['close_description'] = $this->appendLine($existingIncident->close_description ?? '', $stateDescription);
} elseif ($incidentState === 'Canceled') {
$data['incident_state'] = 'Canceled';
$data['cancel_description'] = $this->appendLine($existingIncident->cancel_description ?? '', $stateDescription);
} else {
$data['open_description'] = $this->appendLine($existingIncident->open_description ?? '', $description);
}
$existingIncident->fill($data);
$existingIncident->save();
return [
'ok' => true,
'created' => false,
'incident_id' => (int) $existingIncident->id,
];
}
$incident = CurrentIncident::query()->create([
'student_id' => $student->id,
'student_name' => trim((string) $student->firstname.' '.(string) $student->lastname),
'grade' => $grade,
'incident' => $incidentType,
'incident_datetime' => $currentDateTime,
'incident_state' => 'Open',
'updated_by_open' => $userId,
'open_description' => $description,
'semester' => $semester,
'school_year' => $schoolYear,
]);
return [
'ok' => true,
'created' => true,
'incident_id' => (int) $incident->id,
];
}
public function updateState(int $incidentId, string $newState): bool
{
return CurrentIncident::query()->whereKey($incidentId)->update([
'incident_state' => $newState,
]) > 0;
}
public function closeIncident(int $incidentId, string $closeDescription, ?string $actionTaken, int $userId): array
{
$incident = CurrentIncident::query()->find($incidentId);
if (! $incident) {
return ['ok' => false, 'message' => 'Incident not found.'];
}
if ($incident->incident_state === 'Closed') {
return ['ok' => false, 'message' => 'Incident is already closed.'];
}
$incident->fill([
'incident_state' => 'Closed',
'updated_by_closed' => $userId,
'close_description' => $closeDescription,
'action_taken' => $actionTaken,
]);
$incident->save();
return $this->moveToHistory($incident);
}
public function cancelIncident(int $incidentId, ?string $cancelDescription, ?string $actionTaken, int $userId): array
{
$incident = CurrentIncident::query()->find($incidentId);
if (! $incident) {
return ['ok' => false, 'message' => 'Incident not found.'];
}
if ($incident->incident_state === 'Canceled') {
return ['ok' => false, 'message' => 'Incident is already canceled.'];
}
$incident->fill([
'incident_state' => 'Canceled',
'updated_by_canceled' => $userId,
'cancel_description' => $cancelDescription,
'action_taken' => $actionTaken,
]);
$incident->save();
return $this->moveToHistory($incident);
}
private function moveToHistory(CurrentIncident $incident): array
{
return DB::transaction(function () use ($incident) {
$history = Incident::query()->create([
'student_id' => $incident->student_id,
'student_name' => $incident->student_name,
'grade' => $incident->grade,
'incident' => $incident->incident,
'incident_datetime' => $incident->incident_datetime,
'incident_state' => $incident->incident_state,
'updated_by_open' => $incident->updated_by_open,
'open_description' => $incident->open_description,
'updated_by_closed' => $incident->updated_by_closed,
'close_description' => $incident->close_description,
'action_taken' => $incident->action_taken,
'updated_by_canceled' => $incident->updated_by_canceled,
'cancel_description' => $incident->cancel_description,
'semester' => $incident->semester,
'school_year' => $incident->school_year,
'created_at' => $incident->created_at,
'updated_at' => $incident->updated_at,
]);
$incident->delete();
return [
'ok' => true,
'incident_id' => (int) $history->id,
];
});
}
private function appendLine(string $existing, string $append): string
{
if ($existing === '') {
return $append;
}
return $existing.PHP_EOL.$append;
}
}