# Financial Workflow System - Test Plan ## Overview This document outlines the complete testing strategy for the financial workflow system implementing the "會計管帳,出納管錢" (Accountant manages books, Cashier manages money) principle. --- ## Test Environment Setup ### Prerequisites ```bash # 1. Run setup script ./setup-financial-workflow.sh # 2. Verify test users created php artisan tinker >>> User::where('email', 'like', '%@test.com')->pluck('email', 'name') # 3. Check permissions >>> Role::with('permissions')->get() ``` ### Test Users | Email | Password | Role | Purpose | |-------|----------|------|---------| | cashier@test.com | password | finance_cashier | Test cashier operations | | accountant@test.com | password | finance_accountant | Test accountant operations | | chair@test.com | password | finance_chair | Test chair approvals | | requester@test.com | password | finance_requester | Test document creation | --- ## 1. Manual Testing Checklist ### 1.1 Stage 1: Approval Workflow #### Small Amount (< 5,000) - Cashier → Accountant - [ ] **Step 1**: Login as `requester@test.com` - [ ] Navigate to `/admin/finance-documents/create` - [ ] Create document with: - Title: "小額報銷測試" - Amount: 3,000 - Request Type: expense_reimbursement - Upload attachment - [ ] Verify document created with status "pending" - [ ] Verify amount_tier automatically set to "small" - [ ] **Step 2**: Login as `cashier@test.com` - [ ] Navigate to `/admin/finance-documents` - [ ] Find pending document - [ ] Click "Approve" - [ ] Verify status changed to "approved_cashier" - [ ] Verify email sent to accountant - [ ] **Step 3**: Login as `accountant@test.com` - [ ] View document - [ ] Click "Approve" - [ ] Verify status changed to "approved_accountant" - [ ] Verify message shows "小額申請審核完成,可以製作付款單" - [ ] Verify "Create Payment Order" button appears #### Medium Amount (5,000-50,000) - Cashier → Accountant → Chair - [ ] **Step 1**: Create document with amount: 25,000 - [ ] **Step 2**: Cashier approves - [ ] **Step 3**: Accountant approves - [ ] Verify message shows "已送交理事長審核" - [ ] **Step 4**: Login as `chair@test.com` - [ ] Approve document - [ ] Verify status changed to "approved_chair" - [ ] Verify message shows "審核流程完成" #### Large Amount (> 50,000) - Cashier → Accountant → Chair → Board - [ ] **Step 1**: Create document with amount: 75,000 - [ ] **Step 2-4**: Complete cashier, accountant, chair approvals - [ ] **Step 5**: Verify `requires_board_meeting` flag is true - [ ] **Step 6**: Verify message shows "大額申請仍需理事會核准" --- ### 1.2 Stage 2: Payment Workflow #### Create Payment Order (Accountant) - [ ] **Step 1**: Login as `accountant@test.com` - [ ] **Step 2**: Navigate to approved document - [ ] **Step 3**: Click "製作付款單" - [ ] **Step 4**: Fill payment order form: - Payee Name: "Test Vendor" - Payment Method: "bank_transfer" - Bank Name: "Test Bank" - Bank Code: "007" - Account Number: "1234567890" - Amount: (auto-filled from document) - Notes: "測試付款單" - [ ] **Step 5**: Submit form - [ ] **Step 6**: Verify: - [ ] Payment order created with unique number (PO-YYYYMMDD-####) - [ ] Status is "pending_verification" - [ ] finance_document updated with payment_order_created_at - [ ] Redirect to payment order show page #### Verify Payment Order (Cashier) - [ ] **Step 1**: Login as `cashier@test.com` - [ ] **Step 2**: Navigate to `/admin/payment-orders` - [ ] **Step 3**: Find pending payment order - [ ] **Step 4**: Click to view details - [ ] **Step 5**: Review payment information - [ ] **Step 6**: Option A - Approve: - [ ] Enter verification notes - [ ] Click "通過覆核" - [ ] Verify status changed to "verified" - [ ] Verify execution form appears - [ ] **Step 7**: Option B - Reject: - [ ] Enter rejection reason - [ ] Click "駁回" - [ ] Verify status changed to "cancelled" #### Execute Payment (Cashier) - [ ] **Step 1**: With verified payment order - [ ] **Step 2**: Fill execution form: - Transaction Reference: "TXN-2025-001" - Upload payment receipt (PDF/image) - Execution notes: "已完成轉帳" - [ ] **Step 3**: Click "確認執行付款" - [ ] **Step 4**: Verify: - [ ] Status changed to "executed" - [ ] Execution status is "completed" - [ ] Receipt can be downloaded - [ ] finance_document updated with payment_executed_at --- ### 1.3 Stage 3: Recording Workflow #### Cashier Ledger Entry - [ ] **Step 1**: Login as `cashier@test.com` - [ ] **Step 2**: Navigate to `/admin/cashier-ledger/create` - [ ] **Step 3**: Fill form: - Finance Document: (select executed payment) - Entry Date: (today) - Entry Type: "payment" - Payment Method: "bank_transfer" - Bank Account: "Main Account" - Amount: (from payment order) - Receipt Number: "RCP-001" - Transaction Reference: (from payment order) - Notes: "記錄付款" - [ ] **Step 4**: Submit form - [ ] **Step 5**: Verify: - [ ] Entry created - [ ] Balance_before calculated from previous entry - [ ] Balance_after = balance_before - amount - [ ] finance_document updated with cashier_ledger_entry_id #### Accounting Transaction (Accountant) - [ ] **Step 1**: Login as `accountant@test.com` - [ ] **Step 2**: Navigate to `/admin/transactions/create` - [ ] **Step 3**: Create accounting entry with debit/credit - [ ] **Step 4**: Link to finance document - [ ] **Step 5**: Verify transaction recorded --- ### 1.4 Stage 4: Reconciliation Workflow #### Prepare Bank Reconciliation (Cashier) - [ ] **Step 1**: Login as `cashier@test.com` - [ ] **Step 2**: Navigate to `/admin/bank-reconciliations/create` - [ ] **Step 3**: Fill reconciliation form: - Reconciliation Month: "2025-11" - Bank Statement Balance: 500,000 - Bank Statement Date: 2025-11-30 - Upload bank statement (PDF) - System Book Balance: (auto-calculated from ledger) - [ ] **Step 4**: Add outstanding items: - Outstanding checks: [{"amount": 5000, "check_number": "CHK-001"}] - Deposits in transit: [{"amount": 10000, "date": "2025-11-29"}] - Bank charges: [{"amount": 50, "description": "Service fee"}] - [ ] **Step 5**: Submit form - [ ] **Step 6**: Verify: - [ ] Reconciliation created - [ ] Adjusted balance calculated correctly - [ ] Discrepancy detected if amounts don't match - [ ] Status based on discrepancy #### Review Bank Reconciliation (Accountant) - [ ] **Step 1**: Login as `accountant@test.com` - [ ] **Step 2**: Navigate to pending reconciliation - [ ] **Step 3**: Review outstanding items - [ ] **Step 4**: Click "Review" - [ ] **Step 5**: Verify reviewed_at timestamp set #### Approve Bank Reconciliation (Chair) - [ ] **Step 1**: Login as `chair@test.com` - [ ] **Step 2**: Navigate to reviewed reconciliation - [ ] **Step 3**: Click "Approve" - [ ] **Step 4**: Verify: - [ ] Status changed to "completed" or "discrepancy" - [ ] Approved_at timestamp set --- ## 2. Automated Tests ### 2.1 Feature Tests Create file: `tests/Feature/FinancialWorkflowTest.php` ```php seed(FinancialWorkflowPermissionsSeeder::class); } /** @test */ public function small_amount_workflow_completes_without_chair() { // Create users $cashier = User::factory()->create(); $accountant = User::factory()->create(); $requester = User::factory()->create(); $cashier->assignRole('finance_cashier'); $accountant->assignRole('finance_accountant'); $requester->assignRole('finance_requester'); // Step 1: Requester submits $document = FinanceDocument::create([ 'submitted_by_user_id' => $requester->id, 'title' => 'Small Expense', 'amount' => 3000, 'request_type' => 'expense_reimbursement', 'status' => 'pending', 'submitted_at' => now(), ]); $document->amount_tier = $document->determineAmountTier(); $document->save(); $this->assertEquals('small', $document->amount_tier); // Step 2: Cashier approves $this->actingAs($cashier) ->post(route('admin.finance.approve', $document)) ->assertRedirect(); $document->refresh(); $this->assertEquals('approved_cashier', $document->status); // Step 3: Accountant approves $this->actingAs($accountant) ->post(route('admin.finance.approve', $document)) ->assertRedirect(); $document->refresh(); $this->assertEquals('approved_accountant', $document->status); $this->assertTrue($document->isApprovalStageComplete()); } /** @test */ public function medium_amount_requires_chair_approval() { // Similar test for medium amount... } /** @test */ public function accountant_can_create_payment_order() { // Test payment order creation... } /** @test */ public function cashier_can_verify_payment_order() { // Test payment verification... } /** @test */ public function cashier_can_execute_payment() { // Test payment execution... } /** @test */ public function cashier_ledger_calculates_balance_correctly() { // Test balance calculation... } /** @test */ public function bank_reconciliation_detects_discrepancy() { // Test discrepancy detection... } } ``` ### 2.2 Unit Tests Create file: `tests/Unit/PaymentOrderTest.php` ```php assertStringStartsWith('PO-', $number1); $this->assertStringStartsWith('PO-', $number2); $this->assertNotEquals($number1, $number2); } /** @test */ public function can_be_verified_when_pending() { $order = PaymentOrder::factory()->create([ 'status' => 'pending_verification', 'verification_status' => 'pending', ]); $this->assertTrue($order->canBeVerifiedByCashier()); } /** @test */ public function cannot_be_verified_when_already_verified() { $order = PaymentOrder::factory()->create([ 'status' => 'verified', 'verification_status' => 'approved', ]); $this->assertFalse($order->canBeVerifiedByCashier()); } /** @test */ public function can_be_executed_when_verified_and_approved() { $order = PaymentOrder::factory()->create([ 'status' => 'verified', 'verification_status' => 'approved', 'execution_status' => 'pending', ]); $this->assertTrue($order->canBeExecuted()); } } ``` ### 2.3 Integration Tests ```php /** @test */ public function complete_workflow_from_document_to_reconciliation() { // 1. Create and approve document // 2. Create payment order // 3. Verify payment order // 4. Execute payment // 5. Record in cashier ledger // 6. Create accounting transaction // 7. Perform bank reconciliation // Assert all steps completed successfully } ``` --- ## 3. Permission Tests ### Test Permission Enforcement ```php /** @test */ public function non_cashier_cannot_verify_payment() { $accountant = User::factory()->create(); $accountant->assignRole('finance_accountant'); $order = PaymentOrder::factory()->create([ 'status' => 'pending_verification', ]); $this->actingAs($accountant) ->post(route('admin.payment-orders.verify', $order)) ->assertForbidden(); } /** @test */ public function non_accountant_cannot_create_payment_order() { $cashier = User::factory()->create(); $cashier->assignRole('finance_cashier'); $document = FinanceDocument::factory()->create([ 'status' => 'approved_accountant', ]); $this->actingAs($cashier) ->post(route('admin.payment-orders.store', $document), [ 'payee_name' => 'Test', 'payment_amount' => 1000, 'payment_method' => 'cash', ]) ->assertForbidden(); } ``` --- ## 4. Edge Cases and Error Handling ### Test Cases - [ ] Cannot approve already approved document - [ ] Cannot verify already verified payment order - [ ] Cannot execute payment without verification - [ ] Cannot create payment order for unapproved document - [ ] Balance calculation with negative balance - [ ] Bank reconciliation with exact match (no discrepancy) - [ ] Bank reconciliation with large discrepancy - [ ] File upload size limits - [ ] Invalid file types - [ ] Missing required fields - [ ] Concurrent access to same document - [ ] Cancelling executed payment order (should fail) --- ## 5. Performance Tests ### Load Testing Checklist - [ ] Create 1,000 finance documents - [ ] Create 1,000 payment orders - [ ] Create 10,000 ledger entries - [ ] Test pagination performance - [ ] Test search/filter performance - [ ] Test balance calculation with large datasets - [ ] Test bank reconciliation with many outstanding items --- ## 6. Security Tests ### Security Checklist - [ ] SQL injection in search filters - [ ] XSS in notes fields - [ ] CSRF token validation - [ ] File upload security (malicious files) - [ ] Path traversal in file downloads - [ ] Authorization bypass attempts - [ ] Rate limiting on sensitive operations --- ## 7. User Acceptance Testing (UAT) ### UAT Checklist - [ ] UI is intuitive and easy to navigate - [ ] Error messages are clear and helpful - [ ] Success messages provide adequate feedback - [ ] Forms validate input properly - [ ] Tables display data correctly - [ ] Pagination works smoothly - [ ] Filters work as expected - [ ] File uploads work reliably - [ ] Downloads work correctly - [ ] Email notifications are received - [ ] Mobile responsiveness (if applicable) --- ## 8. Regression Testing ### After Each Change - [ ] Run all automated tests - [ ] Test complete workflow manually - [ ] Verify no existing functionality broken - [ ] Check database integrity - [ ] Verify audit logs still working --- ## Test Execution Log | Date | Tester | Test Section | Status | Notes | |------|--------|--------------|--------|-------| | | | | | | --- ## Bugs/Issues Tracker | ID | Priority | Description | Steps to Reproduce | Status | Fixed By | |----|----------|-------------|-------------------|--------|----------| | | | | | | | --- ## Sign-off - [ ] All manual tests passed - [ ] All automated tests passing - [ ] Performance acceptable - [ ] Security verified - [ ] UAT completed - [ ] Documentation complete **Tested by**: ________________ **Date**: ________________ **Approved by**: ________________ **Date**: ________________