diff --git a/src/common/enums/permission.enum.ts b/src/common/enums/permission.enum.ts index d3ccff8..ad9d0ba 100644 --- a/src/common/enums/permission.enum.ts +++ b/src/common/enums/permission.enum.ts @@ -47,6 +47,12 @@ export enum PermissionEnum { MANAGE_CRITICISMS = 'manage_criticisms', MANAGE_ANNOUNCEMENTS = 'manage_announcements', + + + // Notif Permsissions + NEW_REQUEST_NOTIFICATION='new_request_notification', + + NEW_PAYMENT_NOTIFICATION='new_payment_notification', } /** @@ -83,5 +89,7 @@ export const PermissionTitles: Record = { [PermissionEnum.MANAGE_PRINT]: "مدیریت فرم چاپ", [PermissionEnum.MANAGE_LEARNINGS]: "مدیریت آموزش‌ها", [PermissionEnum.MANAGE_CRITICISMS]: "مدیریت انتقادها و پیشنهادها", - [PermissionEnum.MANAGE_ANNOUNCEMENTS]: "مدیریت اطلاعیه‌ها" + [PermissionEnum.MANAGE_ANNOUNCEMENTS]: "مدیریت اطلاعیه‌ها", + [PermissionEnum.NEW_REQUEST_NOTIFICATION]: "", + [PermissionEnum.NEW_PAYMENT_NOTIFICATION]: "" }; diff --git a/src/modules/payment/events/payment.events.ts b/src/modules/payment/events/payment.events.ts index 664a193..6932ae4 100644 --- a/src/modules/payment/events/payment.events.ts +++ b/src/modules/payment/events/payment.events.ts @@ -1,20 +1,16 @@ -import { PaymentMethodEnum } from "../interface/payment"; - -export class paymentSucceedEvent { - constructor( - public readonly orderId: string, - public readonly orderNumber: string, - public readonly paymentMethod: PaymentMethodEnum, - public readonly total: number - ) { } -} - - - export class onlinePaymentSucceedEvent { constructor( public readonly paymentId: string, - public readonly orderId: string, + public readonly invoiceId: string, + public readonly invoiceNumber: string, + public readonly total: number, + ) { } +} + +export class newCashPaymentEvent { + constructor( + public readonly paymentId: string, + public readonly invoiceId: string, public readonly orderNumber: string, public readonly total: number, ) { } diff --git a/src/modules/payment/listeners/payment.listeners.ts b/src/modules/payment/listeners/payment.listeners.ts index 2fe9fea..cbed05d 100644 --- a/src/modules/payment/listeners/payment.listeners.ts +++ b/src/modules/payment/listeners/payment.listeners.ts @@ -1,35 +1,69 @@ import { Injectable, Logger } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; +import { EntityManager } from '@mikro-orm/postgresql'; import { AdminRepository } from 'src/modules/admin/repositories/admin.repository'; -import { onlinePaymentSucceedEvent, paymentSucceedEvent } from '../events/payment.events'; +import { onlinePaymentSucceedEvent } from '../events/payment.events'; import { PermissionEnum } from 'src/common/enums/permission.enum'; import { NotifEvent } from 'src/modules/notification/interfaces/notification.interface'; -import { NotificationService } from 'src/modules/notification/services/notification.service'; -import { ConfigService } from '@nestjs/config'; -// import { OrderService } from 'src/modules/order/providers/order.service'; +import { Notification } from 'src/modules/notification/entities/notification.entity'; +import { NotificationQueueService } from 'src/modules/notification/services/notification-queue.service'; @Injectable() export class PaymentListeners { private readonly logger = new Logger(PaymentListeners.name); - private orderCreatedSmsTemplateId: string; - private paymentSucceedSmsTemplateId: string; - constructor( - private readonly adminService: AdminRepository, - private readonly notificationService: NotificationService, - private readonly configService: ConfigService, - // private readonly orderService: OrderService, - ) { - this.orderCreatedSmsTemplateId = this.configService.get('SMS_PATTERN_ORDER_CREATED') ?? '123'; - this.paymentSucceedSmsTemplateId = this.configService.get('SMS_PATTERN_ONLINE_PAYMENT_SUCCEED') ?? '123'; - } - private getPaymentMethodFarsi(method: string): string { - const methodMap: Record = { - Cash: 'نقدی', - Wallet: 'کیف پول', - Online: 'آنلاین', - }; - return methodMap[method] || method; + constructor( + private readonly adminRepository: AdminRepository, + private readonly em: EntityManager, + private readonly notificationQueueService: NotificationQueueService, + ) {} + + @OnEvent(onlinePaymentSucceedEvent.name) + async handleOnlinePaymentVerified(event: InstanceType) { + try { + this.logger.log( + `Online payment verified: paymentId=${event.paymentId}, invoiceNumber=${event.invoiceNumber}, total=${event.total}`, + ); + + const admins = await this.adminRepository.findAdminsWithPermission( + PermissionEnum.NEW_PAYMENT_NOTIFICATION, + ); + + if (admins.length === 0) { + this.logger.log('No admins with NEW_PAYMENT_NOTIFICATION permission'); + return; + } + + const body = `پرداخت آنلاین جدید: پیش‌فاکتور شماره ${event.invoiceNumber} به مبلغ ${event.total.toLocaleString('fa-IR')} تومان`; + + const notifications = admins.map((admin) => + this.em.create(Notification, { + admin, + title: NotifEvent.PAYMENT_SUCCESS, + content: body, + }), + ); + + await this.em.persistAndFlush(notifications); + + await this.notificationQueueService.addBulkInAppNotifications( + notifications.map((n) => ({ + recipient: { adminId: n.admin!.id }, + subject: NotifEvent.PAYMENT_SUCCESS, + body, + notificationId: n.id, + })), + ); + + this.logger.log( + `Notification sent to ${admins.length} admin(s) for online payment ${event.paymentId}`, + ); + } catch (error) { + this.logger.error( + `Failed to send notification for online payment ${event.paymentId}`, + error instanceof Error ? error.stack : String(error), + ); + } } // @OnEvent(paymentSucceedEvent.name) diff --git a/src/modules/payment/services/payments.service.ts b/src/modules/payment/services/payments.service.ts index 114fda7..8018f0a 100644 --- a/src/modules/payment/services/payments.service.ts +++ b/src/modules/payment/services/payments.service.ts @@ -6,7 +6,7 @@ import { GatewayManager } from '../gateways/gateway.manager'; import { OrderPaymentContext } from '../interface/payment'; import { PaymentMessage, OrderMessage } from 'src/common/enums/message.enum'; import { EventEmitter2 } from '@nestjs/event-emitter'; -import { onlinePaymentSucceedEvent, paymentSucceedEvent } from '../events/payment.events'; +import { onlinePaymentSucceedEvent, newCashPaymentEvent } from '../events/payment.events'; import { OrderService } from 'src/modules/order/providers/order.service'; import { PayOrderDto } from '../dto/pay-order.dto'; import { PaymentRepository } from '../repositories/payment.repository'; @@ -147,11 +147,11 @@ export class PaymentService { await em.persistAndFlush([payment, newCreditTransaction]); }); - - this.eventEmitter.emit( - paymentSucceedEvent.name, - new paymentSucceedEvent(ctx.invoice.id, String(ctx.invoice?.invoiceNumber) || '', ctx.method, ctx.amount), - ); +//TODO + // this.eventEmitter.emit( + // newCashPaymentEvent.name, + // new newCashPaymentEvent(ctx.invoice.id, String(ctx.invoice?.invoiceNumber) || '', ctx.method, ctx.amount), + // ); } private async handleOnlinePayment(ctx: OrderPaymentContext): Promise<{ paymentUrl: string }> { diff --git a/src/seeders/data/roles.data.ts b/src/seeders/data/roles.data.ts index 968e626..2d5d1e1 100644 --- a/src/seeders/data/roles.data.ts +++ b/src/seeders/data/roles.data.ts @@ -16,7 +16,7 @@ export const rolesData: RoleConfig[] = [ }, { - name: 'admin', + name: 'interior-admin', title: 'مدیر داخلی', isSystem: true, permissionFilter: (name: PermissionEnum) => name !==PermissionEnum.MANAGE_ROLES @@ -26,7 +26,9 @@ export const rolesData: RoleConfig[] = [ name: 'accountant', title: 'حسابدار', isSystem: true, - permissionFilter: (name: PermissionEnum) => name==PermissionEnum.MANAGE_PAYMENTS + permissionFilter: (name: PermissionEnum) => + name === PermissionEnum.MANAGE_PAYMENTS || + name === PermissionEnum.NEW_PAYMENT_NOTIFICATION, }, {