diff --git a/app/Livewire/OrderSuccess.php b/app/Livewire/OrderSuccess.php index a2469750..35b753c6 100644 --- a/app/Livewire/OrderSuccess.php +++ b/app/Livewire/OrderSuccess.php @@ -3,7 +3,8 @@ namespace App\Livewire; use App\Enums\Subscription; -use App\Models\User; +use App\Models\License; +use Illuminate\Database\Eloquent\ModelNotFoundException; use Laravel\Cashier\Cashier; use Livewire\Attributes\Layout; use Livewire\Attributes\Title; @@ -31,84 +32,37 @@ public function mount(string $checkoutSessionId): void public function loadData(): void { - $this->email = $this->loadEmail(); - $this->licenseKey = $this->loadLicenseKey(); - $this->subscription = $this->loadSubscription(); - } - - private function loadEmail(): ?string - { - if ($email = session($this->sessionKey('email'))) { - return $email; - } - try { - $checkoutSession = Cashier::stripe()->checkout->sessions->retrieve($this->checkoutSessionId); + $subscriptionId = Cashier::stripe()->checkout->sessions->retrieve($this->checkoutSessionId)->subscription; } catch (InvalidRequestException $e) { - return $this->redirect('/mobile'); - } - - if (! ($email = $checkoutSession?->customer_details?->email)) { - return null; - } - - session()->put($this->sessionKey('email'), $email); - - return $email; - } - - private function loadLicenseKey(): ?string - { - if ($licenseKey = session($this->sessionKey('license_key'))) { - return $licenseKey; - } - - if (! $this->email) { - return null; - } - - $user = User::where('email', $this->email)->first(); + $this->redirect('/mobile'); - if (! $user) { - return null; + return; } - $license = $user->licenses()->latest()->first(); + $subscriptionRecord = Cashier::$subscriptionModel::query() + ->whereNotNull('stripe_id') + ->where('stripe_id', $subscriptionId) + ->first(); - if (! $license) { - return null; + if (! $subscriptionRecord) { + return; } - session()->put($this->sessionKey('license_key'), $license->key); - - return $license->key; - } + $subscriptionItem = Cashier::$subscriptionItemModel::query() + ->whereBelongsTo($subscriptionRecord) + ->first(); - private function loadSubscription(): ?Subscription - { - if ($subscription = session($this->sessionKey('subscription'))) { - return Subscription::tryFrom($subscription); - } + if (! $subscriptionItem) { + report(new ModelNotFoundException("No subscription item found for subscription record [{$subscriptionRecord->id}].")); - try { - $priceId = Cashier::stripe()->checkout->sessions->allLineItems($this->checkoutSessionId)->first()?->price->id; - } catch (InvalidRequestException $e) { - return $this->redirect('/mobile'); + return; } - if (! $priceId) { - return null; - } - - $subscription = Subscription::fromStripePriceId($priceId); - - session()->put($this->sessionKey('subscription'), $subscription->value); - - return $subscription; - } - - private function sessionKey(string $key): string - { - return "{$this->checkoutSessionId}.{$key}"; + $this->subscription = Subscription::fromStripePriceId($subscriptionItem->stripe_price); + $this->email = $subscriptionRecord->user->email; + $this->licenseKey = License::query() + ->whereBelongsTo($subscriptionItem) + ->first()?->key; } } diff --git a/tests/Feature/Livewire/OrderSuccessTest.php b/tests/Feature/Livewire/OrderSuccessTest.php index 611120f7..44da2f7e 100644 --- a/tests/Feature/Livewire/OrderSuccessTest.php +++ b/tests/Feature/Livewire/OrderSuccessTest.php @@ -7,7 +7,7 @@ use App\Models\License; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase; -use Illuminate\Support\Facades\Session; +use Laravel\Cashier\Cashier; use Livewire\Livewire; use PHPUnit\Framework\Attributes\Test; use Stripe\Checkout\Session as CheckoutSession; @@ -39,10 +39,8 @@ public function it_renders_successfully() #[Test] public function it_displays_loading_state_when_no_license_key_is_available() { - Session::flush(); - Livewire::test(OrderSuccess::class, ['checkoutSessionId' => 'cs_test_123']) - ->assertSet('email', 'test@example.com') + ->assertSet('email', null) ->assertSet('licenseKey', null) ->assertSee('License registration in progress') ->assertSee('check your email'); @@ -51,17 +49,31 @@ public function it_displays_loading_state_when_no_license_key_is_available() #[Test] public function it_displays_license_key_when_available_in_database() { - Session::flush(); - $user = User::factory()->create([ 'email' => 'test@example.com', + 'stripe_id' => 'cus_test123', ]); - License::factory()->create([ - 'user_id' => $user->id, - 'key' => 'db-license-key-12345', - 'policy_name' => 'max', - ]); + $subscription = Cashier::$subscriptionModel::factory() + ->for($user, 'user') + ->create([ + 'stripe_id' => 'sub_test123', + ]); + + $subscriptionItem = Cashier::$subscriptionItemModel::factory() + ->for($subscription, 'subscription') + ->create([ + 'stripe_id' => 'si_test123', + 'stripe_price' => Subscription::Max->stripePriceId(), + ]); + + $license = License::factory() + ->for($user, 'user') + ->for($subscriptionItem, 'subscriptionItem') + ->create([ + 'key' => 'db-license-key-12345', + 'policy_name' => 'max', + ]); Livewire::test(OrderSuccess::class, ['checkoutSessionId' => 'cs_test_123']) ->assertSet('email', 'test@example.com') @@ -71,26 +83,9 @@ public function it_displays_license_key_when_available_in_database() ->assertDontSee('License registration in progress'); } - #[Test] - public function it_uses_session_data_when_available() - { - $checkoutSessionId = 'cs_test_123'; - - Session::put("$checkoutSessionId.email", 'session@example.com'); - Session::put("$checkoutSessionId.license_key", 'session-license-key'); - - Livewire::test(OrderSuccess::class, ['checkoutSessionId' => 'cs_test_123']) - ->assertSet('email', 'session@example.com') - ->assertSet('licenseKey', 'session-license-key') - ->assertSee('session-license-key') - ->assertSee('session@example.com'); - } - #[Test] public function it_polls_for_updates_from_database() { - Session::flush(); - $component = Livewire::test(OrderSuccess::class, ['checkoutSessionId' => 'cs_test_123']) ->assertSet('licenseKey', null) ->assertSee('License registration in progress') @@ -98,13 +93,29 @@ public function it_polls_for_updates_from_database() $user = User::factory()->create([ 'email' => 'test@example.com', + 'stripe_id' => 'cus_test123', ]); - License::factory()->create([ - 'user_id' => $user->id, - 'key' => 'db-polled-license-key', - 'policy_name' => 'max', - ]); + $subscription = Cashier::$subscriptionModel::factory() + ->for($user, 'user') + ->create([ + 'stripe_id' => 'sub_test123', + ]); + + $subscriptionItem = Cashier::$subscriptionItemModel::factory() + ->for($subscription, 'subscription') + ->create([ + 'stripe_id' => 'si_test123', + 'stripe_price' => Subscription::Max->stripePriceId(), + ]); + + $license = License::factory() + ->for($user, 'user') + ->for($subscriptionItem, 'subscriptionItem') + ->create([ + 'key' => 'db-polled-license-key', + 'policy_name' => 'max', + ]); $component->call('loadData') ->assertSet('licenseKey', 'db-polled-license-key') @@ -144,9 +155,11 @@ private function mockStripeClient(): void { $mockCheckoutSession = CheckoutSession::constructFrom([ 'id' => 'cs_test_123', + 'customer' => 'cus_test123', 'customer_details' => [ 'email' => 'test@example.com', ], + 'subscription' => 'sub_test123', ]); $mockCheckoutSessionLineItems = Collection::constructFrom([