Features: - Implement two fee types: entrance fee and annual fee (both NT$1,000) - Add 50% discount for disability certificate holders - Add disability certificate upload in member profile - Integrate disability verification into cashier approval workflow - Add membership fee settings in system admin Document permissions: - Fix hard-coded role logic in Document model - Use permission-based authorization instead of role checks Additional features: - Add announcements, general ledger, and trial balance modules - Add income management and accounting entries - Add comprehensive test suite with factories - Update UI translations to Traditional Chinese 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
216 lines
6.2 KiB
PHP
216 lines
6.2 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Roles;
|
|
|
|
use App\Models\FinanceDocument;
|
|
use App\Models\Member;
|
|
use App\Models\MembershipPayment;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Spatie\Permission\Models\Permission;
|
|
use Spatie\Permission\Models\Role;
|
|
use Tests\TestCase;
|
|
use Tests\Traits\CreatesFinanceData;
|
|
use Tests\Traits\CreatesMemberData;
|
|
use Tests\Traits\SeedsRolesAndPermissions;
|
|
|
|
/**
|
|
* Role Permission Tests
|
|
*
|
|
* Tests role-based access control and permissions.
|
|
*/
|
|
class RolePermissionTest extends TestCase
|
|
{
|
|
use RefreshDatabase, SeedsRolesAndPermissions, CreatesMemberData, CreatesFinanceData;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
Storage::fake('private');
|
|
Storage::fake('local');
|
|
$this->seedRolesAndPermissions();
|
|
}
|
|
|
|
/**
|
|
* Test admin can access admin dashboard
|
|
*/
|
|
public function test_admin_can_access_admin_dashboard(): void
|
|
{
|
|
$admin = $this->createAdmin();
|
|
|
|
$response = $this->actingAs($admin)->get(route('admin.dashboard'));
|
|
|
|
$response->assertStatus(200);
|
|
}
|
|
|
|
/**
|
|
* Test member cannot access admin dashboard
|
|
*/
|
|
public function test_member_cannot_access_admin_dashboard(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
$user->assignRole('member');
|
|
|
|
$response = $this->actingAs($user)->get(route('admin.dashboard'));
|
|
|
|
$response->assertStatus(403);
|
|
}
|
|
|
|
/**
|
|
* Test cashier can approve payments
|
|
*/
|
|
public function test_cashier_can_approve_payments(): void
|
|
{
|
|
$cashier = $this->createCashier();
|
|
$data = $this->createMemberWithPendingPayment();
|
|
|
|
$response = $this->actingAs($cashier)->post(
|
|
route('admin.membership-payments.approve', $data['payment'])
|
|
);
|
|
|
|
$data['payment']->refresh();
|
|
$this->assertEquals(MembershipPayment::STATUS_APPROVED_CASHIER, $data['payment']->status);
|
|
}
|
|
|
|
/**
|
|
* Test accountant cannot approve pending payment directly
|
|
*/
|
|
public function test_accountant_cannot_approve_pending_payment_directly(): void
|
|
{
|
|
$accountant = $this->createAccountant();
|
|
$data = $this->createMemberWithPendingPayment();
|
|
|
|
$response = $this->actingAs($accountant)->post(
|
|
route('admin.membership-payments.approve', $data['payment'])
|
|
);
|
|
|
|
// Should be forbidden or redirect with error
|
|
$data['payment']->refresh();
|
|
$this->assertNotEquals(MembershipPayment::STATUS_APPROVED_ACCOUNTANT, $data['payment']->status);
|
|
}
|
|
|
|
/**
|
|
* Test chair can approve after accountant
|
|
*/
|
|
public function test_chair_can_approve_after_accountant(): void
|
|
{
|
|
$chair = $this->createChair();
|
|
$data = $this->createMemberWithPaymentAtStage('accountant_approved');
|
|
|
|
$response = $this->actingAs($chair)->post(
|
|
route('admin.membership-payments.approve', $data['payment'])
|
|
);
|
|
|
|
$data['payment']->refresh();
|
|
$this->assertEquals(MembershipPayment::STATUS_APPROVED_CHAIR, $data['payment']->status);
|
|
}
|
|
|
|
/**
|
|
* Test finance_cashier can approve finance documents
|
|
*/
|
|
public function test_finance_cashier_can_approve_finance_documents(): void
|
|
{
|
|
$cashier = $this->createCashier();
|
|
$document = $this->createFinanceDocument([
|
|
'status' => FinanceDocument::STATUS_PENDING,
|
|
]);
|
|
|
|
$response = $this->actingAs($cashier)->post(
|
|
route('admin.finance-documents.approve', $document)
|
|
);
|
|
|
|
$document->refresh();
|
|
$this->assertEquals(FinanceDocument::STATUS_APPROVED_CASHIER, $document->status);
|
|
}
|
|
|
|
/**
|
|
* Test unauthorized user cannot approve
|
|
*/
|
|
public function test_unauthorized_user_cannot_approve(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
$data = $this->createMemberWithPendingPayment();
|
|
|
|
$response = $this->actingAs($user)->post(
|
|
route('admin.membership-payments.approve', $data['payment'])
|
|
);
|
|
|
|
$response->assertStatus(403);
|
|
}
|
|
|
|
/**
|
|
* Test role can be assigned to user
|
|
*/
|
|
public function test_role_can_be_assigned_to_user(): void
|
|
{
|
|
$admin = $this->createAdmin();
|
|
$user = User::factory()->create();
|
|
|
|
$response = $this->actingAs($admin)->post(
|
|
route('admin.users.assign-role', $user),
|
|
['role' => 'finance_cashier']
|
|
);
|
|
|
|
$this->assertTrue($user->hasRole('finance_cashier'));
|
|
}
|
|
|
|
/**
|
|
* Test role can be removed from user
|
|
*/
|
|
public function test_role_can_be_removed_from_user(): void
|
|
{
|
|
$admin = $this->createAdmin();
|
|
$user = User::factory()->create();
|
|
$user->assignRole('finance_cashier');
|
|
|
|
$response = $this->actingAs($admin)->post(
|
|
route('admin.users.remove-role', $user),
|
|
['role' => 'finance_cashier']
|
|
);
|
|
|
|
$this->assertFalse($user->hasRole('finance_cashier'));
|
|
}
|
|
|
|
/**
|
|
* Test permission check for member management
|
|
*/
|
|
public function test_permission_check_for_member_management(): void
|
|
{
|
|
$admin = $this->createAdmin();
|
|
$member = $this->createPendingMember();
|
|
|
|
$response = $this->actingAs($admin)->patch(
|
|
route('admin.members.update-status', $member),
|
|
['membership_status' => Member::STATUS_ACTIVE]
|
|
);
|
|
|
|
$member->refresh();
|
|
$this->assertEquals(Member::STATUS_ACTIVE, $member->membership_status);
|
|
}
|
|
|
|
/**
|
|
* Test super admin has all permissions
|
|
*/
|
|
public function test_super_admin_has_all_permissions(): void
|
|
{
|
|
$superAdmin = User::factory()->create();
|
|
$superAdmin->assignRole('super_admin');
|
|
|
|
$this->assertTrue($superAdmin->can('manage-members'));
|
|
$this->assertTrue($superAdmin->can('approve-payments'));
|
|
$this->assertTrue($superAdmin->can('manage-finance'));
|
|
}
|
|
|
|
/**
|
|
* Test role hierarchy for approvals
|
|
*/
|
|
public function test_role_hierarchy_for_approvals(): void
|
|
{
|
|
// Chair should be able to do everything accountant can
|
|
$chair = $this->createChair();
|
|
|
|
$this->assertTrue($chair->hasRole('finance_chair'));
|
|
}
|
|
}
|