Skip to content

Commit 4dac846

Browse files
simonhampclaude
andcommitted
Add country and payout currency selection to developer onboarding
Collect the developer's country and preferred payout currency during Stripe Connect onboarding. This ensures Express accounts are created with the correct country parameter and enables multi-currency payouts for European/EEA countries. - Add country (108 Stripe-supported countries) and payout_currency fields to developer_accounts table - Add StripeConnectCountries support class with country data, currency names, and validation methods - Update Livewire Onboarding component with reactive country/currency selection - Use Flux Pro searchable listbox for the country dropdown - Display currency names (e.g. "US Dollar (USD)") in the currency select - Request card_payments capability alongside transfers to support all countries including cross-border (fixes JP account creation error) - Add comprehensive validation in DeveloperOnboardingController - Pass country to Stripe Connect account creation - Use developer's payout_currency for transfers instead of hardcoded USD - Install livewire/flux-pro for searchable select component - Update CLAUDE.md with correct dependency versions (Filament v5, Livewire v4, PHP 8.4.19) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3d7bcc4 commit 4dac846

14 files changed

Lines changed: 760 additions & 10 deletions

File tree

CLAUDE.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ The Laravel Boost guidelines are specifically curated by Laravel maintainers for
88
## Foundational Context
99
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
1010

11-
- php - 8.4.18
12-
- filament/filament (FILAMENT) - v3
11+
- php - 8.4.19
12+
- filament/filament (FILAMENT) - v5
1313
- laravel/cashier (CASHIER) - v15
1414
- laravel/framework (LARAVEL) - v12
1515
- laravel/horizon (HORIZON) - v5
@@ -18,7 +18,7 @@ This application is a Laravel application and its main Laravel ecosystems packag
1818
- laravel/prompts (PROMPTS) - v0
1919
- laravel/sanctum (SANCTUM) - v4
2020
- laravel/socialite (SOCIALITE) - v5
21-
- livewire/livewire (LIVEWIRE) - v3
21+
- livewire/livewire (LIVEWIRE) - v4
2222
- laravel/mcp (MCP) - v0
2323
- laravel/pint (PINT) - v1
2424
- laravel/sail (SAIL) - v1

app/Http/Controllers/DeveloperOnboardingController.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
use App\Models\DeveloperAccount;
66
use App\Services\StripeConnectService;
7+
use App\Support\StripeConnectCountries;
78
use Illuminate\Http\RedirectResponse;
89
use Illuminate\Http\Request;
10+
use Illuminate\Validation\Rule;
911
use Illuminate\View\View;
1012

