182 lines
6.1 KiB
PHP
182 lines
6.1 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\LeaveApplication;
|
|
use App\Models\User;
|
|
use App\Services\EmployeeService;
|
|
use App\Services\LeaveService;
|
|
use Illuminate\Http\Request;
|
|
use Exception;
|
|
|
|
class LeaveApiController extends Controller
|
|
{
|
|
protected EmployeeService $employeeService;
|
|
protected LeaveService $leaveService;
|
|
|
|
public function __construct(EmployeeService $employeeService, LeaveService $leaveService)
|
|
{
|
|
$this->employeeService = $employeeService;
|
|
$this->leaveService = $leaveService;
|
|
}
|
|
|
|
public function balances(Request $request)
|
|
{
|
|
try {
|
|
$employee = $this->employeeService->resolveEmployee($request->user());
|
|
} catch (Exception $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'data' => [],
|
|
'message' => 'Employee profile not found',
|
|
'errors' => null,
|
|
], 403);
|
|
}
|
|
|
|
$balances = $this->leaveService->getBalances($employee);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => $balances,
|
|
'message' => null,
|
|
'errors' => null,
|
|
]);
|
|
}
|
|
|
|
public function applications(Request $request)
|
|
{
|
|
try {
|
|
$employee = $this->employeeService->resolveEmployee($request->user());
|
|
} catch (Exception $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'data' => [],
|
|
'message' => 'Employee profile not found',
|
|
'errors' => null,
|
|
], 403);
|
|
}
|
|
|
|
$applications = LeaveApplication::where('employee_id', $request->user()->id)
|
|
->orderBy('created_at', 'desc')
|
|
->get();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => $applications,
|
|
'message' => null,
|
|
'errors' => null,
|
|
]);
|
|
}
|
|
|
|
public function apply(Request $request)
|
|
{
|
|
$request->validate([
|
|
'leave_type' => 'nullable|string',
|
|
'leave_type_id' => 'nullable|integer',
|
|
'start_date' => 'required|date',
|
|
'end_date' => 'required|date|after_or_equal:start_date',
|
|
'reason' => 'required|string',
|
|
]);
|
|
|
|
try {
|
|
$employee = $this->employeeService->resolveEmployee($request->user());
|
|
} catch (Exception $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'data' => null,
|
|
'message' => 'Employee profile not found',
|
|
'errors' => null,
|
|
], 403);
|
|
}
|
|
|
|
$application = $this->leaveService->submitApplication($request->user(), $employee, $request->all());
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Leave application submitted successfully',
|
|
'data' => $application,
|
|
'errors' => null,
|
|
], 201);
|
|
}
|
|
|
|
public function updateStatus(Request $request, $id)
|
|
{
|
|
$request->validate([
|
|
'status' => 'required|string|in:approved,rejected,cancelled,pending',
|
|
]);
|
|
|
|
$user = $request->user();
|
|
$application = LeaveApplication::find($id);
|
|
|
|
if (!$application) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'data' => null,
|
|
'message' => 'Leave application not found',
|
|
'errors' => null,
|
|
], 404);
|
|
}
|
|
|
|
$employee = $this->employeeService->resolveEmployee($user);
|
|
|
|
// Scoping & authorization checks
|
|
if ($request->status === 'cancelled') {
|
|
$isOwner = in_array($application->employee_id, [$employee->id, $user->id]) || $application->created_by === $user->id;
|
|
if (!$isOwner && !in_array($user->type, ['company', 'hr', 'superadmin', 'manager'])) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'data' => null,
|
|
'message' => 'Unauthorized to cancel this leave application',
|
|
'errors' => null,
|
|
], 403);
|
|
}
|
|
} else {
|
|
// Approval or Rejection requires manager / HR role within same company tenant
|
|
$userType = strtolower($user->type ?? '');
|
|
$isElevatedRole = in_array($userType, ['company', 'hr', 'superadmin', 'manager']);
|
|
|
|
if (!$isElevatedRole) {
|
|
try {
|
|
$isElevatedRole = $user->hasAnyRole(['company', 'hr', 'superadmin', 'manager']);
|
|
} catch (\Throwable $e) {
|
|
$isElevatedRole = false;
|
|
}
|
|
}
|
|
|
|
$empUser = User::find($application->employee_id)
|
|
?? Employee::find($application->employee_id)?->user
|
|
?? User::find($application->created_by);
|
|
|
|
$appCompanyId = $empUser ? ($empUser->type === 'company' ? $empUser->id : ($empUser->created_by ?: $empUser->id)) : null;
|
|
$approverCompanyId = $user->type === 'company' ? $user->id : ($user->created_by ?: $user->id);
|
|
|
|
$isSuperAdmin = in_array($userType, ['superadmin']);
|
|
$isSameCompany = ($appCompanyId !== null && $approverCompanyId !== null && (int)$appCompanyId === (int)$approverCompanyId);
|
|
|
|
if (!$isElevatedRole || (!$isSameCompany && !$isSuperAdmin)) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'data' => null,
|
|
'message' => 'Unauthorized to review this leave application. Approval requires authorized manager or HR within the same organization.',
|
|
'errors' => null,
|
|
], 403);
|
|
}
|
|
}
|
|
|
|
$application->update(['status' => $request->status]);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Leave application status updated to ' . $request->status,
|
|
'data' => $application,
|
|
'errors' => null,
|
|
]);
|
|
}
|
|
|
|
public function cancel(Request $request, $id)
|
|
{
|
|
return $this->updateStatus($request->merge(['status' => 'cancelled']), $id);
|
|
}
|
|
}
|