fix: add notiftype

This commit is contained in:
mahyargdz
2025-03-03 11:39:59 +03:30
parent 0abac00bde
commit c302ab1c77
9 changed files with 106 additions and 11 deletions
+2
View File
@@ -357,6 +357,8 @@ export const enum NotificationMessage {
ANSWER_TICKET_MESSAGE = "پاسخ جدیدی برای تیکت [ticketId] دریافت کردید",
CREATE_TICKET = "ایجاد تیکت",
CREATE_TICKET_MESSAGE = "تیکت شما با شماره [ticketId] ثبت شد",
ASSIGN_TICKET_MESSAGE = "یک تیکت به شماره [ticketId] به شما اختصاص یافت",
ASSIGN_TICKET = "اختصاص تیکت",
}
export const enum SubscriptionMessage {
+2
View File
@@ -16,6 +16,7 @@ export function smsConfigs() {
SMS_PATTERN_WALLET_DEDUCTION: configService.getOrThrow<string>("SMS_PATTERN_WALLET_DEDUCTION"),
SMS_PATTERN_TICKET_CREATED: configService.getOrThrow<string>("SMS_PATTERN_TICKET_CREATED"),
SMS_PATTERN_TICKET_ANSWERED: configService.getOrThrow<string>("SMS_PATTERN_WALLET_DEDUCTION"),
SMS_PATTERN_TICKET_ASSIGNED_ADMIN: configService.getOrThrow<string>("SMS_PATTERN_TICKET_ASSIGNED_ADMIN"),
};
},
};
@@ -33,4 +34,5 @@ export interface ISmsConfigs {
SMS_PATTERN_WALLET_DEDUCTION: string;
SMS_PATTERN_TICKET_CREATED: string;
SMS_PATTERN_TICKET_ANSWERED: string;
SMS_PATTERN_TICKET_ASSIGNED_ADMIN: string;
}
@@ -19,6 +19,7 @@ export interface ITicketNotificationData extends IBaseNotificationData {
ticketId: string;
subject: string;
date: Date;
user?: string;
}
export interface IWalletNotificationData extends IBaseNotificationData {
@@ -247,6 +247,25 @@ export class NotificationsService {
}
return this.createNotification({ title: NotificationMessage.CREATE_TICKET, type: NotifType.CREATE_TICKET, message, recipientId });
}
//************************ */
//TODO: fix this cause this for admin
async createAssignTicketNotificationForAdmin(recipientId: string, data: ITicketNotificationData, queryRunner: QueryRunner) {
const message = NotificationMessage.ASSIGN_TICKET_MESSAGE.replace("[ticketId]", data.ticketId);
//sent notification based on the userSettings
// const { isActive } = await this.userSettingsService.getUserNotificationSettingWithType(
// NotifType.ANSWER_TICKET,
// recipientId,
// queryRunner,
// );
// if (isActive) {
await this.smsService.sendTicketAssignedToAdminSms(data.userPhone, data.ticketId, data.subject, data.user!);
//send email too
// }
return this.createNotification(
{ title: NotificationMessage.ASSIGN_TICKET, type: NotifType.ASSIGN_TICKET, message, recipientId },
queryRunner,
);
}
//************************ */
@@ -29,6 +29,8 @@ export enum NotifType {
// Support category
ANSWER_TICKET = "ANSWER_TICKET",
CREATE_TICKET = "CREATE_TICKET",
//
ASSIGN_TICKET = "ASSIGN_TICKET",
}
export const NotifDescriptions: Record<NotifType, { fa: string; category: NotifCategory }> = {
@@ -53,4 +55,6 @@ export const NotifDescriptions: Record<NotifType, { fa: string; category: NotifC
// Support category
[NotifType.ANSWER_TICKET]: { fa: "پاسخ تیکت", category: NotifCategory.SUPPORT },
[NotifType.CREATE_TICKET]: { fa: "ثبت تیکت جدید", category: NotifCategory.SUPPORT },
//TODO: FIX THIS this is for admin
[NotifType.ASSIGN_TICKET]: { fa: "ارجاع تیکت", category: NotifCategory.SUPPORT },
};
@@ -101,8 +101,10 @@ export class TicketsService {
async toggleCategoryStatus(paramDto: ParamDto) {
const category = await this.ticketsCategoryRepository.findCategoryById(paramDto.id);
if (!category) throw new BadRequestException(TicketMessageEnum.CATEGORY_NOT_FOUND);
//
category.isActive = !category.isActive;
await this.ticketsCategoryRepository.save(category);
//
return {
message: CommonMessage.UPDATE_SUCCESS,
isActive: category.isActive,
@@ -119,7 +121,10 @@ export class TicketsService {
let service;
const user = await this.usersService.findOneByIdWithQueryRunner(userId, queryRunner);
const ticketCategory = await queryRunner.manager.findOneBy(TicketCategory, { id: createDto.categoryId });
const ticketCategory = await queryRunner.manager.findOne(TicketCategory, {
where: { id: createDto.categoryId },
relations: { group: { users: true } },
});
if (!ticketCategory) throw new BadRequestException(TicketMessageEnum.CATEGORY_NOT_FOUND);
const { attachmentUrls } = createDto;
@@ -149,6 +154,25 @@ export class TicketsService {
await queryRunner.manager.save(Ticket, ticket);
const assignedUser = await this.autoAssignUser(ticketCategory);
//send notification to assignedUser
if (assignedUser) {
ticket.assignedTo = assignedUser;
await queryRunner.manager.save(Ticket, ticket);
await this.notificationsService.createAssignTicketNotificationForAdmin(
assignedUser.id,
{
ticketId: ticket.numericId.toString(),
subject: ticket.subject,
date: ticket.createdAt,
userPhone: user.phone,
userEmail: user.email,
user: `${user.firstName} ${user.lastName}`,
},
queryRunner,
);
}
await this.notificationsService.createTicketNotification(
userId,
{
@@ -374,4 +398,17 @@ export class TicketsService {
});
return ticketCount;
}
//******************************** */
async autoAssignUser(category: TicketCategory): Promise<User | null> {
if (!category.group) return null;
const { users } = await this.usersService.getUsersByGroup(category.group.id);
if (users.length === 0) return null;
users.sort((a, b) => (a.tickets.length || 0) - (b.tickets.length || 0));
return users[0];
}
}
+8 -10
View File
@@ -491,22 +491,20 @@ export class UsersService {
async findOneCustomer(userId: string) {
const customer = await this.userRepository.findOne({
where: {
id: userId,
roles: {
name: RoleEnum.USER,
},
},
relations: {
legalUser: true,
realUser: true,
},
where: { id: userId, roles: { name: RoleEnum.USER } },
relations: { legalUser: true, realUser: true },
});
return { customer };
}
/************************************************************ */
async getUsersByGroup(groupId: string) {
const users = await this.userRepository.find({ where: { groups: { id: groupId } }, relations: { tickets: true } });
return { users };
}
/************************************************************ */
async getAdmins(queryDto: SearchAdminQueryDto) {
const { limit, skip } = PaginationUtils(queryDto);
const queryBuilder = this.userRepository.createQueryBuilder("user");
+1
View File
@@ -40,5 +40,6 @@ export type TemplateParams =
| "newBalance"
| "reason"
| "dueDate"
| "user"
| "subject"
| "message";
@@ -303,6 +303,37 @@ export class SmsService {
this.logger.error("error in sending sms", error);
}
}
//************************************************* */
async sendTicketAssignedToAdminSms(mobile: string, ticketId: string, subject: string, user: string) {
const smsData: ISmsVerifyBody = {
Parameters: [
{ name: "ticketId", value: ticketId },
{ name: "subject", value: subject },
{ name: "user", value: user },
],
Mobile: mobile,
TemplateId: this.smsConfigs.SMS_PATTERN_TICKET_ASSIGNED_ADMIN,
};
try {
const { data } = await firstValueFrom(
this.httpService
.post<ISmsVerifyResponse>(`${this.smsConfigs.API_URL}/send/verify`, smsData, {
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
})
.pipe(
catchError((err: AxiosError) => {
this.logger.error("error in sending ticket assigned sms", err);
throw new InternalServerErrorException("error in sending ticket assigned sms");
}),
),
);
return data;
} catch (error) {
this.logger.error("error in sending sms", error);
}
}
//************************************************* */