Initial commit

This commit is contained in:
2025-11-20 23:21:05 +08:00
commit 13bc6db529
378 changed files with 54527 additions and 0 deletions

View File

@@ -0,0 +1,302 @@
<?php
namespace Tests\Unit;
use App\Models\BankReconciliation;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
/**
* Bank Reconciliation Model Unit Tests
*
* Tests calculation and validation methods in BankReconciliation model
*/
class BankReconciliationTest extends TestCase
{
use RefreshDatabase;
/** @test */
public function it_calculates_adjusted_balance_with_all_items()
{
$reconciliation = new BankReconciliation([
'system_book_balance' => 100000,
'outstanding_checks' => [
['check_number' => 'CHK001', 'amount' => 3000],
['check_number' => 'CHK002', 'amount' => 2000],
],
'deposits_in_transit' => [
['date' => '2024-01-15', 'amount' => 5000],
['date' => '2024-01-16', 'amount' => 3000],
],
'bank_charges' => [
['amount' => 500],
['amount' => 200],
],
]);
// Adjusted = 100000 + (5000 + 3000) - (3000 + 2000) - (500 + 200) = 102300
$adjusted = $reconciliation->calculateAdjustedBalance();
$this->assertEquals(102300, $adjusted);
}
/** @test */
public function it_calculates_adjusted_balance_with_no_items()
{
$reconciliation = new BankReconciliation([
'system_book_balance' => 50000,
'outstanding_checks' => null,
'deposits_in_transit' => null,
'bank_charges' => null,
]);
$adjusted = $reconciliation->calculateAdjustedBalance();
$this->assertEquals(50000, $adjusted);
}
/** @test */
public function it_calculates_adjusted_balance_with_empty_arrays()
{
$reconciliation = new BankReconciliation([
'system_book_balance' => 50000,
'outstanding_checks' => [],
'deposits_in_transit' => [],
'bank_charges' => [],
]);
$adjusted = $reconciliation->calculateAdjustedBalance();
$this->assertEquals(50000, $adjusted);
}
/** @test */
public function it_calculates_discrepancy_correctly()
{
$reconciliation = new BankReconciliation([
'bank_statement_balance' => 100000,
'system_book_balance' => 95000,
'outstanding_checks' => [
['amount' => 3000],
],
'deposits_in_transit' => [
['amount' => 5000],
],
'bank_charges' => [
['amount' => 500],
],
]);
// Adjusted = 95000 + 5000 - 3000 - 500 = 96500
// Discrepancy = |100000 - 96500| = 3500
$discrepancy = $reconciliation->calculateDiscrepancy();
$this->assertEquals(3500, $discrepancy);
}
/** @test */
public function it_detects_discrepancy_above_tolerance()
{
$reconciliation = new BankReconciliation([
'bank_statement_balance' => 100000,
'system_book_balance' => 95000,
'outstanding_checks' => [],
'deposits_in_transit' => [],
'bank_charges' => [],
]);
// Discrepancy = 5000, which is > 0.01
$this->assertTrue($reconciliation->hasDiscrepancy());
}
/** @test */
public function it_allows_small_discrepancy_within_tolerance()
{
$reconciliation = new BankReconciliation([
'bank_statement_balance' => 100000.00,
'system_book_balance' => 100000.00,
'outstanding_checks' => [],
'deposits_in_transit' => [],
'bank_charges' => [],
]);
// Discrepancy = 0, which is <= 0.01
$this->assertFalse($reconciliation->hasDiscrepancy());
}
/** @test */
public function it_generates_outstanding_items_summary_correctly()
{
$reconciliation = new BankReconciliation([
'outstanding_checks' => [
['check_number' => 'CHK001', 'amount' => 3000],
['check_number' => 'CHK002', 'amount' => 2000],
['check_number' => 'CHK003', 'amount' => 1500],
],
'deposits_in_transit' => [
['date' => '2024-01-15', 'amount' => 5000],
['date' => '2024-01-16', 'amount' => 3000],
],
'bank_charges' => [
['amount' => 500],
['amount' => 200],
['amount' => 100],
],
]);
$summary = $reconciliation->getOutstandingItemsSummary();
$this->assertEquals(6500, $summary['total_outstanding_checks']);
$this->assertEquals(3, $summary['outstanding_checks_count']);
$this->assertEquals(8000, $summary['total_deposits_in_transit']);
$this->assertEquals(2, $summary['deposits_in_transit_count']);
$this->assertEquals(800, $summary['total_bank_charges']);
$this->assertEquals(3, $summary['bank_charges_count']);
}
/** @test */
public function it_handles_null_outstanding_items_in_summary()
{
$reconciliation = new BankReconciliation([
'outstanding_checks' => null,
'deposits_in_transit' => null,
'bank_charges' => null,
]);
$summary = $reconciliation->getOutstandingItemsSummary();
$this->assertEquals(0, $summary['total_outstanding_checks']);
$this->assertEquals(0, $summary['outstanding_checks_count']);
$this->assertEquals(0, $summary['total_deposits_in_transit']);
$this->assertEquals(0, $summary['deposits_in_transit_count']);
$this->assertEquals(0, $summary['total_bank_charges']);
$this->assertEquals(0, $summary['bank_charges_count']);
}
/** @test */
public function it_can_be_reviewed_when_pending()
{
$reconciliation = new BankReconciliation([
'reconciliation_status' => 'pending',
'reviewed_at' => null,
]);
$this->assertTrue($reconciliation->canBeReviewed());
}
/** @test */
public function it_cannot_be_reviewed_when_already_reviewed()
{
$reconciliation = new BankReconciliation([
'reconciliation_status' => 'pending',
'reviewed_at' => now(),
]);
$this->assertFalse($reconciliation->canBeReviewed());
}
/** @test */
public function it_can_be_approved_when_reviewed()
{
$reconciliation = new BankReconciliation([
'reconciliation_status' => 'pending',
'reviewed_at' => now(),
'approved_at' => null,
]);
$this->assertTrue($reconciliation->canBeApproved());
}
/** @test */
public function it_cannot_be_approved_when_not_reviewed()
{
$reconciliation = new BankReconciliation([
'reconciliation_status' => 'pending',
'reviewed_at' => null,
'approved_at' => null,
]);
$this->assertFalse($reconciliation->canBeApproved());
}
/** @test */
public function it_cannot_be_approved_when_already_approved()
{
$reconciliation = new BankReconciliation([
'reconciliation_status' => 'completed',
'reviewed_at' => now(),
'approved_at' => now(),
]);
$this->assertFalse($reconciliation->canBeApproved());
}
/** @test */
public function it_detects_pending_status()
{
$pending = new BankReconciliation(['reconciliation_status' => 'pending']);
$this->assertTrue($pending->isPending());
$completed = new BankReconciliation(['reconciliation_status' => 'completed']);
$this->assertFalse($completed->isPending());
}
/** @test */
public function it_detects_completed_status()
{
$completed = new BankReconciliation(['reconciliation_status' => 'completed']);
$this->assertTrue($completed->isCompleted());
$pending = new BankReconciliation(['reconciliation_status' => 'pending']);
$this->assertFalse($pending->isCompleted());
}
/** @test */
public function it_detects_unresolved_discrepancy()
{
$withDiscrepancy = new BankReconciliation([
'reconciliation_status' => 'discrepancy',
]);
$this->assertTrue($withDiscrepancy->hasUnresolvedDiscrepancy());
$completed = new BankReconciliation([
'reconciliation_status' => 'completed',
]);
$this->assertFalse($completed->hasUnresolvedDiscrepancy());
}
/** @test */
public function status_text_is_correct()
{
$pending = new BankReconciliation(['reconciliation_status' => 'pending']);
$this->assertEquals('待覆核', $pending->getStatusText());
$completed = new BankReconciliation(['reconciliation_status' => 'completed']);
$this->assertEquals('已完成', $completed->getStatusText());
$discrepancy = new BankReconciliation(['reconciliation_status' => 'discrepancy']);
$this->assertEquals('有差異', $discrepancy->getStatusText());
}
/** @test */
public function it_handles_missing_amounts_in_outstanding_items()
{
$reconciliation = new BankReconciliation([
'system_book_balance' => 100000,
'outstanding_checks' => [
['check_number' => 'CHK001'], // Missing amount
['check_number' => 'CHK002', 'amount' => 2000],
],
'deposits_in_transit' => [
['date' => '2024-01-15'], // Missing amount
['date' => '2024-01-16', 'amount' => 3000],
],
'bank_charges' => [
['description' => 'Fee'], // Missing amount
['amount' => 200],
],
]);
// Should handle missing amounts gracefully (treat as 0)
$adjusted = $reconciliation->calculateAdjustedBalance();
// 100000 + 3000 - 2000 - 200 = 100800
$this->assertEquals(100800, $adjusted);
}
}