add grading, attendnace management
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Attendance;
|
||||
|
||||
use App\Http\Controllers\Api\Core\BaseApiController;
|
||||
use App\Models\Configuration;
|
||||
use App\Models\EarlyDismissalSignature;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class EarlyDismissalsController extends BaseApiController
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/v1/attendance/early-dismissals
|
||||
* Returns early dismissal records grouped by report_date, plus a signature map.
|
||||
*/
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$schoolYear = $request->query('school_year');
|
||||
$semester = $request->query('semester');
|
||||
|
||||
$query = DB::table('parent_attendance_reports as par')
|
||||
->select([
|
||||
'par.id',
|
||||
'par.report_date',
|
||||
'par.dismiss_time',
|
||||
'par.reason',
|
||||
'par.status',
|
||||
'par.school_year',
|
||||
'par.semester',
|
||||
'par.class_section_id',
|
||||
's.firstname',
|
||||
's.lastname',
|
||||
'cs.class_section_name',
|
||||
])
|
||||
->join('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')
|
||||
->orderBy('par.report_date', 'desc')
|
||||
->orderByRaw("CONCAT(s.firstname, ' ', s.lastname) ASC");
|
||||
|
||||
if ($schoolYear) {
|
||||
$query->where('par.school_year', $schoolYear);
|
||||
}
|
||||
if ($semester) {
|
||||
$query->where('par.semester', $semester);
|
||||
}
|
||||
|
||||
$rows = $query->get();
|
||||
|
||||
$groups = [];
|
||||
foreach ($rows as $row) {
|
||||
$date = $row->report_date ?? 'Unknown';
|
||||
$groups[$date][] = [
|
||||
'id' => $row->id,
|
||||
'firstname' => $row->firstname,
|
||||
'lastname' => $row->lastname,
|
||||
'class_section_name' => $row->class_section_name,
|
||||
'dismiss_time' => $row->dismiss_time,
|
||||
'reason' => $row->reason,
|
||||
'status' => $row->status,
|
||||
'school_year' => $row->school_year,
|
||||
'semester' => $row->semester,
|
||||
];
|
||||
}
|
||||
|
||||
$dates = array_keys($groups);
|
||||
$signatures = EarlyDismissalSignature::query()
|
||||
->whereIn('report_date', $dates)
|
||||
->get(['report_date', 'filename', 'original_name']);
|
||||
|
||||
$signatureByDate = [];
|
||||
foreach ($signatures as $sig) {
|
||||
$signatureByDate[(string) $sig->report_date] = [
|
||||
'filename' => $sig->filename,
|
||||
'original_name' => $sig->original_name,
|
||||
];
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'groups' => $groups,
|
||||
'signatureByDate' => $signatureByDate,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/v1/attendance/early-dismissals/student-options
|
||||
* Returns active students with their current class section.
|
||||
*/
|
||||
public function studentOptions(): JsonResponse
|
||||
{
|
||||
$students = DB::table('students as s')
|
||||
->select([
|
||||
's.id',
|
||||
's.firstname',
|
||||
's.lastname',
|
||||
'cs.class_section_name',
|
||||
])
|
||||
->leftJoin('student_class as sc', function ($j) {
|
||||
$j->on('sc.student_id', '=', 's.id')
|
||||
->where('sc.school_year', '=', Configuration::getConfigValueByKey('school_year'));
|
||||
})
|
||||
->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'sc.class_section_id')
|
||||
->where('s.is_active', 1)
|
||||
->orderByRaw("CONCAT(s.firstname, ' ', s.lastname) ASC")
|
||||
->get();
|
||||
|
||||
return $this->success(['students' => $students]);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/v1/attendance/early-dismissals
|
||||
* Creates a new early dismissal record.
|
||||
*/
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'student_id' => ['required', 'integer', 'min:1', 'exists:students,id'],
|
||||
'date' => ['required', 'date_format:Y-m-d'],
|
||||
'dismiss_time' => ['required', 'date_format:H:i'],
|
||||
'reason' => ['nullable', 'string', 'max:2000'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidationError($validator->errors()->toArray());
|
||||
}
|
||||
|
||||
$data = $validator->validated();
|
||||
|
||||
$schoolYear = (string) Configuration::getConfigValueByKey('school_year');
|
||||
$semester = (string) Configuration::getConfigValueByKey('semester');
|
||||
|
||||
$sc = DB::table('student_class')
|
||||
->where('student_id', $data['student_id'])
|
||||
->where('school_year', $schoolYear)
|
||||
->orderBy('id')
|
||||
->first();
|
||||
|
||||
$classSectionId = $sc?->class_section_id ?? null;
|
||||
|
||||
$parentId = DB::table('students')
|
||||
->where('id', $data['student_id'])
|
||||
->value('parent_id') ?? Auth::id();
|
||||
|
||||
DB::table('parent_attendance_reports')->insert([
|
||||
'parent_id' => $parentId ?? Auth::id(),
|
||||
'student_id' => $data['student_id'],
|
||||
'class_section_id' => $classSectionId,
|
||||
'report_date' => $data['date'],
|
||||
'type' => 'early_dismissal',
|
||||
'dismiss_time' => $data['dismiss_time'],
|
||||
'reason' => $data['reason'] ?? null,
|
||||
'semester' => $semester,
|
||||
'school_year' => $schoolYear,
|
||||
'status' => 'new',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
return $this->success([], 'Early dismissal saved.', Response::HTTP_CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/v1/attendance/early-dismissals/signature
|
||||
* Uploads (or replaces) the signature file for a report date.
|
||||
*/
|
||||
public function uploadSignature(Request $request): JsonResponse
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'report_date' => ['required', 'date_format:Y-m-d'],
|
||||
'school_year' => ['nullable', 'string', 'max:16'],
|
||||
'semester' => ['nullable', 'string', 'max:32'],
|
||||
'signature_file' => ['required', 'file', 'mimes:jpg,jpeg,png,webp,gif,pdf', 'max:5120'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidationError($validator->errors()->toArray());
|
||||
}
|
||||
|
||||
$file = $request->file('signature_file');
|
||||
$reportDate = $request->input('report_date');
|
||||
$schoolYear = $request->input('school_year') ?: (string) Configuration::getConfigValueByKey('school_year');
|
||||
$semester = $request->input('semester') ?: (string) Configuration::getConfigValueByKey('semester');
|
||||
|
||||
$dir = storage_path('uploads/early_dismissal_signatures');
|
||||
if (!is_dir($dir)) {
|
||||
mkdir($dir, 0755, true);
|
||||
}
|
||||
|
||||
$existing = EarlyDismissalSignature::query()
|
||||
->where('report_date', $reportDate)
|
||||
->where('school_year', $schoolYear)
|
||||
->where('semester', $semester)
|
||||
->first();
|
||||
|
||||
if ($existing?->filename && file_exists($dir . '/' . $existing->filename)) {
|
||||
unlink($dir . '/' . $existing->filename);
|
||||
}
|
||||
|
||||
$filename = uniqid('sig_', true) . '.' . $file->getClientOriginalExtension();
|
||||
$file->move($dir, $filename);
|
||||
|
||||
EarlyDismissalSignature::updateOrCreate(
|
||||
['report_date' => $reportDate, 'school_year' => $schoolYear, 'semester' => $semester],
|
||||
[
|
||||
'filename' => $filename,
|
||||
'original_name' => $file->getClientOriginalName(),
|
||||
'mime_type' => $file->getClientMimeType(),
|
||||
'file_size' => $file->getSize(),
|
||||
'uploaded_by' => Auth::id(),
|
||||
]
|
||||
);
|
||||
|
||||
return $this->success(['filename' => $filename], 'Signature uploaded.');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user