Add membership fee system with disability discount and fix document permissions
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>
This commit is contained in:
270
tests/Feature/BatchOperations/BatchOperationsTest.php
Normal file
270
tests/Feature/BatchOperations/BatchOperationsTest.php
Normal file
@@ -0,0 +1,270 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\BatchOperations;
|
||||
|
||||
use App\Models\FinanceDocument;
|
||||
use App\Models\Issue;
|
||||
use App\Models\Member;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Tests\TestCase;
|
||||
use Tests\Traits\CreatesFinanceData;
|
||||
use Tests\Traits\CreatesMemberData;
|
||||
use Tests\Traits\SeedsRolesAndPermissions;
|
||||
|
||||
/**
|
||||
* Batch Operations Tests
|
||||
*
|
||||
* Tests bulk operations on records.
|
||||
*/
|
||||
class BatchOperationsTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase, SeedsRolesAndPermissions, CreatesMemberData, CreatesFinanceData;
|
||||
|
||||
protected User $admin;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
Storage::fake('private');
|
||||
Storage::fake('local');
|
||||
$this->seedRolesAndPermissions();
|
||||
$this->admin = $this->createAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batch member status update
|
||||
*/
|
||||
public function test_batch_member_status_update(): void
|
||||
{
|
||||
$members = [];
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$members[] = $this->createPendingMember();
|
||||
}
|
||||
|
||||
$memberIds = array_map(fn ($m) => $m->id, $members);
|
||||
|
||||
$response = $this->actingAs($this->admin)->post(
|
||||
route('admin.members.batch-update'),
|
||||
[
|
||||
'member_ids' => $memberIds,
|
||||
'action' => 'activate',
|
||||
]
|
||||
);
|
||||
|
||||
foreach ($members as $member) {
|
||||
$member->refresh();
|
||||
$this->assertEquals(Member::STATUS_ACTIVE, $member->membership_status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batch member suspend
|
||||
*/
|
||||
public function test_batch_member_suspend(): void
|
||||
{
|
||||
$members = [];
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$members[] = $this->createActiveMember();
|
||||
}
|
||||
|
||||
$memberIds = array_map(fn ($m) => $m->id, $members);
|
||||
|
||||
$response = $this->actingAs($this->admin)->post(
|
||||
route('admin.members.batch-update'),
|
||||
[
|
||||
'member_ids' => $memberIds,
|
||||
'action' => 'suspend',
|
||||
]
|
||||
);
|
||||
|
||||
foreach ($members as $member) {
|
||||
$member->refresh();
|
||||
$this->assertEquals(Member::STATUS_SUSPENDED, $member->membership_status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batch issue status update
|
||||
*/
|
||||
public function test_batch_issue_status_update(): void
|
||||
{
|
||||
$issues = [];
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$issues[] = Issue::factory()->create([
|
||||
'created_by_user_id' => $this->admin->id,
|
||||
'status' => Issue::STATUS_NEW,
|
||||
]);
|
||||
}
|
||||
|
||||
$issueIds = array_map(fn ($i) => $i->id, $issues);
|
||||
|
||||
$response = $this->actingAs($this->admin)->post(
|
||||
route('admin.issues.batch-update'),
|
||||
[
|
||||
'issue_ids' => $issueIds,
|
||||
'status' => Issue::STATUS_IN_PROGRESS,
|
||||
]
|
||||
);
|
||||
|
||||
foreach ($issues as $issue) {
|
||||
$issue->refresh();
|
||||
$this->assertEquals(Issue::STATUS_IN_PROGRESS, $issue->status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batch issue assign
|
||||
*/
|
||||
public function test_batch_issue_assign(): void
|
||||
{
|
||||
$assignee = User::factory()->create();
|
||||
|
||||
$issues = [];
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$issues[] = Issue::factory()->create([
|
||||
'created_by_user_id' => $this->admin->id,
|
||||
'assignee_id' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
$issueIds = array_map(fn ($i) => $i->id, $issues);
|
||||
|
||||
$response = $this->actingAs($this->admin)->post(
|
||||
route('admin.issues.batch-assign'),
|
||||
[
|
||||
'issue_ids' => $issueIds,
|
||||
'assignee_id' => $assignee->id,
|
||||
]
|
||||
);
|
||||
|
||||
foreach ($issues as $issue) {
|
||||
$issue->refresh();
|
||||
$this->assertEquals($assignee->id, $issue->assignee_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batch issue close
|
||||
*/
|
||||
public function test_batch_issue_close(): void
|
||||
{
|
||||
$issues = [];
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$issues[] = Issue::factory()->create([
|
||||
'created_by_user_id' => $this->admin->id,
|
||||
'status' => Issue::STATUS_REVIEW,
|
||||
]);
|
||||
}
|
||||
|
||||
$issueIds = array_map(fn ($i) => $i->id, $issues);
|
||||
|
||||
$response = $this->actingAs($this->admin)->post(
|
||||
route('admin.issues.batch-update'),
|
||||
[
|
||||
'issue_ids' => $issueIds,
|
||||
'status' => Issue::STATUS_CLOSED,
|
||||
]
|
||||
);
|
||||
|
||||
foreach ($issues as $issue) {
|
||||
$issue->refresh();
|
||||
$this->assertEquals(Issue::STATUS_CLOSED, $issue->status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batch operation with empty selection
|
||||
*/
|
||||
public function test_batch_operation_with_empty_selection(): void
|
||||
{
|
||||
$response = $this->actingAs($this->admin)->post(
|
||||
route('admin.members.batch-update'),
|
||||
[
|
||||
'member_ids' => [],
|
||||
'action' => 'activate',
|
||||
]
|
||||
);
|
||||
|
||||
$response->assertSessionHasErrors('member_ids');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batch operation with invalid IDs
|
||||
*/
|
||||
public function test_batch_operation_with_invalid_ids(): void
|
||||
{
|
||||
$response = $this->actingAs($this->admin)->post(
|
||||
route('admin.members.batch-update'),
|
||||
[
|
||||
'member_ids' => [99999, 99998],
|
||||
'action' => 'activate',
|
||||
]
|
||||
);
|
||||
|
||||
// Should handle gracefully
|
||||
$response->assertRedirect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batch export members
|
||||
*/
|
||||
public function test_batch_export_members(): void
|
||||
{
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$this->createActiveMember();
|
||||
}
|
||||
|
||||
$response = $this->actingAs($this->admin)->get(
|
||||
route('admin.members.export', ['format' => 'csv'])
|
||||
);
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('content-type', 'text/csv; charset=UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batch operation requires permission
|
||||
*/
|
||||
public function test_batch_operation_requires_permission(): void
|
||||
{
|
||||
$regularUser = User::factory()->create();
|
||||
$member = $this->createPendingMember();
|
||||
|
||||
$response = $this->actingAs($regularUser)->post(
|
||||
route('admin.members.batch-update'),
|
||||
[
|
||||
'member_ids' => [$member->id],
|
||||
'action' => 'activate',
|
||||
]
|
||||
);
|
||||
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batch operation limit
|
||||
*/
|
||||
public function test_batch_operation_limit(): void
|
||||
{
|
||||
// Create many members
|
||||
$members = [];
|
||||
for ($i = 0; $i < 100; $i++) {
|
||||
$members[] = $this->createPendingMember();
|
||||
}
|
||||
|
||||
$memberIds = array_map(fn ($m) => $m->id, $members);
|
||||
|
||||
$response = $this->actingAs($this->admin)->post(
|
||||
route('admin.members.batch-update'),
|
||||
[
|
||||
'member_ids' => $memberIds,
|
||||
'action' => 'activate',
|
||||
]
|
||||
);
|
||||
|
||||
// Should handle large batch
|
||||
$this->assertTrue($response->isRedirect() || $response->isSuccessful());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user