From 0d063b2b6b7a3ad14c10443e7827bf6fe868fe14 Mon Sep 17 00:00:00 2001 From: pradeepkumar Date: Fri, 17 Apr 2026 18:58:29 +0530 Subject: [PATCH] feat: add admin endpoints to list all subscription plans and sync plan details from Stripe --- src/stripe/stripe.controller.ts | 16 +++++++++++++ src/stripe/subscription.service.ts | 37 ++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/stripe/stripe.controller.ts b/src/stripe/stripe.controller.ts index b204878..dbcb36b 100644 --- a/src/stripe/stripe.controller.ts +++ b/src/stripe/stripe.controller.ts @@ -191,6 +191,22 @@ export class StripeController { return this.subscriptionService.getRevenueStats(); } + @Get('admin/plans') + @Roles(UserRole.ADMIN) + @ApiBearerAuth() + @ApiOperation({ summary: 'List all subscription plans including inactive (admin)' }) + async getAdminPlans() { + return this.subscriptionService.getAllPlansAdmin(); + } + + @Post('admin/plans/:id/sync') + @Roles(UserRole.ADMIN) + @ApiBearerAuth() + @ApiOperation({ summary: 'Sync a plan from Stripe (refreshes amount/currency/interval/name/description)' }) + async syncPlan(@Param('id') id: string) { + return this.subscriptionService.syncPlanFromStripe(id); + } + @Post('admin/plans') @Roles(UserRole.ADMIN) @ApiBearerAuth() diff --git a/src/stripe/subscription.service.ts b/src/stripe/subscription.service.ts index df52ecd..317a93f 100644 --- a/src/stripe/subscription.service.ts +++ b/src/stripe/subscription.service.ts @@ -97,6 +97,43 @@ export class SubscriptionService { }); } + async getAllPlansAdmin() { + return this.prisma.subscriptionPlan.findMany({ + orderBy: [{ isActive: 'desc' }, { sortOrder: 'asc' }], + }); + } + + async syncPlanFromStripe(planId: string) { + const plan = await this.prisma.subscriptionPlan.findUnique({ where: { id: planId } }); + if (!plan) throw new Error('Plan not found'); + + const stripe = this.stripeService.getStripe(); + const price = await stripe.prices.retrieve(plan.stripePriceId, { expand: ['product'] }); + + const amount = typeof price.unit_amount === 'number' ? price.unit_amount : plan.amount; + const currency = price.currency || plan.currency; + const interval = price.recurring?.interval || plan.interval; + const product = price.product as { name?: string; description?: string | null } | string | null; + + const productName = + typeof product === 'object' && product && product.name ? product.name : plan.name; + const productDescription = + typeof product === 'object' && product && product.description !== undefined + ? product.description + : plan.description; + + return this.prisma.subscriptionPlan.update({ + where: { id: planId }, + data: { + amount, + currency, + interval, + name: productName, + description: productDescription, + }, + }); + } + async getPaymentHistory(userId: string) { return this.prisma.payment.findMany({ where: { userId },