refactor: implement strict role-based access control and scoped data visibility for finance and HR operations
This commit is contained in:
parent
36124c6535
commit
1de9d32136
@ -30,8 +30,8 @@ public function index(Request $request): Response
|
||||
$user = $request->user();
|
||||
|
||||
return Inertia::render('admin/finance/employee-advances/Index', [
|
||||
'employeeAdvances' => $this->employeeAdvanceService->paginateForIndex($tableQuery),
|
||||
'summary' => $this->employeeAdvanceService->outstandingSummary(),
|
||||
'employeeAdvances' => $this->employeeAdvanceService->paginateForIndex($tableQuery, $user),
|
||||
'summary' => $this->employeeAdvanceService->outstandingSummary($user),
|
||||
'authEmployeeId' => $user?->employee?->id,
|
||||
'canSubmit' => $user?->can(Permission::EMPLOYEE_ADVANCES_CREATE->value)
|
||||
&& ! $user->can(Permission::EMPLOYEE_ADVANCES_VERIFY->value)
|
||||
@ -71,7 +71,12 @@ public function destroy(EmployeeAdvance $employeeAdvance): RedirectResponse
|
||||
|
||||
public function approve(EmployeeAdvance $employeeAdvance): RedirectResponse
|
||||
{
|
||||
$this->employeeAdvanceService->approve($employeeAdvance, auth()->user());
|
||||
$user = auth()->user();
|
||||
if ($user && ! $user->hasAnyRole(['owner', 'developer', 'direktur'])) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$this->employeeAdvanceService->approve($employeeAdvance, $user);
|
||||
|
||||
$this->flashSuccess('Kasbon berhasil disetujui dan dicairkan dari kas.');
|
||||
|
||||
@ -80,10 +85,15 @@ public function approve(EmployeeAdvance $employeeAdvance): RedirectResponse
|
||||
|
||||
public function reject(RejectEmployeeAdvanceRequest $request, EmployeeAdvance $employeeAdvance): RedirectResponse
|
||||
{
|
||||
$user = auth()->user();
|
||||
if ($user && ! $user->hasAnyRole(['owner', 'developer', 'direktur'])) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$this->employeeAdvanceService->reject(
|
||||
$employeeAdvance,
|
||||
$request->validated('reason'),
|
||||
auth()->user(),
|
||||
$user,
|
||||
);
|
||||
|
||||
$this->flashSuccess('Kasbon berhasil ditolak.');
|
||||
@ -93,7 +103,12 @@ public function reject(RejectEmployeeAdvanceRequest $request, EmployeeAdvance $e
|
||||
|
||||
public function pay(EmployeeAdvance $employeeAdvance): RedirectResponse
|
||||
{
|
||||
$this->employeeAdvanceService->pay($employeeAdvance, auth()->user());
|
||||
$user = auth()->user();
|
||||
if ($user && ! $user->hasAnyRole(['owner', 'developer', 'direktur'])) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$this->employeeAdvanceService->pay($employeeAdvance, $user);
|
||||
|
||||
$this->flashSuccess('Kasbon berhasil dilunasi.');
|
||||
|
||||
|
||||
@ -20,10 +20,15 @@ public function __construct(
|
||||
|
||||
public function storeAdjustment(PayrollAdjustmentRequest $request, Payroll $payroll): RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
if ($user && ! $user->hasAnyRole(['owner', 'developer', 'direktur'])) {
|
||||
abort(403, 'Anda tidak memiliki akses untuk menambah penyesuaian gaji.');
|
||||
}
|
||||
|
||||
$this->payrollService->addAdjustment(
|
||||
$payroll,
|
||||
$request->validated(),
|
||||
$request->user(),
|
||||
$user,
|
||||
);
|
||||
|
||||
$this->flashSuccess('Penyesuaian gaji berhasil ditambahkan.');
|
||||
@ -35,10 +40,15 @@ public function storeAdjustment(PayrollAdjustmentRequest $request, Payroll $payr
|
||||
|
||||
public function updateAdjustment(PayrollAdjustmentRequest $request, PayrollAdjustment $payrollAdjustment): RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
if ($user && ! $user->hasAnyRole(['owner', 'developer', 'direktur'])) {
|
||||
abort(403, 'Anda tidak memiliki akses untuk mengubah penyesuaian gaji.');
|
||||
}
|
||||
|
||||
$this->payrollService->updateAdjustment(
|
||||
$payrollAdjustment,
|
||||
$request->validated(),
|
||||
$request->user(),
|
||||
$user,
|
||||
);
|
||||
|
||||
$this->flashSuccess('Penyesuaian gaji berhasil diperbarui.');
|
||||
@ -50,6 +60,11 @@ public function updateAdjustment(PayrollAdjustmentRequest $request, PayrollAdjus
|
||||
|
||||
public function destroyAdjustment(PayrollAdjustment $payrollAdjustment): RedirectResponse
|
||||
{
|
||||
$user = auth()->user();
|
||||
if ($user && ! $user->hasAnyRole(['owner', 'developer', 'direktur'])) {
|
||||
abort(403, 'Anda tidak memiliki akses untuk menghapus penyesuaian gaji.');
|
||||
}
|
||||
|
||||
$payroll = $payrollAdjustment->payroll;
|
||||
|
||||
$this->payrollService->deleteAdjustment($payrollAdjustment);
|
||||
|
||||
@ -25,15 +25,16 @@ public function index(Request $request): Response
|
||||
$tableQuery = $this->parseDataTableQuery($request);
|
||||
$periodId = $request->integer('period_id') ?: null;
|
||||
$period = $this->payrollService->resolvePeriod($periodId);
|
||||
$user = $request->user();
|
||||
|
||||
return Inertia::render('admin/finance/payroll/Index', [
|
||||
'periods' => $this->payrollService->listPeriods(),
|
||||
'currentPeriod' => $period,
|
||||
'payrolls' => $period
|
||||
? $this->payrollService->paginateForPeriod($period, $tableQuery)
|
||||
? $this->payrollService->paginateForPeriod($period, $tableQuery, $user)
|
||||
: null,
|
||||
'summary' => $period
|
||||
? $this->payrollService->periodSummary($period)
|
||||
? $this->payrollService->periodSummary($period, $user)
|
||||
: null,
|
||||
'adjustmentTypes' => PayrollAdjustmentType::selectOptions(),
|
||||
'filters' => array_merge(
|
||||
|
||||
@ -26,10 +26,10 @@ public function index(Request $request): Response
|
||||
{
|
||||
$user = $request->user();
|
||||
$employee = $user?->employee;
|
||||
$canManageAll = $user?->can(Permission::ATTENDANCES_MANAGE->value) ?? false;
|
||||
$isManager = $user?->hasAnyRole(['owner', 'developer', 'direktur']) ?? false;
|
||||
|
||||
$scopedEmployeeId = $canManageAll ? null : $employee?->id;
|
||||
$hasScopedAccess = $canManageAll || $employee !== null;
|
||||
$scopedEmployeeId = $isManager ? null : $employee?->id;
|
||||
$hasScopedAccess = $isManager || $employee !== null;
|
||||
|
||||
$start = $request->date('start') ?? now()->startOfMonth();
|
||||
$end = $request->date('end') ?? now()->endOfMonth();
|
||||
@ -46,7 +46,7 @@ public function index(Request $request): Response
|
||||
: null,
|
||||
'canCheckIn' => ($user?->can(Permission::ATTENDANCES_CREATE->value) ?? false)
|
||||
&& $employee !== null,
|
||||
'canManageAll' => $canManageAll,
|
||||
'canManageAll' => $isManager,
|
||||
'calendarRange' => [
|
||||
'start' => $start->toDateString(),
|
||||
'end' => $end->toDateString(),
|
||||
@ -74,6 +74,13 @@ public function checkOut(AttendanceCheckOutRequest $request): RedirectResponse
|
||||
|
||||
public function destroy(Attendance $attendance): RedirectResponse
|
||||
{
|
||||
$user = auth()->user();
|
||||
if ($user && ! $user->hasAnyRole(['owner', 'developer', 'direktur'])) {
|
||||
if ($attendance->employee_id !== $user->employee?->id) {
|
||||
abort(403, 'Anda tidak memiliki akses untuk menghapus data presensi ini.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->attendanceService->delete($attendance);
|
||||
|
||||
$this->flashDeleted('Data presensi');
|
||||
|
||||
@ -39,7 +39,7 @@ public function index(Request $request): Response
|
||||
}
|
||||
|
||||
return Inertia::render('admin/hr/leave-requests/Index', [
|
||||
'leaveRequests' => $this->leaveRequestService->paginateForIndex($tableQuery),
|
||||
'leaveRequests' => $this->leaveRequestService->paginateForIndex($tableQuery, $user),
|
||||
'authEmployeeId' => $user?->employee?->id,
|
||||
'canSubmit' => $user?->can(Permission::LEAVE_REQUESTS_CREATE->value)
|
||||
&& ! $user->can(Permission::LEAVE_REQUESTS_VERIFY->value)
|
||||
@ -80,7 +80,12 @@ public function destroy(LeaveRequest $leaveRequest): RedirectResponse
|
||||
|
||||
public function approve(LeaveRequest $leaveRequest): RedirectResponse
|
||||
{
|
||||
$this->leaveRequestService->approve($leaveRequest, auth()->user());
|
||||
$user = auth()->user();
|
||||
if ($user && ! $user->hasAnyRole(['owner', 'developer', 'direktur'])) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$this->leaveRequestService->approve($leaveRequest, $user);
|
||||
|
||||
$this->flashSuccess('Pengajuan cuti berhasil disetujui.');
|
||||
|
||||
@ -89,10 +94,15 @@ public function approve(LeaveRequest $leaveRequest): RedirectResponse
|
||||
|
||||
public function reject(RejectLeaveRequestRequest $request, LeaveRequest $leaveRequest): RedirectResponse
|
||||
{
|
||||
$user = auth()->user();
|
||||
if ($user && ! $user->hasAnyRole(['owner', 'developer', 'direktur'])) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$this->leaveRequestService->reject(
|
||||
$leaveRequest,
|
||||
$request->validated('reason'),
|
||||
auth()->user(),
|
||||
$user,
|
||||
);
|
||||
|
||||
$this->flashSuccess('Pengajuan cuti berhasil ditolak.');
|
||||
|
||||
@ -26,15 +26,19 @@ public function __construct(
|
||||
/**
|
||||
* @return array{outstanding_amount: int, outstanding_amount_formatted: string, outstanding_count: int}
|
||||
*/
|
||||
public function outstandingSummary(): array
|
||||
public function outstandingSummary(?User $user = null): array
|
||||
{
|
||||
$outstandingAmount = (int) EmployeeAdvance::query()
|
||||
->where('status', EmployeeAdvanceStatus::APPROVED)
|
||||
->sum('amount');
|
||||
$query = EmployeeAdvance::query()
|
||||
->where('status', EmployeeAdvanceStatus::APPROVED);
|
||||
|
||||
$outstandingCount = EmployeeAdvance::query()
|
||||
->where('status', EmployeeAdvanceStatus::APPROVED)
|
||||
->count();
|
||||
if ($user !== null && ! $user->hasAnyRole(['owner', 'developer', 'direktur'])) {
|
||||
$employeeId = $user->employee?->id ?? -1;
|
||||
$query->where('employee_id', $employeeId);
|
||||
}
|
||||
|
||||
$outstandingAmount = (int) $query->sum('amount');
|
||||
|
||||
$outstandingCount = $query->count();
|
||||
|
||||
return [
|
||||
'outstanding_amount' => $outstandingAmount,
|
||||
@ -46,10 +50,14 @@ public function outstandingSummary(): array
|
||||
/**
|
||||
* @param array{search: string, sort: string, direction: 'asc'|'desc'} $tableQuery
|
||||
*/
|
||||
public function paginateForIndex(array $tableQuery): LengthAwarePaginator
|
||||
public function paginateForIndex(array $tableQuery, User $user): LengthAwarePaginator
|
||||
{
|
||||
$query = EmployeeAdvance::query()
|
||||
->with(['employee.user.profile', 'rejection'])
|
||||
->when(! $user->hasAnyRole(['owner', 'developer', 'direktur']), function (Builder $query) use ($user): void {
|
||||
$employeeId = $user->employee?->id ?? -1;
|
||||
$query->where('employee_id', $employeeId);
|
||||
})
|
||||
->when($tableQuery['search'] !== '', function (Builder $query) use ($tableQuery): void {
|
||||
$search = $tableQuery['search'];
|
||||
$query->where(function (Builder $query) use ($search): void {
|
||||
|
||||
@ -59,15 +59,19 @@ public function resolvePeriod(?int $periodId): ?PayrollPeriod
|
||||
/**
|
||||
* @return array{total_amount: int, total_amount_formatted: string, total_count: int, status: string, status_label: string}
|
||||
*/
|
||||
public function periodSummary(PayrollPeriod $period): array
|
||||
public function periodSummary(PayrollPeriod $period, User $user): array
|
||||
{
|
||||
$totalAmount = (int) Payroll::query()
|
||||
->where('payroll_period_id', $period->id)
|
||||
->sum('total_amount');
|
||||
$query = Payroll::query()
|
||||
->where('payroll_period_id', $period->id);
|
||||
|
||||
$totalCount = Payroll::query()
|
||||
->where('payroll_period_id', $period->id)
|
||||
->count();
|
||||
if (! $user->hasAnyRole(['owner', 'developer', 'direktur'])) {
|
||||
$employeeId = $user->employee?->id ?? -1;
|
||||
$query->where('employee_id', $employeeId);
|
||||
}
|
||||
|
||||
$totalAmount = (int) $query->sum('total_amount');
|
||||
|
||||
$totalCount = $query->count();
|
||||
|
||||
return [
|
||||
'total_amount' => $totalAmount,
|
||||
@ -81,11 +85,15 @@ public function periodSummary(PayrollPeriod $period): array
|
||||
/**
|
||||
* @param array{search: string, sort: string, direction: 'asc'|'desc'} $tableQuery
|
||||
*/
|
||||
public function paginateForPeriod(PayrollPeriod $period, array $tableQuery): LengthAwarePaginator
|
||||
public function paginateForPeriod(PayrollPeriod $period, array $tableQuery, User $user): LengthAwarePaginator
|
||||
{
|
||||
$query = Payroll::query()
|
||||
->with(['employee.user.profile', 'payrollPeriod', 'adjustments.createdBy.profile'])
|
||||
->where('payroll_period_id', $period->id)
|
||||
->when(! $user->hasAnyRole(['owner', 'developer', 'direktur']), function (Builder $query) use ($user): void {
|
||||
$employeeId = $user->employee?->id ?? -1;
|
||||
$query->where('employee_id', $employeeId);
|
||||
})
|
||||
->when($tableQuery['search'] !== '', function (Builder $query) use ($tableQuery): void {
|
||||
$search = $tableQuery['search'];
|
||||
$query->where(function (Builder $query) use ($search): void {
|
||||
|
||||
@ -24,10 +24,14 @@ public function __construct(
|
||||
/**
|
||||
* @param array{search: string, sort: string, direction: 'asc'|'desc'} $tableQuery
|
||||
*/
|
||||
public function paginateForIndex(array $tableQuery): LengthAwarePaginator
|
||||
public function paginateForIndex(array $tableQuery, User $user): LengthAwarePaginator
|
||||
{
|
||||
$query = LeaveRequest::query()
|
||||
->with(['employee.user.profile', 'rejection'])
|
||||
->when(! $user->hasAnyRole(['owner', 'developer', 'direktur']), function (Builder $query) use ($user): void {
|
||||
$employeeId = $user->employee?->id ?? -1;
|
||||
$query->where('employee_id', $employeeId);
|
||||
})
|
||||
->when($tableQuery['search'] !== '', function (Builder $query) use ($tableQuery): void {
|
||||
$search = $tableQuery['search'];
|
||||
$query->where(function (Builder $query) use ($search): void {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user