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>
244 lines
6.9 KiB
PHP
244 lines
6.9 KiB
PHP
<?php
|
|
|
|
namespace Tests\Browser;
|
|
|
|
use App\Models\FinanceDocument;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Laravel\Dusk\Browser;
|
|
use Tests\DuskTestCase;
|
|
|
|
/**
|
|
* Finance Workflow Browser Tests
|
|
*
|
|
* Tests the finance workflow user interface and user experience.
|
|
*/
|
|
class FinanceWorkflowBrowserTest extends DuskTestCase
|
|
{
|
|
use DatabaseMigrations;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->artisan('db:seed', ['--class' => 'FinancialWorkflowPermissionsSeeder']);
|
|
}
|
|
|
|
/**
|
|
* Create a cashier user
|
|
*/
|
|
protected function createCashier(): User
|
|
{
|
|
$user = User::factory()->create([
|
|
'email' => 'cashier@test.com',
|
|
'password' => Hash::make('password'),
|
|
]);
|
|
$user->assignRole('finance_cashier');
|
|
|
|
return $user;
|
|
}
|
|
|
|
/**
|
|
* Create an accountant user
|
|
*/
|
|
protected function createAccountant(): User
|
|
{
|
|
$user = User::factory()->create([
|
|
'email' => 'accountant@test.com',
|
|
'password' => Hash::make('password'),
|
|
]);
|
|
$user->assignRole('finance_accountant');
|
|
|
|
return $user;
|
|
}
|
|
|
|
/**
|
|
* Test finance dashboard loads
|
|
*/
|
|
public function test_finance_dashboard_loads(): void
|
|
{
|
|
$cashier = $this->createCashier();
|
|
|
|
$this->browse(function (Browser $browser) use ($cashier) {
|
|
$browser->loginAs($cashier)
|
|
->visit(route('admin.finance.index'))
|
|
->assertSee('財務管理');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test can create finance document
|
|
*/
|
|
public function test_can_create_finance_document(): void
|
|
{
|
|
$accountant = $this->createAccountant();
|
|
|
|
$this->browse(function (Browser $browser) use ($accountant) {
|
|
$browser->loginAs($accountant)
|
|
->visit(route('admin.finance-documents.create'))
|
|
->assertSee('新增財務單據')
|
|
->assertPresent('input[name="title"]')
|
|
->assertPresent('input[name="amount"]');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test finance document list shows status
|
|
*/
|
|
public function test_finance_document_list_shows_status(): void
|
|
{
|
|
$cashier = $this->createCashier();
|
|
|
|
FinanceDocument::factory()->create([
|
|
'status' => FinanceDocument::STATUS_PENDING,
|
|
'title' => '測試單據',
|
|
]);
|
|
|
|
$this->browse(function (Browser $browser) use ($cashier) {
|
|
$browser->loginAs($cashier)
|
|
->visit(route('admin.finance-documents.index'))
|
|
->assertSee('測試單據')
|
|
->assertSee('待審核');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test cashier can see approve button
|
|
*/
|
|
public function test_cashier_can_see_approve_button(): void
|
|
{
|
|
$cashier = $this->createCashier();
|
|
|
|
$document = FinanceDocument::factory()->create([
|
|
'status' => FinanceDocument::STATUS_PENDING,
|
|
]);
|
|
|
|
$this->browse(function (Browser $browser) use ($cashier, $document) {
|
|
$browser->loginAs($cashier)
|
|
->visit(route('admin.finance-documents.show', $document))
|
|
->assertSee('核准');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test cashier can see reject button
|
|
*/
|
|
public function test_cashier_can_see_reject_button(): void
|
|
{
|
|
$cashier = $this->createCashier();
|
|
|
|
$document = FinanceDocument::factory()->create([
|
|
'status' => FinanceDocument::STATUS_PENDING,
|
|
]);
|
|
|
|
$this->browse(function (Browser $browser) use ($cashier, $document) {
|
|
$browser->loginAs($cashier)
|
|
->visit(route('admin.finance-documents.show', $document))
|
|
->assertSee('退回');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test approval requires confirmation
|
|
*/
|
|
public function test_approval_requires_confirmation(): void
|
|
{
|
|
$cashier = $this->createCashier();
|
|
|
|
$document = FinanceDocument::factory()->create([
|
|
'status' => FinanceDocument::STATUS_PENDING,
|
|
]);
|
|
|
|
$this->browse(function (Browser $browser) use ($cashier, $document) {
|
|
$browser->loginAs($cashier)
|
|
->visit(route('admin.finance-documents.show', $document))
|
|
->press('核准')
|
|
->assertDialogOpened();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test document amount is formatted
|
|
*/
|
|
public function test_document_amount_is_formatted(): void
|
|
{
|
|
$cashier = $this->createCashier();
|
|
|
|
FinanceDocument::factory()->create([
|
|
'status' => FinanceDocument::STATUS_PENDING,
|
|
'amount' => 15000,
|
|
]);
|
|
|
|
$this->browse(function (Browser $browser) use ($cashier) {
|
|
$browser->loginAs($cashier)
|
|
->visit(route('admin.finance-documents.index'))
|
|
->assertSee('15,000');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test filter by status works
|
|
*/
|
|
public function test_filter_by_status_works(): void
|
|
{
|
|
$cashier = $this->createCashier();
|
|
|
|
FinanceDocument::factory()->create([
|
|
'status' => FinanceDocument::STATUS_PENDING,
|
|
'title' => '待審核單據',
|
|
]);
|
|
|
|
FinanceDocument::factory()->create([
|
|
'status' => FinanceDocument::STATUS_APPROVED_CASHIER,
|
|
'title' => '已核准單據',
|
|
]);
|
|
|
|
$this->browse(function (Browser $browser) use ($cashier) {
|
|
$browser->loginAs($cashier)
|
|
->visit(route('admin.finance-documents.index'))
|
|
->select('status', FinanceDocument::STATUS_PENDING)
|
|
->press('篩選')
|
|
->assertSee('待審核單據')
|
|
->assertDontSee('已核准單據');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test rejection requires reason
|
|
*/
|
|
public function test_rejection_requires_reason(): void
|
|
{
|
|
$cashier = $this->createCashier();
|
|
|
|
$document = FinanceDocument::factory()->create([
|
|
'status' => FinanceDocument::STATUS_PENDING,
|
|
]);
|
|
|
|
$this->browse(function (Browser $browser) use ($cashier, $document) {
|
|
$browser->loginAs($cashier)
|
|
->visit(route('admin.finance-documents.show', $document))
|
|
->press('退回')
|
|
->waitFor('.modal')
|
|
->assertSee('退回原因');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test document history is visible
|
|
*/
|
|
public function test_document_history_is_visible(): void
|
|
{
|
|
$cashier = $this->createCashier();
|
|
|
|
$document = FinanceDocument::factory()->create([
|
|
'status' => FinanceDocument::STATUS_APPROVED_CASHIER,
|
|
]);
|
|
|
|
$this->browse(function (Browser $browser) use ($cashier, $document) {
|
|
$browser->loginAs($cashier)
|
|
->visit(route('admin.finance-documents.show', $document))
|
|
->assertSee('審核歷程');
|
|
});
|
|
}
|
|
}
|