gestion des services
This commit is contained in:
parent
7262d03365
commit
4e359efd5e
@ -26,7 +26,7 @@ async function bootstrap() {
|
|||||||
|
|
||||||
// Swagger
|
// Swagger
|
||||||
const config = new DocumentBuilder()
|
const config = new DocumentBuilder()
|
||||||
.setTitle('Payment Hub API')
|
.setTitle('Merchant Config API')
|
||||||
.setDescription('Unified DCB Payment Aggregation Platform')
|
.setDescription('Unified DCB Payment Aggregation Platform')
|
||||||
.setVersion('1.0.0')
|
.setVersion('1.0.0')
|
||||||
.addBearerAuth()
|
.addBearerAuth()
|
||||||
|
|||||||
@ -12,10 +12,10 @@ import {
|
|||||||
HttpStatus,
|
HttpStatus,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/swagger';
|
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/swagger';
|
||||||
import { MerchantService } from './services/merchant.service';
|
import { MerchantService } from '../services/merchant.service';
|
||||||
import { CreateMerchantPartnerDto } from './dto/create.merchant.dto';
|
import { CreateMerchantPartnerDto } from '../dto/create.merchant.dto';
|
||||||
import { UpdateMerchantPartnerDto } from './dto/ update.merchant.dto';
|
import { UpdateMerchantPartnerDto } from '../dto/ update.merchant.dto';
|
||||||
import { AddUserToMerchantDto, UpdateUserRoleDto } from './dto/merchant.user.dto';
|
import { AddUserToMerchantDto, UpdateUserRoleDto } from '../dto/merchant.user.dto';
|
||||||
|
|
||||||
@ApiTags('merchants')
|
@ApiTags('merchants')
|
||||||
@Controller('merchants')
|
@Controller('merchants')
|
||||||
130
src/merchant/controllers/service.controller.ts
Normal file
130
src/merchant/controllers/service.controller.ts
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import {
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Body,
|
||||||
|
Patch,
|
||||||
|
Param,
|
||||||
|
Delete,
|
||||||
|
ParseIntPipe,
|
||||||
|
HttpCode,
|
||||||
|
HttpStatus,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
|
||||||
|
import { ServiceManagementService } from '../services/service.service';
|
||||||
|
import { CreateServiceDto } from '../dto/create.service.dto';
|
||||||
|
import { UpdateServiceDto } from '../dto/update.service.dto';
|
||||||
|
import { CreatePlanDto } from '../dto/create.plan.dto';
|
||||||
|
import { UpdatePlanDto } from '../dto/update.plan.dto';
|
||||||
|
|
||||||
|
@ApiTags('services')
|
||||||
|
@Controller('services')
|
||||||
|
export class ServiceController {
|
||||||
|
constructor(private readonly serviceManagementService: ServiceManagementService) {}
|
||||||
|
|
||||||
|
// ==================== SERVICE ENDPOINTS ====================
|
||||||
|
|
||||||
|
@Post()
|
||||||
|
@ApiOperation({ summary: 'Create a new service for a merchant' })
|
||||||
|
@ApiResponse({ status: 201, description: 'Service created successfully' })
|
||||||
|
@ApiResponse({ status: 400, description: 'Bad request - validation failed' })
|
||||||
|
@ApiResponse({ status: 404, description: 'Merchant not found' })
|
||||||
|
create(@Body() createServiceDto: CreateServiceDto) {
|
||||||
|
return this.serviceManagementService.createService(createServiceDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('merchant/:merchantId')
|
||||||
|
@ApiOperation({ summary: 'Get all services for a merchant' })
|
||||||
|
@ApiParam({ name: 'merchantId', type: Number })
|
||||||
|
@ApiResponse({ status: 200, description: 'List of merchant services' })
|
||||||
|
@ApiResponse({ status: 404, description: 'Merchant not found' })
|
||||||
|
findAllByMerchant(@Param('merchantId', ParseIntPipe) merchantId: number) {
|
||||||
|
return this.serviceManagementService.findAllByMerchant(merchantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get(':id')
|
||||||
|
@ApiOperation({ summary: 'Get service by ID' })
|
||||||
|
@ApiParam({ name: 'id', type: Number })
|
||||||
|
@ApiResponse({ status: 200, description: 'Service found' })
|
||||||
|
@ApiResponse({ status: 404, description: 'Service not found' })
|
||||||
|
findOne(@Param('id', ParseIntPipe) id: number) {
|
||||||
|
return this.serviceManagementService.findOneService(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch(':id')
|
||||||
|
@ApiOperation({ summary: 'Update service' })
|
||||||
|
@ApiParam({ name: 'id', type: Number })
|
||||||
|
@ApiResponse({ status: 200, description: 'Service updated successfully' })
|
||||||
|
@ApiResponse({ status: 404, description: 'Service not found' })
|
||||||
|
update(
|
||||||
|
@Param('id', ParseIntPipe) id: number,
|
||||||
|
@Body() updateServiceDto: UpdateServiceDto,
|
||||||
|
) {
|
||||||
|
return this.serviceManagementService.updateService(id, updateServiceDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(':id')
|
||||||
|
@HttpCode(HttpStatus.NO_CONTENT)
|
||||||
|
@ApiOperation({ summary: 'Delete service' })
|
||||||
|
@ApiParam({ name: 'id', type: Number })
|
||||||
|
@ApiResponse({ status: 204, description: 'Service deleted successfully' })
|
||||||
|
@ApiResponse({ status: 404, description: 'Service not found' })
|
||||||
|
remove(@Param('id', ParseIntPipe) id: number) {
|
||||||
|
return this.serviceManagementService.removeService(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== PLAN ENDPOINTS ====================
|
||||||
|
|
||||||
|
@Post(':serviceId/plans')
|
||||||
|
@ApiOperation({ summary: 'Create a new plan for a service' })
|
||||||
|
@ApiParam({ name: 'serviceId', type: Number })
|
||||||
|
@ApiResponse({ status: 201, description: 'Plan created successfully' })
|
||||||
|
@ApiResponse({ status: 400, description: 'Bad request - validation failed' })
|
||||||
|
@ApiResponse({ status: 404, description: 'Service not found' })
|
||||||
|
createPlan(
|
||||||
|
@Param('serviceId', ParseIntPipe) serviceId: number,
|
||||||
|
@Body() createPlanDto: CreatePlanDto,
|
||||||
|
) {
|
||||||
|
return this.serviceManagementService.createPlan(serviceId, createPlanDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get(':serviceId/plans')
|
||||||
|
@ApiOperation({ summary: 'Get all plans for a service' })
|
||||||
|
@ApiParam({ name: 'serviceId', type: Number })
|
||||||
|
@ApiResponse({ status: 200, description: 'List of service plans' })
|
||||||
|
@ApiResponse({ status: 404, description: 'Service not found' })
|
||||||
|
findAllPlans(@Param('serviceId', ParseIntPipe) serviceId: number) {
|
||||||
|
return this.serviceManagementService.findAllPlansByService(serviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('plans/:planId')
|
||||||
|
@ApiOperation({ summary: 'Get plan by ID' })
|
||||||
|
@ApiParam({ name: 'planId', type: Number })
|
||||||
|
@ApiResponse({ status: 200, description: 'Plan found' })
|
||||||
|
@ApiResponse({ status: 404, description: 'Plan not found' })
|
||||||
|
findOnePlan(@Param('planId', ParseIntPipe) planId: number) {
|
||||||
|
return this.serviceManagementService.findOnePlan(planId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch('plans/:planId')
|
||||||
|
@ApiOperation({ summary: 'Update plan' })
|
||||||
|
@ApiParam({ name: 'planId', type: Number })
|
||||||
|
@ApiResponse({ status: 200, description: 'Plan updated successfully' })
|
||||||
|
@ApiResponse({ status: 404, description: 'Plan not found' })
|
||||||
|
updatePlan(
|
||||||
|
@Param('planId', ParseIntPipe) planId: number,
|
||||||
|
@Body() updatePlanDto: UpdatePlanDto,
|
||||||
|
) {
|
||||||
|
return this.serviceManagementService.updatePlan(planId, updatePlanDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete('plans/:planId')
|
||||||
|
@HttpCode(HttpStatus.NO_CONTENT)
|
||||||
|
@ApiOperation({ summary: 'Delete plan' })
|
||||||
|
@ApiParam({ name: 'planId', type: Number })
|
||||||
|
@ApiResponse({ status: 204, description: 'Plan deleted successfully' })
|
||||||
|
@ApiResponse({ status: 404, description: 'Plan not found' })
|
||||||
|
removePlan(@Param('planId', ParseIntPipe) planId: number) {
|
||||||
|
return this.serviceManagementService.removePlan(planId);
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/merchant/dto/create.plan.dto.ts
Normal file
64
src/merchant/dto/create.plan.dto.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import {
|
||||||
|
IsString,
|
||||||
|
IsNotEmpty,
|
||||||
|
IsEnum,
|
||||||
|
IsNumber,
|
||||||
|
Min,
|
||||||
|
} from 'class-validator';
|
||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { Periodicity, Currency } from "generated/prisma";
|
||||||
|
|
||||||
|
export class CreatePlanDto {
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Plan name',
|
||||||
|
example: 'Monthly Premium',
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Plan type',
|
||||||
|
enum: Periodicity,
|
||||||
|
example: 'Monthly',
|
||||||
|
})
|
||||||
|
@IsEnum(Periodicity)
|
||||||
|
@IsNotEmpty()
|
||||||
|
type: Periodicity;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Plan amount',
|
||||||
|
example: 5000,
|
||||||
|
})
|
||||||
|
@IsNumber()
|
||||||
|
@Min(0)
|
||||||
|
@IsNotEmpty()
|
||||||
|
amount: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Tax amount',
|
||||||
|
example: 900,
|
||||||
|
})
|
||||||
|
@IsNumber()
|
||||||
|
@Min(0)
|
||||||
|
@IsNotEmpty()
|
||||||
|
tax: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Currency',
|
||||||
|
enum: Currency,
|
||||||
|
example: 'XOF',
|
||||||
|
})
|
||||||
|
@IsEnum(Currency)
|
||||||
|
@IsNotEmpty()
|
||||||
|
currency: Currency;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Billing periodicity',
|
||||||
|
enum: Periodicity,
|
||||||
|
example: 'Monthly',
|
||||||
|
})
|
||||||
|
@IsEnum(Periodicity)
|
||||||
|
@IsNotEmpty()
|
||||||
|
periodicity: Periodicity;
|
||||||
|
}
|
||||||
28
src/merchant/dto/create.service.dto.ts
Normal file
28
src/merchant/dto/create.service.dto.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { IsString, IsNotEmpty, IsOptional, IsInt } from 'class-validator';
|
||||||
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class CreateServiceDto {
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Service name',
|
||||||
|
example: 'Premium Streaming',
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Service description',
|
||||||
|
example: 'Access to premium content streaming',
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
description?: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Merchant partner ID',
|
||||||
|
example: 1,
|
||||||
|
})
|
||||||
|
@IsInt()
|
||||||
|
@IsNotEmpty()
|
||||||
|
merchantPartnerId: number;
|
||||||
|
}
|
||||||
4
src/merchant/dto/update.plan.dto.ts
Normal file
4
src/merchant/dto/update.plan.dto.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { PartialType } from '@nestjs/swagger';
|
||||||
|
import { CreatePlanDto } from './create.plan.dto';
|
||||||
|
|
||||||
|
export class UpdatePlanDto extends PartialType(CreatePlanDto) {}
|
||||||
7
src/merchant/dto/update.service.dto.ts
Normal file
7
src/merchant/dto/update.service.dto.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { PartialType } from '@nestjs/swagger';
|
||||||
|
import { CreateServiceDto } from './create.service.dto';
|
||||||
|
import { OmitType } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class UpdateServiceDto extends PartialType(
|
||||||
|
OmitType(CreateServiceDto, ['merchantPartnerId'] as const),
|
||||||
|
) {}
|
||||||
42
src/merchant/entities/service.entity.ts
Normal file
42
src/merchant/entities/service.entity.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { Service, Plan, MerchantPartner, Periodicity, Currency } from "generated/prisma";
|
||||||
|
|
||||||
|
export type ServiceEntity = Service;
|
||||||
|
|
||||||
|
export type PlanEntity = Plan & {
|
||||||
|
service?: Service;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ServiceWithPlans = Service & {
|
||||||
|
plans: Plan[];
|
||||||
|
merchantPartner?: MerchantPartner;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface CreateServiceData {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
merchantPartnerId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateServiceData {
|
||||||
|
name?: string;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreatePlanData {
|
||||||
|
name: string;
|
||||||
|
type: Periodicity;
|
||||||
|
amount: number;
|
||||||
|
tax: number;
|
||||||
|
currency: Currency;
|
||||||
|
periodicity: Periodicity;
|
||||||
|
serviceId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdatePlanData {
|
||||||
|
name?: string;
|
||||||
|
type?: Periodicity;
|
||||||
|
amount?: number;
|
||||||
|
tax?: number;
|
||||||
|
currency?: Currency;
|
||||||
|
periodicity?: Periodicity;
|
||||||
|
}
|
||||||
@ -2,11 +2,13 @@ import { Module } from '@nestjs/common';
|
|||||||
import { HttpModule } from '@nestjs/axios';
|
import { HttpModule } from '@nestjs/axios';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { EventEmitterModule } from '@nestjs/event-emitter';
|
import { EventEmitterModule } from '@nestjs/event-emitter';
|
||||||
import { MerchantController } from './merchant.controller';
|
import { MerchantController } from './controllers/merchant.controller';
|
||||||
|
|
||||||
import { HttpUserServiceClient } from './services/user.service.client';
|
import { HttpUserServiceClient } from './services/user.service.client';
|
||||||
import { PrismaService } from 'src/shared/services/prisma.service';
|
import { PrismaService } from 'src/shared/services/prisma.service';
|
||||||
import { MerchantService } from './services/merchant.service';
|
import { MerchantService } from './services/merchant.service';
|
||||||
|
import { ServiceController } from './controllers/service.controller';
|
||||||
|
import { ServiceManagementService } from './services/service.service';
|
||||||
|
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
@ -15,9 +17,10 @@ import { MerchantService } from './services/merchant.service';
|
|||||||
ConfigModule,
|
ConfigModule,
|
||||||
EventEmitterModule.forRoot(),
|
EventEmitterModule.forRoot(),
|
||||||
],
|
],
|
||||||
controllers: [MerchantController],
|
controllers: [MerchantController,ServiceController],
|
||||||
providers: [
|
providers: [
|
||||||
MerchantService,
|
MerchantService,
|
||||||
|
ServiceManagementService,
|
||||||
PrismaService,
|
PrismaService,
|
||||||
HttpUserServiceClient
|
HttpUserServiceClient
|
||||||
],
|
],
|
||||||
|
|||||||
267
src/merchant/services/service.service.ts
Normal file
267
src/merchant/services/service.service.ts
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
|
import { PrismaService } from 'src/shared/services/prisma.service';
|
||||||
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
|
import { CreateServiceDto } from '../dto/create.service.dto';
|
||||||
|
import { UpdateServiceDto } from '../dto/update.service.dto';
|
||||||
|
import { CreatePlanDto } from '../dto/create.plan.dto';
|
||||||
|
import { UpdatePlanDto } from '../dto/update.plan.dto';
|
||||||
|
import { ServiceWithPlans, PlanEntity } from '../entities/service.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ServiceManagementService {
|
||||||
|
constructor(
|
||||||
|
private readonly prisma: PrismaService,
|
||||||
|
private readonly eventEmitter: EventEmitter2,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
// ==================== SERVICE METHODS ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new service for a merchant
|
||||||
|
*/
|
||||||
|
async createService(dto: CreateServiceDto): Promise<ServiceWithPlans> {
|
||||||
|
// Check if merchant exists
|
||||||
|
const merchant = await this.prisma.merchantPartner.findUnique({
|
||||||
|
where: { id: dto.merchantPartnerId },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!merchant) {
|
||||||
|
throw new NotFoundException(
|
||||||
|
`Merchant with ID ${dto.merchantPartnerId} not found`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = await this.prisma.service.create({
|
||||||
|
data: {
|
||||||
|
name: dto.name,
|
||||||
|
description: dto.description,
|
||||||
|
merchantPartnerId: dto.merchantPartnerId,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
plans: true,
|
||||||
|
merchantPartner: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this.eventEmitter.emit('service.created', {
|
||||||
|
serviceId: service.id,
|
||||||
|
serviceName: service.name,
|
||||||
|
merchantId: dto.merchantPartnerId,
|
||||||
|
timestamp: new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all services for a merchant
|
||||||
|
*/
|
||||||
|
async findAllByMerchant(merchantId: number): Promise<ServiceWithPlans[]> {
|
||||||
|
// Check if merchant exists
|
||||||
|
const merchant = await this.prisma.merchantPartner.findUnique({
|
||||||
|
where: { id: merchantId },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!merchant) {
|
||||||
|
throw new NotFoundException(`Merchant with ID ${merchantId} not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.prisma.service.findMany({
|
||||||
|
where: { merchantPartnerId: merchantId },
|
||||||
|
include: {
|
||||||
|
plans: true,
|
||||||
|
merchantPartner: true,
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
createdAt: 'desc',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find service by ID
|
||||||
|
*/
|
||||||
|
async findOneService(id: number): Promise<ServiceWithPlans> {
|
||||||
|
const service = await this.prisma.service.findUnique({
|
||||||
|
where: { id },
|
||||||
|
include: {
|
||||||
|
plans: true,
|
||||||
|
merchantPartner: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!service) {
|
||||||
|
throw new NotFoundException(`Service with ID ${id} not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update service
|
||||||
|
*/
|
||||||
|
async updateService(
|
||||||
|
id: number,
|
||||||
|
dto: UpdateServiceDto,
|
||||||
|
): Promise<ServiceWithPlans> {
|
||||||
|
await this.findOneService(id); // Check if exists
|
||||||
|
|
||||||
|
const service = await this.prisma.service.update({
|
||||||
|
where: { id },
|
||||||
|
data: {
|
||||||
|
name: dto.name,
|
||||||
|
description: dto.description,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
plans: true,
|
||||||
|
merchantPartner: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this.eventEmitter.emit('service.updated', {
|
||||||
|
serviceId: id,
|
||||||
|
serviceName: service.name,
|
||||||
|
timestamp: new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete service
|
||||||
|
*/
|
||||||
|
async removeService(id: number): Promise<void> {
|
||||||
|
await this.findOneService(id); // Check if exists
|
||||||
|
|
||||||
|
await this.prisma.service.delete({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
this.eventEmitter.emit('service.deleted', {
|
||||||
|
serviceId: id,
|
||||||
|
timestamp: new Date(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== PLAN METHODS ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new plan for a service
|
||||||
|
*/
|
||||||
|
async createPlan(
|
||||||
|
serviceId: number,
|
||||||
|
dto: CreatePlanDto,
|
||||||
|
): Promise<PlanEntity> {
|
||||||
|
// Check if service exists
|
||||||
|
await this.findOneService(serviceId);
|
||||||
|
|
||||||
|
const plan = await this.prisma.plan.create({
|
||||||
|
data: {
|
||||||
|
name: dto.name,
|
||||||
|
type: dto.type,
|
||||||
|
amount: dto.amount,
|
||||||
|
tax: dto.tax,
|
||||||
|
currency: dto.currency,
|
||||||
|
periodicity: dto.periodicity,
|
||||||
|
serviceId,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
service: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this.eventEmitter.emit('plan.created', {
|
||||||
|
planId: plan.id,
|
||||||
|
planName: plan.name,
|
||||||
|
serviceId,
|
||||||
|
amount: plan.amount,
|
||||||
|
currency: plan.currency,
|
||||||
|
timestamp: new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all plans for a service
|
||||||
|
*/
|
||||||
|
async findAllPlansByService(serviceId: number): Promise<PlanEntity[]> {
|
||||||
|
// Check if service exists
|
||||||
|
await this.findOneService(serviceId);
|
||||||
|
|
||||||
|
return this.prisma.plan.findMany({
|
||||||
|
where: { serviceId },
|
||||||
|
include: {
|
||||||
|
service: true,
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
amount: 'asc',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find plan by ID
|
||||||
|
*/
|
||||||
|
async findOnePlan(id: number): Promise<PlanEntity> {
|
||||||
|
const plan = await this.prisma.plan.findUnique({
|
||||||
|
where: { id },
|
||||||
|
include: {
|
||||||
|
service: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!plan) {
|
||||||
|
throw new NotFoundException(`Plan with ID ${id} not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update plan
|
||||||
|
*/
|
||||||
|
async updatePlan(id: number, dto: UpdatePlanDto): Promise<PlanEntity> {
|
||||||
|
await this.findOnePlan(id); // Check if exists
|
||||||
|
|
||||||
|
const plan = await this.prisma.plan.update({
|
||||||
|
where: { id },
|
||||||
|
data: {
|
||||||
|
name: dto.name,
|
||||||
|
type: dto.type,
|
||||||
|
amount: dto.amount,
|
||||||
|
tax: dto.tax,
|
||||||
|
currency: dto.currency,
|
||||||
|
periodicity: dto.periodicity,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
service: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this.eventEmitter.emit('plan.updated', {
|
||||||
|
planId: id,
|
||||||
|
planName: plan.name,
|
||||||
|
amount: plan.amount,
|
||||||
|
timestamp: new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete plan
|
||||||
|
*/
|
||||||
|
async removePlan(id: number): Promise<void> {
|
||||||
|
await this.findOnePlan(id); // Check if exists
|
||||||
|
|
||||||
|
await this.prisma.plan.delete({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
this.eventEmitter.emit('plan.deleted', {
|
||||||
|
planId: id,
|
||||||
|
timestamp: new Date(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user