Files
prn2026/tests/Feature/FinanceModuleTest.php
2026-06-03 08:51:22 +08:00

156 lines
5.5 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\Application;
use App\Models\ApplicationDocument;
use App\Models\BankVerification;
use App\Models\ExportLog;
use App\Models\Position;
use App\Models\PusatMengundi;
use App\Models\StaffAssignment;
use App\Models\User;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
class FinanceModuleTest extends TestCase
{
use RefreshDatabase;
public function test_admin_kewangan_can_view_approved_staff_bank_list(): void
{
$this->seed(DatabaseSeeder::class);
$finance = User::query()->where('email', 'kewangan@prn.local')->firstOrFail();
$application = $this->assignedApplication('Finance View', '910101105551');
$this->actingAs($finance)
->get(route('kewangan.bank.index'))
->assertOk()
->assertSee($application->name)
->assertSee('Penyata ada');
}
public function test_admin_kewangan_can_verify_bank_account(): void
{
$this->seed(DatabaseSeeder::class);
$finance = User::query()->where('email', 'kewangan@prn.local')->firstOrFail();
$application = $this->assignedApplication('Finance Verify', '910101105552');
$verification = $application->bankVerification()->firstOrFail();
$this->actingAs($finance)
->patch(route('kewangan.bank.update', $verification), [
'status' => 'verified',
'finance_note' => 'Akaun disahkan.',
])
->assertRedirect(route('kewangan.bank.show', $verification));
$verification->refresh();
$this->assertSame('verified', $verification->status);
$this->assertSame('Akaun disahkan.', $verification->finance_note);
$this->assertSame($finance->id, $verification->verified_by_user_id);
$this->assertNotNull($verification->verified_at);
}
public function test_finance_filters_missing_bank_statement_and_account_number(): void
{
$this->seed(DatabaseSeeder::class);
$finance = User::query()->where('email', 'kewangan@prn.local')->firstOrFail();
$complete = $this->assignedApplication('Finance Complete', '910101105553');
$missing = $this->assignedApplication('Finance Missing', '910101105554', false, false);
$this->actingAs($finance)
->get(route('kewangan.bank.index', [
'missing_bank_statement' => 1,
'missing_account_number' => 1,
]))
->assertOk()
->assertSee($missing->name)
->assertDontSee($complete->name);
}
public function test_admin_kewangan_cannot_change_assignment(): void
{
$this->seed(DatabaseSeeder::class);
$finance = User::query()->where('email', 'kewangan@prn.local')->firstOrFail();
$assignment = StaffAssignment::query()->firstOrFail();
$this->actingAs($finance)
->get(route('admin.management.assignments.edit', $assignment))
->assertForbidden();
}
public function test_finance_export_creates_export_log(): void
{
Storage::fake('local');
$this->seed(DatabaseSeeder::class);
$finance = User::query()->where('email', 'kewangan@prn.local')->firstOrFail();
$this->assignedApplication('Finance Export', '910101105555');
$this->actingAs($finance)
->get(route('kewangan.bank.export'))
->assertOk();
$exportLog = ExportLog::query()->where('report_type', 'finance_verification_list')->firstOrFail();
$this->assertSame($finance->id, $exportLog->generated_by_user_id);
$this->assertNotNull($exportLog->generated_at);
$this->assertSame('local', $exportLog->disk);
Storage::disk('local')->assertExists($exportLog->path);
}
private function assignedApplication(string $name, string $icNumber, bool $withBankStatement = true, bool $withAccountNumber = true): Application
{
$pusat = PusatMengundi::query()->where('code', 'PM001')->firstOrFail();
$position = Position::query()->where('code', 'PAPM')->firstOrFail();
$application = Application::factory()->create([
'election_id' => $pusat->election_id,
'pusat_mengundi_id' => $pusat->id,
'requested_position_id' => $position->id,
'approved_position_id' => $position->id,
'status' => 'assigned',
'name' => $name,
'ic_number' => $icNumber,
'bank_name' => 'Maybank',
'bank_account_number' => $withAccountNumber ? '1234567890' : null,
]);
BankVerification::query()->create([
'application_id' => $application->id,
'status' => 'pending',
]);
StaffAssignment::query()->create([
'election_id' => $pusat->election_id,
'application_id' => $application->id,
'position_id' => $position->id,
'pusat_mengundi_id' => $pusat->id,
'status' => 'active',
'assigned_at' => now(),
'source' => 'test',
]);
if ($withBankStatement) {
ApplicationDocument::query()->create([
'application_id' => $application->id,
'document_type' => 'bank_statement',
'disk' => 'local',
'path' => 'applications/'.$application->public_uuid.'/bank.pdf',
'original_name' => 'bank.pdf',
'mime_type' => 'application/pdf',
'size' => 12,
]);
}
return $application;
}
}