fix: cloud + stripe related
This commit is contained in:
49
app/Console/Commands/CloudCheckSubscription.php
Normal file
49
app/Console/Commands/CloudCheckSubscription.php
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Team;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class CloudCheckSubscription extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'cloud:check-subscription';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Check Cloud subscriptions';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key'));
|
||||||
|
$activeSubscribers = Team::whereRelation('subscription', 'stripe_invoice_paid', true)->get();
|
||||||
|
foreach ($activeSubscribers as $team) {
|
||||||
|
$stripeSubscriptionId = $team->subscription->stripe_subscription_id;
|
||||||
|
$stripeInvoicePaid = $team->subscription->stripe_invoice_paid;
|
||||||
|
$stripeCustomerId = $team->subscription->stripe_customer_id;
|
||||||
|
if (! $stripeSubscriptionId) {
|
||||||
|
echo "Team {$team->id} has no subscription, but invoice status is: {$stripeInvoicePaid}\n";
|
||||||
|
echo "Link on Stripe: https://dashboard.stripe.com/customers/{$stripeCustomerId}\n";
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$subscription = $stripe->subscriptions->retrieve($stripeSubscriptionId);
|
||||||
|
if ($subscription->status === 'active') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
echo "Subscription {$stripeSubscriptionId} is not active ({$subscription->status})\n";
|
||||||
|
echo "Link on Stripe: https://dashboard.stripe.com/subscriptions/{$stripeSubscriptionId}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -5,8 +5,6 @@ namespace App\Http\Controllers\Webhook;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Jobs\ServerLimitCheckJob;
|
use App\Jobs\ServerLimitCheckJob;
|
||||||
use App\Jobs\SubscriptionInvoiceFailedJob;
|
use App\Jobs\SubscriptionInvoiceFailedJob;
|
||||||
use App\Jobs\SubscriptionTrialEndedJob;
|
|
||||||
use App\Jobs\SubscriptionTrialEndsSoonJob;
|
|
||||||
use App\Models\Subscription;
|
use App\Models\Subscription;
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
use App\Models\Webhook;
|
use App\Models\Webhook;
|
||||||
@@ -260,42 +258,7 @@ class Stripe extends Controller
|
|||||||
$customerId = data_get($data, 'customer');
|
$customerId = data_get($data, 'customer');
|
||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
||||||
$team = data_get($subscription, 'team');
|
$team = data_get($subscription, 'team');
|
||||||
if ($team) {
|
$team?->subscriptionEnded();
|
||||||
$team->trialEnded();
|
|
||||||
}
|
|
||||||
$subscription->update([
|
|
||||||
'stripe_subscription_id' => null,
|
|
||||||
'stripe_plan_id' => null,
|
|
||||||
'stripe_cancel_at_period_end' => false,
|
|
||||||
'stripe_invoice_paid' => false,
|
|
||||||
'stripe_trial_already_ended' => false,
|
|
||||||
]);
|
|
||||||
// send_internal_notification('customer.subscription.deleted for customer: '.$customerId);
|
|
||||||
break;
|
|
||||||
case 'customer.subscription.trial_will_end':
|
|
||||||
// Not used for now
|
|
||||||
$customerId = data_get($data, 'customer');
|
|
||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
|
||||||
$team = data_get($subscription, 'team');
|
|
||||||
if (! $team) {
|
|
||||||
return response('No team found for subscription: '.$subscription->id, 400);
|
|
||||||
}
|
|
||||||
SubscriptionTrialEndsSoonJob::dispatch($team);
|
|
||||||
break;
|
|
||||||
case 'customer.subscription.paused':
|
|
||||||
$customerId = data_get($data, 'customer');
|
|
||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
|
||||||
$team = data_get($subscription, 'team');
|
|
||||||
if (! $team) {
|
|
||||||
return response('No team found for subscription: '.$subscription->id, 400);
|
|
||||||
}
|
|
||||||
$team->trialEnded();
|
|
||||||
$subscription->update([
|
|
||||||
'stripe_trial_already_ended' => true,
|
|
||||||
'stripe_invoice_paid' => false,
|
|
||||||
]);
|
|
||||||
SubscriptionTrialEndedJob::dispatch($team);
|
|
||||||
// send_internal_notification('Subscription paused for customer: '.$customerId);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Unhandled event type
|
// Unhandled event type
|
||||||
|
@@ -1,42 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Jobs;
|
|
||||||
|
|
||||||
use App\Models\Team;
|
|
||||||
use Illuminate\Bus\Queueable;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
|
||||||
|
|
||||||
class SubscriptionTrialEndedJob implements ShouldBeEncrypted, ShouldQueue
|
|
||||||
{
|
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
public Team $team
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public function handle(): void
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$session = getStripeCustomerPortalSession($this->team);
|
|
||||||
$mail = new MailMessage;
|
|
||||||
$mail->subject('Action required: You trial in Coolify Cloud ended.');
|
|
||||||
$mail->view('emails.trial-ended', [
|
|
||||||
'stripeCustomerPortal' => $session->url,
|
|
||||||
]);
|
|
||||||
$this->team->members()->each(function ($member) use ($mail) {
|
|
||||||
if ($member->isAdmin()) {
|
|
||||||
send_user_an_email($mail, $member->email);
|
|
||||||
send_internal_notification('Trial reminder email sent to '.$member->email);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
send_internal_notification('SubscriptionTrialEndsSoonJob failed with: '.$e->getMessage());
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,42 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Jobs;
|
|
||||||
|
|
||||||
use App\Models\Team;
|
|
||||||
use Illuminate\Bus\Queueable;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
|
||||||
|
|
||||||
class SubscriptionTrialEndsSoonJob implements ShouldBeEncrypted, ShouldQueue
|
|
||||||
{
|
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
public Team $team
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public function handle(): void
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$session = getStripeCustomerPortalSession($this->team);
|
|
||||||
$mail = new MailMessage;
|
|
||||||
$mail->subject('You trial in Coolify Cloud ends soon.');
|
|
||||||
$mail->view('emails.trial-ends-soon', [
|
|
||||||
'stripeCustomerPortal' => $session->url,
|
|
||||||
]);
|
|
||||||
$this->team->members()->each(function ($member) use ($mail) {
|
|
||||||
if ($member->isAdmin()) {
|
|
||||||
send_user_an_email($mail, $member->email);
|
|
||||||
send_internal_notification('Trial reminder email sent to '.$member->email);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
send_internal_notification('SubscriptionTrialEndsSoonJob failed with: '.$e->getMessage());
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Admin;
|
namespace App\Livewire\Admin;
|
||||||
|
|
||||||
|
use App\Models\Team;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Container\Attributes\Auth as AttributesAuth;
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
@@ -43,17 +43,13 @@ class Index extends Component
|
|||||||
|
|
||||||
public function getSubscribers()
|
public function getSubscribers()
|
||||||
{
|
{
|
||||||
$this->inactiveSubscribers = User::whereDoesntHave('teams', function ($query) {
|
$this->inactiveSubscribers = Team::whereRelation('subscription', 'stripe_invoice_paid', false)->count();
|
||||||
$query->whereRelation('subscription', 'stripe_subscription_id', '!=', null);
|
$this->activeSubscribers = Team::whereRelation('subscription', 'stripe_invoice_paid', true)->count();
|
||||||
})->count();
|
|
||||||
$this->activeSubscribers = User::whereHas('teams', function ($query) {
|
|
||||||
$query->whereRelation('subscription', 'stripe_subscription_id', '!=', null);
|
|
||||||
})->count();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function switchUser(int $user_id)
|
public function switchUser(int $user_id)
|
||||||
{
|
{
|
||||||
if (AttributesAuth::id() !== 0) {
|
if (Auth::id() !== 0) {
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
}
|
}
|
||||||
$user = User::find($user_id);
|
$user = User::find($user_id);
|
||||||
|
@@ -257,8 +257,15 @@ class Team extends Model implements SendsDiscord, SendsEmail
|
|||||||
return $this->hasMany(S3Storage::class)->where('is_usable', true);
|
return $this->hasMany(S3Storage::class)->where('is_usable', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function trialEnded()
|
public function subscriptionEnded()
|
||||||
{
|
{
|
||||||
|
$this->subscription->update([
|
||||||
|
'stripe_subscription_id' => null,
|
||||||
|
'stripe_plan_id' => null,
|
||||||
|
'stripe_cancel_at_period_end' => false,
|
||||||
|
'stripe_invoice_paid' => false,
|
||||||
|
'stripe_trial_already_ended' => false,
|
||||||
|
]);
|
||||||
foreach ($this->servers as $server) {
|
foreach ($this->servers as $server) {
|
||||||
$server->settings()->update([
|
$server->settings()->update([
|
||||||
'is_usable' => false,
|
'is_usable' => false,
|
||||||
@@ -267,16 +274,6 @@ class Team extends Model implements SendsDiscord, SendsEmail
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function trialEndedButSubscribed()
|
|
||||||
{
|
|
||||||
foreach ($this->servers as $server) {
|
|
||||||
$server->settings()->update([
|
|
||||||
'is_usable' => true,
|
|
||||||
'is_reachable' => true,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isAnyNotificationEnabled()
|
public function isAnyNotificationEnabled()
|
||||||
{
|
{
|
||||||
if (isCloud()) {
|
if (isCloud()) {
|
||||||
|
Reference in New Issue
Block a user