fix(accounts): sync currency from first account (#430)
## Summary - sync user currency from the first account, manual or connected - reuse one service across manual creation and open banking mapping/auto-create flows - keep later accounts from overwriting user currency - add browser signup + onboarding account creation coverage ## Prod check - users with any account: 210 - first account currency mismatches user currency: 64 - USD user + EUR first account: 36 - first account manual users: 189 - manual-first mismatches: 61 ## Tests - vendor/bin/pint --dirty --format agent - php artisan test --compact tests/Feature/OpenBanking/AccountMappingTest.php tests/Feature/OpenBanking/AuthorizationControllerTest.php tests/Feature/OpenBanking/IndexaCapitalControllerTest.php tests/Feature/OpenBanking/BinanceControllerTest.php tests/Feature/OpenBanking/BitpandaControllerTest.php tests/Feature/OpenBanking/CoinbaseControllerTest.php tests/Feature/Settings/AccountTest.php - php artisan test --compact tests/Browser/OnboardingFlowTest.php --filter='syncs user currency from first onboarding account after signup'
This commit is contained in:
parent
4f42de74a1
commit
0d4c68361a
|
|
@ -10,6 +10,7 @@ use App\Http\Requests\OpenBanking\MapAccountsRequest;
|
|||
use App\Jobs\SyncBankingConnectionJob;
|
||||
use App\Models\Bank;
|
||||
use App\Models\BankingConnection;
|
||||
use App\Services\AccountUserCurrencyService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
|
|
@ -18,7 +19,7 @@ class AccountMappingController extends Controller
|
|||
{
|
||||
use CreatesAccountsFromPending;
|
||||
|
||||
public function show(BankingConnection $connection): Response|RedirectResponse
|
||||
public function show(BankingConnection $connection, AccountUserCurrencyService $accountUserCurrencyService): Response|RedirectResponse
|
||||
{
|
||||
if ($connection->user_id !== auth()->id()) {
|
||||
abort(403);
|
||||
|
|
@ -35,7 +36,7 @@ class AccountMappingController extends Controller
|
|||
|
||||
// During onboarding, skip the mapping UI — auto-create all accounts directly
|
||||
if (! $user->isOnboarded()) {
|
||||
$this->createAccountsFromPending($user, $connection);
|
||||
$this->createAccountsFromPending($user, $connection, $accountUserCurrencyService);
|
||||
SyncBankingConnectionJob::dispatch($connection);
|
||||
|
||||
return redirect()->route('onboarding', ['step' => 'create-account'])
|
||||
|
|
@ -55,7 +56,7 @@ class AccountMappingController extends Controller
|
|||
]);
|
||||
}
|
||||
|
||||
public function store(MapAccountsRequest $request, BankingConnection $connection): RedirectResponse
|
||||
public function store(MapAccountsRequest $request, BankingConnection $connection, AccountUserCurrencyService $accountUserCurrencyService): RedirectResponse
|
||||
{
|
||||
if ($connection->user_id !== auth()->id()) {
|
||||
abort(403);
|
||||
|
|
@ -95,7 +96,7 @@ class AccountMappingController extends Controller
|
|||
?? $accountData['account_id']['iban']
|
||||
?? $connection->aspsp_name.' Account';
|
||||
|
||||
$user->accounts()->create([
|
||||
$account = $user->accounts()->create([
|
||||
'name' => $name,
|
||||
'name_iv' => null,
|
||||
'encrypted' => false,
|
||||
|
|
@ -106,6 +107,8 @@ class AccountMappingController extends Controller
|
|||
'external_account_id' => $uid,
|
||||
'iban' => $accountData['account_id']['iban'] ?? null,
|
||||
]);
|
||||
|
||||
$accountUserCurrencyService->syncFromFirstAccount($account);
|
||||
} elseif ($action === 'link') {
|
||||
$existingAccount = $user->accounts()->find($mapping['existing_account_id']);
|
||||
|
||||
|
|
@ -117,6 +120,8 @@ class AccountMappingController extends Controller
|
|||
'bank_id' => $bank->id,
|
||||
'linked_at' => now(),
|
||||
]);
|
||||
|
||||
$accountUserCurrencyService->syncFromFirstAccount($existingAccount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use App\Http\Requests\OpenBanking\StartAuthorizationRequest;
|
|||
use App\Jobs\SyncBankingConnectionJob;
|
||||
use App\Models\BankingConnection;
|
||||
use App\Models\User;
|
||||
use App\Services\AccountUserCurrencyService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -138,7 +139,7 @@ class AuthorizationController extends Controller
|
|||
/**
|
||||
* Handle the callback from bank authorization.
|
||||
*/
|
||||
public function callback(Request $request, BankingProviderInterface $provider): RedirectResponse
|
||||
public function callback(Request $request, BankingProviderInterface $provider, AccountUserCurrencyService $accountUserCurrencyService): RedirectResponse
|
||||
{
|
||||
$user = auth()->user();
|
||||
$errorRedirectRoute = $user->isOnboarded() ? 'settings.connections.index' : 'onboarding';
|
||||
|
|
@ -224,7 +225,7 @@ class AuthorizationController extends Controller
|
|||
]);
|
||||
|
||||
if (! $user->isOnboarded()) {
|
||||
$this->createAccountsFromPending($user, $connection);
|
||||
$this->createAccountsFromPending($user, $connection, $accountUserCurrencyService);
|
||||
SyncBankingConnectionJob::dispatch($connection);
|
||||
|
||||
return redirect()->route('onboarding', ['step' => 'create-account'])
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use App\Http\Controllers\OpenBanking\Concerns\HandlesSubscriptionGate;
|
|||
use App\Http\Requests\OpenBanking\ConnectBinanceRequest;
|
||||
use App\Jobs\SyncBankingConnectionJob;
|
||||
use App\Models\Bank;
|
||||
use App\Services\AccountUserCurrencyService;
|
||||
use App\Services\Banking\BinanceClient;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
|
@ -21,7 +22,7 @@ class BinanceController extends Controller
|
|||
/**
|
||||
* Validate Binance API credentials and create a connection.
|
||||
*/
|
||||
public function store(ConnectBinanceRequest $request): JsonResponse
|
||||
public function store(ConnectBinanceRequest $request, AccountUserCurrencyService $accountUserCurrencyService): JsonResponse
|
||||
{
|
||||
$validated = $request->validated();
|
||||
$user = auth()->user();
|
||||
|
|
@ -71,7 +72,7 @@ class BinanceController extends Controller
|
|||
]);
|
||||
|
||||
if (! $user->isOnboarded()) {
|
||||
$this->createAccountsFromPending($user, $connection);
|
||||
$this->createAccountsFromPending($user, $connection, $accountUserCurrencyService);
|
||||
SyncBankingConnectionJob::dispatch($connection);
|
||||
|
||||
return response()->json([
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use App\Http\Controllers\OpenBanking\Concerns\HandlesSubscriptionGate;
|
|||
use App\Http\Requests\OpenBanking\ConnectBitpandaRequest;
|
||||
use App\Jobs\SyncBankingConnectionJob;
|
||||
use App\Models\Bank;
|
||||
use App\Services\AccountUserCurrencyService;
|
||||
use App\Services\Banking\BitpandaClient;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
|
@ -21,7 +22,7 @@ class BitpandaController extends Controller
|
|||
/**
|
||||
* Validate Bitpanda API key and create a connection.
|
||||
*/
|
||||
public function store(ConnectBitpandaRequest $request): JsonResponse
|
||||
public function store(ConnectBitpandaRequest $request, AccountUserCurrencyService $accountUserCurrencyService): JsonResponse
|
||||
{
|
||||
$validated = $request->validated();
|
||||
$user = auth()->user();
|
||||
|
|
@ -70,7 +71,7 @@ class BitpandaController extends Controller
|
|||
]);
|
||||
|
||||
if (! $user->isOnboarded()) {
|
||||
$this->createAccountsFromPending($user, $connection);
|
||||
$this->createAccountsFromPending($user, $connection, $accountUserCurrencyService);
|
||||
SyncBankingConnectionJob::dispatch($connection);
|
||||
|
||||
return response()->json([
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use App\Http\Controllers\OpenBanking\Concerns\HandlesSubscriptionGate;
|
|||
use App\Http\Requests\OpenBanking\ConnectCoinbaseRequest;
|
||||
use App\Jobs\SyncBankingConnectionJob;
|
||||
use App\Models\Bank;
|
||||
use App\Services\AccountUserCurrencyService;
|
||||
use App\Services\Banking\CoinbaseClient;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
|
@ -21,7 +22,7 @@ class CoinbaseController extends Controller
|
|||
/**
|
||||
* Validate Coinbase CDP API credentials and create a connection.
|
||||
*/
|
||||
public function store(ConnectCoinbaseRequest $request): JsonResponse
|
||||
public function store(ConnectCoinbaseRequest $request, AccountUserCurrencyService $accountUserCurrencyService): JsonResponse
|
||||
{
|
||||
$validated = $request->validated();
|
||||
$user = auth()->user();
|
||||
|
|
@ -71,7 +72,7 @@ class CoinbaseController extends Controller
|
|||
]);
|
||||
|
||||
if (! $user->isOnboarded()) {
|
||||
$this->createAccountsFromPending($user, $connection);
|
||||
$this->createAccountsFromPending($user, $connection, $accountUserCurrencyService);
|
||||
SyncBankingConnectionJob::dispatch($connection);
|
||||
|
||||
return response()->json([
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use App\Enums\BankingConnectionStatus;
|
|||
use App\Models\Bank;
|
||||
use App\Models\BankingConnection;
|
||||
use App\Models\User;
|
||||
use App\Services\AccountUserCurrencyService;
|
||||
|
||||
trait CreatesAccountsFromPending
|
||||
{
|
||||
|
|
@ -17,7 +18,7 @@ trait CreatesAccountsFromPending
|
|||
* Indexa Capital, Binance, Bitpanda, and Coinbase; Checking for everything else) and clears the
|
||||
* pending data once accounts have been created.
|
||||
*/
|
||||
private function createAccountsFromPending(User $user, BankingConnection $connection): void
|
||||
private function createAccountsFromPending(User $user, BankingConnection $connection, AccountUserCurrencyService $accountUserCurrencyService): void
|
||||
{
|
||||
$bank = Bank::firstOrCreate(
|
||||
['name' => $connection->aspsp_name, 'user_id' => null],
|
||||
|
|
@ -44,7 +45,7 @@ trait CreatesAccountsFromPending
|
|||
?? $accountData['account_id']['iban']
|
||||
?? $connection->aspsp_name.' Account';
|
||||
|
||||
$user->accounts()->create([
|
||||
$account = $user->accounts()->create([
|
||||
'name' => $name,
|
||||
'name_iv' => null,
|
||||
'encrypted' => false,
|
||||
|
|
@ -55,6 +56,8 @@ trait CreatesAccountsFromPending
|
|||
'external_account_id' => $uid,
|
||||
'iban' => $accountData['account_id']['iban'] ?? null,
|
||||
]);
|
||||
|
||||
$accountUserCurrencyService->syncFromFirstAccount($account);
|
||||
}
|
||||
|
||||
$connection->update([
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use App\Http\Controllers\OpenBanking\Concerns\HandlesSubscriptionGate;
|
|||
use App\Http\Requests\OpenBanking\ConnectIndexaCapitalRequest;
|
||||
use App\Jobs\SyncBankingConnectionJob;
|
||||
use App\Models\Bank;
|
||||
use App\Services\AccountUserCurrencyService;
|
||||
use App\Services\Banking\IndexaCapitalClient;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
|
@ -21,7 +22,7 @@ class IndexaCapitalController extends Controller
|
|||
/**
|
||||
* Validate the Indexa Capital API token and create a connection.
|
||||
*/
|
||||
public function store(ConnectIndexaCapitalRequest $request): JsonResponse
|
||||
public function store(ConnectIndexaCapitalRequest $request, AccountUserCurrencyService $accountUserCurrencyService): JsonResponse
|
||||
{
|
||||
$validated = $request->validated();
|
||||
$user = auth()->user();
|
||||
|
|
@ -64,7 +65,7 @@ class IndexaCapitalController extends Controller
|
|||
]);
|
||||
|
||||
if (! $user->isOnboarded()) {
|
||||
$this->createAccountsFromPending($user, $connection);
|
||||
$this->createAccountsFromPending($user, $connection, $accountUserCurrencyService);
|
||||
SyncBankingConnectionJob::dispatch($connection);
|
||||
|
||||
return response()->json([
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use App\Jobs\GenerateHistoricalLoanBalancesJob;
|
|||
use App\Jobs\GenerateHistoricalRealEstateBalancesJob;
|
||||
use App\Models\Account;
|
||||
use App\Models\User;
|
||||
use App\Services\AccountUserCurrencyService;
|
||||
use App\Services\LoanBalanceGeneratorService;
|
||||
use App\Services\RealEstateBalanceGeneratorService;
|
||||
use Carbon\Carbon;
|
||||
|
|
@ -46,7 +47,7 @@ class AccountController extends Controller
|
|||
/**
|
||||
* Store a newly created account.
|
||||
*/
|
||||
public function store(StoreAccountRequest $request, RealEstateBalanceGeneratorService $balanceGenerator, LoanBalanceGeneratorService $loanBalanceGenerator): RedirectResponse|JsonResponse
|
||||
public function store(StoreAccountRequest $request, RealEstateBalanceGeneratorService $balanceGenerator, LoanBalanceGeneratorService $loanBalanceGenerator, AccountUserCurrencyService $accountUserCurrencyService): RedirectResponse|JsonResponse
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = Auth::user();
|
||||
|
|
@ -168,10 +169,7 @@ class AccountController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
// Set user's currency_code from first account
|
||||
if ($user->accounts()->count() === 1) {
|
||||
$user->update(['currency_code' => $account->currency_code]);
|
||||
}
|
||||
$accountUserCurrencyService->syncFromFirstAccount($account);
|
||||
|
||||
if ($request->wantsJson()) {
|
||||
return response()->json($account, 201);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Account;
|
||||
use App\Models\User;
|
||||
|
||||
class AccountUserCurrencyService
|
||||
{
|
||||
public function syncFromFirstAccount(Account $account): void
|
||||
{
|
||||
$user = $account->user;
|
||||
|
||||
if (! $user instanceof User) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($user->accounts()->count() !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sync($user, $account);
|
||||
}
|
||||
|
||||
private function sync(User $user, Account $account): void
|
||||
{
|
||||
$currencyCode = strtoupper($account->currency_code);
|
||||
|
||||
if ($user->currency_code === $currencyCode) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user->forceFill(['currency_code' => $currencyCode])->save();
|
||||
}
|
||||
}
|
||||
|
|
@ -28,6 +28,70 @@ it('redirects new registration to email verification', function () {
|
|||
]);
|
||||
});
|
||||
|
||||
it('syncs user currency from first onboarding account after signup', function () {
|
||||
Bank::factory()->create(['name' => 'Signup Test Bank']);
|
||||
|
||||
$page = visit('/register?force=1');
|
||||
|
||||
$page->assertSee('Create an account')
|
||||
->fill('name', 'Currency Signup User')
|
||||
->fill('email', 'currency-signup@example.com')
|
||||
->fill('password', 'password123456')
|
||||
->fill('password_confirmation', 'password123456')
|
||||
->click('@register-user-button')
|
||||
->wait(3)
|
||||
->assertPathIs('/email/verify')
|
||||
->assertNoJavascriptErrors();
|
||||
|
||||
$user = User::where('email', 'currency-signup@example.com')->firstOrFail();
|
||||
|
||||
expect($user->currency_code)->toBe('USD');
|
||||
|
||||
$user->forceFill(['email_verified_at' => now()])->save();
|
||||
|
||||
$this->actingAs($user->refresh());
|
||||
|
||||
$page = visit('/onboarding');
|
||||
|
||||
$page->assertPathIs('/onboarding')
|
||||
->assertSee('Welcome to')
|
||||
->click("Let's Get Started")
|
||||
->wait(1)
|
||||
->assertSee('Account Types')
|
||||
->click('Create Your First Account')
|
||||
->wait(1)
|
||||
->assertSee('Create an Account')
|
||||
->click('Manual')
|
||||
->wait(1)
|
||||
->click('Continue')
|
||||
->wait(1)
|
||||
->fill('#display_name', 'Euro Checking Account')
|
||||
->click('Select bank...')
|
||||
->wait(1)
|
||||
->fill('[placeholder="Search bank..."]', 'Signup')
|
||||
->wait(1)
|
||||
->click('Signup Test Bank')
|
||||
->wait(1)
|
||||
->click('Select account type')
|
||||
->wait(1)
|
||||
->click('[role="option"]:has-text("Checking")')
|
||||
->wait(1)
|
||||
->click('Select currency')
|
||||
->wait(1)
|
||||
->click('[role="option"]:has-text("EUR")')
|
||||
->wait(1)
|
||||
->click('Create Account')
|
||||
->wait(5)
|
||||
->assertNoJavascriptErrors();
|
||||
|
||||
$user->refresh();
|
||||
$account = $user->accounts()->first();
|
||||
|
||||
expect($user->currency_code)->toBe('EUR');
|
||||
expect($account)->not->toBeNull();
|
||||
expect($account->currency_code)->toBe('EUR');
|
||||
});
|
||||
|
||||
it('redirects onboarded user away from onboarding page to dashboard', function () {
|
||||
$user = User::factory()->onboarded()->create();
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,38 @@ test('show redirects if no pending accounts', function () {
|
|||
$response->assertRedirect(route('settings.connections.index'));
|
||||
});
|
||||
|
||||
test('show auto-creates pending accounts and updates currency during onboarding', function () {
|
||||
Queue::fake();
|
||||
|
||||
$user = User::factory()->notOnboarded()->create(['currency_code' => 'USD']);
|
||||
$connection = BankingConnection::factory()->awaitingMapping()->create([
|
||||
'user_id' => $user->id,
|
||||
'pending_accounts_data' => [
|
||||
[
|
||||
'uid' => 'ext-1',
|
||||
'currency' => 'EUR',
|
||||
'name' => 'Euro Checking',
|
||||
'account_id' => ['iban' => 'ES1234567890'],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('open-banking.map-accounts', $connection))
|
||||
->assertRedirect(route('onboarding', ['step' => 'create-account']));
|
||||
|
||||
expect($user->refresh()->currency_code)->toBe('EUR');
|
||||
|
||||
$this->assertDatabaseHas('accounts', [
|
||||
'user_id' => $user->id,
|
||||
'banking_connection_id' => $connection->id,
|
||||
'external_account_id' => 'ext-1',
|
||||
'currency_code' => 'EUR',
|
||||
]);
|
||||
|
||||
Queue::assertPushed(SyncBankingConnectionJob::class);
|
||||
});
|
||||
|
||||
test('show returns 403 for other user\'s connection', function () {
|
||||
$user = User::factory()->onboarded()->create();
|
||||
$otherUser = User::factory()->onboarded()->create();
|
||||
|
|
@ -150,6 +182,121 @@ test('store creates investment accounts for crypto provider connections', functi
|
|||
'coinbase' => ['coinbase', 'Coinbase', 'coinbase-portfolio'],
|
||||
]);
|
||||
|
||||
test('store updates user currency from first account created from mapping', function () {
|
||||
Queue::fake();
|
||||
|
||||
$user = User::factory()->onboarded()->create(['currency_code' => 'USD']);
|
||||
$connection = BankingConnection::factory()->awaitingMapping()->create([
|
||||
'user_id' => $user->id,
|
||||
'aspsp_name' => 'Test Bank',
|
||||
'pending_accounts_data' => [
|
||||
[
|
||||
'uid' => 'ext-1',
|
||||
'currency' => 'EUR',
|
||||
'name' => 'Euro Checking',
|
||||
'account_id' => ['iban' => 'ES1234567890'],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->post(route('open-banking.map-accounts.store', $connection), [
|
||||
'mappings' => [
|
||||
[
|
||||
'bank_account_uid' => 'ext-1',
|
||||
'action' => 'create',
|
||||
'existing_account_id' => null,
|
||||
],
|
||||
],
|
||||
])
|
||||
->assertRedirect(route('settings.connections.index'));
|
||||
|
||||
expect($user->refresh()->currency_code)->toBe('EUR');
|
||||
});
|
||||
|
||||
test('store does not update user currency from later mapped accounts', function () {
|
||||
Queue::fake();
|
||||
|
||||
$user = User::factory()->onboarded()->create(['currency_code' => 'EUR']);
|
||||
$existingConnection = BankingConnection::factory()->create(['user_id' => $user->id]);
|
||||
|
||||
Account::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'currency_code' => 'EUR',
|
||||
'banking_connection_id' => $existingConnection->id,
|
||||
'external_account_id' => 'existing-ext',
|
||||
]);
|
||||
|
||||
$user->update(['currency_code' => 'USD']);
|
||||
|
||||
$connection = BankingConnection::factory()->awaitingMapping()->create([
|
||||
'user_id' => $user->id,
|
||||
'aspsp_name' => 'Second Bank',
|
||||
'pending_accounts_data' => [
|
||||
[
|
||||
'uid' => 'ext-2',
|
||||
'currency' => 'GBP',
|
||||
'name' => 'Pound Checking',
|
||||
'account_id' => ['iban' => 'GB1234567890'],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->post(route('open-banking.map-accounts.store', $connection), [
|
||||
'mappings' => [
|
||||
[
|
||||
'bank_account_uid' => 'ext-2',
|
||||
'action' => 'create',
|
||||
'existing_account_id' => null,
|
||||
],
|
||||
],
|
||||
])
|
||||
->assertRedirect(route('settings.connections.index'));
|
||||
|
||||
expect($user->refresh()->currency_code)->toBe('USD');
|
||||
});
|
||||
|
||||
test('store updates user currency when linking first account', function () {
|
||||
Queue::fake();
|
||||
|
||||
$user = User::factory()->onboarded()->create(['currency_code' => 'USD']);
|
||||
$bank = Bank::factory()->create();
|
||||
$existingAccount = Account::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'bank_id' => $bank->id,
|
||||
'currency_code' => 'EUR',
|
||||
'banking_connection_id' => null,
|
||||
]);
|
||||
|
||||
$connection = BankingConnection::factory()->awaitingMapping()->create([
|
||||
'user_id' => $user->id,
|
||||
'aspsp_name' => 'Test Bank',
|
||||
'pending_accounts_data' => [
|
||||
[
|
||||
'uid' => 'ext-1',
|
||||
'currency' => 'EUR',
|
||||
'name' => 'Bank Account',
|
||||
'account_id' => ['iban' => 'ES1234567890'],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->post(route('open-banking.map-accounts.store', $connection), [
|
||||
'mappings' => [
|
||||
[
|
||||
'bank_account_uid' => 'ext-1',
|
||||
'action' => 'link',
|
||||
'existing_account_id' => $existingAccount->id,
|
||||
],
|
||||
],
|
||||
])
|
||||
->assertRedirect(route('settings.connections.index'));
|
||||
|
||||
expect($user->refresh()->currency_code)->toBe('EUR');
|
||||
});
|
||||
|
||||
test('store with action link links existing account', function () {
|
||||
Queue::fake();
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,21 @@ it('can create a new account with plaintext name', function () {
|
|||
]);
|
||||
});
|
||||
|
||||
it('updates user currency from first manually created account', function () {
|
||||
actingAs($this->user);
|
||||
|
||||
$response = $this->post(route('accounts.store'), [
|
||||
'name' => 'My Euro Account',
|
||||
'bank_id' => $this->bank->id,
|
||||
'currency_code' => 'EUR',
|
||||
'type' => AccountType::Checking->value,
|
||||
]);
|
||||
|
||||
$response->assertRedirect();
|
||||
|
||||
expect($this->user->refresh()->currency_code)->toBe('EUR');
|
||||
});
|
||||
|
||||
it('can create a new account without a bank', function () {
|
||||
actingAs($this->user);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue