diff --git a/app/Http/Controllers/DeveloperOnboardingController.php b/app/Http/Controllers/DeveloperOnboardingController.php index 57ea3e52..994414ef 100644 --- a/app/Http/Controllers/DeveloperOnboardingController.php +++ b/app/Http/Controllers/DeveloperOnboardingController.php @@ -7,7 +7,9 @@ use App\Support\StripeConnectCountries; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Log; use Illuminate\Validation\Rule; +use Stripe\Exception\InvalidRequestException; class DeveloperOnboardingController extends Controller { @@ -38,7 +40,17 @@ public function start(Request $request): RedirectResponse $developerAccount = $user->developerAccount; if (! $developerAccount) { - $developerAccount = $this->stripeConnectService->createConnectAccount($user, $country, $payoutCurrency); + try { + $developerAccount = $this->stripeConnectService->createConnectAccount($user, $country, $payoutCurrency); + } catch (InvalidRequestException $e) { + Log::warning('Stripe Connect account creation failed', [ + 'user_id' => $user->id, + 'country' => $country, + 'error' => $e->getMessage(), + ]); + + 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.']); + } } else { $developerAccount->update([ 'country' => $country, diff --git a/app/Support/StripeConnectCountries.php b/app/Support/StripeConnectCountries.php index 824029f1..40e9bd5d 100644 --- a/app/Support/StripeConnectCountries.php +++ b/app/Support/StripeConnectCountries.php @@ -56,7 +56,6 @@ class StripeConnectCountries 'ID' => ['name' => 'Indonesia', 'flag' => "\u{1F1EE}\u{1F1E9}", 'default_currency' => 'IDR', 'currencies' => ['IDR']], 'IE' => ['name' => 'Ireland', 'flag' => "\u{1F1EE}\u{1F1EA}", 'default_currency' => 'EUR', 'currencies' => ['EUR', 'GBP', 'USD', 'CHF', 'DKK', 'NOK', 'SEK']], 'IL' => ['name' => 'Israel', 'flag' => "\u{1F1EE}\u{1F1F1}", 'default_currency' => 'ILS', 'currencies' => ['ILS']], - 'IN' => ['name' => 'India', 'flag' => "\u{1F1EE}\u{1F1F3}", 'default_currency' => 'INR', 'currencies' => ['INR']], 'IS' => ['name' => 'Iceland', 'flag' => "\u{1F1EE}\u{1F1F8}", 'default_currency' => 'ISK', 'currencies' => ['ISK', 'EUR', 'GBP', 'USD', 'CHF', 'DKK', 'NOK', 'SEK']], 'IT' => ['name' => 'Italy', 'flag' => "\u{1F1EE}\u{1F1F9}", 'default_currency' => 'EUR', 'currencies' => ['EUR', 'GBP', 'USD', 'CHF', 'DKK', 'NOK', 'SEK']], 'JM' => ['name' => 'Jamaica', 'flag' => "\u{1F1EF}\u{1F1F2}", 'default_currency' => 'JMD', 'currencies' => ['JMD']], @@ -64,7 +63,6 @@ class StripeConnectCountries 'JP' => ['name' => 'Japan', 'flag' => "\u{1F1EF}\u{1F1F5}", 'default_currency' => 'JPY', 'currencies' => ['JPY']], 'KE' => ['name' => 'Kenya', 'flag' => "\u{1F1F0}\u{1F1EA}", 'default_currency' => 'KES', 'currencies' => ['KES']], 'KH' => ['name' => 'Cambodia', 'flag' => "\u{1F1F0}\u{1F1ED}", 'default_currency' => 'USD', 'currencies' => ['USD']], - 'KR' => ['name' => 'South Korea', 'flag' => "\u{1F1F0}\u{1F1F7}", 'default_currency' => 'KRW', 'currencies' => ['KRW']], 'KW' => ['name' => 'Kuwait', 'flag' => "\u{1F1F0}\u{1F1FC}", 'default_currency' => 'KWD', 'currencies' => ['KWD']], 'LC' => ['name' => 'St. Lucia', 'flag' => "\u{1F1F1}\u{1F1E8}", 'default_currency' => 'XCD', 'currencies' => ['XCD']], '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 'MU' => ['name' => 'Mauritius', 'flag' => "\u{1F1F2}\u{1F1FA}", 'default_currency' => 'MUR', 'currencies' => ['MUR']], 'MX' => ['name' => 'Mexico', 'flag' => "\u{1F1F2}\u{1F1FD}", 'default_currency' => 'MXN', 'currencies' => ['MXN']], 'MY' => ['name' => 'Malaysia', 'flag' => "\u{1F1F2}\u{1F1FE}", 'default_currency' => 'MYR', 'currencies' => ['MYR']], - 'NA' => ['name' => 'Namibia', 'flag' => "\u{1F1F3}\u{1F1E6}", 'default_currency' => 'NAD', 'currencies' => ['NAD']], - 'NG' => ['name' => 'Nigeria', 'flag' => "\u{1F1F3}\u{1F1EC}", 'default_currency' => 'NGN', 'currencies' => ['NGN']], 'NL' => ['name' => 'Netherlands', 'flag' => "\u{1F1F3}\u{1F1F1}", 'default_currency' => 'EUR', 'currencies' => ['EUR', 'GBP', 'USD', 'CHF', 'DKK', 'NOK', 'SEK']], 'NO' => ['name' => 'Norway', 'flag' => "\u{1F1F3}\u{1F1F4}", 'default_currency' => 'NOK', 'currencies' => ['NOK', 'EUR', 'GBP', 'USD', 'CHF', 'DKK', 'SEK']], 'NZ' => ['name' => 'New Zealand', 'flag' => "\u{1F1F3}\u{1F1FF}", 'default_currency' => 'NZD', 'currencies' => ['NZD']], @@ -111,7 +107,6 @@ class StripeConnectCountries 'TN' => ['name' => 'Tunisia', 'flag' => "\u{1F1F9}\u{1F1F3}", 'default_currency' => 'TND', 'currencies' => ['TND']], 'TR' => ['name' => "T\u{00FC}rkiye", 'flag' => "\u{1F1F9}\u{1F1F7}", 'default_currency' => 'TRY', 'currencies' => ['TRY']], 'TT' => ['name' => 'Trinidad & Tobago', 'flag' => "\u{1F1F9}\u{1F1F9}", 'default_currency' => 'TTD', 'currencies' => ['TTD']], - 'TW' => ['name' => 'Taiwan', 'flag' => "\u{1F1F9}\u{1F1FC}", 'default_currency' => 'TWD', 'currencies' => ['TWD']], 'TZ' => ['name' => 'Tanzania', 'flag' => "\u{1F1F9}\u{1F1FF}", 'default_currency' => 'TZS', 'currencies' => ['TZS']], 'US' => ['name' => 'United States', 'flag' => "\u{1F1FA}\u{1F1F8}", 'default_currency' => 'USD', 'currencies' => ['USD']], 'UY' => ['name' => 'Uruguay', 'flag' => "\u{1F1FA}\u{1F1FE}", 'default_currency' => 'UYU', 'currencies' => ['UYU']], @@ -155,13 +150,11 @@ class StripeConnectCountries 'HUF' => 'Hungarian Forint', 'IDR' => 'Indonesian Rupiah', 'ILS' => 'Israeli Shekel', - 'INR' => 'Indian Rupee', 'ISK' => 'Icelandic Krona', 'JMD' => 'Jamaican Dollar', 'JOD' => 'Jordanian Dinar', 'JPY' => 'Japanese Yen', 'KES' => 'Kenyan Shilling', - 'KRW' => 'South Korean Won', 'KWD' => 'Kuwaiti Dinar', 'LKR' => 'Sri Lankan Rupee', 'MAD' => 'Moroccan Dirham', @@ -173,8 +166,6 @@ class StripeConnectCountries 'MUR' => 'Mauritian Rupee', 'MXN' => 'Mexican Peso', 'MYR' => 'Malaysian Ringgit', - 'NAD' => 'Namibian Dollar', - 'NGN' => 'Nigerian Naira', 'NOK' => 'Norwegian Krone', 'NZD' => 'New Zealand Dollar', 'OMR' => 'Omani Rial', @@ -194,7 +185,6 @@ class StripeConnectCountries 'TND' => 'Tunisian Dinar', 'TRY' => 'Turkish Lira', 'TTD' => 'Trinidad & Tobago Dollar', - 'TWD' => 'New Taiwan Dollar', 'TZS' => 'Tanzanian Shilling', 'USD' => 'US Dollar', 'UYU' => 'Uruguayan Peso', diff --git a/tests/Feature/DeveloperTermsTest.php b/tests/Feature/DeveloperTermsTest.php index f7986f2e..1c52422a 100644 --- a/tests/Feature/DeveloperTermsTest.php +++ b/tests/Feature/DeveloperTermsTest.php @@ -13,6 +13,7 @@ use Laravel\Pennant\Feature; use Livewire\Livewire; use Mockery; +use Stripe\Exception\InvalidRequestException; use Tests\TestCase; class DeveloperTermsTest extends TestCase @@ -291,6 +292,58 @@ public function onboarding_start_requires_payout_currency(): void $response->assertSessionHasErrors('payout_currency'); } + /** @test */ + public function onboarding_start_rejects_india_as_unsupported_country(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user) + ->post(route('customer.developer.onboarding.start'), [ + 'accepted_plugin_terms' => '1', + 'country' => 'IN', + 'payout_currency' => 'INR', + ]); + + $response->assertSessionHasErrors('country'); + } + + /** @test */ + public function onboarding_start_rejects_taiwan_as_unsupported_country(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user) + ->post(route('customer.developer.onboarding.start'), [ + 'accepted_plugin_terms' => '1', + 'country' => 'TW', + 'payout_currency' => 'TWD', + ]); + + $response->assertSessionHasErrors('country'); + } + + /** @test */ + public function onboarding_start_handles_stripe_error_gracefully(): void + { + $user = User::factory()->create(); + + $mockService = Mockery::mock(StripeConnectService::class); + $mockService->shouldReceive('createConnectAccount') + ->once() + ->andThrow(new InvalidRequestException('Connected accounts in XX cannot be created by platforms in US.')); + + $this->app->instance(StripeConnectService::class, $mockService); + + $response = $this->actingAs($user) + ->post(route('customer.developer.onboarding.start'), [ + 'accepted_plugin_terms' => '1', + 'country' => 'US', + 'payout_currency' => 'USD', + ]); + + $response->assertSessionHasErrors('country'); + } + /** @test */ public function onboarding_start_rejects_invalid_currency_for_country(): void { diff --git a/tests/Unit/StripeConnectCountriesTest.php b/tests/Unit/StripeConnectCountriesTest.php index a8d1fb30..8bd9ebb6 100644 --- a/tests/Unit/StripeConnectCountriesTest.php +++ b/tests/Unit/StripeConnectCountriesTest.php @@ -12,7 +12,7 @@ public function all_returns_all_supported_countries(): void { $countries = StripeConnectCountries::all(); - $this->assertCount(108, $countries); + $this->assertCount(103, $countries); $this->assertArrayHasKey('US', $countries); $this->assertArrayHasKey('GB', $countries); $this->assertArrayHasKey('DE', $countries); @@ -98,7 +98,7 @@ public function supported_country_codes_returns_array_of_codes(): void $this->assertContains('US', $codes); $this->assertContains('GB', $codes); - $this->assertCount(108, $codes); + $this->assertCount(103, $codes); } /** @test */ @@ -128,6 +128,41 @@ public function every_used_currency_has_a_name(): void } } + /** @test */ + public function india_is_not_in_supported_countries(): void + { + $this->assertFalse(StripeConnectCountries::isSupported('IN')); + $this->assertArrayNotHasKey('IN', StripeConnectCountries::all()); + } + + /** @test */ + public function taiwan_is_not_in_supported_countries(): void + { + $this->assertFalse(StripeConnectCountries::isSupported('TW')); + $this->assertArrayNotHasKey('TW', StripeConnectCountries::all()); + } + + /** @test */ + public function south_korea_is_not_in_supported_countries(): void + { + $this->assertFalse(StripeConnectCountries::isSupported('KR')); + $this->assertArrayNotHasKey('KR', StripeConnectCountries::all()); + } + + /** @test */ + public function nigeria_is_not_in_supported_countries(): void + { + $this->assertFalse(StripeConnectCountries::isSupported('NG')); + $this->assertArrayNotHasKey('NG', StripeConnectCountries::all()); + } + + /** @test */ + public function namibia_is_not_in_supported_countries(): void + { + $this->assertFalse(StripeConnectCountries::isSupported('NA')); + $this->assertArrayNotHasKey('NA', StripeConnectCountries::all()); + } + /** @test */ public function each_country_has_required_keys(): void {