1113
class DeveloperOnboardingController extends Controller
@@ -32,16 +34,33 @@ public function start(Request $request): RedirectResponse
3234
{
3335
$request->validate([
3436
'accepted_plugin_terms' => ['required', 'accepted'],
37+
'country' => ['required', 'string', 'size:2', Rule::in(StripeConnectCountries::supportedCountryCodes())],
38+
'payout_currency' => ['required', 'string', 'size:3'],
3539
], [
3640
'accepted_plugin_terms.required' => 'You must accept the Plugin Developer Terms and Conditions.',
3741
'accepted_plugin_terms.accepted' => 'You must accept the Plugin Developer Terms and Conditions.',
42+
'country.required' => 'Please select your country.',
43+
'country.in' => 'The selected country is not supported for Stripe Connect.',
44+
'payout_currency.required' => 'Please select a payout currency.',
3845
]);
3946

47+
$country = strtoupper($request->input('country'));
48+
$payoutCurrency = strtoupper($request->input('payout_currency'));
49+
50+
if (! StripeConnectCountries::isValidCurrencyForCountry($country, $payoutCurrency)) {
51+
return back()->withErrors(['payout_currency' => 'The selected currency is not available for your country.']);
52+
}
53+
4054
$user = $request->user();
4155
$developerAccount = $user->developerAccount;
4256

4357
if (! $developerAccount) {
44-
$developerAccount = $this->stripeConnectService->createConnectAccount($user);
58+
$developerAccount = $this->stripeConnectService->createConnectAccount($user, $country, $payoutCurrency);
59+
} else {
60+
$developerAccount->update([
61+
'country' => $country,
62+
'payout_currency' => $payoutCurrency,
63+
]);
4564
}
4665

4766
if (! $developerAccount->hasAcceptedCurrentTerms()) {

app/Livewire/Customer/Developer/Onboarding.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace App\Livewire\Customer\Developer;
44

5+
use App\Support\StripeConnectCountries;
56
use Livewire\Attributes\Computed;
67
use Livewire\Attributes\Layout;
78
use Livewire\Attributes\Title;
@@ -11,13 +12,31 @@
1112
#[Title('Developer Onboarding')]
1213
class Onboarding extends Component
1314
{
15+
public string $country = '';
16+
17+
public string $payoutCurrency = '';
18+
1419
public function mount(): void
1520
{
1621
$developerAccount = auth()->user()->developerAccount;
1722

1823
if ($developerAccount && $developerAccount->hasCompletedOnboarding()) {
1924
$this->redirect(route('customer.developer.dashboard'), navigate: true);
2025
}
26+
27+
if ($developerAccount) {
28+
$this->country = $developerAccount->country ?? '';
29+
$this->payoutCurrency = $developerAccount->payout_currency ?? '';
30+
}
31+
}
32+
33+
public function updatedCountry(string $value): void
34+
{
35+
if (StripeConnectCountries::isSupported($value)) {
36+
$this->payoutCurrency = StripeConnectCountries::defaultCurrency($value);
37+
} else {
38+
$this->payoutCurrency = '';
39+
}
2140
}
2241

2342
#[Computed]
@@ -32,6 +51,39 @@ public function hasExistingAccount(): bool
3251
return $this->developerAccount !== null;
3352
}
3453

54+
/**
55+
* @return array<string, array{name: string, flag: string, default_currency: string, currencies: list<string>}>
56+
*/
57+
#[Computed]
58+
public function countries(): array
59+
{
60+
$countries = StripeConnectCountries::all();
61+
62+
uasort($countries, fn (array $a, array $b) => $a['name'] <=> $b['name']);
63+
64+
return $countries;
65+
}
66+
67+
/**
68+
* @return array<string, string>
69+
*/
70+
#[Computed]
71+
public function availableCurrencies(): array
72+
{
73+
if (! $this->country || ! StripeConnectCountries::isSupported($this->country)) {
74+
return [];
75+
}
76+
77+
$currencies = StripeConnectCountries::availableCurrencies($this->country);
78+
79+
$named = [];
80+
foreach ($currencies as $code) {
81+
$named[$code] = StripeConnectCountries::currencyName($code);
82+
}
83+
84+
return $named;
85+
}
86+
3587
public function render()
3688
{
3789
return view('livewire.customer.developer.onboarding');

app/Services/StripeConnectService.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,17 @@
1919
*/
2020
class StripeConnectService
2121
{
22-
public function createConnectAccount(User $user): DeveloperAccount
22+
public function createConnectAccount(User $user, string $country, string $payoutCurrency): DeveloperAccount
2323
{
2424
$account = Cashier::stripe()->accounts->create([
2525
'type' => 'express',
26+
'country' => $country,
2627
'email' => $user->email,
2728
'metadata' => [
2829
'user_id' => $user->id,
2930
],
3031
'capabilities' => [
32+
'card_payments' => ['requested' => true],
3133
'transfers' => ['requested' => true],
3234
],
3335
]);
@@ -38,6 +40,8 @@ public function createConnectAccount(User $user): DeveloperAccount
3840
'stripe_connect_status' => StripeConnectStatus::Pending,
3941
'payouts_enabled' => false,
4042
'charges_enabled' => false,
43+
'country' => $country,
44+
'payout_currency' => $payoutCurrency,
4145
]);
4246
}
4347

@@ -109,7 +113,7 @@ public function processTransfer(PluginPayout $payout): bool
109113
try {
110114
$transferParams = [
111115
'amount' => $payout->developer_amount,
112-
'currency' => 'usd',
116+
'currency' => strtolower($developerAccount->payout_currency ?? 'usd'),
113117
'destination' => $developerAccount->stripe_connect_account_id,
114118
'metadata' => [
115119
'payout_id' => $payout->id,

0 commit comments

Comments
 (0)