diff --git a/backoffice/src/plans/plans.controller.ts b/backoffice/src/plans/plans.controller.ts index 2d7eb55..8c70168 100644 --- a/backoffice/src/plans/plans.controller.ts +++ b/backoffice/src/plans/plans.controller.ts @@ -1,11 +1,30 @@ -import { Controller, Get, Param } from '@nestjs/common'; -import { ApiTags, ApiOperation } from '@nestjs/swagger'; -import { PlansService } from './plans.service'; +import { Controller, Get, Post, Patch, Delete, Param, Body, NotFoundException } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiBody, ApiBearerAuth } from '@nestjs/swagger'; +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') @Controller('plans') export class PlansController { - constructor(private readonly plansService: PlansService) {} + constructor(private readonly plansService: PlansService) { } @Get() @ApiOperation({ summary: 'Get all plans' }) @@ -16,6 +35,42 @@ export class PlansController { @Get(':id') @ApiOperation({ summary: 'Get plan by ID' }) 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` }; } } + diff --git a/backoffice/src/plans/plans.service.ts b/backoffice/src/plans/plans.service.ts index 3e97038..af04930 100644 --- a/backoffice/src/plans/plans.service.ts +++ b/backoffice/src/plans/plans.service.ts @@ -12,7 +12,7 @@ export interface Plan { @Injectable() export class PlansService { - private readonly plans: Plan[] = [ + private plans: Plan[] = [ { id: 'starter', name: 'Starter', @@ -53,7 +53,32 @@ export class PlansService { getAllPlans(): Plan[] { return this.plans; } + getPlanById(id: string): Plan | undefined { return this.plans.find((p) => p.id === id); } + + createPlan(plan: Plan): Plan { + this.plans.push(plan); + return plan; + } + + updatePlan(id: string, updates: Partial): 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; + } } + diff --git a/backoffice/src/stripe/stripe.controller.ts b/backoffice/src/stripe/stripe.controller.ts new file mode 100644 index 0000000..3d85b4a --- /dev/null +++ b/backoffice/src/stripe/stripe.controller.ts @@ -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, + ); + } +} diff --git a/backoffice/src/stripe/stripe.module.ts b/backoffice/src/stripe/stripe.module.ts index ea86599..8388c5e 100644 --- a/backoffice/src/stripe/stripe.module.ts +++ b/backoffice/src/stripe/stripe.module.ts @@ -1,11 +1,14 @@ import { Module, Global } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { StripeService } from './stripe.service'; +import { StripeController } from './stripe.controller'; @Global() @Module({ imports: [ConfigModule], + controllers: [StripeController], providers: [StripeService], exports: [StripeService], }) -export class StripeModule {} +export class StripeModule { } +