update controllers logic
This commit is contained in:
@@ -4,10 +4,12 @@ namespace App\Services\Parents;
|
||||
|
||||
use App\Models\AttendanceData;
|
||||
use App\Models\AttendanceRecord;
|
||||
use App\Models\EarlyDismissalSignature;
|
||||
use App\Models\ParentAttendanceReport;
|
||||
use App\Models\Student;
|
||||
use App\Models\ClassSection;
|
||||
use App\Services\SemesterRangeService;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ParentAttendanceReportService
|
||||
@@ -254,12 +256,12 @@ class ParentAttendanceReportService
|
||||
];
|
||||
}
|
||||
|
||||
public function listReports(string $start, ?string $end, ?string $schoolYear, ?string $semester): array
|
||||
public function listReports(string $start, ?string $end, ?string $schoolYear, ?string $semester, int $parentId): array
|
||||
{
|
||||
return ParentAttendanceReport::listForDateRange($start, $end, $schoolYear, $semester);
|
||||
return ParentAttendanceReport::listForDateRange($start, $end, $schoolYear, $semester, $parentId);
|
||||
}
|
||||
|
||||
public function checkExisting(array $payload): array
|
||||
public function checkExisting(int $parentId, array $payload): array
|
||||
{
|
||||
$datesPost = $payload['dates'] ?? null;
|
||||
$dateSingle = $payload['date'] ?? null;
|
||||
@@ -286,6 +288,15 @@ class ParentAttendanceReportService
|
||||
return [];
|
||||
}
|
||||
|
||||
$uniqueIds = array_values(array_unique($studentIds));
|
||||
$ownedCount = Student::query()
|
||||
->where('parent_id', $parentId)
|
||||
->whereIn('id', $uniqueIds)
|
||||
->count();
|
||||
if ($ownedCount !== count($uniqueIds)) {
|
||||
throw new \RuntimeException('Invalid student selection.');
|
||||
}
|
||||
|
||||
$rows = DB::table('parent_attendance_reports as par')
|
||||
->select('par.student_id', 'par.type', 'par.report_date', 's.firstname', 's.lastname')
|
||||
->leftJoin('students as s', 's.id', '=', 'par.student_id')
|
||||
@@ -371,6 +382,275 @@ class ParentAttendanceReportService
|
||||
$row->update($update);
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff index: early dismissal rows grouped by date (+ signature metadata per date).
|
||||
*
|
||||
* Parity with CodeIgniter {@see \App\Controllers\View\ParentAttendanceReportController::earlyDismissals}.
|
||||
*
|
||||
* @return array{groups: array<string, array<int, array<string, mixed>>>, school_year: string, semester: string, signature_by_date: array<string, array<string, mixed>>}
|
||||
*/
|
||||
public function staffEarlyDismissalsIndex(?string $schoolYearParam, ?string $semesterParam): array
|
||||
{
|
||||
$context = $this->configService->context();
|
||||
$schoolYear = filled($schoolYearParam) ? trim((string) $schoolYearParam) : (string) ($context['school_year'] ?? '');
|
||||
$semester = filled($semesterParam) ? trim((string) $semesterParam) : '';
|
||||
|
||||
$b = DB::table('parent_attendance_reports as par')
|
||||
->select('par.*', 's.firstname', 's.lastname', 'cs.class_section_name')
|
||||
->leftJoin('students as s', 's.id', '=', 'par.student_id')
|
||||
->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'par.class_section_id')
|
||||
->where('par.type', '=', 'early_dismissal');
|
||||
|
||||
if ($schoolYear !== '') {
|
||||
$b->where('par.school_year', $schoolYear);
|
||||
}
|
||||
if ($semester !== '') {
|
||||
$b->where('par.semester', $semester);
|
||||
}
|
||||
|
||||
$rows = $b->orderByDesc('par.report_date')
|
||||
->orderBy('par.dismiss_time')
|
||||
->get()
|
||||
->map(fn ($r) => (array) $r)
|
||||
->all();
|
||||
|
||||
$groups = [];
|
||||
foreach ($rows as $r) {
|
||||
$d = substr((string) ($r['report_date'] ?? ''), 0, 10);
|
||||
if ($d === '') {
|
||||
$d = 'Unknown';
|
||||
}
|
||||
$groups[$d][] = $r;
|
||||
}
|
||||
uksort($groups, static function ($a, $b) {
|
||||
if ($a === 'Unknown' && $b === 'Unknown') {
|
||||
return 0;
|
||||
}
|
||||
if ($a === 'Unknown') {
|
||||
return 1;
|
||||
}
|
||||
if ($b === 'Unknown') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return strcmp((string) $b, (string) $a);
|
||||
});
|
||||
|
||||
$signatureByDate = [];
|
||||
$dates = array_values(array_filter(array_keys($groups), static function ($d) {
|
||||
return preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) $d) === 1;
|
||||
}));
|
||||
if ($dates !== []) {
|
||||
$sigQ = EarlyDismissalSignature::query()->whereIn('report_date', $dates);
|
||||
if ($schoolYear !== '') {
|
||||
$sigQ->where('school_year', $schoolYear);
|
||||
}
|
||||
if ($semester !== '') {
|
||||
$sigQ->where('semester', $semester);
|
||||
}
|
||||
foreach ($sigQ->orderBy('report_date')->get() as $sig) {
|
||||
$d = $sig->report_date instanceof \DateTimeInterface
|
||||
? $sig->report_date->format('Y-m-d')
|
||||
: substr((string) $sig->report_date, 0, 10);
|
||||
if ($d !== '') {
|
||||
$signatureByDate[$d] = $sig->toArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'groups' => $groups,
|
||||
'school_year' => $schoolYear,
|
||||
'semester' => $semester,
|
||||
'signature_by_date' => $signatureByDate,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parity with CodeIgniter {@see \App\Controllers\View\ParentAttendanceReportController::addEarlyDismissalForm}.
|
||||
*
|
||||
* @return array{students: array<int, array<string, mixed>>, default_date: string, school_year: string, semester: string}
|
||||
*/
|
||||
public function staffAddEarlyDismissalFormData(): array
|
||||
{
|
||||
$context = $this->configService->context();
|
||||
$schoolYear = (string) ($context['school_year'] ?? '');
|
||||
$semester = (string) ($context['semester'] ?? '');
|
||||
|
||||
try {
|
||||
$students = DB::table('students as s')
|
||||
->select('s.id', 's.firstname', 's.lastname', 's.parent_id', 'cs.class_section_name', 'sc.class_section_id')
|
||||
->leftJoin('student_class as sc', function ($join) use ($schoolYear) {
|
||||
$join->on('sc.student_id', '=', 's.id')
|
||||
->where('sc.school_year', '=', $schoolYear);
|
||||
})
|
||||
->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'sc.class_section_id')
|
||||
->orderBy('s.lastname')
|
||||
->orderBy('s.firstname')
|
||||
->get()
|
||||
->map(fn ($r) => (array) $r)
|
||||
->all();
|
||||
} catch (\Throwable) {
|
||||
$students = [];
|
||||
}
|
||||
|
||||
[, $defaultDate] = $this->calendarService->computeSundays(0, 26);
|
||||
|
||||
return [
|
||||
'students' => $students,
|
||||
'default_date' => $defaultDate,
|
||||
'school_year' => $schoolYear,
|
||||
'semester' => $semester,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parity with CodeIgniter {@see \App\Controllers\View\ParentAttendanceReportController::saveEarlyDismissal}.
|
||||
*/
|
||||
public function saveStaffEarlyDismissal(int $studentId, string $reportDate, string $dismissTime, string $reason): void
|
||||
{
|
||||
$context = $this->configService->context();
|
||||
$schoolYear = (string) ($context['school_year'] ?? '');
|
||||
$semester = (string) ($context['semester'] ?? '');
|
||||
|
||||
$dt = \DateTime::createFromFormat('Y-m-d', $reportDate);
|
||||
if (! $dt || (int) $dt->format('w') !== 0) {
|
||||
throw new \RuntimeException('Please select a Sunday date.');
|
||||
}
|
||||
|
||||
$stu = Student::query()->select('id', 'parent_id', 'firstname', 'lastname')->find($studentId);
|
||||
if (! $stu || empty($stu->parent_id)) {
|
||||
throw new \RuntimeException('Selected student not found or has no primary parent assigned.');
|
||||
}
|
||||
$parentId = (int) $stu->parent_id;
|
||||
|
||||
$sectionRow = DB::table('student_class')
|
||||
->select('class_section_id')
|
||||
->where('student_id', $studentId)
|
||||
->where('school_year', $schoolYear)
|
||||
->orderByDesc('updated_at')
|
||||
->first();
|
||||
|
||||
$classSectionId = $sectionRow ? (int) $sectionRow->class_section_id : null;
|
||||
|
||||
$qb = ParentAttendanceReport::query()
|
||||
->where('student_id', $studentId)
|
||||
->whereDate('report_date', $reportDate)
|
||||
->where('school_year', $schoolYear);
|
||||
|
||||
$existingAl = (clone $qb)->where(function ($q) {
|
||||
$q->where('type', 'absent')->orWhere('type', 'late');
|
||||
})->first();
|
||||
|
||||
if ($existingAl) {
|
||||
throw new \RuntimeException('Absent/Late already submitted for this student on the selected date.');
|
||||
}
|
||||
|
||||
$existingEd = (clone $qb)->where('type', 'early_dismissal')->first();
|
||||
|
||||
if ($existingEd) {
|
||||
$existingEd->update([
|
||||
'dismiss_time' => $dismissTime !== '' ? $dismissTime : $existingEd->dismiss_time,
|
||||
'reason' => $reason !== '' ? $reason : $existingEd->reason,
|
||||
'status' => 'new',
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ParentAttendanceReport::query()->create([
|
||||
'parent_id' => $parentId,
|
||||
'student_id' => $studentId,
|
||||
'class_section_id' => $classSectionId,
|
||||
'report_date' => $reportDate,
|
||||
'type' => 'early_dismissal',
|
||||
'dismiss_time' => $dismissTime,
|
||||
'reason' => $reason !== '' ? $reason : null,
|
||||
'semester' => $semester,
|
||||
'school_year' => $schoolYear,
|
||||
'status' => 'new',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parity with CodeIgniter {@see \App\Controllers\View\ParentAttendanceReportController::uploadEarlyDismissalSignature}.
|
||||
* Files live under {@see storage_path('uploads/early_dismissal_signatures')} (same as {@see \App\Http\Controllers\Api\Reports\FilesController::earlyDismissalSignature}).
|
||||
*/
|
||||
public function storeEarlyDismissalSignature(
|
||||
UploadedFile $file,
|
||||
string $reportDate,
|
||||
?string $schoolYearPost,
|
||||
?string $semesterPost,
|
||||
int $uploadedByUserId,
|
||||
): void {
|
||||
$dt = \DateTime::createFromFormat('Y-m-d', $reportDate);
|
||||
if (! $dt || (int) $dt->format('w') !== 0) {
|
||||
throw new \RuntimeException('Please select a Sunday date.');
|
||||
}
|
||||
|
||||
$context = $this->configService->context();
|
||||
$schoolYear = $schoolYearPost !== null && $schoolYearPost !== ''
|
||||
? (string) $schoolYearPost
|
||||
: (string) ($context['school_year'] ?? '');
|
||||
$semesterRaw = (string) ($semesterPost ?? '');
|
||||
$hasSemesterFilter = $semesterRaw !== '';
|
||||
$semester = $hasSemesterFilter ? $semesterRaw : null;
|
||||
|
||||
$existsQ = ParentAttendanceReport::query()
|
||||
->where('type', 'early_dismissal')
|
||||
->whereDate('report_date', $reportDate);
|
||||
if ($schoolYear !== '') {
|
||||
$existsQ->where('school_year', $schoolYear);
|
||||
}
|
||||
if ($hasSemesterFilter) {
|
||||
$existsQ->where('semester', $semester);
|
||||
}
|
||||
if (! $existsQ->exists()) {
|
||||
throw new \RuntimeException('No early dismissal records found for that date.');
|
||||
}
|
||||
|
||||
$targetDir = storage_path('uploads/early_dismissal_signatures');
|
||||
if (! is_dir($targetDir) && ! @mkdir($targetDir, 0755, true) && ! is_dir($targetDir)) {
|
||||
throw new \RuntimeException('Upload directory is not available.');
|
||||
}
|
||||
|
||||
$originalName = $file->getClientOriginalName();
|
||||
$mimeType = $file->getClientMimeType();
|
||||
$fileSize = (int) $file->getSize();
|
||||
$filename = $file->hashName();
|
||||
$file->move($targetDir, $filename);
|
||||
|
||||
$payload = [
|
||||
'report_date' => $reportDate,
|
||||
'school_year' => $schoolYear !== '' ? $schoolYear : null,
|
||||
'semester' => $semester,
|
||||
'filename' => $filename,
|
||||
'original_name' => $originalName,
|
||||
'mime_type' => $mimeType,
|
||||
'file_size' => $fileSize,
|
||||
'uploaded_by' => $uploadedByUserId,
|
||||
];
|
||||
|
||||
$existingQ = EarlyDismissalSignature::query()->whereDate('report_date', $reportDate);
|
||||
if ($schoolYear !== '') {
|
||||
$existingQ->where('school_year', $schoolYear);
|
||||
}
|
||||
if ($hasSemesterFilter) {
|
||||
$existingQ->where('semester', $semester);
|
||||
}
|
||||
$existing = $existingQ->first();
|
||||
|
||||
if ($existing) {
|
||||
$oldFile = (string) ($existing->filename ?? '');
|
||||
$existing->update($payload);
|
||||
if ($oldFile !== '' && $oldFile !== $filename) {
|
||||
@unlink($targetDir . DIRECTORY_SEPARATOR . $oldFile);
|
||||
}
|
||||
} else {
|
||||
EarlyDismissalSignature::query()->create($payload);
|
||||
}
|
||||
}
|
||||
|
||||
private function resolveClassSectionLabel(?int $classSectionId): string
|
||||
{
|
||||
$cid = (int) ($classSectionId ?? 0);
|
||||
|
||||
Reference in New Issue
Block a user