fix: prevent duplicate subscriptions by validating active status in webhook and cleaning up stale records during creation

This commit is contained in:
pradeepkumar
2026-04-02 17:58:53 +05:30
parent 0a2d46e81b
commit 360969ae2c
2 changed files with 37 additions and 2 deletions

View File

@@ -91,12 +91,19 @@ export class StripeWebhookController {
const stripeCustomerId = session.customer as string; const stripeCustomerId = session.customer as string;
// Check if subscription already exists (idempotency) // Check if subscription already exists (idempotency)
const existing = await this.subscriptionService.getSubscriptionByStripeId(stripeSubscriptionId); const existingByStripeId = await this.subscriptionService.getSubscriptionByStripeId(stripeSubscriptionId);
if (existing) { if (existingByStripeId) {
this.logger.log(`Subscription ${stripeSubscriptionId} already exists, skipping`); this.logger.log(`Subscription ${stripeSubscriptionId} already exists, skipping`);
return; return;
} }
// Check if user already has an active subscription (prevent duplicates)
const existingActive = await this.subscriptionService.getActivePlan(userId);
if (existingActive) {
this.logger.log(`User ${userId} already has active subscription ${existingActive.id}, skipping duplicate`);
return;
}
await this.subscriptionService.createSubscription({ await this.subscriptionService.createSubscription({
userId, userId,
planId, planId,

View File

@@ -80,6 +80,34 @@ export class StripeService {
throw new BadRequestException('You already have an active subscription'); throw new BadRequestException('You already have an active subscription');
} }
// Clean up any incomplete/failed subscriptions to prevent duplicates
// when user retries payment after a previous failure
const staleSubscriptions = await this.prisma.agentSubscription.findMany({
where: {
userId,
status: { in: ['INCOMPLETE', 'UNPAID', 'PAST_DUE'] },
},
});
if (staleSubscriptions.length > 0) {
// Cancel stale Stripe subscriptions before deleting DB records
for (const sub of staleSubscriptions) {
if (!sub.stripeSubscriptionId) continue;
try {
await this.getStripe().subscriptions.cancel(sub.stripeSubscriptionId);
} catch (err: any) {
this.logger.warn(`Could not cancel stale Stripe subscription ${sub.stripeSubscriptionId}: ${err.message}`);
}
}
await this.prisma.agentSubscription.deleteMany({
where: {
userId,
status: { in: ['INCOMPLETE', 'UNPAID', 'PAST_DUE'] },
},
});
this.logger.log(`Cleaned up ${staleSubscriptions.length} stale subscription(s) for user ${userId}`);
}
// Get or create Stripe customer // Get or create Stripe customer
const user = await this.prisma.user.findUnique({ const user = await this.prisma.user.findUnique({
where: { id: userId }, where: { id: userId },