227 lines
8.0 KiB
PHP
227 lines
8.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Administrator;
|
|
|
|
use App\Libraries\StaffTimeOffLinkService;
|
|
use App\Models\StaffAttendance;
|
|
use App\Models\User;
|
|
use App\Services\SemesterRangeService;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Mail;
|
|
|
|
class AdministratorAbsenceService
|
|
{
|
|
public function __construct(
|
|
protected AdministratorSharedService $shared,
|
|
protected User $userModel,
|
|
protected StaffAttendance $staffAttendanceModel,
|
|
protected SemesterRangeService $semesterRangeService,
|
|
protected StaffTimeOffLinkService $staffTimeOffLinkService,
|
|
) {
|
|
}
|
|
|
|
public function getAbsenceFormData(int $userId): array
|
|
{
|
|
$admin = $this->userModel->find($userId);
|
|
$displayName = $admin
|
|
? trim(($admin->firstname ?? '') . ' ' . ($admin->lastname ?? ''))
|
|
: 'Administrator';
|
|
|
|
$semester = $this->shared->getSemester();
|
|
$schoolYear = $this->shared->getSchoolYear();
|
|
|
|
$existing = $this->staffAttendanceModel
|
|
->where('user_id', $userId)
|
|
->where('semester', $semester)
|
|
->where('school_year', $schoolYear)
|
|
->orderByDesc('date')
|
|
->get()
|
|
->toArray();
|
|
|
|
return [
|
|
'admin_name' => $displayName,
|
|
'semester' => $semester,
|
|
'schoolYear' => $schoolYear,
|
|
'existing' => $existing,
|
|
'availableDates' => $this->shared->allowedAbsenceDates(),
|
|
];
|
|
}
|
|
|
|
public function submit(Request $request, int $userId): array
|
|
{
|
|
$semester = $this->shared->getSemester();
|
|
$schoolYear = $this->shared->getSchoolYear();
|
|
|
|
if ($schoolYear === '') {
|
|
return [
|
|
'success' => false,
|
|
'message' => 'Semester or school year not configured.',
|
|
'status' => 422,
|
|
];
|
|
}
|
|
|
|
$dates = (array) $request->input('dates', []);
|
|
$reasonType = trim((string) $request->input('reason_type', ''));
|
|
$reasonText = trim((string) $request->input('reason', ''));
|
|
|
|
if ($reasonText === '') {
|
|
return [
|
|
'success' => false,
|
|
'message' => 'Reason is required.',
|
|
'status' => 422,
|
|
];
|
|
}
|
|
|
|
$reasonBase = $reasonType !== '' ? strtolower($reasonType) : '';
|
|
$reason = $reasonBase !== '' ? ($reasonBase . ': ' . $reasonText) : $reasonText;
|
|
|
|
$allowedSet = array_fill_keys($this->shared->allowedAbsenceDates(), true);
|
|
|
|
$roleName = method_exists($this->userModel, 'getUserRole')
|
|
? ($this->userModel->getUserRole($userId) ?: null)
|
|
: null;
|
|
|
|
$saved = 0;
|
|
$invalid = [];
|
|
$savedDates = [];
|
|
|
|
$dates = array_values(array_unique(array_map('strval', $dates)));
|
|
|
|
foreach ($dates as $d) {
|
|
$d = trim($d);
|
|
if ($d === '') {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
$parsed = \Carbon\Carbon::createFromFormat('Y-m-d', $d);
|
|
if ($parsed->format('Y-m-d') !== $d || empty($allowedSet[$d])) {
|
|
$invalid[] = $d;
|
|
continue;
|
|
}
|
|
} catch (\Throwable) {
|
|
$invalid[] = $d;
|
|
continue;
|
|
}
|
|
|
|
$semesterForDate = $this->semesterRangeService->getSemesterForDate($d);
|
|
if ($semesterForDate === '') {
|
|
$semesterForDate = $semester;
|
|
}
|
|
|
|
$ok = $this->staffAttendanceModel->upsertOne(
|
|
userId: $userId,
|
|
roleName: $roleName,
|
|
date: $d,
|
|
semester: $semesterForDate,
|
|
schoolYear: $schoolYear,
|
|
status: StaffAttendance::STATUS_ABSENT,
|
|
reason: $reason,
|
|
editorId: $userId
|
|
);
|
|
|
|
if ($ok) {
|
|
$saved++;
|
|
$savedDates[] = $d;
|
|
}
|
|
}
|
|
|
|
if (!empty($invalid)) {
|
|
return [
|
|
'success' => false,
|
|
'message' => 'Invalid dates: ' . implode(', ', $invalid),
|
|
'status' => 422,
|
|
];
|
|
}
|
|
|
|
$this->sendPrincipalNotification(
|
|
userId: $userId,
|
|
roleName: $roleName,
|
|
semester: $semester,
|
|
schoolYear: $schoolYear,
|
|
reasonType: $reasonType,
|
|
reasonText: $reasonText,
|
|
dates: $dates,
|
|
savedDates: $savedDates
|
|
);
|
|
|
|
return [
|
|
'success' => true,
|
|
'message' => $saved . ' day(s) saved as absent.',
|
|
'saved' => $saved,
|
|
'dates' => $savedDates,
|
|
'status' => 200,
|
|
];
|
|
}
|
|
|
|
protected function sendPrincipalNotification(
|
|
int $userId,
|
|
?string $roleName,
|
|
string $semester,
|
|
string $schoolYear,
|
|
string $reasonType,
|
|
string $reasonText,
|
|
array $dates,
|
|
array $savedDates
|
|
): void {
|
|
try {
|
|
$user = $this->userModel->find($userId);
|
|
$fullName = trim(($user->firstname ?? '') . ' ' . ($user->lastname ?? '')) ?: 'Administrator';
|
|
$userEmail = $user->email ?? '';
|
|
$role = $roleName ?: 'admin';
|
|
$dateList = !empty($savedDates) ? implode(', ', $savedDates) : implode(', ', $dates);
|
|
|
|
$subject = sprintf(
|
|
'TimeOff Request: %s (%s) — %s',
|
|
$fullName,
|
|
ucfirst((string) $role),
|
|
$dateList ?: 'No dates'
|
|
);
|
|
|
|
$submittedAt = now()->toDateTimeString();
|
|
|
|
$body = '<div style="font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:1.5;">'
|
|
. '<h3 style="margin:0 0 8px;">New TimeOff Request</h3>'
|
|
. '<p style="margin:0 0 12px;">A staff time-off request was submitted from the administrator portal.</p>'
|
|
. '<table cellpadding="6" cellspacing="0" style="border-collapse:collapse;">'
|
|
. '<tr><td><strong>Name</strong></td><td>' . e($fullName) . '</td></tr>'
|
|
. '<tr><td><strong>Email</strong></td><td>' . e($userEmail) . '</td></tr>'
|
|
. '<tr><td><strong>Role</strong></td><td>' . e((string) $role) . '</td></tr>'
|
|
. '<tr><td><strong>Semester</strong></td><td>' . e($semester) . '</td></tr>'
|
|
. '<tr><td><strong>School Year</strong></td><td>' . e($schoolYear) . '</td></tr>'
|
|
. '<tr><td><strong>Reason Type</strong></td><td>' . e($reasonType ?: '-') . '</td></tr>'
|
|
. '<tr><td><strong>Reason</strong></td><td>' . e($reasonText) . '</td></tr>'
|
|
. '<tr><td><strong>Dates</strong></td><td>' . e($dateList ?: '-') . '</td></tr>'
|
|
. '<tr><td><strong>Submitted At</strong></td><td>' . e($submittedAt) . '</td></tr>'
|
|
. '</table>'
|
|
. '</div>';
|
|
|
|
$token = $this->staffTimeOffLinkService->createToken([
|
|
'uid' => $userId,
|
|
'email' => $userEmail,
|
|
'name' => $fullName,
|
|
'role' => $role,
|
|
'dates' => $dateList ?: '-',
|
|
'reason' => $reasonText,
|
|
'reason_type' => $reasonType,
|
|
'submitted_at' => $submittedAt,
|
|
'origin' => 'administrator portal',
|
|
]);
|
|
|
|
$notifyUrl = url('/timeoff/notify/' . rawurlencode($token));
|
|
|
|
$body .= '<p style="margin-top:16px;">Click <a href="' . e($notifyUrl) . '">Send confirmation email to '
|
|
. e($fullName)
|
|
. '</a> so the staff member is notified automatically. This link expires in 14 days.</p>';
|
|
|
|
$principalEmail = env('PRINCIPAL_EMAIL', 'principal@alrahmaisgl.org');
|
|
|
|
Mail::html($body, function ($message) use ($principalEmail, $subject) {
|
|
$message->to($principalEmail)->subject($subject);
|
|
});
|
|
} catch (\Throwable $e) {
|
|
Log::error('Failed to send TimeOff email (admin): ' . $e->getMessage());
|
|
}
|
|
}
|
|
} |