From 4766d11d3d29872e213c8b09fd6fac952cfe91ad Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Mon, 30 Mar 2026 19:47:49 +0100 Subject: [PATCH] Treat comped users as non-subscribers on pricing page Comped users now see the normal checkout button instead of "You're on Ultra" or the upgrade modal. Their comped subscription is canceled when they proceed to checkout, allowing a fresh paid subscription. Co-Authored-By: Claude Opus 4.6 --- app/Livewire/Customer/Dashboard.php | 6 +++++ app/Livewire/MobilePricing.php | 7 +++++- app/Models/User.php | 21 ++++++++++++++++++ tests/Feature/MobilePricingTest.php | 34 +++++++++++++++++++++++++++-- 4 files changed, 65 insertions(+), 3 deletions(-) diff --git a/app/Livewire/Customer/Dashboard.php b/app/Livewire/Customer/Dashboard.php index 9818a50f..e82e03a0 100644 --- a/app/Livewire/Customer/Dashboard.php +++ b/app/Livewire/Customer/Dashboard.php @@ -31,6 +31,12 @@ public function activeSubscription() return auth()->user()->subscription(); } + #[Computed] + public function isCompedSubscription(): bool + { + return auth()->user()->hasCompedSubscription(); + } + #[Computed] public function subscriptionName(): ?string { diff --git a/app/Livewire/MobilePricing.php b/app/Livewire/MobilePricing.php index 4c71ecb6..1fe14e33 100644 --- a/app/Livewire/MobilePricing.php +++ b/app/Livewire/MobilePricing.php @@ -69,6 +69,11 @@ public function createCheckoutSession(?string $plan, ?User $user = null) return; } + // Cancel any comped subscription before creating a new paid one + if ($user->hasCompedSubscription()) { + $user->subscription('default')->cancelNow(); + } + $user->createOrGetStripeCustomer(); $checkout = $user @@ -209,7 +214,7 @@ public function render() $subscription = $user->subscription('default'); - if ($subscription && $subscription->active()) { + if ($subscription && $subscription->active() && ! $user->hasCompedSubscription()) { $hasExistingSubscription = true; $isAlreadyUltra = $user->hasActiveUltraSubscription(); diff --git a/app/Models/User.php b/app/Models/User.php index 82da1024..0aee5dbc 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -215,6 +215,27 @@ public function hasMaxAccess(): bool return $this->hasActiveMaxLicense() || $this->hasActiveMaxSubLicense(); } + /** + * Check if the user's subscription is a comped (free) subscription. + * Covers both legacy comped (is_comped flag) and comped Ultra price. + */ + public function hasCompedSubscription(): bool + { + $subscription = $this->subscription(); + + if (! $subscription || ! $subscription->active()) { + return false; + } + + if ($subscription->is_comped) { + return true; + } + + $compedPriceId = config('subscriptions.plans.max.stripe_price_id_comped'); + + return $compedPriceId && $this->subscribedToPrice($compedPriceId); + } + public function hasActiveUltraSubscription(): bool { $subscription = $this->subscription(); diff --git a/tests/Feature/MobilePricingTest.php b/tests/Feature/MobilePricingTest.php index 47b4973f..5a919e53 100644 --- a/tests/Feature/MobilePricingTest.php +++ b/tests/Feature/MobilePricingTest.php @@ -137,7 +137,7 @@ public function ultra_subscriber_sees_already_on_ultra_message() } #[Test] - public function comped_max_subscriber_sees_upgrade_button() + public function comped_max_subscriber_sees_checkout_button() { $user = User::factory()->create(['stripe_id' => 'cus_'.uniqid()]); Auth::login($user); @@ -155,7 +155,37 @@ public function comped_max_subscriber_sees_upgrade_button() ->create(['stripe_price' => self::MAX_PRICE_ID]); Livewire::test(MobilePricing::class) - ->assertSee('Upgrade to Ultra') + ->assertSeeHtml('wire:click="createCheckoutSession(\'max\')"') + ->assertDontSee('Upgrade to Ultra') + ->assertDontSee('on Ultra', escape: false); + } + + #[Test] + public function comped_ultra_price_subscriber_sees_checkout_button() + { + $compedPriceId = 'price_test_comped_ultra'; + + config([ + 'subscriptions.plans.max.stripe_price_id_comped' => $compedPriceId, + ]); + + $user = User::factory()->create(['stripe_id' => 'cus_'.uniqid()]); + Auth::login($user); + + $subscription = Cashier::$subscriptionModel::factory() + ->for($user) + ->active() + ->create([ + 'stripe_price' => $compedPriceId, + ]); + + Cashier::$subscriptionItemModel::factory() + ->for($subscription, 'subscription') + ->create(['stripe_price' => $compedPriceId]); + + Livewire::test(MobilePricing::class) + ->assertSeeHtml('wire:click="createCheckoutSession(\'max\')"') + ->assertDontSee('Upgrade to Ultra') ->assertDontSee('on Ultra', escape: false); }