diff --git a/src/stripe/stripe.controller.ts b/src/stripe/stripe.controller.ts index 248f2b1..fd8a2f4 100644 --- a/src/stripe/stripe.controller.ts +++ b/src/stripe/stripe.controller.ts @@ -42,14 +42,19 @@ export class StripeController { @Post('create-checkout-session') @ApiBearerAuth() - @ApiOperation({ summary: 'Create a Stripe Checkout session for subscription' }) + @ApiOperation({ + summary: 'Create a Stripe Checkout session for subscription', + }) @HttpCode(HttpStatus.OK) async createCheckoutSession( @CurrentUser() user: any, @Body() dto: CreateCheckoutDto, ) { - const frontendUrl = this.configService.get('app.frontendUrl') || 'http://localhost:3000'; - const successUrl = dto.successUrl || `${frontendUrl}/agent/settings/billings/confirmation`; + const frontendUrl = + this.configService.get('app.frontendUrl') || + 'http://localhost:3000'; + const successUrl = + dto.successUrl || `${frontendUrl}/agent/settings/billings/confirmation`; const cancelUrl = dto.cancelUrl || `${frontendUrl}/agent/settings/billings`; return this.stripeService.createCheckoutSession( @@ -73,7 +78,9 @@ export class StripeController { throw new BadRequestException('No active subscription found'); } - const returnUrl = dto.returnUrl || `${this.configService.get('app.frontendUrl') || 'http://localhost:3000'}/agent/settings/billings`; + const returnUrl = + dto.returnUrl || + `${this.configService.get('app.frontendUrl') || 'http://localhost:3000'}/agent/settings/billings`; return this.stripeService.createBillingPortalSession( subscription.stripeCustomerId, returnUrl, @@ -85,7 +92,35 @@ export class StripeController { @ApiOperation({ summary: 'Get current user subscription status' }) async getSubscription(@CurrentUser() user: any) { const subscription = await this.subscriptionService.getActivePlan(user.id); - return subscription || null; + if (!subscription) return null; + + // Sync from Stripe if key fields are missing + if ( + subscription.stripeSubscriptionId && + (!subscription.currentPeriodEnd || + subscription.cancelAtPeriodEnd === null) + ) { + try { + const stripeSub = await this.stripeService.getSubscription( + subscription.stripeSubscriptionId, + ); + const updated = await this.subscriptionService.updateSubscriptionStatus( + subscription.stripeSubscriptionId, + subscription.status, + { + currentPeriodEnd: new Date( + stripeSub.items.data[0].current_period_end * 1000, + ), + cancelAtPeriodEnd: stripeSub.cancel_at_period_end, + }, + ); + return updated; + } catch { + // Fall through to return existing data + } + } + + return subscription; } @Post('cancel-subscription') @@ -98,12 +133,20 @@ export class StripeController { throw new BadRequestException('No active subscription found'); } - await this.stripeService.cancelSubscription(subscription.stripeSubscriptionId, true); + const stripeSubscription = await this.stripeService.cancelSubscription( + subscription.stripeSubscriptionId, + true, + ); return this.subscriptionService.updateSubscriptionStatus( subscription.stripeSubscriptionId, 'ACTIVE', - { cancelAtPeriodEnd: true }, + { + cancelAtPeriodEnd: true, + currentPeriodEnd: new Date( + stripeSubscription.items.data[0].current_period_end * 1000, + ), + }, ); } diff --git a/src/stripe/stripe.service.ts b/src/stripe/stripe.service.ts index 2daef3c..78de312 100644 --- a/src/stripe/stripe.service.ts +++ b/src/stripe/stripe.service.ts @@ -18,13 +18,17 @@ export class StripeService { apiVersion: '2025-02-24.acacia' as any, }); } else { - this.logger.warn('Stripe secret key not configured. Stripe features will be unavailable.'); + this.logger.warn( + 'Stripe secret key not configured. Stripe features will be unavailable.', + ); } } private getStripe(): Stripe { if (!this.stripe) { - throw new BadRequestException('Stripe is not configured. Please set STRIPE_SECRET_KEY in environment.'); + throw new BadRequestException( + 'Stripe is not configured. Please set STRIPE_SECRET_KEY in environment.', + ); } return this.stripe; } @@ -90,7 +94,11 @@ export class StripeService { ? `${user.agentProfile.firstName || ''} ${user.agentProfile.lastName || ''}`.trim() : undefined; - const customerId = await this.createCustomer(userId, user.email, customerName); + const customerId = await this.createCustomer( + userId, + user.email, + customerName, + ); const session = await this.getStripe().checkout.sessions.create({ customer: customerId, @@ -144,11 +152,19 @@ export class StripeService { return this.getStripe().subscriptions.cancel(stripeSubscriptionId); } - constructWebhookEvent( - payload: Buffer, - signature: string, - ): Stripe.Event { - const webhookSecret = this.configService.get('stripe.webhookSecret') || ''; - return this.getStripe().webhooks.constructEvent(payload, signature, webhookSecret); + async getSubscription( + stripeSubscriptionId: string, + ): Promise { + return this.getStripe().subscriptions.retrieve(stripeSubscriptionId); + } + + constructWebhookEvent(payload: Buffer, signature: string): Stripe.Event { + const webhookSecret = + this.configService.get('stripe.webhookSecret') || ''; + return this.getStripe().webhooks.constructEvent( + payload, + signature, + webhookSecret, + ); } }