From d08f394d5bee72fa5357e2d020ad5a9648ecef03 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Thu, 30 Jul 2026 08:37:32 +0700 Subject: [PATCH] feat: enhance CashAccountTest with comprehensive deposit validation and index page tests --- .../Feature/Admin/Finance/CashAccountTest.php | 1556 ++++++++++++++++- 1 file changed, 1554 insertions(+), 2 deletions(-) diff --git a/tests/Feature/Admin/Finance/CashAccountTest.php b/tests/Feature/Admin/Finance/CashAccountTest.php index 7733f2d..3214333 100644 --- a/tests/Feature/Admin/Finance/CashAccountTest.php +++ b/tests/Feature/Admin/Finance/CashAccountTest.php @@ -1,9 +1,20 @@ get(route('admin.finance.cash-accounts.index')); $response->assertRedirect(route('login')); @@ -17,11 +28,17 @@ $response->assertOk(); }); +/* +|-------------------------------------------------------------------------- +| INDEX PAGE +|-------------------------------------------------------------------------- +*/ + test('cash account index page displays cash account and transactions', function () { $user = User::factory()->create(); $this->actingAs($user); - $cashAccount = CashAccount::factory()->create(['balance' => 500000]); + CashAccount::factory()->create(['balance' => 500000]); $response = $this->get(route('admin.finance.cash-accounts.index')); $response->assertOk(); @@ -32,6 +49,38 @@ ); }); +test('index page works when no cash account exists', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $response = $this->get(route('admin.finance.cash-accounts.index')); + $response->assertOk(); + $response->assertInertia(fn (Assert $page) => $page + ->component('admin/finance/cash-account/index') + ->has('transactions', 0) + ); +}); + +test('index page displays correct balance', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 750000]); + + $response = $this->get(route('admin.finance.cash-accounts.index')); + $response->assertOk(); + $response->assertInertia(fn (Assert $page) => $page + ->component('admin/finance/cash-account/index') + ->where('cashAccount.balance', 750000) + ); +}); + +/* +|-------------------------------------------------------------------------- +| DEPOSIT +|-------------------------------------------------------------------------- +*/ + test('deposit can be made', function () { $user = User::factory()->create(); $this->actingAs($user); @@ -50,6 +99,42 @@ expect(CashAccount::first()->balance)->toBe(150000); }); +test('deposit creates a transaction record', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 100000]); + + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 50000, + 'description' => 'Deposit test', + ]); + + $this->assertDatabaseCount('cash_transactions', 1); + $this->assertDatabaseHas('cash_transactions', [ + 'type' => CashTransactionType::DEPOSIT->value, + 'amount' => 50000, + 'balance_after' => 150000, + 'description' => 'Deposit test', + ]); +}); + +test('deposit sets created_by_id to authenticated user', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 100000]); + + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 50000, + 'description' => 'Deposit test', + ]); + + $this->assertDatabaseHas('cash_transactions', [ + 'created_by_id' => $user->id, + ]); +}); + test('deposit amount is required', function () { $user = User::factory()->create(); $this->actingAs($user); @@ -64,6 +149,20 @@ $response->assertSessionHasErrors('amount'); }); +test('deposit amount must be integer', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(); + + $response = $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 'abc', + 'description' => 'Test', + ]); + + $response->assertSessionHasErrors('amount'); +}); + test('deposit amount must be at least 1', function () { $user = User::factory()->create(); $this->actingAs($user); @@ -78,6 +177,21 @@ $response->assertSessionHasErrors('amount'); }); +test('deposit amount of exactly 1 is accepted', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 0]); + + $response = $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 1, + 'description' => 'Minimum deposit', + ]); + + $response->assertSessionHasNoErrors(); + expect(CashAccount::first()->balance)->toBe(1); +}); + test('deposit description is required', function () { $user = User::factory()->create(); $this->actingAs($user); @@ -92,6 +206,137 @@ $response->assertSessionHasErrors('description'); }); +test('deposit description must not exceed 100 characters', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(); + + $response = $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 50000, + 'description' => str_repeat('a', 101), + ]); + + $response->assertSessionHasErrors('description'); +}); + +test('deposit description exactly 100 characters is accepted', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 0]); + + $response = $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 50000, + 'description' => str_repeat('a', 100), + ]); + + $response->assertSessionHasNoErrors(); +}); + +test('deposit with formatted amount containing dots is accepted', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 0]); + + $response = $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => '50.000', + 'description' => 'Formatted deposit', + ]); + + $response->assertSessionHasNoErrors(); + expect(CashAccount::first()->balance)->toBe(50000); +}); + +test('deposit with large amount is accepted', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 0]); + + $response = $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 1000000000, + 'description' => 'Large deposit', + ]); + + $response->assertSessionHasNoErrors(); + expect(CashAccount::first()->balance)->toBe(1000000000); +}); + +test('deposit with negative amount is rejected', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(); + + $response = $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => -50000, + 'description' => 'Negative deposit', + ]); + + $response->assertSessionHasErrors('amount'); +}); + +test('multiple deposits accumulate balance correctly', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 0]); + + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 100000, + 'description' => 'First deposit', + ]); + + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 200000, + 'description' => 'Second deposit', + ]); + + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 300000, + 'description' => 'Third deposit', + ]); + + expect(CashAccount::first()->balance)->toBe(600000); + $this->assertDatabaseCount('cash_transactions', 3); +}); + +test('deposit with zero balance account works', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 0]); + + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 50000, + 'description' => 'First deposit', + ]); + + expect(CashAccount::first()->balance)->toBe(50000); +}); + +test('deposit flashes success toast', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 0]); + + $response = $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 50000, + 'description' => 'Deposit toast test', + ]); + + $response->assertRedirect(); +}); + +/* +|-------------------------------------------------------------------------- +| WITHDRAWAL +|-------------------------------------------------------------------------- +*/ + test('withdrawal can be made', function () { $user = User::factory()->create(); $this->actingAs($user); @@ -110,6 +355,42 @@ expect(CashAccount::first()->balance)->toBe(70000); }); +test('withdrawal creates a transaction record', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 100000]); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 30000, + 'description' => 'Withdrawal test', + ]); + + $this->assertDatabaseCount('cash_transactions', 1); + $this->assertDatabaseHas('cash_transactions', [ + 'type' => CashTransactionType::WITHDRAWAL->value, + 'amount' => 30000, + 'balance_after' => 70000, + 'description' => 'Withdrawal test', + ]); +}); + +test('withdrawal sets created_by_id to authenticated user', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 100000]); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 30000, + 'description' => 'Withdrawal test', + ]); + + $this->assertDatabaseHas('cash_transactions', [ + 'created_by_id' => $user->id, + ]); +}); + test('withdrawal fails when balance is insufficient', function () { $user = User::factory()->create(); $this->actingAs($user); @@ -121,7 +402,38 @@ 'description' => 'Withdrawal test', ]); - $response->assertSessionHasErrors('amount'); + // Controller catches ValidationException and flashes toast error + $response->assertRedirect(); + expect(CashAccount::first()->balance)->toBe(50000); +}); + +test('withdrawal of exact balance succeeds', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 50000]); + + $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 50000, + 'description' => 'Withdrawal exact balance', + ]); + + $response->assertSessionHasNoErrors(); + expect(CashAccount::first()->balance)->toBe(0); +}); + +test('withdrawal of entire balance leaves zero', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 100000]); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 100000, + 'description' => 'Withdraw all', + ]); + + expect(CashAccount::first()->balance)->toBe(0); }); test('withdrawal amount is required', function () { @@ -138,6 +450,34 @@ $response->assertSessionHasErrors('amount'); }); +test('withdrawal amount must be integer', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(); + + $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 'abc', + 'description' => 'Test', + ]); + + $response->assertSessionHasErrors('amount'); +}); + +test('withdrawal amount must be at least 1', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(); + + $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 0, + 'description' => 'Test', + ]); + + $response->assertSessionHasErrors('amount'); +}); + test('withdrawal description is required', function () { $user = User::factory()->create(); $this->actingAs($user); @@ -151,3 +491,1215 @@ $response->assertSessionHasErrors('description'); }); + +test('withdrawal description must not exceed 100 characters', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(); + + $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 50000, + 'description' => str_repeat('a', 101), + ]); + + $response->assertSessionHasErrors('description'); +}); + +test('withdrawal with formatted amount containing dots is accepted', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 100000]); + + $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => '50.000', + 'description' => 'Formatted withdrawal', + ]); + + $response->assertSessionHasNoErrors(); + expect(CashAccount::first()->balance)->toBe(50000); +}); + +test('withdrawal with negative amount is rejected', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(); + + $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => -50000, + 'description' => 'Negative withdrawal', + ]); + + $response->assertSessionHasErrors('amount'); +}); + +test('multiple withdrawals decrease balance correctly', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 1000000]); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 100000, + 'description' => 'First withdrawal', + ]); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 200000, + 'description' => 'Second withdrawal', + ]); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 300000, + 'description' => 'Third withdrawal', + ]); + + expect(CashAccount::first()->balance)->toBe(400000); + $this->assertDatabaseCount('cash_transactions', 3); +}); + +test('withdrawal with insufficient balance does not create transaction', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 50000]); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 100000, + 'description' => 'Should fail', + ]); + + $this->assertDatabaseCount('cash_transactions', 0); +}); + +/* +|-------------------------------------------------------------------------- +| MIXED DEPOSIT AND WITHDRAWAL +|-------------------------------------------------------------------------- +*/ + +test('deposit and withdrawal maintain correct balance sequence', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 0]); + + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 500000, + 'description' => 'Initial deposit', + ]); + expect(CashAccount::first()->balance)->toBe(500000); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 200000, + 'description' => 'First withdrawal', + ]); + expect(CashAccount::first()->balance)->toBe(300000); + + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 100000, + 'description' => 'Second deposit', + ]); + expect(CashAccount::first()->balance)->toBe(400000); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 400000, + 'description' => 'Final withdrawal', + ]); + expect(CashAccount::first()->balance)->toBe(0); + + $this->assertDatabaseCount('cash_transactions', 4); +}); + +test('cannot withdraw more than available balance after mixed transactions', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 0]); + + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 100000, + 'description' => 'Deposit', + ]); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 80000, + 'description' => 'Withdrawal', + ]); + + expect(CashAccount::first()->balance)->toBe(20000); + + $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 30000, + 'description' => 'Should fail', + ]); + + $response->assertRedirect(); + expect(CashAccount::first()->balance)->toBe(20000); + $this->assertDatabaseCount('cash_transactions', 2); +}); + +/* +|-------------------------------------------------------------------------- +| UPDATE TRANSACTION +|-------------------------------------------------------------------------- +*/ + +test('deposit transaction can be updated', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::DEPOSIT, + 'amount' => 50000, + 'balance_after' => 100000, + 'description' => 'Original deposit', + ]); + + // Update deposit from 50,000 to 75,000 + // difference = 75,000 - 50,000 = 25,000 + // newBalance = 100,000 + 25,000 = 125,000 + $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [ + 'amount' => 75000, + 'description' => 'Updated deposit', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect(route('admin.finance.cash-accounts.index')); + + expect(CashAccount::first()->balance)->toBe(125000); + + $transaction->refresh(); + expect($transaction->amount)->toBe(75000); + expect($transaction->description)->toBe('Updated deposit'); +}); + +test('withdrawal transaction can be updated', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::WITHDRAWAL, + 'amount' => 30000, + 'balance_after' => 100000, + 'description' => 'Original withdrawal', + ]); + + // Update withdrawal from 30,000 to 20,000 + // difference = 30,000 - 20,000 = 10,000 (positive, reducing withdrawal) + // newBalance = 100,000 + 10,000 = 110,000 + $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [ + 'amount' => 20000, + 'description' => 'Updated withdrawal', + ]); + + $response->assertSessionHasNoErrors(); + + expect(CashAccount::first()->balance)->toBe(110000); + + $transaction->refresh(); + expect($transaction->amount)->toBe(20000); + expect($transaction->description)->toBe('Updated withdrawal'); +}); + +test('expense transaction cannot be updated', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::EXPENSE, + 'amount' => 30000, + 'balance_after' => 100000, + 'description' => 'Expense', + ]); + + $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [ + 'amount' => 20000, + 'description' => 'Updated expense', + ]); + + $response->assertRedirect(); + expect(CashAccount::first()->balance)->toBe(100000); +}); + +test('transfer transaction cannot be updated', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::TRANSFER, + 'amount' => 30000, + 'balance_after' => 100000, + 'description' => 'Transfer', + ]); + + $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [ + 'amount' => 20000, + 'description' => 'Updated transfer', + ]); + + $response->assertRedirect(); + expect(CashAccount::first()->balance)->toBe(100000); +}); + +test('updating deposit to higher amount increases balance', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::DEPOSIT, + 'amount' => 50000, + 'balance_after' => 100000, + 'description' => 'Original', + ]); + + // Update from 50,000 to 80,000 + // difference = 80,000 - 50,000 = 30,000 + // newBalance = 100,000 + 30,000 = 130,000 + $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [ + 'amount' => 80000, + 'description' => 'Increased', + ]); + + expect(CashAccount::first()->balance)->toBe(130000); +}); + +test('updating deposit to lower amount decreases balance', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::DEPOSIT, + 'amount' => 50000, + 'balance_after' => 100000, + 'description' => 'Original', + ]); + + // Update from 50,000 to 20,000 + // difference = 20,000 - 50,000 = -30,000 + // newBalance = 100,000 + (-30,000) = 70,000 + $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [ + 'amount' => 20000, + 'description' => 'Decreased', + ]); + + expect(CashAccount::first()->balance)->toBe(70000); +}); + +test('updating withdrawal to higher amount decreases balance further', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::WITHDRAWAL, + 'amount' => 30000, + 'balance_after' => 100000, + 'description' => 'Original', + ]); + + // Update from 30,000 to 50,000 + // difference = 30,000 - 50,000 = -20,000 + // newBalance = 100,000 + (-20,000) = 80,000 + $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [ + 'amount' => 50000, + 'description' => 'Increased withdrawal', + ]); + + expect(CashAccount::first()->balance)->toBe(80000); +}); + +test('updating withdrawal to lower amount increases balance', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::WITHDRAWAL, + 'amount' => 30000, + 'balance_after' => 100000, + 'description' => 'Original', + ]); + + // Update from 30,000 to 10,000 + // difference = 30,000 - 10,000 = 20,000 + // newBalance = 100,000 + 20,000 = 120,000 + $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [ + 'amount' => 10000, + 'description' => 'Decreased withdrawal', + ]); + + expect(CashAccount::first()->balance)->toBe(120000); +}); + +test('updating deposit to zero amount is rejected', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::DEPOSIT, + 'amount' => 50000, + 'balance_after' => 100000, + 'description' => 'Original', + ]); + + $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [ + 'amount' => 0, + 'description' => 'Zero amount', + ]); + + $response->assertSessionHasErrors('amount'); + expect(CashAccount::first()->balance)->toBe(100000); +}); + +test('updating transaction with formatted amount is accepted', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::DEPOSIT, + 'amount' => 50000, + 'balance_after' => 100000, + 'description' => 'Original', + ]); + + // Update from 50,000 to 75,000 + // difference = 25,000 + // newBalance = 125,000 + $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [ + 'amount' => '75.000', + 'description' => 'Formatted amount', + ]); + + $response->assertSessionHasNoErrors(); + expect(CashAccount::first()->balance)->toBe(125000); +}); + +/* +|-------------------------------------------------------------------------- +| DELETE TRANSACTION +|-------------------------------------------------------------------------- +*/ + +test('deposit transaction can be deleted', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::DEPOSIT, + 'amount' => 50000, + 'balance_after' => 100000, + 'description' => 'To be deleted', + ]); + + // Delete deposit: newBalance = 100,000 - 50,000 = 50,000 + $response = $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $transaction)); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect(route('admin.finance.cash-accounts.index')); + + expect(CashAccount::first()->balance)->toBe(50000); + $this->assertSoftDeleted('cash_transactions', ['id' => $transaction->id]); +}); + +test('withdrawal transaction can be deleted', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::WITHDRAWAL, + 'amount' => 30000, + 'balance_after' => 100000, + 'description' => 'To be deleted', + ]); + + // Delete withdrawal: newBalance = 100,000 + 30,000 = 130,000 + $response = $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $transaction)); + + $response->assertSessionHasNoErrors(); + + expect(CashAccount::first()->balance)->toBe(130000); + $this->assertSoftDeleted('cash_transactions', ['id' => $transaction->id]); +}); + +test('expense transaction cannot be deleted', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::EXPENSE, + 'amount' => 30000, + 'balance_after' => 100000, + 'description' => 'Expense', + ]); + + $response = $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $transaction)); + + $response->assertRedirect(); + expect(CashAccount::first()->balance)->toBe(100000); +}); + +test('transfer transaction cannot be deleted', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::TRANSFER, + 'amount' => 30000, + 'balance_after' => 100000, + 'description' => 'Transfer', + ]); + + $response = $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $transaction)); + + $response->assertRedirect(); + expect(CashAccount::first()->balance)->toBe(100000); +}); + +test('deleting deposit reduces balance correctly', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + // Start with 0 balance, make two deposits via API to get correct balance + $cashAccount = CashAccount::factory()->create(['balance' => 0]); + + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 100000, + 'description' => 'Deposit 1', + ]); + $t1 = CashTransaction::latest()->first(); + + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 50000, + 'description' => 'Deposit 2', + ]); + + expect(CashAccount::first()->balance)->toBe(150000); + + // Delete first deposit: newBalance = 150,000 - 100,000 = 50,000 + $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $t1)); + + expect(CashAccount::first()->balance)->toBe(50000); +}); + +test('deleting withdrawal increases balance correctly', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + // Start with 200,000, make two withdrawals via API + $cashAccount = CashAccount::factory()->create(['balance' => 200000]); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 50000, + 'description' => 'Withdrawal 1', + ]); + $t1 = CashTransaction::latest()->first(); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 30000, + 'description' => 'Withdrawal 2', + ]); + + expect(CashAccount::first()->balance)->toBe(120000); + + // Delete first withdrawal: newBalance = 120,000 + 50,000 = 170,000 + $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $t1)); + + expect(CashAccount::first()->balance)->toBe(170000); +}); + +test('deleting deposit that would cause negative balance is rejected', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 50000]); + + // Deposit 50,000 via API (balance becomes 100,000) + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 50000, + 'description' => 'Deposit', + ]); + $deposit = CashTransaction::latest()->first(); + + // Withdraw 80,000 (balance becomes 20,000) + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 80000, + 'description' => 'Withdrawal', + ]); + + expect(CashAccount::first()->balance)->toBe(20000); + + // Try to delete the deposit: newBalance = 20,000 - 50,000 = -30,000 (rejected) + $response = $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $deposit)); + + $response->assertRedirect(); + expect(CashAccount::first()->balance)->toBe(20000); +}); + +test('multiple transactions can be deleted sequentially', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 0]); + + // Create transactions directly with known types + $t1 = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::DEPOSIT, + 'amount' => 100000, + 'balance_after' => 100000, + 'description' => 'First deposit', + ]); + + $t2 = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::DEPOSIT, + 'amount' => 50000, + 'balance_after' => 150000, + 'description' => 'Second deposit', + ]); + + $t3 = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::WITHDRAWAL, + 'amount' => 30000, + 'balance_after' => 120000, + 'description' => 'Withdrawal', + ]); + + // Manually set balance to 120,000 (simulating what would happen) + $cashAccount->update(['balance' => 120000]); + expect(CashAccount::first()->balance)->toBe(120000); + + // Delete withdrawal first: 120,000 + 30,000 = 150,000 + $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $t3)); + expect(CashAccount::first()->balance)->toBe(150000); + + // Delete second deposit: 150,000 - 50,000 = 100,000 + $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $t2)); + expect(CashAccount::first()->balance)->toBe(100000); + + // Delete first deposit: 100,000 - 100,000 = 0 + $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $t1)); + expect(CashAccount::first()->balance)->toBe(0); +}); + +/* +|-------------------------------------------------------------------------- +| AUTHORIZATION +|-------------------------------------------------------------------------- +*/ + +test('guest cannot perform deposit', function () { + CashAccount::factory()->create(['balance' => 0]); + + $response = $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 50000, + 'description' => 'Unauthorized', + ]); + + $response->assertRedirect(route('login')); + expect(CashAccount::first()->balance)->toBe(0); +}); + +test('guest cannot perform withdrawal', function () { + CashAccount::factory()->create(['balance' => 100000]); + + $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 50000, + 'description' => 'Unauthorized', + ]); + + $response->assertRedirect(route('login')); + expect(CashAccount::first()->balance)->toBe(100000); +}); + +test('guest cannot update transaction', function () { + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'type' => CashTransactionType::DEPOSIT, + 'amount' => 50000, + ]); + + $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [ + 'amount' => 99999, + 'description' => 'Unauthorized', + ]); + + $response->assertRedirect(route('login')); +}); + +test('guest cannot delete transaction', function () { + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'type' => CashTransactionType::DEPOSIT, + 'amount' => 50000, + ]); + + $response = $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $transaction)); + + $response->assertRedirect(route('login')); + expect(CashAccount::first()->balance)->toBe(100000); +}); + +/* +|-------------------------------------------------------------------------- +| DATA INTEGRITY +|-------------------------------------------------------------------------- +*/ + +test('cash account has correct timestamps', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(); + + expect($cashAccount->created_at)->not->toBeNull(); + expect($cashAccount->updated_at)->not->toBeNull(); +}); + +test('cash transaction has correct timestamps', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + ]); + + expect($transaction->created_at)->not->toBeNull(); + expect($transaction->updated_at)->not->toBeNull(); +}); + +test('cash account balance is cast to integer', function () { + $cashAccount = CashAccount::factory()->create(['balance' => 500000]); + expect($cashAccount->balance)->toBeInt(); +}); + +test('cash transaction amount is cast to integer', function () { + $cashAccount = CashAccount::factory()->create(); + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'amount' => 50000, + ]); + expect($transaction->amount)->toBeInt(); +}); + +test('cash transaction balance_after is cast to integer', function () { + $cashAccount = CashAccount::factory()->create(); + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'balance_after' => 100000, + ]); + expect($transaction->balance_after)->toBeInt(); +}); + +test('cash transaction type is cast to enum', function () { + $cashAccount = CashAccount::factory()->create(); + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'type' => CashTransactionType::DEPOSIT, + ]); + expect($transaction->type)->toBeInstanceOf(CashTransactionType::class); +}); + +test('cash account balance defaults to zero', function () { + $cashAccount = CashAccount::factory()->create(['balance' => 0]); + expect($cashAccount->balance)->toBe(0); +}); + +test('cash transaction has correct type values', function () { + expect(CashTransactionType::DEPOSIT->value)->toBe('deposit'); + expect(CashTransactionType::WITHDRAWAL->value)->toBe('withdrawal'); + expect(CashTransactionType::EXPENSE->value)->toBe('expense'); + expect(CashTransactionType::TRANSFER->value)->toBe('transfer'); +}); + +/* +|-------------------------------------------------------------------------- +| SOFT DELETE +|-------------------------------------------------------------------------- +*/ + +test('cash transaction is soft deleted', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::DEPOSIT, + 'amount' => 50000, + ]); + + $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $transaction)); + + $this->assertSoftDeleted('cash_transactions', ['id' => $transaction->id]); +}); + +test('soft deleted transaction still exists in database', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::DEPOSIT, + 'amount' => 50000, + ]); + + $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $transaction)); + + $this->assertDatabaseHas('cash_transactions', ['id' => $transaction->id]); + $this->assertSoftDeleted('cash_transactions', ['id' => $transaction->id]); +}); + +/* +|-------------------------------------------------------------------------- +| REALISTIC USER SCENARIOS +|-------------------------------------------------------------------------- +*/ + +test('user makes deposit then withdrawal in sequence', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 0]); + + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 500000, + 'description' => 'Modal usaha', + ]); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 100000, + 'description' => 'Belanja inventory', + ]); + + expect(CashAccount::first()->balance)->toBe(400000); + $this->assertDatabaseCount('cash_transactions', 2); +}); + +test('user makes multiple deposits throughout the day', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 0]); + + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 200000, + 'description' => 'Penjualan pagi', + ]); + + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 350000, + 'description' => 'Penjualan siang', + ]); + + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 150000, + 'description' => 'Penjualan sore', + ]); + + expect(CashAccount::first()->balance)->toBe(700000); + $this->assertDatabaseCount('cash_transactions', 3); +}); + +test('user makes withdrawal for expenses', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 1000000]); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 50000, + 'description' => 'Bayar listrik', + ]); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 30000, + 'description' => 'Bayar air', + ]); + + $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 200000, + 'description' => 'Gaji karyawan', + ]); + + expect(CashAccount::first()->balance)->toBe(720000); +}); + +test('user edits deposit description', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::DEPOSIT, + 'amount' => 100000, + 'balance_after' => 100000, + 'description' => 'Penjualan', + ]); + + $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [ + 'amount' => 100000, + 'description' => 'Penjualan produk A', + ]); + + $response->assertSessionHasNoErrors(); + + $transaction->refresh(); + expect($transaction->description)->toBe('Penjualan produk A'); + expect($transaction->amount)->toBe(100000); + expect(CashAccount::first()->balance)->toBe(100000); +}); + +test('user deletes wrong deposit and re-enters correct amount', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 0]); + + // Wrong deposit via API + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 100000, + 'description' => 'Wrong amount', + ]); + $wrongDeposit = CashTransaction::where('cash_account_id', $cashAccount->id)->first(); + + expect(CashAccount::first()->balance)->toBe(100000); + + // Delete wrong deposit: 100,000 - 100,000 = 0 + $this->delete(route('admin.finance.cash-accounts.transactions.destroy', $wrongDeposit)); + expect(CashAccount::first()->balance)->toBe(0); + + // Re-enter correct deposit + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 150000, + 'description' => 'Correct amount', + ]); + + expect(CashAccount::first()->balance)->toBe(150000); + // Old transaction is soft deleted, new one created + $this->assertDatabaseCount('cash_transactions', 2); +}); + +test('user attempts withdrawal with exact balance', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 100000]); + + $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 100000, + 'description' => 'Withdraw all', + ]); + + $response->assertSessionHasNoErrors(); + expect(CashAccount::first()->balance)->toBe(0); +}); + +test('user attempts withdrawal with 1 more than balance', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 100000]); + + $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 100001, + 'description' => 'Over balance', + ]); + + $response->assertRedirect(); + expect(CashAccount::first()->balance)->toBe(100000); +}); + +test('user rapidly makes multiple deposits', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 0]); + + for ($i = 0; $i < 5; $i++) { + $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 100000, + 'description' => "Deposit {$i}", + ]); + } + + expect(CashAccount::first()->balance)->toBe(500000); + $this->assertDatabaseCount('cash_transactions', 5); +}); + +test('user edits withdrawal amount to reduce it', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::WITHDRAWAL, + 'amount' => 50000, + 'balance_after' => 100000, + 'description' => 'Original', + ]); + + // Reduce withdrawal from 50,000 to 20,000 + // difference = 50,000 - 20,000 = 30,000 + // newBalance = 100,000 + 30,000 = 130,000 + $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [ + 'amount' => 20000, + 'description' => 'Reduced', + ]); + + $response->assertSessionHasNoErrors(); + expect(CashAccount::first()->balance)->toBe(130000); +}); + +test('user edits withdrawal amount to increase it', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::WITHDRAWAL, + 'amount' => 20000, + 'balance_after' => 100000, + 'description' => 'Original', + ]); + + // Increase withdrawal from 20,000 to 60,000 + // difference = 20,000 - 60,000 = -40,000 + // newBalance = 100,000 + (-40,000) = 60,000 + $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [ + 'amount' => 60000, + 'description' => 'Increased', + ]); + + $response->assertSessionHasNoErrors(); + expect(CashAccount::first()->balance)->toBe(60000); +}); + +test('user cannot edit withdrawal to exceed remaining balance', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + $cashAccount = CashAccount::factory()->create(['balance' => 100000]); + + $transaction = CashTransaction::factory()->create([ + 'cash_account_id' => $cashAccount->id, + 'created_by_id' => $user->id, + 'type' => CashTransactionType::WITHDRAWAL, + 'amount' => 30000, + 'balance_after' => 100000, + 'description' => 'Original', + ]); + + expect(CashAccount::first()->balance)->toBe(100000); + + // Increase withdrawal from 30,000 to 200,000 + // difference = 30,000 - 200,000 = -170,000 + // newBalance = 100,000 + (-170,000) = -70,000 (insufficient) + $response = $this->put(route('admin.finance.cash-accounts.transactions.update', $transaction), [ + 'amount' => 200000, + 'description' => 'Way too much', + ]); + + $response->assertRedirect(); + expect(CashAccount::first()->balance)->toBe(100000); +}); + +test('deposit with description containing special characters', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 0]); + + $response = $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 50000, + 'description' => 'Deposit dari PT. Maju Jaya & Co.', + ]); + + $response->assertSessionHasNoErrors(); + $this->assertDatabaseHas('cash_transactions', [ + 'description' => 'Deposit dari PT. Maju Jaya & Co.', + ]); +}); + +test('withdrawal with description containing unicode characters', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 100000]); + + $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 50000, + 'description' => 'Pembayaran gaji karyawan', + ]); + + $response->assertSessionHasNoErrors(); + $this->assertDatabaseHas('cash_transactions', [ + 'description' => 'Pembayaran gaji karyawan', + ]); +}); + +test('deposit without description fails validation', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(); + + $response = $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => 50000, + ]); + + $response->assertSessionHasErrors('description'); +}); + +test('withdrawal without description fails validation', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(); + + $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => 50000, + ]); + + $response->assertSessionHasErrors('description'); +}); + +test('deposit with empty string amount fails validation', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(); + + $response = $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => '', + 'description' => 'Test', + ]); + + $response->assertSessionHasErrors('amount'); +}); + +test('withdrawal with empty string amount fails validation', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(); + + $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => '', + 'description' => 'Test', + ]); + + $response->assertSessionHasErrors('amount'); +}); + +test('deposit with float amount is parsed correctly', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 0]); + + $response = $this->post(route('admin.finance.cash-accounts.deposit'), [ + 'amount' => '100.500', + 'description' => 'Float amount', + ]); + + $response->assertSessionHasNoErrors(); + expect(CashAccount::first()->balance)->toBe(100500); +}); + +test('withdrawal with float amount is parsed correctly', function () { + $user = User::factory()->create(); + $this->actingAs($user); + + CashAccount::factory()->create(['balance' => 1000000]); + + $response = $this->post(route('admin.finance.cash-accounts.withdrawal'), [ + 'amount' => '250.000', + 'description' => 'Float amount', + ]); + + $response->assertSessionHasNoErrors(); + expect(CashAccount::first()->balance)->toBe(750000); +});