Files
usher-manage-stack/tests/Feature/CashierLedgerWorkflowTest.php

317 lines
10 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\CashierLedgerEntry;
use App\Models\FinanceDocument;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Spatie\Permission\Models\Role;
use Tests\TestCase;
/**
* Cashier Ledger Workflow Feature Tests
*
* Tests cashier ledger entry creation and balance tracking
*/
class CashierLedgerWorkflowTest extends TestCase
{
use RefreshDatabase, WithFaker;
protected User $cashier;
protected function setUp(): void
{
parent::setUp();
$this->withoutMiddleware([\App\Http\Middleware\EnsureUserIsAdmin::class, \App\Http\Middleware\VerifyCsrfToken::class]);
$this->artisan('db:seed', ['--class' => 'FinancialWorkflowPermissionsSeeder']);
\Spatie\Permission\Models\Permission::findOrCreate('record_cashier_ledger', 'web');
\Spatie\Permission\Models\Permission::findOrCreate('view_cashier_ledger', 'web');
Role::firstOrCreate(['name' => 'finance_cashier']);
$this->cashier = User::factory()->create(['email' => 'cashier@test.com']);
$this->cashier->is_admin = true;
$this->cashier->save();
$this->cashier->assignRole('finance_cashier');
$this->cashier->givePermissionTo(['record_cashier_ledger', 'view_cashier_ledger']);
}
/** @test */
public function cashier_can_create_receipt_entry()
{
$this->actingAs($this->cashier);
$response = $this->post(route('admin.cashier-ledger.store'), [
'entry_type' => 'receipt',
'entry_date' => now()->format('Y-m-d'),
'amount' => 5000,
'payment_method' => 'bank_transfer',
'bank_account' => 'Test Bank 1234567890',
'receipt_number' => 'RCP001',
'notes' => 'Test receipt entry',
]);
$response->assertRedirect();
$this->assertDatabaseHas('cashier_ledger_entries', [
'entry_type' => 'receipt',
'amount' => 5000,
'bank_account' => 'Test Bank 1234567890',
'recorded_by_cashier_id' => $this->cashier->id,
]);
}
/** @test */
public function receipt_entry_increases_balance()
{
// Create initial entry
$entry1 = CashierLedgerEntry::create([
'entry_type' => 'receipt',
'entry_date' => now(),
'amount' => 10000,
'payment_method' => 'cash',
'bank_account' => 'Test Account',
'balance_before' => 0,
'balance_after' => 10000,
'recorded_by_cashier_id' => $this->cashier->id,
'recorded_at' => now(),
]);
$this->assertEquals(10000, $entry1->balance_after);
// Create second receipt entry
$entry2 = CashierLedgerEntry::create([
'entry_type' => 'receipt',
'entry_date' => now(),
'amount' => 5000,
'payment_method' => 'cash',
'bank_account' => 'Test Account',
'balance_before' => 10000,
'balance_after' => 15000,
'recorded_by_cashier_id' => $this->cashier->id,
'recorded_at' => now(),
]);
$this->assertEquals(15000, $entry2->balance_after);
$this->assertEquals(15000, CashierLedgerEntry::getLatestBalance('Test Account'));
}
/** @test */
public function payment_entry_decreases_balance()
{
// Create initial balance
CashierLedgerEntry::create([
'entry_type' => 'receipt',
'entry_date' => now(),
'amount' => 20000,
'payment_method' => 'cash',
'bank_account' => 'Test Account',
'balance_before' => 0,
'balance_after' => 20000,
'recorded_by_cashier_id' => $this->cashier->id,
'recorded_at' => now(),
]);
// Create payment entry
$paymentEntry = CashierLedgerEntry::create([
'entry_type' => 'payment',
'entry_date' => now(),
'amount' => 8000,
'payment_method' => 'cash',
'bank_account' => 'Test Account',
'balance_before' => 20000,
'balance_after' => 12000,
'recorded_by_cashier_id' => $this->cashier->id,
'recorded_at' => now(),
]);
$this->assertEquals(12000, $paymentEntry->balance_after);
$this->assertEquals(12000, CashierLedgerEntry::getLatestBalance('Test Account'));
}
/** @test */
public function balance_calculation_is_correct()
{
$entry = new CashierLedgerEntry([
'entry_type' => 'receipt',
'amount' => 5000,
]);
$newBalance = $entry->calculateBalanceAfter(10000);
$this->assertEquals(15000, $newBalance);
$entry->entry_type = 'payment';
$newBalance = $entry->calculateBalanceAfter(10000);
$this->assertEquals(5000, $newBalance);
}
/** @test */
public function separate_balances_are_maintained_for_different_accounts()
{
// Account 1
CashierLedgerEntry::create([
'entry_type' => 'receipt',
'entry_date' => now(),
'amount' => 10000,
'payment_method' => 'bank_transfer',
'bank_account' => 'Bank A - 1111',
'balance_before' => 0,
'balance_after' => 10000,
'recorded_by_cashier_id' => $this->cashier->id,
'recorded_at' => now(),
]);
// Account 2
CashierLedgerEntry::create([
'entry_type' => 'receipt',
'entry_date' => now(),
'amount' => 5000,
'payment_method' => 'bank_transfer',
'bank_account' => 'Bank B - 2222',
'balance_before' => 0,
'balance_after' => 5000,
'recorded_by_cashier_id' => $this->cashier->id,
'recorded_at' => now(),
]);
$this->assertEquals(10000, CashierLedgerEntry::getLatestBalance('Bank A - 1111'));
$this->assertEquals(5000, CashierLedgerEntry::getLatestBalance('Bank B - 2222'));
}
/** @test */
public function ledger_entry_can_be_linked_to_finance_document()
{
$financeDoc = FinanceDocument::factory()->create([
'amount' => 3000,
'status' => 'approved_accountant',
]);
$entry = CashierLedgerEntry::create([
'finance_document_id' => $financeDoc->id,
'entry_type' => 'payment',
'entry_date' => now(),
'amount' => 3000,
'payment_method' => 'cash',
'bank_account' => 'Test Account',
'balance_before' => 10000,
'balance_after' => 7000,
'recorded_by_cashier_id' => $this->cashier->id,
'recorded_at' => now(),
]);
$this->assertEquals($financeDoc->id, $entry->finance_document_id);
$this->assertInstanceOf(FinanceDocument::class, $entry->financeDocument);
}
/** @test */
public function entry_type_helper_methods_work_correctly()
{
$receiptEntry = new CashierLedgerEntry(['entry_type' => 'receipt']);
$this->assertTrue($receiptEntry->isReceipt());
$this->assertFalse($receiptEntry->isPayment());
$paymentEntry = new CashierLedgerEntry(['entry_type' => 'payment']);
$this->assertTrue($paymentEntry->isPayment());
$this->assertFalse($paymentEntry->isReceipt());
}
/** @test */
public function payment_method_text_is_correctly_displayed()
{
$entry1 = new CashierLedgerEntry(['payment_method' => 'cash']);
$this->assertEquals('現金', $entry1->getPaymentMethodText());
$entry2 = new CashierLedgerEntry(['payment_method' => 'bank_transfer']);
$this->assertEquals('銀行轉帳', $entry2->getPaymentMethodText());
$entry3 = new CashierLedgerEntry(['payment_method' => 'check']);
$this->assertEquals('支票', $entry3->getPaymentMethodText());
}
/** @test */
public function cashier_can_view_balance_report()
{
// Create multiple entries
CashierLedgerEntry::create([
'entry_type' => 'receipt',
'entry_date' => now(),
'amount' => 100000,
'payment_method' => 'bank_transfer',
'bank_account' => 'Main Account',
'balance_before' => 0,
'balance_after' => 100000,
'recorded_by_cashier_id' => $this->cashier->id,
'recorded_at' => now(),
]);
CashierLedgerEntry::create([
'entry_type' => 'payment',
'entry_date' => now(),
'amount' => 30000,
'payment_method' => 'bank_transfer',
'bank_account' => 'Main Account',
'balance_before' => 100000,
'balance_after' => 70000,
'recorded_by_cashier_id' => $this->cashier->id,
'recorded_at' => now(),
]);
$this->actingAs($this->cashier);
$response = $this->get(route('admin.cashier-ledger.balance-report'));
$response->assertStatus(200);
$response->assertViewHas('accounts');
$response->assertViewHas('monthlySummary');
}
/** @test */
public function zero_balance_is_returned_for_new_account()
{
$balance = CashierLedgerEntry::getLatestBalance('New Account');
$this->assertEquals(0, $balance);
}
/** @test */
public function ledger_entries_can_be_filtered_by_date_range()
{
$this->actingAs($this->cashier);
// Create entries with different dates
CashierLedgerEntry::create([
'entry_type' => 'receipt',
'entry_date' => now()->subDays(10),
'amount' => 1000,
'payment_method' => 'cash',
'bank_account' => 'Test',
'balance_before' => 0,
'balance_after' => 1000,
'recorded_by_cashier_id' => $this->cashier->id,
'recorded_at' => now()->subDays(10),
]);
CashierLedgerEntry::create([
'entry_type' => 'receipt',
'entry_date' => now(),
'amount' => 2000,
'payment_method' => 'cash',
'bank_account' => 'Test',
'balance_before' => 1000,
'balance_after' => 3000,
'recorded_by_cashier_id' => $this->cashier->id,
'recorded_at' => now(),
]);
$response = $this->get(route('admin.cashier-ledger.index', [
'date_from' => now()->subDays(5)->format('Y-m-d'),
'date_to' => now()->format('Y-m-d'),
]));
$response->assertStatus(200);
}
}