diff --git a/src/modules/request/events/request.events.ts b/src/modules/request/events/request.events.ts new file mode 100644 index 0000000..95aed57 --- /dev/null +++ b/src/modules/request/events/request.events.ts @@ -0,0 +1,7 @@ +export class RequestCreatedEvent { + constructor( + public readonly requestId: string, + public readonly requestNumber: number, + public readonly userId: string, + ) {} +} diff --git a/src/modules/request/listeners/request.listeners.ts b/src/modules/request/listeners/request.listeners.ts new file mode 100644 index 0000000..fee1bd9 --- /dev/null +++ b/src/modules/request/listeners/request.listeners.ts @@ -0,0 +1,67 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { OnEvent } from '@nestjs/event-emitter'; +import { ConfigService } from '@nestjs/config'; +import { AdminRepository } from 'src/modules/admin/repositories/admin.repository'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; +import { NotificationService } from 'src/modules/notification/services/notification.service'; +import { NotifChannelEnum, NotifTitle } from 'src/modules/notification/interfaces/notification.interface'; +import { RequestCreatedEvent } from '../events/request.events'; + +@Injectable() +export class RequestListeners { + private readonly logger = new Logger(RequestListeners.name); + private newRequestSmsTemplateId: string; + + constructor( + private readonly adminRepository: AdminRepository, + private readonly notificationService: NotificationService, + private readonly configService: ConfigService, + ) { + this.newRequestSmsTemplateId = + this.configService.get('SMS_PATTERN_NEW_REQUEST') ?? 'new-request'; + } + + @OnEvent(RequestCreatedEvent.name) + async handleRequestCreated(event: RequestCreatedEvent) { + try { + this.logger.log( + `Request created event: requestId=${event.requestId}, requestNumber=${event.requestNumber}, userId=${event.userId}`, + ); + + const admins = await this.adminRepository.findAdminsWithPermission( + PermissionEnum.NEW_REQUEST_NOTIFICATION, + ); + + if (admins.length === 0) { + this.logger.log('No admins with NEW_REQUEST_NOTIFICATION permission'); + return; + } + + const body = `درخواست جدید شماره ${event.requestNumber}`; + + await this.notificationService.sendNotification({ + channels: [NotifChannelEnum.SMS], + recipients: admins.map((admin) => ({ adminId: admin.id })), + message: { + title: NotifTitle.NEW_REQUEST, + content: body, + sms: { + templateId: this.newRequestSmsTemplateId, + parameters: { + requestNumber: String(event.requestNumber), + }, + }, + }, + }); + + this.logger.log( + `SMS notification sent for ${admins.length} admin(s) for new request ${event.requestId}`, + ); + } catch (error) { + this.logger.error( + `Failed to send notification for request created: ${event.requestId}`, + error instanceof Error ? error.stack : String(error), + ); + } + } +} diff --git a/src/modules/request/request.module.ts b/src/modules/request/request.module.ts index 495af42..41cd3a4 100644 --- a/src/modules/request/request.module.ts +++ b/src/modules/request/request.module.ts @@ -10,6 +10,9 @@ import { ProductModule } from '../product/product.module'; import { FormBuilderModule } from '../form-builder/form-builder.module'; import { AuthModule } from '../auth/auth.module'; import { JwtModule } from '@nestjs/jwt'; +import { AdminModule } from '../admin/admin.module'; +import { NotificationsModule } from '../notification/notifications.module'; +import { RequestListeners } from './listeners/request.listeners'; @Module({ imports: [ @@ -18,9 +21,11 @@ import { JwtModule } from '@nestjs/jwt'; ProductModule, FormBuilderModule, JwtModule, - AuthModule + AuthModule, + AdminModule, + NotificationsModule, ], controllers: [RequestController], - providers: [RequestService, RequestRepository], + providers: [RequestService, RequestRepository, RequestListeners], }) export class RequestModule {} diff --git a/src/modules/request/request.service.ts b/src/modules/request/request.service.ts index 370eddb..be2e3a4 100644 --- a/src/modules/request/request.service.ts +++ b/src/modules/request/request.service.ts @@ -1,5 +1,6 @@ import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common'; import { EntityManager } from '@mikro-orm/postgresql'; +import { EventEmitter2 } from '@nestjs/event-emitter'; import { CreateRequestDto } from './dto/create-request.dto'; import { UpdateRequestDto } from './dto/update-request.dto'; import { FindRequestsDto } from './dto/find-requests.dto'; @@ -10,6 +11,7 @@ import { UserService } from '../user/providers/user.service'; import { ProductService } from '../product/providers/product.service'; import { FieldRepository } from '../form-builder/repository/field.repository'; import { RequestRepository } from './repositories/request.repository'; +import { RequestCreatedEvent } from './events/request.events'; @Injectable() export class RequestService { @@ -19,6 +21,7 @@ export class RequestService { private readonly userService: UserService, private readonly productService: ProductService, private readonly fieldRepository: FieldRepository, + private readonly eventEmitter: EventEmitter2, ) { } async create(createRequestDto: CreateRequestDto, userId: string) { @@ -47,6 +50,10 @@ export class RequestService { } await em.flush(); + this.eventEmitter.emit( + RequestCreatedEvent.name, + new RequestCreatedEvent(request.id, request.requestNumber, user.id), + ); return request; }); }