feat(auth): enforce strict branch scoping for branch-assigned HR and staff accounts

- Introduce authBranchId() helper to resolve assigned branch while allowing company admin/superadmin cross-branch oversight
- Restrict branch, department, and employee listings and mutations to assigned branch for branch-scoped accounts
- Scope attendance records, biometric logs, leave applications/balances, payslips, shifts, and announcements by assigned branch
- Add comprehensive automated feature tests in BranchScopedAccessTest to prevent branch cross-visibility regression
This commit is contained in:
2026-09-10 11:14:24 +08:00
parent 4b350c4628
commit 7f467600e9
18 changed files with 937 additions and 144 deletions

View File

@@ -17,9 +17,15 @@ class LeaveBalanceController extends Controller
public function index(Request $request)
{
if (Auth::user()->can('manage-leave-balances') || Auth::user()->can('view-leave-balances')) {
$scopedBranchId = authBranchId();
$query = LeaveBalance::with(['employee', 'leaveType', 'leavePolicy', 'creator'])
->where(function ($q) {
if (Auth::user()->can('manage-any-leave-balances')) {
->where(function ($q) use ($scopedBranchId) {
if ($scopedBranchId) {
$q->whereIn('created_by', getCompanyAndUsersId())
->whereHas('employee.employee', function ($eq) use ($scopedBranchId) {
$eq->where('branch_id', $scopedBranchId);
});
} elseif (Auth::user()->can('manage-any-leave-balances')) {
$q->whereIn('created_by', getCompanyAndUsersId());
} elseif (Auth::user()->can('manage-leave-balances')) {
$branchId = Auth::user()->branch_id ?? Auth::user()->employee->branch_id ?? null;
@@ -123,8 +129,11 @@ class LeaveBalanceController extends Controller
{
// Get employees for filter dropdown (compatible with getFilteredEmployees logic)
$employeeQuery = Employee::whereIn('created_by', getCompanyAndUsersId());
$scopedBranchId = authBranchId();
if (Auth::user()->can('manage-leave-balances') && !Auth::user()->can('manage-any-leave-balances')) {
if ($scopedBranchId) {
$employeeQuery->where('branch_id', $scopedBranchId);
} elseif (Auth::user()->can('manage-leave-balances') && !Auth::user()->can('manage-any-leave-balances')) {
$branchId = Auth::user()->branch_id ?? Auth::user()->employee->branch_id ?? null;
if ($branchId) {
$employeeQuery->where('branch_id', $branchId);