diff --git a/app/Http/Controllers/Webhook/Stripe.php b/app/Http/Controllers/Webhook/Stripe.php index 55c94a618..5d297b242 100644 --- a/app/Http/Controllers/Webhook/Stripe.php +++ b/app/Http/Controllers/Webhook/Stripe.php @@ -13,7 +13,6 @@ use App\Models\Webhook; use Exception; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; -use Illuminate\Support\Sleep; use Illuminate\Support\Str; class Stripe extends Controller @@ -64,22 +63,18 @@ class Stripe extends Controller $piData = $stripe->paymentIntents->retrieve($pi, []); $customerId = data_get($piData, 'customer'); $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if (! $subscription) { - Sleep::for(5)->seconds(); - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - } - if (! $subscription) { - Sleep::for(5)->seconds(); - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - } if ($subscription) { $subscriptionId = data_get($subscription, 'stripe_subscription_id'); $stripe->subscriptions->cancel($subscriptionId, []); $subscription->update([ 'stripe_invoice_paid' => false, ]); + send_internal_notification("Early fraud warning created Refunded, subscription canceled. Charge: {$charge}, id: {$id}, pi: {$pi}"); + } else { + send_internal_notification("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}"); + + return response("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}", 400); } - send_internal_notification("Early fraud warning created Refunded, subscription canceled. Charge: {$charge}, id: {$id}, pi: {$pi}"); break; case 'checkout.session.completed': $clientReferenceId = data_get($data, 'client_reference_id'); @@ -95,7 +90,8 @@ class Stripe extends Controller $found = $team->members->where('id', $userId)->first(); if (! $found->isAdmin()) { send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}."); - throw new Exception("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}."); + + return response("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.", 400); } $subscription = Subscription::where('team_id', $teamId)->first(); if ($subscription) { @@ -123,13 +119,13 @@ class Stripe extends Controller break; } $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if (! $subscription) { - Sleep::for(5)->seconds(); - $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); + if ($subscription) { + $subscription->update([ + 'stripe_invoice_paid' => true, + ]); + } else { + return response("No subscription found for customer: {$customerId}", 400); } - $subscription->update([ - 'stripe_invoice_paid' => true, - ]); break; case 'invoice.payment_failed': $customerId = data_get($data, 'customer'); @@ -167,7 +163,42 @@ class Stripe extends Controller } send_internal_notification('Subscription payment failed for customer: '.$customerId); break; + case 'customer.subscription.created': + $customerId = data_get($data, 'customer'); + $subscriptionId = data_get($data, 'id'); + $teamId = data_get($data, 'metadata.team_id'); + $userId = data_get($data, 'metadata.user_id'); + if (! $teamId || ! $userId) { + $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); + if ($subscription) { + return response("Subscription already exists for customer: {$customerId}", 200); + } + + return response('No team id or user id found', 400); + } + $team = Team::find($teamId); + $found = $team->members->where('id', $userId)->first(); + if (! $found->isAdmin()) { + send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}."); + + return response("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}.", 400); + } + $subscription = Subscription::where('team_id', $teamId)->first(); + if ($subscription) { + return response("Subscription already exists for team: {$teamId}", 200); + } else { + Subscription::create([ + 'team_id' => $teamId, + 'stripe_subscription_id' => $subscriptionId, + 'stripe_customer_id' => $customerId, + 'stripe_invoice_paid' => false, + ]); + + return response('Subscription created'); + } case 'customer.subscription.updated': + $teamId = data_get($data, 'metadata.team_id'); + $userId = data_get($data, 'metadata.user_id'); $customerId = data_get($data, 'customer'); $status = data_get($data, 'status'); $subscriptionId = data_get($data, 'items.data.0.subscription'); @@ -177,32 +208,27 @@ class Stripe extends Controller break; } $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if (! $subscription) { - Sleep::for(5)->seconds(); - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - } if (! $subscription) { if ($status === 'incomplete_expired') { - // send_internal_notification('Subscription incomplete expired for customer: '.$customerId); - return response('Subscription incomplete expired', 200); } - // send_internal_notification('No subscription found for: '.$customerId); - - return response('No subscription found', 400); + if ($teamId) { + $subscription = Subscription::create([ + 'team_id' => $teamId, + 'stripe_subscription_id' => $subscriptionId, + 'stripe_customer_id' => $customerId, + 'stripe_invoice_paid' => false, + ]); + } else { + return response('No subscription and team id found', 400); + } } - $trialEndedAlready = data_get($subscription, 'stripe_trial_already_ended'); $cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end'); - $alreadyCancelAtPeriodEnd = data_get($subscription, 'stripe_cancel_at_period_end'); $feedback = data_get($data, 'cancellation_details.feedback'); $comment = data_get($data, 'cancellation_details.comment'); $lookup_key = data_get($data, 'items.data.0.price.lookup_key'); - if (str($lookup_key)->contains('ultimate') || str($lookup_key)->contains('dynamic')) { - if (str($lookup_key)->contains('dynamic')) { - $quantity = data_get($data, 'items.data.0.quantity', 2); - } else { - $quantity = data_get($data, 'items.data.0.quantity', 10); - } + if (str($lookup_key)->contains('dynamic')) { + $quantity = data_get($data, 'items.data.0.quantity', 2); $team = data_get($subscription, 'team'); if ($team) { $team->update([ @@ -221,28 +247,12 @@ class Stripe extends Controller $subscription->update([ 'stripe_invoice_paid' => false, ]); - // send_internal_notification('Subscription paused or incomplete for customer: '.$customerId); } - - // Trial ended but subscribed, reactive servers - if ($trialEndedAlready && $status === 'active') { - $team = data_get($subscription, 'team'); - $team->trialEndedButSubscribed(); - } - if ($feedback) { $reason = "Cancellation feedback for {$customerId}: '".$feedback."'"; if ($comment) { $reason .= ' with comment: \''.$comment."'"; } - // send_internal_notification($reason); - } - if ($alreadyCancelAtPeriodEnd !== $cancelAtPeriodEnd) { - if ($cancelAtPeriodEnd) { - // send_internal_notification('Subscription cancelled at period end for team: ' . $subscription->team->id); - } else { - // send_internal_notification('customer.subscription.updated for customer: '.$customerId); - } } break; case 'customer.subscription.deleted': @@ -268,7 +278,7 @@ class Stripe extends Controller $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); $team = data_get($subscription, 'team'); if (! $team) { - throw new Exception('No team found for subscription: '.$subscription->id); + return response('No team found for subscription: '.$subscription->id, 400); } SubscriptionTrialEndsSoonJob::dispatch($team); break; @@ -277,7 +287,7 @@ class Stripe extends Controller $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); $team = data_get($subscription, 'team'); if (! $team) { - throw new Exception('No team found for subscription: '.$subscription->id); + return response('No team found for subscription: '.$subscription->id, 400); } $team->trialEnded(); $subscription->update([ diff --git a/app/Livewire/Subscription/PricingPlans.php b/app/Livewire/Subscription/PricingPlans.php index 09d11038d..9186cc978 100644 --- a/app/Livewire/Subscription/PricingPlans.php +++ b/app/Livewire/Subscription/PricingPlans.php @@ -8,31 +8,14 @@ use Stripe\Stripe; class PricingPlans extends Component { - public bool $isTrial = false; - - public function mount() - { - $this->isTrial = ! data_get(currentTeam(), 'subscription.stripe_trial_already_ended'); - if (config('constants.limits.trial_period') == 0) { - $this->isTrial = false; - } - } - public function subscribeStripe($type) { - $team = currentTeam(); Stripe::setApiKey(config('subscription.stripe_api_key')); $priceId = match ($type) { - 'basic-monthly' => config('subscription.stripe_price_id_basic_monthly'), - 'basic-yearly' => config('subscription.stripe_price_id_basic_yearly'), - 'pro-monthly' => config('subscription.stripe_price_id_pro_monthly'), - 'pro-yearly' => config('subscription.stripe_price_id_pro_yearly'), - 'ultimate-monthly' => config('subscription.stripe_price_id_ultimate_monthly'), - 'ultimate-yearly' => config('subscription.stripe_price_id_ultimate_yearly'), 'dynamic-monthly' => config('subscription.stripe_price_id_dynamic_monthly'), 'dynamic-yearly' => config('subscription.stripe_price_id_dynamic_yearly'), - default => config('subscription.stripe_price_id_basic_monthly'), + default => config('subscription.stripe_price_id_dynamic_monthly'), }; if (! $priceId) { @@ -46,7 +29,11 @@ class PricingPlans extends Component 'client_reference_id' => auth()->user()->id.':'.currentTeam()->id, 'line_items' => [[ 'price' => $priceId, - 'quantity' => 1, + 'adjustable_quantity' => [ + 'enabled' => true, + 'minimum' => 2, + ], + 'quantity' => 2, ]], 'tax_id_collection' => [ 'enabled' => true, @@ -54,39 +41,18 @@ class PricingPlans extends Component 'automatic_tax' => [ 'enabled' => true, ], - + 'subscription_data' => [ + 'metadata' => [ + 'user_id' => auth()->user()->id, + 'team_id' => currentTeam()->id, + ], + ], + 'payment_method_collection' => 'if_required', 'mode' => 'subscription', 'success_url' => route('dashboard', ['success' => true]), 'cancel_url' => route('subscription.index', ['cancelled' => true]), ]; - if (str($type)->contains('ultimate')) { - $payload['line_items'][0]['adjustable_quantity'] = [ - 'enabled' => true, - 'minimum' => 10, - ]; - $payload['line_items'][0]['quantity'] = 10; - } - if (str($type)->contains('dynamic')) { - $payload['line_items'][0]['adjustable_quantity'] = [ - 'enabled' => true, - 'minimum' => 2, - ]; - $payload['line_items'][0]['quantity'] = 2; - } - if (! data_get($team, 'subscription.stripe_trial_already_ended')) { - if (config('constants.limits.trial_period') > 0) { - $payload['subscription_data'] = [ - 'trial_period_days' => config('constants.limits.trial_period'), - 'trial_settings' => [ - 'end_behavior' => [ - 'missing_payment_method' => 'cancel', - ], - ], - ]; - } - $payload['payment_method_collection'] = 'if_required'; - } $customer = currentTeam()->subscription?->stripe_customer_id ?? null; if ($customer) { $payload['customer'] = $customer; diff --git a/resources/views/livewire/subscription/pricing-plans.blade.php b/resources/views/livewire/subscription/pricing-plans.blade.php index 384a09369..82b491eb1 100644 --- a/resources/views/livewire/subscription/pricing-plans.blade.php +++ b/resources/views/livewire/subscription/pricing-plans.blade.php @@ -14,21 +14,18 @@ :class="selected === 'yearly' ? 'dark:bg-coollabs-100 bg-warning dark:text-white' : ''"> - Annually (save ~20%) + Annually (save ~20%)
Dynamic pricing based on the number of servers you connect. -
+
$5
@@ -43,43 +40,38 @@
$3
- per additional servers billed monthly (+VAT)
+ per additional servers billed monthly (+VAT)
$2.7
- per additional servers billed annually (+VAT)
+ per additional servers billed annually (+VAT)