fix: subscriptions
This commit is contained in:
parent
5b6667c461
commit
923af88336
@ -12,7 +12,7 @@ class ServerController extends Controller
|
||||
|
||||
public function new_server()
|
||||
{
|
||||
if (!is_cloud() || isInstanceAdmin()) {
|
||||
if (!is_cloud()) {
|
||||
return view('server.create', [
|
||||
'limit_reached' => false,
|
||||
'private_keys' => PrivateKey::ownedByCurrentTeam()->get(),
|
||||
|
@ -48,8 +48,8 @@ public function subscribeStripe($type)
|
||||
'enabled' => true,
|
||||
],
|
||||
'mode' => 'subscription',
|
||||
'success_url' => route('subscription.success'),
|
||||
'cancel_url' => route('subscription.index',['cancelled' => true]),
|
||||
'success_url' => route('dashboard', ['success' => true]),
|
||||
'cancel_url' => route('subscription.index', ['cancelled' => true]),
|
||||
];
|
||||
$customer = currentTeam()->subscription?->stripe_customer_id ?? null;
|
||||
if ($customer) {
|
||||
|
@ -37,7 +37,7 @@ public function handle(): void
|
||||
|
||||
private function cleanup_waitlist()
|
||||
{
|
||||
$waitlist = Waitlist::whereVerified(false)->where('created_at', '<', now()->subMinutes(config('constants.waitlist.confirmation_valid_for_minutes')))->get();
|
||||
$waitlist = Waitlist::whereVerified(false)->where('created_at', '<', now()->subMinutes(config('constants.waitlist.expiration')))->get();
|
||||
foreach ($waitlist as $item) {
|
||||
$item->delete();
|
||||
}
|
||||
|
@ -9,7 +9,6 @@
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Stripe\Stripe;
|
||||
|
||||
class SubscriptionInvoiceFailedJob implements ShouldQueue
|
||||
{
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Subscription extends Model
|
||||
{
|
||||
@ -14,19 +15,44 @@ public function team()
|
||||
}
|
||||
public function type()
|
||||
{
|
||||
$basic = explode(',', config('subscription.lemon_squeezy_basic_plan_ids'));
|
||||
$pro = explode(',', config('subscription.lemon_squeezy_pro_plan_ids'));
|
||||
$ultimate = explode(',', config('subscription.lemon_squeezy_ultimate_plan_ids'));
|
||||
if (isLemon()) {
|
||||
$basic = explode(',', config('subscription.lemon_squeezy_basic_plan_ids'));
|
||||
$pro = explode(',', config('subscription.lemon_squeezy_pro_plan_ids'));
|
||||
$ultimate = explode(',', config('subscription.lemon_squeezy_ultimate_plan_ids'));
|
||||
|
||||
$subscription = $this->lemon_variant_id;
|
||||
if (in_array($subscription, $basic)) {
|
||||
return 'basic';
|
||||
$subscription = $this->lemon_variant_id;
|
||||
if (in_array($subscription, $basic)) {
|
||||
return 'basic';
|
||||
}
|
||||
if (in_array($subscription, $pro)) {
|
||||
return 'pro';
|
||||
}
|
||||
if (in_array($subscription, $ultimate)) {
|
||||
return 'ultimate';
|
||||
}
|
||||
}
|
||||
if (in_array($subscription, $pro)) {
|
||||
return 'pro';
|
||||
}
|
||||
if (in_array($subscription, $ultimate)) {
|
||||
return 'ultimate';
|
||||
if (isStripe()) {
|
||||
if (!$this->stripe_plan_id) {
|
||||
return 'unknown';
|
||||
}
|
||||
$subscription = Subscription::where('id', $this->id)->first();
|
||||
if (!$subscription) {
|
||||
return null;
|
||||
}
|
||||
$subscriptionPlanId = data_get($subscription,'stripe_plan_id');
|
||||
if (!$subscriptionPlanId) {
|
||||
return null;
|
||||
}
|
||||
$subscriptionConfigs = collect(config('subscription'));
|
||||
$stripePlanId = null;
|
||||
$subscriptionConfigs->map(function ($value, $key) use ($subscriptionPlanId, &$stripePlanId) {
|
||||
if ($value === $subscriptionPlanId){
|
||||
$stripePlanId = $key;
|
||||
};
|
||||
})->first();
|
||||
if ($stripePlanId) {
|
||||
return Str::of($stripePlanId)->after('stripe_price_id_')->before('_')->lower();
|
||||
}
|
||||
}
|
||||
return 'unknown';
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ protected static function boot()
|
||||
$team = [
|
||||
'name' => $user->name . "'s Team",
|
||||
'personal_team' => true,
|
||||
'boarding' => true
|
||||
'show_boarding' => true
|
||||
];
|
||||
if ($user->id === 0) {
|
||||
$team['id'] = 0;
|
||||
@ -94,7 +94,7 @@ public function isInstanceAdmin()
|
||||
|
||||
public function currentTeam()
|
||||
{
|
||||
return session('currentTeam');
|
||||
return Team::find(session('currentTeam')->id);
|
||||
}
|
||||
|
||||
public function otherTeams()
|
||||
|
@ -56,16 +56,16 @@ function isSubscriptionActive()
|
||||
if (!$subscription) {
|
||||
return false;
|
||||
}
|
||||
if (config('subscription.provider') === 'lemon') {
|
||||
if (isLemon()) {
|
||||
return $subscription->lemon_status === 'active';
|
||||
}
|
||||
if (config('subscription.provider') === 'stripe') {
|
||||
// if (isPaddle()) {
|
||||
// return $subscription->paddle_status === 'active';
|
||||
// }
|
||||
if (isStripe()) {
|
||||
return $subscription->stripe_invoice_paid === true && $subscription->stripe_cancel_at_period_end === false;
|
||||
}
|
||||
return false;
|
||||
// if (config('subscription.provider') === 'paddle') {
|
||||
// return $subscription->paddle_status === 'active';
|
||||
// }
|
||||
|
||||
}
|
||||
function isSubscriptionOnGracePeriod()
|
||||
@ -78,12 +78,12 @@ function isSubscriptionOnGracePeriod()
|
||||
if (!$subscription) {
|
||||
return false;
|
||||
}
|
||||
if (config('subscription.provider') === 'lemon') {
|
||||
if (isLemon()) {
|
||||
$is_still_grace_period = $subscription->lemon_ends_at &&
|
||||
Carbon::parse($subscription->lemon_ends_at) > Carbon::now();
|
||||
return $is_still_grace_period;
|
||||
}
|
||||
if (config('subscription.provider') === 'stripe') {
|
||||
if (isStripe()) {
|
||||
return $subscription->stripe_cancel_at_period_end;
|
||||
}
|
||||
return false;
|
||||
@ -92,6 +92,15 @@ function subscriptionProvider()
|
||||
{
|
||||
return config('subscription.provider');
|
||||
}
|
||||
function isLemon () {
|
||||
return config('subscription.provider') === 'lemon';
|
||||
}
|
||||
function isStripe() {
|
||||
return config('subscription.provider') === 'stripe';
|
||||
}
|
||||
function isPaddle() {
|
||||
return config('subscription.provider') === 'paddle';
|
||||
}
|
||||
function getStripeCustomerPortalSession(Team $team)
|
||||
{
|
||||
Stripe::setApiKey(config('subscription.stripe_api_key'));
|
||||
@ -124,5 +133,6 @@ function allowedPathsForBoardingAccounts()
|
||||
...allowedPathsForUnsubscribedAccounts(),
|
||||
'boarding',
|
||||
'livewire/message/boarding',
|
||||
'livewire/message/boarding.index',
|
||||
];
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
return [
|
||||
'waitlist' => [
|
||||
'confirmation_valid_for_minutes' => 10,
|
||||
'expiration' => 10,
|
||||
],
|
||||
'invitation' => [
|
||||
'link' => [
|
||||
@ -15,5 +15,10 @@
|
||||
'pro' => 10,
|
||||
'ultimate' => 25,
|
||||
],
|
||||
'smtp' => [
|
||||
'basic' => false,
|
||||
'pro' => true,
|
||||
'ultimate' => true,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('subscriptions', function (Blueprint $table) {
|
||||
$table->string('stripe_plan_id')->nullable()->after('stripe_cancel_at_period_end');
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('subscriptions', function (Blueprint $table) {
|
||||
$table->dropColumn('stripe_plan_id');
|
||||
});
|
||||
}
|
||||
};
|
@ -12,7 +12,9 @@
|
||||
@if ($attributes->get('type') === 'submit')
|
||||
<span wire:target="submit" wire:loading.delay class="loading loading-xs text-warning loading-spinner"></span>
|
||||
@else
|
||||
<span wire:target="{{ explode('(', $attributes->whereStartsWith('wire:click')->first())[0] }}" wire:loading.delay
|
||||
class="loading loading-xs loading-spinner"></span>
|
||||
@if ($attributes->has('wire:click'))
|
||||
<span wire:target="{{ $attributes->get('wire:click') }}" wire:loading.delay
|
||||
class="loading loading-xs loading-spinner"></span>
|
||||
@endif
|
||||
@endif
|
||||
</button>
|
||||
|
@ -4,20 +4,10 @@
|
||||
<ol class="inline-flex items-center">
|
||||
<li>
|
||||
<div class="flex items-center">
|
||||
<span>Currently active team: {{ session('currentTeam.name') }}</span>
|
||||
<span>Currently active team: <span
|
||||
class="text-warning">{{ session('currentTeam.name') }}</span></span>
|
||||
</div>
|
||||
</li>
|
||||
@if (session('currentTeam.description'))
|
||||
<li class="inline-flex items-center">
|
||||
<svg aria-hidden="true" class="w-4 h-4 mx-1 font-bold text-warning" fill="currentColor"
|
||||
viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd"
|
||||
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<span class="truncate">{{ Str::limit(session('currentTeam.description'), 52) }}</span>
|
||||
</li>
|
||||
@endif
|
||||
</ol>
|
||||
</nav>
|
||||
<nav class="navbar-main">
|
||||
|
@ -1,4 +1,4 @@
|
||||
Someone added this email to the Coolify Cloud's waitlist.
|
||||
<br>
|
||||
<a href="{{ $confirmation_url }}">Click here to confirm</a>! The link will expire in {{config('constants.waitlist.confirmation_valid_for_minutes')}} minutes.<br><br>
|
||||
<a href="{{ $confirmation_url }}">Click here to confirm</a>! The link will expire in {{config('constants.waitlist.expiration')}} minutes.<br><br>
|
||||
You have no idea what <a href="https://coolify.io">Coolify Cloud</a> is or this waitlist? <a href="{{ $cancel_url }}">Click here to remove</a> you from the waitlist.
|
||||
|
@ -1,9 +1,19 @@
|
||||
<div>
|
||||
@if (session('error'))
|
||||
<span x-data x-init="$wire.emit('error', '{{ session('error') }}')"/>
|
||||
<span x-data x-init="$wire.emit('error', '{{ session('error') }}')" />
|
||||
@endif
|
||||
<h1>Dashboard</h1>
|
||||
<div class="subtitle">Something <x-highlighted text="(more)" /> useful will be here.</div>
|
||||
@if (request()->query->get('success'))
|
||||
<div class="rounded alert alert-success">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 stroke-current shrink-0" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<span>Your subscription has been activated! Welcome onboard!</span>
|
||||
</div>
|
||||
@endif
|
||||
<div class="w-full rounded stats stats-vertical lg:stats-horizontal">
|
||||
<div class="stat">
|
||||
<div class="stat-title">Servers</div>
|
||||
@ -25,4 +35,5 @@
|
||||
<div class="stat-value">{{ $s3s }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -1,17 +1,23 @@
|
||||
<div>
|
||||
@if (subscriptionProvider() === 'stripe')
|
||||
@if (currentTeam()->subscription->stripe_cancel_at_period_end)
|
||||
<div>Subscription is active but on cancel period.</div>
|
||||
@else
|
||||
<div>Subscription is active. Last invoice is
|
||||
{{ currentTeam()->subscription->stripe_invoice_paid ? 'paid' : 'not paid' }}.</div>
|
||||
@endif
|
||||
|
||||
@if (currentTeam()->subscription->stripe_cancel_at_period_end)
|
||||
<a class="hover:no-underline" href="{{ route('subscription.index') }}"><x-forms.button>Subscribe
|
||||
again</x-forms.button></a>
|
||||
@endif
|
||||
<x-forms.button wire:click='stripeCustomerPortal'>Manage My Subscription</x-forms.button>
|
||||
<div class="pt-4">
|
||||
<div>Current Plan: <span class="text-warning">{{ data_get(currentTeam(), 'subscription')->type() }}<span>
|
||||
</div>
|
||||
@if (currentTeam()->subscription->stripe_cancel_at_period_end)
|
||||
<div>Subscription is active but on cancel period.</div>
|
||||
@else
|
||||
<div>Subscription is active. Last invoice is
|
||||
{{ currentTeam()->subscription->stripe_invoice_paid ? 'paid' : 'not paid' }}.</div>
|
||||
@endif
|
||||
|
||||
@if (currentTeam()->subscription->stripe_cancel_at_period_end)
|
||||
<a class="hover:no-underline" href="{{ route('subscription.index') }}"><x-forms.button>Subscribe
|
||||
again</x-forms.button></a>
|
||||
@endif
|
||||
<div>To update your subscription (upgrade / downgrade), please <a class="text-white underline"
|
||||
href="https://docs.coollabs.io/contact" target="_blank">contact us.</a></div>
|
||||
</div>
|
||||
@endif
|
||||
@if (subscriptionProvider() === 'lemon')
|
||||
<div>Status: {{ currentTeam()->subscription->lemon_status }}</div>
|
||||
|
@ -13,7 +13,7 @@
|
||||
<div>You can't delete your last team.</div>
|
||||
@elseif(currentTeam()->subscription &&
|
||||
currentTeam()->subscription?->lemon_status !== 'cancelled')
|
||||
<div>Please cancel your subscription before delete this team (Manage My Subscription button).</div>
|
||||
<div>Please cancel your subscription before delete this team (Manage My Subscription).</div>
|
||||
@else
|
||||
@if (currentTeam()->isEmpty())
|
||||
<div class="pb-4">This will delete your team. Beware! There is no coming back!</div>
|
||||
|
@ -1,3 +0,0 @@
|
||||
<x-layout-subscription>
|
||||
Cancel
|
||||
</x-layout-subscription>
|
@ -10,12 +10,16 @@
|
||||
<span>Currently active team: <span
|
||||
class="text-warning">{{ session('currentTeam.name') }}</span></span>
|
||||
</div>
|
||||
@if(request()->query->get('cancelled'))
|
||||
<div class="rounded alert alert-error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 stroke-current shrink-0" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
||||
<span>Something went wrong with your subscription. Please try again or contact support.</span>
|
||||
</div>
|
||||
@endif
|
||||
@if (request()->query->get('cancelled'))
|
||||
<div class="mb-6 rounded alert alert-error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 stroke-current shrink-0" fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<span>Something went wrong with your subscription. Please try again or contact support.</span>
|
||||
</div>
|
||||
@endif
|
||||
@if (config('subscription.provider') !== null)
|
||||
<livewire:subscription.pricing-plans />
|
||||
@endif
|
||||
|
@ -1,3 +0,0 @@
|
||||
<x-layout>
|
||||
Success
|
||||
</x-layout>
|
@ -99,8 +99,6 @@
|
||||
Route::get('/force-password-reset', [Controller::class, 'force_passoword_reset'])->name('auth.force-password-reset');
|
||||
});
|
||||
Route::get('/subscription', [Controller::class, 'subscription'])->name('subscription.index');
|
||||
Route::get('/subscription/success', fn () => view('subscription.success'))->name('subscription.success');
|
||||
Route::get('/subscription/cancel', fn () => view('profile'))->name('subscription.cancel');
|
||||
Route::get('/settings', [Controller::class, 'settings'])->name('settings.configuration');
|
||||
Route::get('/settings/license', [Controller::class, 'license'])->name('settings.license');
|
||||
Route::get('/profile', fn () => view('profile', ['request' => request()]))->name('profile');
|
||||
|
@ -181,7 +181,7 @@
|
||||
ray($email, $confirmation_code);
|
||||
try {
|
||||
$found = Waitlist::where('uuid', $confirmation_code)->where('email', $email)->first();
|
||||
if ($found && !$found->verified && $found->created_at > now()->subMinutes(config('constants.waitlist.confirmation_valid_for_minutes'))) {
|
||||
if ($found && !$found->verified && $found->created_at > now()->subMinutes(config('constants.waitlist.expiration'))) {
|
||||
$found->verified = true;
|
||||
$found->save();
|
||||
send_internal_notification('Waitlist confirmed: ' . $email);
|
||||
@ -267,9 +267,11 @@
|
||||
break;
|
||||
case 'customer.subscription.updated':
|
||||
$subscriptionId = data_get($data, 'items.data.0.subscription');
|
||||
$planId = data_get($data, 'items.data.0.plan.id');
|
||||
$cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end');
|
||||
$subscription = Subscription::where('stripe_subscription_id', $subscriptionId)->firstOrFail();
|
||||
$subscription->update([
|
||||
'stripe_plan_id' => $planId,
|
||||
'stripe_cancel_at_period_end' => $cancelAtPeriodEnd,
|
||||
]);
|
||||
break;
|
||||
@ -277,6 +279,8 @@
|
||||
$subscriptionId = data_get($data, 'items.data.0.subscription');
|
||||
$subscription = Subscription::where('stripe_subscription_id', $subscriptionId)->firstOrFail();
|
||||
$subscription->update([
|
||||
'stripe_subscription_id' => null,
|
||||
'stripe_plan_id'=> null,
|
||||
'stripe_cancel_at_period_end' => false,
|
||||
'stripe_invoice_paid' => false,
|
||||
]);
|
||||
|
Loading…
Reference in New Issue
Block a user