Files
HRM-System/tests/Feature/BranchScopedAccessTest.php

881 lines
30 KiB
PHP

<?php
namespace Tests\Feature;
use Tests\TestCase;
use App\Models\User;
use App\Models\Branch;
use App\Models\Department;
use App\Models\Employee;
use App\Models\PayrollRun;
use App\Models\PayrollEntry;
use App\Models\Payslip;
use App\Models\OvertimeApplication;
use App\Models\ThirteenthMonthRun;
use App\Models\ThirteenthMonthEntry;
use App\Models\BiometricAttendance;
use App\Models\LeaveType;
use App\Models\LeavePolicy;
use App\Models\LeaveApplication;
use App\Models\LeaveBalance;
use App\Models\EmployeeSalary;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
class BranchScopedAccessTest extends TestCase
{
use RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
// Ensure permissions exist
Permission::firstOrCreate(['name' => 'manage-branches']);
Permission::firstOrCreate(['name' => 'manage-any-branches']);
Permission::firstOrCreate(['name' => 'manage-departments']);
Permission::firstOrCreate(['name' => 'manage-any-departments']);
Permission::firstOrCreate(['name' => 'manage-employees']);
Permission::firstOrCreate(['name' => 'manage-any-employees']);
Permission::firstOrCreate(['name' => 'manage-payslips']);
Permission::firstOrCreate(['name' => 'manage-any-payslips']);
Permission::firstOrCreate(['name' => 'manage-payroll-runs']);
Permission::firstOrCreate(['name' => 'manage-biometric-attendance']);
Permission::firstOrCreate(['name' => 'manage-leave-applications']);
Permission::firstOrCreate(['name' => 'manage-any-leave-applications']);
Permission::firstOrCreate(['name' => 'manage-own-leave-applications']);
Permission::firstOrCreate(['name' => 'manage-leave-balances']);
Permission::firstOrCreate(['name' => 'manage-any-leave-balances']);
Permission::firstOrCreate(['name' => 'manage-own-leave-balances']);
Permission::firstOrCreate(['name' => 'view-leave-balances']);
Permission::firstOrCreate(['name' => 'view-leave-applications']);
Permission::firstOrCreate(['name' => 'manage-employee-salaries']);
Permission::firstOrCreate(['name' => 'manage-any-employee-salaries']);
Permission::firstOrCreate(['name' => 'view-payroll-runs']);
Permission::firstOrCreate(['name' => 'download-payslips']);
}
public function test_auth_branch_id_helper_resolution()
{
$company = User::create([
'name' => 'Company Admin',
'email' => 'company_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'company',
]);
$superadmin = User::create([
'name' => 'Super Admin',
'email' => 'admin_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'superadmin',
]);
$branch = Branch::create([
'name' => 'Branch Alpha',
'created_by' => $company->id,
]);
$userDirectBranch = User::create([
'name' => 'Branch User',
'email' => 'hr_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'hr',
'branch_id' => $branch->id,
'created_by' => $company->id,
]);
$this->actingAs($company);
$this->assertNull(authBranchId());
$this->actingAs($superadmin);
$this->assertNull(authBranchId());
$this->actingAs($userDirectBranch);
$this->assertEquals($branch->id, authBranchId());
}
public function test_branch_scoped_user_only_sees_assigned_branch()
{
$company = User::create([
'name' => 'Company Admin',
'email' => 'company_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'company',
]);
$company->givePermissionTo('manage-branches');
$company->givePermissionTo('manage-any-branches');
$branchA = Branch::create([
'name' => 'Branch Alpha',
'created_by' => $company->id,
]);
$branchB = Branch::create([
'name' => 'Branch Beta',
'created_by' => $company->id,
]);
$hrUser = User::create([
'name' => 'HR User Branch A',
'email' => 'hr_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'hr',
'branch_id' => $branchA->id,
'created_by' => $company->id,
]);
$hrUser->givePermissionTo('manage-branches');
$hrUser->givePermissionTo('manage-any-branches');
// Test HR accessing branches index
$response = $this->actingAs($hrUser)->get(route('hr.branches.index'));
$response->assertStatus(200);
$response->assertSee('Branch Alpha');
$response->assertDontSee('Branch Beta');
// Test Company Admin accessing branches index
$companyResponse = $this->actingAs($company)->get(route('hr.branches.index'));
$companyResponse->assertStatus(200);
$companyResponse->assertSee('Branch Alpha');
$companyResponse->assertSee('Branch Beta');
}
public function test_branch_scoped_user_only_sees_assigned_branch_departments_and_employees()
{
$company = User::create([
'name' => 'Company Admin',
'email' => 'company_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'company',
]);
$branchA = Branch::create([
'name' => 'Branch Alpha',
'created_by' => $company->id,
]);
$branchB = Branch::create([
'name' => 'Branch Beta',
'created_by' => $company->id,
]);
$deptA = Department::create([
'name' => 'Dept Alpha Finance',
'branch_id' => $branchA->id,
'created_by' => $company->id,
]);
$deptB = Department::create([
'name' => 'Dept Beta Logistics',
'branch_id' => $branchB->id,
'created_by' => $company->id,
]);
// Employee in Branch A
$userA = User::create([
'name' => 'Employee Alpha User',
'email' => 'alpha_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $company->id,
]);
Employee::create([
'user_id' => $userA->id,
'employee_id' => 'EMP-A-' . rand(100, 999),
'branch_id' => $branchA->id,
'department_id' => $deptA->id,
'created_by' => $company->id,
]);
// Employee in Branch B
$userB = User::create([
'name' => 'Employee Beta User',
'email' => 'beta_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $company->id,
]);
Employee::create([
'user_id' => $userB->id,
'employee_id' => 'EMP-B-' . rand(100, 999),
'branch_id' => $branchB->id,
'department_id' => $deptB->id,
'created_by' => $company->id,
]);
$hrUser = User::create([
'name' => 'HR Branch A User',
'email' => 'hr_a_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'hr',
'branch_id' => $branchA->id,
'created_by' => $company->id,
]);
$hrUser->givePermissionTo('manage-departments');
$hrUser->givePermissionTo('manage-any-departments');
$hrUser->givePermissionTo('manage-employees');
$hrUser->givePermissionTo('manage-any-employees');
// Department index check
$deptResponse = $this->actingAs($hrUser)->get(route('hr.departments.index'));
$deptResponse->assertStatus(200);
$deptResponse->assertSee('Dept Alpha Finance');
$deptResponse->assertDontSee('Dept Beta Logistics');
// Employee index check
$empResponse = $this->actingAs($hrUser)->get(route('hr.employees.index'));
$empResponse->assertStatus(200);
$empResponse->assertSee('Employee Alpha User');
$empResponse->assertDontSee('Employee Beta User');
}
public function test_branch_scoped_user_only_sees_assigned_branch_payslips()
{
$company = User::create([
'name' => 'Company Admin',
'email' => 'company_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'company',
]);
$branchA = Branch::create([
'name' => 'Branch Alpha',
'created_by' => $company->id,
]);
$branchB = Branch::create([
'name' => 'Branch Beta',
'created_by' => $company->id,
]);
// Employee A
$userA = User::create([
'name' => 'Employee Alpha User',
'email' => 'alpha_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $company->id,
]);
Employee::create([
'user_id' => $userA->id,
'employee_id' => 'EMP-A-' . rand(100, 999),
'branch_id' => $branchA->id,
'created_by' => $company->id,
]);
// Employee B
$userB = User::create([
'name' => 'Employee Beta User',
'email' => 'beta_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $company->id,
]);
Employee::create([
'user_id' => $userB->id,
'employee_id' => 'EMP-B-' . rand(100, 999),
'branch_id' => $branchB->id,
'created_by' => $company->id,
]);
$payrollRun = PayrollRun::create([
'title' => 'May 1-15 2026',
'payroll_frequency' => 'monthly',
'pay_period_start' => '2026-05-01',
'pay_period_end' => '2026-05-15',
'pay_date' => '2026-05-15',
'status' => 'completed',
'created_by' => $company->id,
]);
$entryA = PayrollEntry::create([
'payroll_run_id' => $payrollRun->id,
'employee_id' => $userA->id,
'basic_salary' => 10000,
'created_by' => $company->id,
]);
$entryB = PayrollEntry::create([
'payroll_run_id' => $payrollRun->id,
'employee_id' => $userB->id,
'basic_salary' => 10000,
'created_by' => $company->id,
]);
// Payslips
$payslipA = Payslip::create([
'payroll_entry_id' => $entryA->id,
'employee_id' => $userA->id,
'payslip_number' => 'PAY-ALPHA-001',
'pay_period_start' => '2026-05-01',
'pay_period_end' => '2026-05-15',
'pay_date' => '2026-05-15',
'status' => 'generated',
'created_by' => $company->id,
]);
$payslipB = Payslip::create([
'payroll_entry_id' => $entryB->id,
'employee_id' => $userB->id,
'payslip_number' => 'PAY-BETA-002',
'pay_period_start' => '2026-05-01',
'pay_period_end' => '2026-05-15',
'pay_date' => '2026-05-15',
'status' => 'generated',
'created_by' => $company->id,
]);
$hrUser = User::create([
'name' => 'HR Branch A User',
'email' => 'hr_a_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'hr',
'branch_id' => $branchA->id,
'created_by' => $company->id,
]);
$hrUser->givePermissionTo('manage-payslips');
$hrUser->givePermissionTo('manage-any-payslips');
$response = $this->actingAs($hrUser)->get(route('hr.payslips.index'));
$response->assertStatus(200);
$response->assertSee('PAY-ALPHA-001');
$response->assertDontSee('PAY-BETA-002');
}
public function test_branch_scoped_user_only_sees_assigned_branch_overtime_requests()
{
$company = User::create([
'name' => 'Company Admin',
'email' => 'company_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'company',
]);
$branchA = Branch::create([
'name' => 'Branch Alpha',
'created_by' => $company->id,
]);
$branchB = Branch::create([
'name' => 'Branch Beta',
'created_by' => $company->id,
]);
// Employee in Branch A
$userA = User::create([
'name' => 'Employee Alpha User',
'email' => 'alpha_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $company->id,
]);
Employee::create([
'user_id' => $userA->id,
'employee_id' => 'EMP-A-' . rand(100, 999),
'branch_id' => $branchA->id,
'created_by' => $company->id,
]);
// Employee in Branch B
$userB = User::create([
'name' => 'Employee Beta User',
'email' => 'beta_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $company->id,
]);
Employee::create([
'user_id' => $userB->id,
'employee_id' => 'EMP-B-' . rand(100, 999),
'branch_id' => $branchB->id,
'created_by' => $company->id,
]);
// Overtime requests
OvertimeApplication::create([
'user_id' => $userA->id,
'date' => '2026-05-10',
'requested_hours' => 2.5,
'reason' => 'Alpha Overtime Work',
'status' => 'pending',
]);
OvertimeApplication::create([
'user_id' => $userB->id,
'date' => '2026-05-10',
'requested_hours' => 3.0,
'reason' => 'Beta Overtime Work',
'status' => 'pending',
]);
$hrUser = User::create([
'name' => 'HR Branch A User',
'email' => 'hr_a_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'hr',
'branch_id' => $branchA->id,
'created_by' => $company->id,
]);
$response = $this->actingAs($hrUser)->get(route('hr.overtime.index'));
$response->assertStatus(200);
$response->assertSee('Alpha Overtime Work');
$response->assertDontSee('Beta Overtime Work');
}
public function test_branch_scoped_user_only_sees_assigned_branch_thirteenth_month()
{
$company = User::create([
'name' => 'Company Admin',
'email' => 'company_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'company',
]);
$branchA = Branch::create([
'name' => 'Branch Alpha',
'created_by' => $company->id,
]);
$branchB = Branch::create([
'name' => 'Branch Beta',
'created_by' => $company->id,
]);
// Employee in Branch A
$userA = User::create([
'name' => 'Employee Alpha User',
'email' => 'alpha_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $company->id,
]);
Employee::create([
'user_id' => $userA->id,
'employee_id' => 'EMP-A-' . rand(100, 999),
'branch_id' => $branchA->id,
'created_by' => $company->id,
]);
// Employee in Branch B
$userB = User::create([
'name' => 'Employee Beta User',
'email' => 'beta_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $company->id,
]);
Employee::create([
'user_id' => $userB->id,
'employee_id' => 'EMP-B-' . rand(100, 999),
'branch_id' => $branchB->id,
'created_by' => $company->id,
]);
$hrUser = User::create([
'name' => 'HR Branch A User',
'email' => 'hr_a_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'hr',
'branch_id' => $branchA->id,
'created_by' => $company->id,
]);
$hrUser->givePermissionTo('manage-payroll-runs');
$response = $this->actingAs($hrUser)->get(route('hr.thirteenth-month.index'));
$response->assertStatus(200);
$response->assertSee('Employee Alpha User');
$response->assertDontSee('Employee Beta User');
}
public function test_branch_scoped_user_only_sees_assigned_branch_biometric_attendance()
{
$company = User::create([
'name' => 'Company Admin',
'email' => 'company_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'company',
]);
$branchA = Branch::create([
'name' => 'Branch Alpha',
'created_by' => $company->id,
]);
$branchB = Branch::create([
'name' => 'Branch Beta',
'created_by' => $company->id,
]);
// Employee in Branch A
$userA = User::create([
'name' => 'Employee Alpha User',
'email' => 'alpha_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $company->id,
]);
$empA = Employee::create([
'user_id' => $userA->id,
'employee_id' => 'EMP-A-' . rand(100, 999),
'biometric_emp_id' => 'BIO-101',
'branch_id' => $branchA->id,
'created_by' => $company->id,
]);
// Employee in Branch B
$userB = User::create([
'name' => 'Employee Beta User',
'email' => 'beta_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $company->id,
]);
$empB = Employee::create([
'user_id' => $userB->id,
'employee_id' => 'EMP-B-' . rand(100, 999),
'biometric_emp_id' => 'BIO-102',
'branch_id' => $branchB->id,
'created_by' => $company->id,
]);
// Biometric punches
BiometricAttendance::create([
'biometric_emp_id' => 'BIO-101',
'punch_time' => '2026-05-10 09:00:00',
'punch_state' => 0,
'branch_id' => $branchA->id,
'sync_status' => 'pending',
]);
BiometricAttendance::create([
'biometric_emp_id' => 'BIO-102',
'punch_time' => '2026-05-10 09:00:00',
'punch_state' => 0,
'branch_id' => $branchB->id,
'sync_status' => 'pending',
]);
$hrUser = User::create([
'name' => 'HR Branch A User',
'email' => 'hr_a_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'hr',
'branch_id' => $branchA->id,
'created_by' => $company->id,
]);
$hrUser->givePermissionTo('manage-biometric-attendance');
$response = $this->actingAs($hrUser)->get(route('hr.biometric-attendance.index'));
$response->assertStatus(200);
$response->assertSee('BIO-101');
$response->assertDontSee('BIO-102');
// Test show route for foreign branch punch
$foreignShowResponse = $this->actingAs($hrUser)->get(route('hr.biometric-attendance.show', [
'employeeCode' => 'BIO-102',
'date' => '2026-05-10',
]));
$foreignShowResponse->assertStatus(403);
}
public function test_payroll_runs_and_payslips_are_branch_scoped()
{
$company = User::create([
'name' => 'Company Admin',
'email' => 'company_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'company',
]);
$branchA = Branch::create(['name' => 'Branch Alpha', 'created_by' => $company->id]);
$branchB = Branch::create(['name' => 'Branch Beta', 'created_by' => $company->id]);
$userA = User::create([
'name' => 'Employee Alpha User',
'email' => 'alpha_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $company->id,
]);
$empA = Employee::create([
'user_id' => $userA->id,
'employee_id' => 'EMP-A-' . rand(100, 999),
'branch_id' => $branchA->id,
'created_by' => $company->id,
]);
$userB = User::create([
'name' => 'Employee Beta User',
'email' => 'beta_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $company->id,
]);
$empB = Employee::create([
'user_id' => $userB->id,
'employee_id' => 'EMP-B-' . rand(100, 999),
'branch_id' => $branchB->id,
'created_by' => $company->id,
]);
$run = PayrollRun::create([
'title' => 'May 2026 Payroll',
'pay_period_start' => '2026-05-01',
'pay_period_end' => '2026-05-15',
'pay_date' => '2026-05-16',
'status' => 'draft',
'employee_count' => 2,
'total_gross_pay' => 30000,
'total_net_pay' => 28000,
'created_by' => $company->id,
]);
$entryA = PayrollEntry::create([
'payroll_run_id' => $run->id,
'employee_id' => $userA->id,
'basic_salary' => 15000,
'gross_pay' => 15000,
'net_pay' => 14000,
'status' => 'draft',
'created_by' => $company->id,
]);
$entryB = PayrollEntry::create([
'payroll_run_id' => $run->id,
'employee_id' => $userB->id,
'basic_salary' => 15000,
'gross_pay' => 15000,
'net_pay' => 14000,
'status' => 'draft',
'created_by' => $company->id,
]);
$payslipA = Payslip::create([
'payroll_entry_id' => $entryA->id,
'employee_id' => $userA->id,
'payslip_number' => 'PS-A-101',
'pay_period_start' => '2026-05-01',
'pay_period_end' => '2026-05-15',
'pay_date' => '2026-05-16',
'status' => 'generated',
'created_by' => $company->id,
]);
$payslipB = Payslip::create([
'payroll_entry_id' => $entryB->id,
'employee_id' => $userB->id,
'payslip_number' => 'PS-B-102',
'pay_period_start' => '2026-05-01',
'pay_period_end' => '2026-05-15',
'pay_date' => '2026-05-16',
'status' => 'generated',
'created_by' => $company->id,
]);
$hrUser = User::create([
'name' => 'HR Branch A User',
'email' => 'hr_a_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'hr',
'branch_id' => $branchA->id,
'created_by' => $company->id,
]);
$hrUser->givePermissionTo('manage-payroll-runs');
$hrUser->givePermissionTo('view-payroll-runs');
$hrUser->givePermissionTo('manage-payslips');
// HR views Payroll Run show
$runShowResponse = $this->actingAs($hrUser)->get(route('hr.payroll-runs.show', $run->id));
$runShowResponse->assertStatus(200);
$runShowResponse->assertSee('Employee Alpha User');
$runShowResponse->assertDontSee('Employee Beta User');
// HR views Payslips index
$payslipIndexResponse = $this->actingAs($hrUser)->get(route('hr.payslips.index'));
$payslipIndexResponse->assertStatus(200);
$payslipIndexResponse->assertSee('PS-A-101');
$payslipIndexResponse->assertDontSee('PS-B-102');
}
public function test_employee_role_sees_own_leave_data_only()
{
$company = User::create([
'name' => 'Company Admin',
'email' => 'company_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'company',
]);
$branch = Branch::create(['name' => 'Main Branch', 'created_by' => $company->id]);
$userA = User::create([
'name' => 'Employee Alice',
'email' => 'alice_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $company->id,
]);
$empA = Employee::create([
'user_id' => $userA->id,
'employee_id' => 'EMP-ALICE',
'branch_id' => $branch->id,
'created_by' => $company->id,
]);
$userB = User::create([
'name' => 'Employee Bob',
'email' => 'bob_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $company->id,
]);
$empB = Employee::create([
'user_id' => $userB->id,
'employee_id' => 'EMP-BOB',
'branch_id' => $branch->id,
'created_by' => $company->id,
]);
$leaveType = LeaveType::create([
'name' => 'Vacation Leave',
'color' => '#3b82f6',
'is_paid' => true,
'status' => 'active',
'created_by' => $company->id,
]);
$leavePolicy = LeavePolicy::create([
'name' => 'Standard Vacation Policy',
'leave_type_id' => $leaveType->id,
'max_days_per_year' => 15,
'requires_approval' => true,
'status' => 'active',
'created_by' => $company->id,
]);
$leaveAppA = LeaveApplication::create([
'employee_id' => $userA->id,
'leave_type_id' => $leaveType->id,
'leave_policy_id' => $leavePolicy->id,
'start_date' => '2026-06-01',
'end_date' => '2026-06-03',
'total_days' => 3,
'reason' => 'Alice Summer Vacation',
'status' => 'pending',
'created_by' => $userA->id,
]);
$leaveAppB = LeaveApplication::create([
'employee_id' => $userB->id,
'leave_type_id' => $leaveType->id,
'leave_policy_id' => $leavePolicy->id,
'start_date' => '2026-06-05',
'end_date' => '2026-06-07',
'total_days' => 3,
'reason' => 'Bob Secret Leave',
'status' => 'pending',
'created_by' => $userB->id,
]);
$balanceA = LeaveBalance::create([
'employee_id' => $userA->id,
'leave_type_id' => $leaveType->id,
'leave_policy_id' => $leavePolicy->id,
'year' => 2026,
'allocated_days' => 15,
'used_days' => 0,
'remaining_days' => 15,
'created_by' => $company->id,
]);
$balanceB = LeaveBalance::create([
'employee_id' => $userB->id,
'leave_type_id' => $leaveType->id,
'leave_policy_id' => $leavePolicy->id,
'year' => 2026,
'allocated_days' => 20,
'used_days' => 5,
'remaining_days' => 15,
'created_by' => $company->id,
]);
// Alice visits hr/leave-applications
$aliceLeavesResponse = $this->actingAs($userA)->get(route('hr.leave-applications.index'));
$aliceLeavesResponse->assertStatus(200);
$aliceLeavesResponse->assertSee('Alice Summer Vacation');
$aliceLeavesResponse->assertDontSee('Bob Secret Leave');
// Alice visits hr/leave-balances
$aliceBalancesResponse = $this->actingAs($userA)->get(route('hr.leave-balances.index'));
$aliceBalancesResponse->assertStatus(200);
$aliceBalancesResponse->assertSee('Employee Alice');
$aliceBalancesResponse->assertDontSee('Employee Bob');
}
public function test_payslip_template_renders_scx_software_header()
{
$company = User::create([
'name' => 'Company Admin',
'email' => 'company_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'company',
]);
$user = User::create([
'name' => 'John Doe',
'email' => 'john_' . uniqid() . '@test.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $company->id,
]);
$emp = Employee::create([
'user_id' => $user->id,
'employee_id' => 'EMP-JD-001',
'created_by' => $company->id,
]);
$run = PayrollRun::create([
'title' => 'May 2026 Payroll',
'pay_period_start' => '2026-05-01',
'pay_period_end' => '2026-05-15',
'pay_date' => '2026-05-16',
'status' => 'draft',
'employee_count' => 1,
'total_gross_pay' => 15000,
'total_net_pay' => 14000,
'created_by' => $company->id,
]);
$entry = PayrollEntry::create([
'payroll_run_id' => $run->id,
'employee_id' => $user->id,
'basic_salary' => 15000,
'gross_pay' => 15000,
'net_pay' => 14000,
'status' => 'draft',
'created_by' => $company->id,
]);
$payslip = Payslip::create([
'payroll_entry_id' => $entry->id,
'employee_id' => $user->id,
'payslip_number' => 'PS-JD-001',
'pay_period_start' => '2026-05-01',
'pay_period_end' => '2026-05-15',
'pay_date' => '2026-05-16',
'status' => 'generated',
'created_by' => $company->id,
]);
$user->givePermissionTo('download-payslips');
$response = $this->actingAs($user)->get(route('hr.payslips.download', $payslip->id));
$response->assertStatus(200);
$response->assertSee('Statlab');
}
}