Add Stripe controller routes and full Plans CRUD in backoffice
This commit is contained in:
parent
ee5a680468
commit
03827302e5
4 changed files with 175 additions and 7 deletions
|
|
@ -1,11 +1,30 @@
|
||||||
import { Controller, Get, Param } from '@nestjs/common';
|
import { Controller, Get, Post, Patch, Delete, Param, Body, NotFoundException } from '@nestjs/common';
|
||||||
import { ApiTags, ApiOperation } from '@nestjs/swagger';
|
import { ApiTags, ApiOperation, ApiBody, ApiBearerAuth } from '@nestjs/swagger';
|
||||||
import { PlansService } from './plans.service';
|
import { PlansService, Plan } from './plans.service';
|
||||||
|
|
||||||
|
class CreatePlanDto {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
monthlyPrice: number;
|
||||||
|
yearlyPrice: number;
|
||||||
|
features: string[];
|
||||||
|
popular?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class UpdatePlanDto {
|
||||||
|
name?: string;
|
||||||
|
description?: string;
|
||||||
|
monthlyPrice?: number;
|
||||||
|
yearlyPrice?: number;
|
||||||
|
features?: string[];
|
||||||
|
popular?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
@ApiTags('Plans')
|
@ApiTags('Plans')
|
||||||
@Controller('plans')
|
@Controller('plans')
|
||||||
export class PlansController {
|
export class PlansController {
|
||||||
constructor(private readonly plansService: PlansService) {}
|
constructor(private readonly plansService: PlansService) { }
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@ApiOperation({ summary: 'Get all plans' })
|
@ApiOperation({ summary: 'Get all plans' })
|
||||||
|
|
@ -16,6 +35,42 @@ export class PlansController {
|
||||||
@Get(':id')
|
@Get(':id')
|
||||||
@ApiOperation({ summary: 'Get plan by ID' })
|
@ApiOperation({ summary: 'Get plan by ID' })
|
||||||
getPlanById(@Param('id') id: string) {
|
getPlanById(@Param('id') id: string) {
|
||||||
return this.plansService.getPlanById(id);
|
const plan = this.plansService.getPlanById(id);
|
||||||
|
if (!plan) {
|
||||||
|
throw new NotFoundException(`Plan with ID ${id} not found`);
|
||||||
|
}
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post()
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@ApiOperation({ summary: 'Create a new plan' })
|
||||||
|
@ApiBody({ type: CreatePlanDto })
|
||||||
|
createPlan(@Body() body: CreatePlanDto) {
|
||||||
|
return this.plansService.createPlan(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch(':id')
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@ApiOperation({ summary: 'Update a plan' })
|
||||||
|
@ApiBody({ type: UpdatePlanDto })
|
||||||
|
updatePlan(@Param('id') id: string, @Body() body: UpdatePlanDto) {
|
||||||
|
const plan = this.plansService.updatePlan(id, body);
|
||||||
|
if (!plan) {
|
||||||
|
throw new NotFoundException(`Plan with ID ${id} not found`);
|
||||||
|
}
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(':id')
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@ApiOperation({ summary: 'Delete a plan' })
|
||||||
|
deletePlan(@Param('id') id: string) {
|
||||||
|
const deleted = this.plansService.deletePlan(id);
|
||||||
|
if (!deleted) {
|
||||||
|
throw new NotFoundException(`Plan with ID ${id} not found`);
|
||||||
|
}
|
||||||
|
return { message: `Plan ${id} deleted successfully` };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ export interface Plan {
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PlansService {
|
export class PlansService {
|
||||||
private readonly plans: Plan[] = [
|
private plans: Plan[] = [
|
||||||
{
|
{
|
||||||
id: 'starter',
|
id: 'starter',
|
||||||
name: 'Starter',
|
name: 'Starter',
|
||||||
|
|
@ -53,7 +53,32 @@ export class PlansService {
|
||||||
getAllPlans(): Plan[] {
|
getAllPlans(): Plan[] {
|
||||||
return this.plans;
|
return this.plans;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlanById(id: string): Plan | undefined {
|
getPlanById(id: string): Plan | undefined {
|
||||||
return this.plans.find((p) => p.id === id);
|
return this.plans.find((p) => p.id === id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createPlan(plan: Plan): Plan {
|
||||||
|
this.plans.push(plan);
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePlan(id: string, updates: Partial<Plan>): Plan | undefined {
|
||||||
|
const index = this.plans.findIndex((p) => p.id === id);
|
||||||
|
if (index === -1) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
this.plans[index] = { ...this.plans[index], ...updates };
|
||||||
|
return this.plans[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
deletePlan(id: string): boolean {
|
||||||
|
const index = this.plans.findIndex((p) => p.id === id);
|
||||||
|
if (index === -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.plans.splice(index, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
85
backoffice/src/stripe/stripe.controller.ts
Normal file
85
backoffice/src/stripe/stripe.controller.ts
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
import { Controller, Get, Post, Body, Param } from '@nestjs/common';
|
||||||
|
import { ApiTags, ApiOperation, ApiBody, ApiBearerAuth } from '@nestjs/swagger';
|
||||||
|
import { StripeService } from './stripe.service';
|
||||||
|
|
||||||
|
class CreateCustomerDto {
|
||||||
|
email: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CreateSubscriptionDto {
|
||||||
|
customerId: string;
|
||||||
|
priceId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CreateCheckoutDto {
|
||||||
|
customerId: string;
|
||||||
|
priceId: string;
|
||||||
|
successUrl: string;
|
||||||
|
cancelUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class BillingPortalDto {
|
||||||
|
customerId: string;
|
||||||
|
returnUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CancelSubscriptionDto {
|
||||||
|
subscriptionId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiTags('Stripe')
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Controller('stripe')
|
||||||
|
export class StripeController {
|
||||||
|
constructor(private readonly stripeService: StripeService) { }
|
||||||
|
|
||||||
|
@Post('customers')
|
||||||
|
@ApiOperation({ summary: 'Create a Stripe customer' })
|
||||||
|
@ApiBody({ type: CreateCustomerDto })
|
||||||
|
async createCustomer(@Body() body: CreateCustomerDto) {
|
||||||
|
return this.stripeService.createCustomer(body.email, body.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('subscriptions')
|
||||||
|
@ApiOperation({ summary: 'Create a subscription' })
|
||||||
|
@ApiBody({ type: CreateSubscriptionDto })
|
||||||
|
async createSubscription(@Body() body: CreateSubscriptionDto) {
|
||||||
|
return this.stripeService.createSubscription(body.customerId, body.priceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('subscriptions/:customerId')
|
||||||
|
@ApiOperation({ summary: 'List subscriptions for a customer' })
|
||||||
|
async listSubscriptions(@Param('customerId') customerId: string) {
|
||||||
|
return this.stripeService.listSubscriptions(customerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('subscriptions/cancel')
|
||||||
|
@ApiOperation({ summary: 'Cancel a subscription' })
|
||||||
|
@ApiBody({ type: CancelSubscriptionDto })
|
||||||
|
async cancelSubscription(@Body() body: CancelSubscriptionDto) {
|
||||||
|
return this.stripeService.cancelSubscription(body.subscriptionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('checkout')
|
||||||
|
@ApiOperation({ summary: 'Create a checkout session' })
|
||||||
|
@ApiBody({ type: CreateCheckoutDto })
|
||||||
|
async createCheckoutSession(@Body() body: CreateCheckoutDto) {
|
||||||
|
return this.stripeService.createCheckoutSession(
|
||||||
|
body.customerId,
|
||||||
|
body.priceId,
|
||||||
|
body.successUrl,
|
||||||
|
body.cancelUrl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('billing-portal')
|
||||||
|
@ApiOperation({ summary: 'Create a billing portal session' })
|
||||||
|
@ApiBody({ type: BillingPortalDto })
|
||||||
|
async createBillingPortalSession(@Body() body: BillingPortalDto) {
|
||||||
|
return this.stripeService.createBillingPortalSession(
|
||||||
|
body.customerId,
|
||||||
|
body.returnUrl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
import { Module, Global } from '@nestjs/common';
|
import { Module, Global } from '@nestjs/common';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { StripeService } from './stripe.service';
|
import { StripeService } from './stripe.service';
|
||||||
|
import { StripeController } from './stripe.controller';
|
||||||
|
|
||||||
@Global()
|
@Global()
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule],
|
imports: [ConfigModule],
|
||||||
|
controllers: [StripeController],
|
||||||
providers: [StripeService],
|
providers: [StripeService],
|
||||||
exports: [StripeService],
|
exports: [StripeService],
|
||||||
})
|
})
|
||||||
export class StripeModule {}
|
export class StripeModule { }
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue