Skip to content

Commit 6bdcd25

Browse files
simonhampclaude
andcommitted
Remove unsupported Stripe Connect countries and add graceful error handling
Remove IN, TW, KR, NG, and NA from the supported countries list as Stripe does not support Express Connect accounts for these countries from US-based platforms (cross-border restrictions or missing card_payments capability). Also adds a try/catch around account creation to handle any future Stripe rejections gracefully instead of showing a 500 error. Closes #45 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 4727552 commit 6bdcd25

4 files changed

Lines changed: 103 additions & 13 deletions

File tree

app/Http/Controllers/DeveloperOnboardingController.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
use App\Support\StripeConnectCountries;
88
use Illuminate\Http\RedirectResponse;
99
use Illuminate\Http\Request;
10+
use Illuminate\Support\Facades\Log;
1011
use Illuminate\Validation\Rule;
12+
use Stripe\Exception\InvalidRequestException;
1113

1214
class DeveloperOnboardingController extends Controller
1315
{
@@ -38,7 +40,17 @@ public function start(Request $request): RedirectResponse
3840
$developerAccount = $user->developerAccount;
3941

4042
if (! $developerAccount) {
41-
$developerAccount = $this->stripeConnectService->createConnectAccount($user, $country, $payoutCurrency);
43+
try {
44+
$developerAccount = $this->stripeConnectService->createConnectAccount($user, $country, $payoutCurrency);
45+
} catch (InvalidRequestException $e) {
46+
Log::warning('Stripe Connect account creation failed', [
47+
'user_id' => $user->id,
48+
'country' => $country,
49+
'error' => $e->getMessage(),
50+
]);
51+
52+
return back()->withErrors(['country' => 'Stripe does not currently support developer accounts in your selected country. Please choose a different country or contact support for assistance.']);
53+
}
4254
} else {
4355
$developerAccount->update([
4456
'country' => $country,

app/Support/StripeConnectCountries.php

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,13 @@ class StripeConnectCountries
5656
'ID' => ['name' => 'Indonesia', 'flag' => "\u{1F1EE}\u{1F1E9}", 'default_currency' => 'IDR', 'currencies' => ['IDR']],
5757
'IE' => ['name' => 'Ireland', 'flag' => "\u{1F1EE}\u{1F1EA}", 'default_currency' => 'EUR', 'currencies' => ['EUR', 'GBP', 'USD', 'CHF', 'DKK', 'NOK', 'SEK']],
5858
'IL' => ['name' => 'Israel', 'flag' => "\u{1F1EE}\u{1F1F1}", 'default_currency' => 'ILS', 'currencies' => ['ILS']],
59-
'IN' => ['name' => 'India', 'flag' => "\u{1F1EE}\u{1F1F3}", 'default_currency' => 'INR', 'currencies' => ['INR']],
6059
'IS' => ['name' => 'Iceland', 'flag' => "\u{1F1EE}\u{1F1F8}", 'default_currency' => 'ISK', 'currencies' => ['ISK', 'EUR', 'GBP', 'USD', 'CHF', 'DKK', 'NOK', 'SEK']],
6160
'IT' => ['name' => 'Italy', 'flag' => "\u{1F1EE}\u{1F1F9}", 'default_currency' => 'EUR', 'currencies' => ['EUR', 'GBP', 'USD', 'CHF', 'DKK', 'NOK', 'SEK']],
6261
'JM' => ['name' => 'Jamaica', 'flag' => "\u{1F1EF}\u{1F1F2}", 'default_currency' => 'JMD', 'currencies' => ['JMD']],
6362
'JO' => ['name' => 'Jordan', 'flag' => "\u{1F1EF}\u{1F1F4}", 'default_currency' => 'JOD', 'currencies' => ['JOD']],
6463
'JP' => ['name' => 'Japan', 'flag' => "\u{1F1EF}\u{1F1F5}", 'default_currency' => 'JPY', 'currencies' => ['JPY']],
6564
'KE' => ['name' => 'Kenya', 'flag' => "\u{1F1F0}\u{1F1EA}", 'default_currency' => 'KES', 'currencies' => ['KES']],
6665
'KH' => ['name' => 'Cambodia', 'flag' => "\u{1F1F0}\u{1F1ED}", 'default_currency' => 'USD', 'currencies' => ['USD']],
67-
'KR' => ['name' => 'South Korea', 'flag' => "\u{1F1F0}\u{1F1F7}", 'default_currency' => 'KRW', 'currencies' => ['KRW']],
6866
'KW' => ['name' => 'Kuwait', 'flag' => "\u{1F1F0}\u{1F1FC}", 'default_currency' => 'KWD', 'currencies' => ['KWD']],
6967
'LC' => ['name' => 'St. Lucia', 'flag' => "\u{1F1F1}\u{1F1E8}", 'default_currency' => 'XCD', 'currencies' => ['XCD']],
7068
'LI' => ['name' => 'Liechtenstein', 'flag' => "\u{1F1F1}\u{1F1EE}", 'default_currency' => 'CHF', 'currencies' => ['CHF', 'EUR', 'GBP', 'USD', 'DKK', 'NOK', 'SEK']],
@@ -83,8 +81,6 @@ class StripeConnectCountries
8381
'MU' => ['name' => 'Mauritius', 'flag' => "\u{1F1F2}\u{1F1FA}", 'default_currency' => 'MUR', 'currencies' => ['MUR']],
8482
'MX' => ['name' => 'Mexico', 'flag' => "\u{1F1F2}\u{1F1FD}", 'default_currency' => 'MXN', 'currencies' => ['MXN']],
8583
'MY' => ['name' => 'Malaysia', 'flag' => "\u{1F1F2}\u{1F1FE}", 'default_currency' => 'MYR', 'currencies' => ['MYR']],
86-
'NA' => ['name' => 'Namibia', 'flag' => "\u{1F1F3}\u{1F1E6}", 'default_currency' => 'NAD', 'currencies' => ['NAD']],
87-
'NG' => ['name' => 'Nigeria', 'flag' => "\u{1F1F3}\u{1F1EC}", 'default_currency' => 'NGN', 'currencies' => ['NGN']],
8884
'NL' => ['name' => 'Netherlands', 'flag' => "\u{1F1F3}\u{1F1F1}", 'default_currency' => 'EUR', 'currencies' => ['EUR', 'GBP', 'USD', 'CHF', 'DKK', 'NOK', 'SEK']],
8985
'NO' => ['name' => 'Norway', 'flag' => "\u{1F1F3}\u{1F1F4}", 'default_currency' => 'NOK', 'currencies' => ['NOK', 'EUR', 'GBP', 'USD', 'CHF', 'DKK', 'SEK']],
9086
'NZ' => ['name' => 'New Zealand', 'flag' => "\u{1F1F3}\u{1F1FF}", 'default_currency' => 'NZD', 'currencies' => ['NZD']],
@@ -111,7 +107,6 @@ class StripeConnectCountries
111107
'TN' => ['name' => 'Tunisia', 'flag' => "\u{1F1F9}\u{1F1F3}", 'default_currency' => 'TND', 'currencies' => ['TND']],
112108
'TR' => ['name' => "T\u{00FC}rkiye", 'flag' => "\u{1F1F9}\u{1F1F7}", 'default_currency' => 'TRY', 'currencies' => ['TRY']],
113109
'TT' => ['name' => 'Trinidad & Tobago', 'flag' => "\u{1F1F9}\u{1F1F9}", 'default_currency' => 'TTD', 'currencies' => ['TTD']],
114-
'TW' => ['name' => 'Taiwan', 'flag' => "\u{1F1F9}\u{1F1FC}", 'default_currency' => 'TWD', 'currencies' => ['TWD']],
115110
'TZ' => ['name' => 'Tanzania', 'flag' => "\u{1F1F9}\u{1F1FF}", 'default_currency' => 'TZS', 'currencies' => ['TZS']],
116111
'US' => ['name' => 'United States', 'flag' => "\u{1F1FA}\u{1F1F8}", 'default_currency' => 'USD', 'currencies' => ['USD']],
117112
'UY' => ['name' => 'Uruguay', 'flag' => "\u{1F1FA}\u{1F1FE}", 'default_currency' => 'UYU', 'currencies' => ['UYU']],
@@ -155,13 +150,11 @@ class StripeConnectCountries
155150
'HUF' => 'Hungarian Forint',
156151
'IDR' => 'Indonesian Rupiah',
157152
'ILS' => 'Israeli Shekel',
158-
'INR' => 'Indian Rupee',
159153
'ISK' => 'Icelandic Krona',
160154
'JMD' => 'Jamaican Dollar',
161155
'JOD' => 'Jordanian Dinar',
162156
'JPY' => 'Japanese Yen',
163157
'KES' => 'Kenyan Shilling',
164-
'KRW' => 'South Korean Won',
165158
'KWD' => 'Kuwaiti Dinar',
166159
'LKR' => 'Sri Lankan Rupee',
167160
'MAD' => 'Moroccan Dirham',
@@ -173,8 +166,6 @@ class StripeConnectCountries
173166
'MUR' => 'Mauritian Rupee',
174167
'MXN' => 'Mexican Peso',
175168
'MYR' => 'Malaysian Ringgit',
176-
'NAD' => 'Namibian Dollar',
177-
'NGN' => 'Nigerian Naira',
178169
'NOK' => 'Norwegian Krone',
179170
'NZD' => 'New Zealand Dollar',
180171
'OMR' => 'Omani Rial',
@@ -194,7 +185,6 @@ class StripeConnectCountries
194185
'TND' => 'Tunisian Dinar',
195186
'TRY' => 'Turkish Lira',
196187
'TTD' => 'Trinidad & Tobago Dollar',
197-
'TWD' => 'New Taiwan Dollar',
198188
'TZS' => 'Tanzanian Shilling',
199189
'USD' => 'US Dollar',
200190
'UYU' => 'Uruguayan Peso',

tests/Feature/DeveloperTermsTest.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Laravel\Pennant\Feature;
1414
use Livewire\Livewire;
1515
use Mockery;
16+
use Stripe\Exception\InvalidRequestException;
1617
use Tests\TestCase;
1718

1819
class DeveloperTermsTest extends TestCase
@@ -291,6 +292,58 @@ public function onboarding_start_requires_payout_currency(): void
291292
$response->assertSessionHasErrors('payout_currency');
292293
}
293294

295+
/** @test */
296+
public function onboarding_start_rejects_india_as_unsupported_country(): void
297+
{
298+
$user = User::factory()->create();
299+
300+
$response = $this->actingAs($user)
301+
->post(route('customer.developer.onboarding.start'), [
302+
'accepted_plugin_terms' => '1',
303+
'country' => 'IN',
304+
'payout_currency' => 'INR',
305+
]);
306+
307+
$response->assertSessionHasErrors('country');
308+
}
309+
310+
/** @test */
311+
public function onboarding_start_rejects_taiwan_as_unsupported_country(): void
312+
{
313+
$user = User::factory()->create();
314+
315+
$response = $this->actingAs($user)
316+
->post(route('customer.developer.onboarding.start'), [
317+
'accepted_plugin_terms' => '1',
318+
'country' => 'TW',
319+
'payout_currency' => 'TWD',
320+
]);
321+
322+
$response->assertSessionHasErrors('country');
323+
}
324+
325+
/** @test */
326+
public function onboarding_start_handles_stripe_error_gracefully(): void
327+
{
328+
$user = User::factory()->create();
329+
330+
$mockService = Mockery::mock(StripeConnectService::class);
331+
$mockService->shouldReceive('createConnectAccount')
332+
->once()
333+
->andThrow(new InvalidRequestException('Connected accounts in XX cannot be created by platforms in US.'));
334+
335+
$this->app->instance(StripeConnectService::class, $mockService);
336+
337+
$response = $this->actingAs($user)
338+
->post(route('customer.developer.onboarding.start'), [
339+
'accepted_plugin_terms' => '1',
340+
'country' => 'US',
341+
'payout_currency' => 'USD',
342+
]);
343+
344+
$response->assertSessionHasErrors('country');
345+
}
346+
294347
/** @test */
295348
public function onboarding_start_rejects_invalid_currency_for_country(): void
296349
{

tests/Unit/StripeConnectCountriesTest.php

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public function all_returns_all_supported_countries(): void
1212
{
1313
$countries = StripeConnectCountries::all();
1414

15-
$this->assertCount(108, $countries);
15+
$this->assertCount(103, $countries);
1616
$this->assertArrayHasKey('US', $countries);
1717
$this->assertArrayHasKey('GB', $countries);
1818
$this->assertArrayHasKey('DE', $countries);
@@ -98,7 +98,7 @@ public function supported_country_codes_returns_array_of_codes(): void
9898

9999
$this->assertContains('US', $codes);
100100
$this->assertContains('GB', $codes);
101-
$this->assertCount(108, $codes);
101+
$this->assertCount(103, $codes);
102102
}
103103

104104
/** @test */
@@ -128,6 +128,41 @@ public function every_used_currency_has_a_name(): void
128128
}
129129
}
130130

131+
/** @test */
132+
public function india_is_not_in_supported_countries(): void
133+
{
134+
$this->assertFalse(StripeConnectCountries::isSupported('IN'));
135+
$this->assertArrayNotHasKey('IN', StripeConnectCountries::all());
136+
}
137+
138+
/** @test */
139+
public function taiwan_is_not_in_supported_countries(): void
140+
{
141+
$this->assertFalse(StripeConnectCountries::isSupported('TW'));
142+
$this->assertArrayNotHasKey('TW', StripeConnectCountries::all());
143+
}
144+
145+
/** @test */
146+
public function south_korea_is_not_in_supported_countries(): void
147+
{
148+
$this->assertFalse(StripeConnectCountries::isSupported('KR'));
149+
$this->assertArrayNotHasKey('KR', StripeConnectCountries::all());
150+
}
151+
152+
/** @test */
153+
public function nigeria_is_not_in_supported_countries(): void
154+
{
155+
$this->assertFalse(StripeConnectCountries::isSupported('NG'));
156+
$this->assertArrayNotHasKey('NG', StripeConnectCountries::all());
157+
}
158+
159+
/** @test */
160+
public function namibia_is_not_in_supported_countries(): void
161+
{
162+
$this->assertFalse(StripeConnectCountries::isSupported('NA'));
163+
$this->assertArrayNotHasKey('NA', StripeConnectCountries::all());
164+
}
165+
131166
/** @test */
132167
public function each_country_has_required_keys(): void
133168
{

0 commit comments

Comments
 (0)