diff --git a/app/Http/Controllers/Webhook/Stripe.php b/app/Http/Controllers/Webhook/Stripe.php index 55c94a618..dce73b2c5 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,6 +163,30 @@ 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'); + $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}", 400); + } else { + Subscription::create([ + 'team_id' => $teamId, + 'stripe_subscription_id' => $subscriptionId, + 'stripe_customer_id' => $customerId, + 'stripe_invoice_paid' => false, + ]); + } + break; case 'customer.subscription.updated': $customerId = data_get($data, 'customer'); $status = data_get($data, 'status'); @@ -177,10 +197,6 @@ 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); @@ -268,7 +284,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 +293,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%)
- {{--
For the detailed list of features, please visit our landing page: coolify.io
--}}

Pay-as-you-go

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)

- + + + +
-
- You need to bring your own servers from any cloud provider (such as Hetzner, DigitalOcean, AWS, etc.) -
-
- (You can connect your RPi, old laptop, or any other device that runs - the supported operating systems.) -
+
+ You need to bring your own servers from any cloud provider (such as Hetzner, DigitalOcean, AWS, + etc.) +
+
+ (You can connect your RPi, old laptop, or any other device that runs + the supported operating systems.) +
-
+
Subscribe @@ -90,120 +82,72 @@ +