Add phone login support and member import functionality

Features:
- Support login via phone number or email (LoginRequest)
- Add members:import-roster command for Excel roster import
- Merge survey emails with roster data

Code Quality (Phase 1-4):
- Add database locking for balance calculation
- Add self-approval checks for finance workflow
- Create service layer (FinanceDocumentApprovalService, PaymentVerificationService)
- Add HasAccountingEntries and HasApprovalWorkflow traits
- Create FormRequest classes for validation
- Add status-badge component
- Define authorization gates in AuthServiceProvider
- Add accounting config file

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-25 03:08:06 +08:00
parent ed7169b64e
commit 42099759e8
66 changed files with 3492 additions and 3803 deletions

View File

@@ -75,7 +75,7 @@ class FinanceWorkflowBrowserTest extends DuskTestCase
$this->browse(function (Browser $browser) use ($accountant) {
$browser->loginAs($accountant)
->visit(route('admin.finance-documents.create'))
->visit(route('admin.finance.create'))
->assertSee('新增財務單據')
->assertPresent('input[name="title"]')
->assertPresent('input[name="amount"]');
@@ -96,7 +96,7 @@ class FinanceWorkflowBrowserTest extends DuskTestCase
$this->browse(function (Browser $browser) use ($cashier) {
$browser->loginAs($cashier)
->visit(route('admin.finance-documents.index'))
->visit(route('admin.finance.index'))
->assertSee('測試單據')
->assertSee('待審核');
});
@@ -115,7 +115,7 @@ class FinanceWorkflowBrowserTest extends DuskTestCase
$this->browse(function (Browser $browser) use ($cashier, $document) {
$browser->loginAs($cashier)
->visit(route('admin.finance-documents.show', $document))
->visit(route('admin.finance.show', $document))
->assertSee('核准');
});
}
@@ -133,7 +133,7 @@ class FinanceWorkflowBrowserTest extends DuskTestCase
$this->browse(function (Browser $browser) use ($cashier, $document) {
$browser->loginAs($cashier)
->visit(route('admin.finance-documents.show', $document))
->visit(route('admin.finance.show', $document))
->assertSee('退回');
});
}
@@ -151,7 +151,7 @@ class FinanceWorkflowBrowserTest extends DuskTestCase
$this->browse(function (Browser $browser) use ($cashier, $document) {
$browser->loginAs($cashier)
->visit(route('admin.finance-documents.show', $document))
->visit(route('admin.finance.show', $document))
->press('核准')
->assertDialogOpened();
});
@@ -171,7 +171,7 @@ class FinanceWorkflowBrowserTest extends DuskTestCase
$this->browse(function (Browser $browser) use ($cashier) {
$browser->loginAs($cashier)
->visit(route('admin.finance-documents.index'))
->visit(route('admin.finance.index'))
->assertSee('15,000');
});
}
@@ -195,7 +195,7 @@ class FinanceWorkflowBrowserTest extends DuskTestCase
$this->browse(function (Browser $browser) use ($cashier) {
$browser->loginAs($cashier)
->visit(route('admin.finance-documents.index'))
->visit(route('admin.finance.index'))
->select('status', FinanceDocument::STATUS_PENDING)
->press('篩選')
->assertSee('待審核單據')
@@ -216,7 +216,7 @@ class FinanceWorkflowBrowserTest extends DuskTestCase
$this->browse(function (Browser $browser) use ($cashier, $document) {
$browser->loginAs($cashier)
->visit(route('admin.finance-documents.show', $document))
->visit(route('admin.finance.show', $document))
->press('退回')
->waitFor('.modal')
->assertSee('退回原因');
@@ -236,7 +236,7 @@ class FinanceWorkflowBrowserTest extends DuskTestCase
$this->browse(function (Browser $browser) use ($cashier, $document) {
$browser->loginAs($cashier)
->visit(route('admin.finance-documents.show', $document))
->visit(route('admin.finance.show', $document))
->assertSee('審核歷程');
});
}