245 lines
9.3 KiB
PHP
Executable File
245 lines
9.3 KiB
PHP
Executable File
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Models\Configuration;
|
|
use App\Models\Staff;
|
|
use App\Models\TeacherClass;
|
|
use App\Models\User;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class StaffController extends BaseApiController
|
|
{
|
|
protected Staff $staff;
|
|
protected User $user;
|
|
protected TeacherClass $teacherClass;
|
|
protected Configuration $config;
|
|
protected string $schoolYear;
|
|
protected string $semester;
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
$this->staff = model(Staff::class);
|
|
$this->user = model(User::class);
|
|
$this->teacherClass = model(TeacherClass::class);
|
|
$this->config = model(Configuration::class);
|
|
$this->schoolYear = (string) ($this->config->getConfig('school_year') ?? '');
|
|
$this->semester = (string) ($this->config->getConfig('semester') ?? '');
|
|
}
|
|
|
|
public function index()
|
|
{
|
|
$page = max(1, (int) ($this->request->getGet('page') ?? 1));
|
|
$perPage = min(100, max(1, (int) ($this->request->getGet('per_page') ?? 20)));
|
|
$role = $this->request->getGet('role');
|
|
|
|
// Roles we never show
|
|
$excludedRoles = ['student', 'parent', 'guest', 'inactive'];
|
|
$normalizedExcluded = array_map('strtolower', $excludedRoles);
|
|
|
|
$placeholders = implode(',', array_fill(0, count($normalizedExcluded), '?'));
|
|
|
|
$query = $this->staff->newQuery()
|
|
->whereRaw('LOWER(active_role) NOT IN (' . $placeholders . ')', $normalizedExcluded);
|
|
|
|
if (!empty($role)) {
|
|
$query->whereRaw('LOWER(active_role) = ?', [strtolower((string) $role)]);
|
|
}
|
|
|
|
$query->orderByDesc('created_at');
|
|
|
|
// Preload assignments for the selected school year (across all semesters)
|
|
$assignRows = DB::table('teacher_class as tc')
|
|
->select('tc.teacher_id', 'tc.position', 'cs.class_section_name')
|
|
->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'tc.class_section_id')
|
|
->where('tc.school_year', (string) $this->schoolYear)
|
|
->get()
|
|
->toArray();
|
|
|
|
$assignByTeacher = [];
|
|
foreach ($assignRows as $row) {
|
|
$teacherId = (int) ($row->teacher_id ?? 0);
|
|
if ($teacherId <= 0) {
|
|
continue;
|
|
}
|
|
$section = trim((string) ($row->class_section_name ?? ''));
|
|
if ($section === '') {
|
|
continue;
|
|
}
|
|
$position = strtolower((string) ($row->position ?? ''));
|
|
if (!in_array($position, ['main', 'ta'], true)) {
|
|
continue;
|
|
}
|
|
$assignByTeacher[$teacherId][] = $section . ' (' . $position . ')';
|
|
}
|
|
|
|
// Get all staff (not paginated) for issues count calculation
|
|
$allStaff = $query->get()->toArray();
|
|
$issuesCount = 0;
|
|
|
|
foreach ($allStaff as $staff) {
|
|
$roleName = strtolower((string) ($staff['active_role'] ?? ''));
|
|
if (in_array($roleName, ['teacher', 'teacher_assistant'], true)) {
|
|
$userId = (int) ($staff['user_id'] ?? 0);
|
|
$labels = $assignByTeacher[$userId] ?? [];
|
|
if (empty($labels)) {
|
|
$issuesCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Paginate the results
|
|
$result = $this->paginate($query, $page, $perPage);
|
|
|
|
// Apply transformations to paginated data
|
|
foreach ($result['data'] as &$staff) {
|
|
$userId = (int) ($staff['user_id'] ?? 0);
|
|
$staff['school_id'] = $userId > 0 ? $this->user->getSchoolIdByUserId($userId) : null;
|
|
|
|
$roleName = strtolower((string) ($staff['active_role'] ?? ''));
|
|
if (in_array($roleName, ['teacher', 'teacher_assistant'], true)) {
|
|
$labels = $assignByTeacher[$userId] ?? [];
|
|
if (!empty($labels)) {
|
|
$staff['class_section'] = implode(', ', array_unique($labels));
|
|
$staff['verification_issue'] = false;
|
|
} else {
|
|
$staff['class_section'] = 'No class assigned';
|
|
$staff['verification_issue'] = true;
|
|
}
|
|
} else {
|
|
$staff['class_section'] = '—';
|
|
$staff['verification_issue'] = false;
|
|
}
|
|
}
|
|
|
|
return $this->success([
|
|
'data' => $result['data'],
|
|
'pagination' => $result['pagination'],
|
|
'issues_count' => $issuesCount,
|
|
'semester' => $this->semester,
|
|
'school_year' => $this->schoolYear,
|
|
], 'Staff members retrieved successfully');
|
|
}
|
|
|
|
public function show($id = null)
|
|
{
|
|
$staff = $this->staff->find($id);
|
|
if (!$staff) {
|
|
return $this->respondError('Staff member not found', Response::HTTP_NOT_FOUND);
|
|
}
|
|
|
|
$staff['school_id'] = $this->user->getSchoolIdByUserId((int) ($staff['user_id'] ?? 0));
|
|
|
|
return $this->success($staff, 'Staff member retrieved successfully');
|
|
}
|
|
|
|
public function store()
|
|
{
|
|
$data = $this->payloadData();
|
|
if (empty($data)) {
|
|
return $this->respondError('Invalid request data', Response::HTTP_BAD_REQUEST);
|
|
}
|
|
|
|
$now = utc_now();
|
|
$payload = [
|
|
'firstname' => trim((string) ($data['firstname'] ?? '')),
|
|
'lastname' => trim((string) ($data['lastname'] ?? '')),
|
|
'email' => trim((string) ($data['email'] ?? '')),
|
|
'phone' => trim((string) ($data['phone'] ?? '')),
|
|
'role_name' => trim((string) ($data['role_name'] ?? '')),
|
|
'school_year' => trim((string) ($data['school_year'] ?? $this->schoolYear)),
|
|
'status' => trim((string) ($data['status'] ?? 'Active')),
|
|
'created_at' => $now,
|
|
'updated_at' => $now,
|
|
];
|
|
|
|
// Set active_role from role_name if provided
|
|
if (!empty($payload['role_name'])) {
|
|
$payload['active_role'] = strtolower($payload['role_name']);
|
|
}
|
|
|
|
try {
|
|
$inserted = $this->staff->insert($payload);
|
|
if (!$inserted) {
|
|
return $this->respondError('Failed to create staff member', Response::HTTP_INTERNAL_SERVER_ERROR);
|
|
}
|
|
|
|
// Fetch the created record
|
|
$staff = $this->staff->where('created_at', $now)->orderBy('id', 'DESC')->first();
|
|
return $this->success($staff, 'Staff member added successfully', Response::HTTP_CREATED);
|
|
} catch (\Throwable $e) {
|
|
\Illuminate\Support\Facades\Log::error('Staff creation error: ' . $e->getMessage());
|
|
return $this->respondError('Failed to create staff member', Response::HTTP_INTERNAL_SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
public function update($id = null)
|
|
{
|
|
$staff = $this->staff->find($id);
|
|
if (!$staff) {
|
|
return $this->respondError('Staff member not found', Response::HTTP_NOT_FOUND);
|
|
}
|
|
|
|
$data = $this->payloadData();
|
|
if (empty($data)) {
|
|
return $this->respondError('Invalid request data', Response::HTTP_BAD_REQUEST);
|
|
}
|
|
|
|
// Only update fields provided by the request to avoid wiping data
|
|
$updateData = [];
|
|
$allowedFields = ['firstname', 'lastname', 'email', 'phone', 'role_name', 'school_year', 'status'];
|
|
|
|
foreach ($allowedFields as $field) {
|
|
if (array_key_exists($field, $data)) {
|
|
$value = $data[$field];
|
|
if ($value !== null && $value !== '') {
|
|
$updateData[$field] = trim((string) $value);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set active_role from role_name if role_name is being updated
|
|
if (isset($updateData['role_name']) && !empty($updateData['role_name'])) {
|
|
$updateData['active_role'] = strtolower($updateData['role_name']);
|
|
}
|
|
|
|
// Always bump updated_at
|
|
$updateData['updated_at'] = utc_now();
|
|
|
|
if (empty($updateData)) {
|
|
return $this->respondError('No changes detected', Response::HTTP_BAD_REQUEST);
|
|
}
|
|
|
|
try {
|
|
$updated = $this->staff->update($id, $updateData);
|
|
if (!$updated) {
|
|
return $this->respondError('Failed to update staff member', Response::HTTP_INTERNAL_SERVER_ERROR);
|
|
}
|
|
|
|
$updatedStaff = $this->staff->find($id);
|
|
return $this->success($updatedStaff, 'Staff member updated successfully');
|
|
} catch (\Throwable $e) {
|
|
\Illuminate\Support\Facades\Log::error('Staff update error: ' . $e->getMessage());
|
|
return $this->respondError('Failed to update staff member', Response::HTTP_INTERNAL_SERVER_ERROR);
|
|
}
|
|
}
|
|
|
|
public function destroy($id = null)
|
|
{
|
|
$staff = $this->staff->find($id);
|
|
if (!$staff) {
|
|
return $this->respondError('Staff member not found', Response::HTTP_NOT_FOUND);
|
|
}
|
|
|
|
try {
|
|
$this->staff->delete($id);
|
|
return $this->respondDeleted(null, 'Staff member deleted successfully');
|
|
} catch (\Throwable $e) {
|
|
\Illuminate\Support\Facades\Log::error('Staff deletion error: ' . $e->getMessage());
|
|
return $this->respondError('Failed to delete staff member', Response::HTTP_INTERNAL_SERVER_ERROR);
|
|
}
|
|
}
|
|
}
|