Merge remote-tracking branch 'origin/next' into feat/railpack

This commit is contained in:
Andras Bacsai 2026-05-11 17:03:25 +02:00
commit 0f904d792b
3 changed files with 74 additions and 11 deletions

View file

@ -9,6 +9,7 @@
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Str;
use Stripe\StripeClient;
class StripeProcessJob implements ShouldBeEncrypted, ShouldQueue
{
@ -35,7 +36,7 @@ public function handle(): void
$data = data_get($this->event, 'data.object');
switch ($type) {
case 'radar.early_fraud_warning.created':
$stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key'));
$stripe = new StripeClient(config('subscription.stripe_api_key'));
$id = data_get($data, 'id');
$charge = data_get($data, 'charge');
if ($charge) {
@ -94,12 +95,12 @@ public function handle(): void
}
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
if (! $subscription) {
throw new \RuntimeException("No subscription found for customer: {$customerId}");
break;
}
if ($subscription->stripe_subscription_id) {
try {
$stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key'));
$stripe = new StripeClient(config('subscription.stripe_api_key'));
$stripeSubscription = $stripe->subscriptions->retrieve(
$subscription->stripe_subscription_id
);
@ -154,7 +155,7 @@ public function handle(): void
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
if (! $subscription) {
// send_internal_notification('invoice.payment_failed failed but no subscription found in Coolify for customer: '.$customerId);
throw new \RuntimeException("No subscription found for customer: {$customerId}");
break;
}
$team = data_get($subscription, 'team');
if (! $team) {
@ -165,7 +166,7 @@ public function handle(): void
// Verify payment status with Stripe API before sending failure notification
if ($paymentIntentId) {
try {
$stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key'));
$stripe = new StripeClient(config('subscription.stripe_api_key'));
$paymentIntent = $stripe->paymentIntents->retrieve($paymentIntentId);
if (in_array($paymentIntent->status, ['processing', 'succeeded', 'requires_action', 'requires_confirmation'])) {
@ -190,7 +191,7 @@ public function handle(): void
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
if (! $subscription) {
// send_internal_notification('payment_intent.payment_failed, no subscription found in Coolify for customer: '.$customerId);
throw new \RuntimeException("No subscription found in Coolify for customer: {$customerId}");
break;
}
if ($subscription->stripe_invoice_paid) {
// send_internal_notification('payment_intent.payment_failed but invoice is active for customer: '.$customerId);
@ -334,7 +335,7 @@ public function handle(): void
}
} else {
// send_internal_notification('Subscription deleted but no subscription found in Coolify for customer: '.$customerId);
throw new \RuntimeException("No subscription found in Coolify for customer: {$customerId}");
break;
}
break;
default:

View file

@ -47,14 +47,10 @@ public function submit()
try {
$this->rateLimit(10);
$this->validate();
$firstLogin = auth()->user()->created_at == auth()->user()->updated_at;
auth()->user()->fill([
'password' => Hash::make($this->password),
'force_password_reset' => false,
])->save();
if ($firstLogin) {
send_internal_notification('First login for '.auth()->user()->email);
}
return redirect()->route('dashboard');
} catch (\Throwable $e) {

View file

@ -2,10 +2,14 @@
use App\Jobs\ServerLimitCheckJob;
use App\Jobs\StripeProcessJob;
use App\Jobs\SubscriptionInvoiceFailedJob;
use App\Jobs\VerifyStripeSubscriptionStatusJob;
use App\Models\Subscription;
use App\Models\Team;
use App\Models\User;
use App\Notifications\Internal\GeneralNotification;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Queue;
uses(RefreshDatabase::class);
@ -228,3 +232,65 @@
Queue::assertNotPushed(ServerLimitCheckJob::class);
});
});
describe('missing subscription Stripe webhooks are ignored', function () {
test('does not send internal notifications or queue follow-up jobs', function (array $event) {
Queue::fake();
$rootTeam = Team::factory()->create(['id' => 0]);
$rootTeam->discordNotificationSettings()->update(['discord_enabled' => true]);
Notification::fake();
$job = new StripeProcessJob($event);
$job->handle();
Notification::assertNothingSent();
Notification::assertNotSentTo($rootTeam, GeneralNotification::class);
Queue::assertNotPushed(SubscriptionInvoiceFailedJob::class);
Queue::assertNotPushed(VerifyStripeSubscriptionStatusJob::class);
})->with([
'invoice paid' => [[
'type' => 'invoice.paid',
'data' => [
'object' => [
'customer' => 'cus_missing_invoice_paid',
'amount_paid' => 1000,
'subscription' => 'sub_missing_invoice_paid',
'lines' => [
'data' => [[
'plan' => ['id' => 'price_dynamic_monthly'],
]],
],
],
],
]],
'invoice payment failed' => [[
'type' => 'invoice.payment_failed',
'data' => [
'object' => [
'customer' => 'cus_missing_invoice_payment_failed',
'id' => 'in_missing_invoice_payment_failed',
'payment_intent' => null,
],
],
]],
'payment intent payment failed' => [[
'type' => 'payment_intent.payment_failed',
'data' => [
'object' => [
'customer' => 'cus_missing_payment_intent_failed',
],
],
]],
'customer subscription deleted' => [[
'type' => 'customer.subscription.deleted',
'data' => [
'object' => [
'customer' => 'cus_missing_subscription_deleted',
'id' => 'sub_missing_subscription_deleted',
],
],
]],
]);
});