feat(payroll,leaves): enforce branch scoping for payroll/payslips/salaries, restrict employee role to own leaves, and set payslip header to SCX Software

This commit is contained in:
2026-09-10 15:15:57 +08:00
parent ef1aa7cf24
commit 20f14c3719
427 changed files with 15410 additions and 14946 deletions

View File

@@ -15,8 +15,17 @@ class PayrollRunController extends Controller
public function index(Request $request)
{
if (Auth::user()->can('manage-payroll-runs')) {
$query = PayrollRun::with(['creator'])->where(function ($q) {
if (Auth::user()->can('manage-any-payroll-runs')) {
$scopedBranchId = authBranchId();
$query = PayrollRun::with(['creator'])->where(function ($q) use ($scopedBranchId) {
if ($scopedBranchId) {
$q->whereIn('created_by', getCompanyAndUsersId())
->where(function ($subQ) use ($scopedBranchId) {
$subQ->where('created_by', Auth::id())
->orWhereHas('payrollEntries.employee.employee', function ($eq) use ($scopedBranchId) {
$eq->where('branch_id', $scopedBranchId);
});
});
} elseif (Auth::user()->can('manage-any-payroll-runs')) {
$q->whereIn('created_by', getCompanyAndUsersId());
} else {
$q->where('created_by', Auth::id());
@@ -73,15 +82,36 @@ class PayrollRunController extends Controller
public function show($payrollRunId)
{
if (Auth::user()->can('view-payroll-runs')) {
$scopedBranchId = authBranchId();
$payrollRun = PayrollRun::where('id', $payrollRunId)
->whereIn('created_by', getCompanyAndUsersId())
->with(['payrollEntries.employee', 'payrollEntries.adjustments'])
->with(['payrollEntries' => function ($q) use ($scopedBranchId) {
if ($scopedBranchId) {
$q->whereHas('employee.employee', function ($eq) use ($scopedBranchId) {
$eq->where('branch_id', $scopedBranchId);
});
}
$q->with(['employee.employee.branch', 'adjustments']);
}])
->first();
if (! $payrollRun) {
return redirect()->back()->with('error', __('Payroll run not found.'));
}
if ($scopedBranchId) {
$branchEntries = $payrollRun->payrollEntries;
if ($branchEntries->isEmpty() && $payrollRun->created_by !== Auth::id()) {
return redirect()->back()->with('error', __('Permission Denied. No records for your branch in this payroll run.'));
}
// Adjust displayed totals and count for branch context
$payrollRun->total_gross_pay = $branchEntries->sum('gross_pay');
$payrollRun->total_deductions = $branchEntries->sum('total_deductions');
$payrollRun->total_net_pay = $branchEntries->sum('net_pay');
$payrollRun->employee_count = $branchEntries->count();
}
return Inertia::render('hr/payroll-runs/show', [
'payrollRun' => $payrollRun,
]);
@@ -243,13 +273,21 @@ class PayrollRunController extends Controller
->whereHas('payrollRun', function ($q) {
$q->whereIn('created_by', getCompanyAndUsersId());
})
->with('payrollRun')
->with(['payrollRun', 'employee.employee'])
->first();
if (! $payrollEntry) {
return redirect()->back()->with('error', __('Payroll entry not found.'));
}
$scopedBranchId = authBranchId();
if ($scopedBranchId) {
$entryBranchId = $payrollEntry->employee?->employee?->branch_id;
if ($entryBranchId && (int)$entryBranchId !== (int)$scopedBranchId) {
return redirect()->back()->with('error', __('Permission Denied. You cannot delete entries outside your branch.'));
}
}
try {
$payrollRun = $payrollEntry->payrollRun;
@@ -276,13 +314,21 @@ class PayrollRunController extends Controller
->whereHas('payrollRun', function ($q) {
$q->whereIn('created_by', getCompanyAndUsersId());
})
->with('payrollRun')
->with(['payrollRun', 'employee.employee'])
->first();
if (! $payrollEntry) {
return redirect()->back()->with('error', __('Payroll entry not found.'));
}
$scopedBranchId = authBranchId();
if ($scopedBranchId) {
$entryBranchId = $payrollEntry->employee?->employee?->branch_id;
if ($entryBranchId && (int)$entryBranchId !== (int)$scopedBranchId) {
return redirect()->back()->with('error', __('Permission Denied. You cannot update entries outside your branch.'));
}
}
if ($payrollEntry->payrollRun->status === 'completed') {
return redirect()->back()->with('error', __('Cannot edit entry in a completed payroll run.'));
}
@@ -371,7 +417,14 @@ class PayrollRunController extends Controller
{
if (Auth::user()->can('export-payroll-runs')) {
try {
$payrollRuns = PayrollRun::whereIn('created_by', getCompanyAndUsersId())->get();
$scopedBranchId = authBranchId();
$query = PayrollRun::whereIn('created_by', getCompanyAndUsersId());
if ($scopedBranchId) {
$query->whereHas('payrollEntries.employee.employee', function ($eq) use ($scopedBranchId) {
$eq->where('branch_id', $scopedBranchId);
});
}
$payrollRuns = $query->get();
$fileName = 'payroll_runs_'.date('Y-m-d_His').'.csv';
$headers = [