Skip to content

Commit 2ed0198

Browse files
simonhampclaude
andauthored
Remove unsupported Stripe Connect countries and add graceful error handling (#344)
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 1eac0c8 commit 2ed0198

File tree

4 files changed

+103
-13
lines changed

4 files changed

+103
-13
lines changed

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)