'finance_cashier']); $this->cashier = User::factory()->create(['email' => 'cashier@test.com']); $this->cashier->assignRole('finance_cashier'); $this->cashier->givePermissionTo(['record_cashier_entry', '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); } }