fix: add notiftype
This commit is contained in:
@@ -357,6 +357,8 @@ export const enum NotificationMessage {
|
|||||||
ANSWER_TICKET_MESSAGE = "پاسخ جدیدی برای تیکت [ticketId] دریافت کردید",
|
ANSWER_TICKET_MESSAGE = "پاسخ جدیدی برای تیکت [ticketId] دریافت کردید",
|
||||||
CREATE_TICKET = "ایجاد تیکت",
|
CREATE_TICKET = "ایجاد تیکت",
|
||||||
CREATE_TICKET_MESSAGE = "تیکت شما با شماره [ticketId] ثبت شد",
|
CREATE_TICKET_MESSAGE = "تیکت شما با شماره [ticketId] ثبت شد",
|
||||||
|
ASSIGN_TICKET_MESSAGE = "یک تیکت به شماره [ticketId] به شما اختصاص یافت",
|
||||||
|
ASSIGN_TICKET = "اختصاص تیکت",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum SubscriptionMessage {
|
export const enum SubscriptionMessage {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export function smsConfigs() {
|
|||||||
SMS_PATTERN_WALLET_DEDUCTION: configService.getOrThrow<string>("SMS_PATTERN_WALLET_DEDUCTION"),
|
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_CREATED: configService.getOrThrow<string>("SMS_PATTERN_TICKET_CREATED"),
|
||||||
SMS_PATTERN_TICKET_ANSWERED: configService.getOrThrow<string>("SMS_PATTERN_WALLET_DEDUCTION"),
|
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_WALLET_DEDUCTION: string;
|
||||||
SMS_PATTERN_TICKET_CREATED: string;
|
SMS_PATTERN_TICKET_CREATED: string;
|
||||||
SMS_PATTERN_TICKET_ANSWERED: string;
|
SMS_PATTERN_TICKET_ANSWERED: string;
|
||||||
|
SMS_PATTERN_TICKET_ASSIGNED_ADMIN: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export interface ITicketNotificationData extends IBaseNotificationData {
|
|||||||
ticketId: string;
|
ticketId: string;
|
||||||
subject: string;
|
subject: string;
|
||||||
date: Date;
|
date: Date;
|
||||||
|
user?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IWalletNotificationData extends IBaseNotificationData {
|
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 });
|
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
|
// Support category
|
||||||
ANSWER_TICKET = "ANSWER_TICKET",
|
ANSWER_TICKET = "ANSWER_TICKET",
|
||||||
CREATE_TICKET = "CREATE_TICKET",
|
CREATE_TICKET = "CREATE_TICKET",
|
||||||
|
//
|
||||||
|
ASSIGN_TICKET = "ASSIGN_TICKET",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NotifDescriptions: Record<NotifType, { fa: string; category: NotifCategory }> = {
|
export const NotifDescriptions: Record<NotifType, { fa: string; category: NotifCategory }> = {
|
||||||
@@ -53,4 +55,6 @@ export const NotifDescriptions: Record<NotifType, { fa: string; category: NotifC
|
|||||||
// Support category
|
// Support category
|
||||||
[NotifType.ANSWER_TICKET]: { fa: "پاسخ تیکت", category: NotifCategory.SUPPORT },
|
[NotifType.ANSWER_TICKET]: { fa: "پاسخ تیکت", category: NotifCategory.SUPPORT },
|
||||||
[NotifType.CREATE_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) {
|
async toggleCategoryStatus(paramDto: ParamDto) {
|
||||||
const category = await this.ticketsCategoryRepository.findCategoryById(paramDto.id);
|
const category = await this.ticketsCategoryRepository.findCategoryById(paramDto.id);
|
||||||
if (!category) throw new BadRequestException(TicketMessageEnum.CATEGORY_NOT_FOUND);
|
if (!category) throw new BadRequestException(TicketMessageEnum.CATEGORY_NOT_FOUND);
|
||||||
|
//
|
||||||
category.isActive = !category.isActive;
|
category.isActive = !category.isActive;
|
||||||
await this.ticketsCategoryRepository.save(category);
|
await this.ticketsCategoryRepository.save(category);
|
||||||
|
//
|
||||||
return {
|
return {
|
||||||
message: CommonMessage.UPDATE_SUCCESS,
|
message: CommonMessage.UPDATE_SUCCESS,
|
||||||
isActive: category.isActive,
|
isActive: category.isActive,
|
||||||
@@ -119,7 +121,10 @@ export class TicketsService {
|
|||||||
let service;
|
let service;
|
||||||
const user = await this.usersService.findOneByIdWithQueryRunner(userId, queryRunner);
|
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);
|
if (!ticketCategory) throw new BadRequestException(TicketMessageEnum.CATEGORY_NOT_FOUND);
|
||||||
|
|
||||||
const { attachmentUrls } = createDto;
|
const { attachmentUrls } = createDto;
|
||||||
@@ -149,6 +154,25 @@ export class TicketsService {
|
|||||||
|
|
||||||
await queryRunner.manager.save(Ticket, ticket);
|
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(
|
await this.notificationsService.createTicketNotification(
|
||||||
userId,
|
userId,
|
||||||
{
|
{
|
||||||
@@ -374,4 +398,17 @@ export class TicketsService {
|
|||||||
});
|
});
|
||||||
return ticketCount;
|
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];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -491,22 +491,20 @@ export class UsersService {
|
|||||||
|
|
||||||
async findOneCustomer(userId: string) {
|
async findOneCustomer(userId: string) {
|
||||||
const customer = await this.userRepository.findOne({
|
const customer = await this.userRepository.findOne({
|
||||||
where: {
|
where: { id: userId, roles: { name: RoleEnum.USER } },
|
||||||
id: userId,
|
relations: { legalUser: true, realUser: true },
|
||||||
roles: {
|
|
||||||
name: RoleEnum.USER,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
relations: {
|
|
||||||
legalUser: true,
|
|
||||||
realUser: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return { customer };
|
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) {
|
async getAdmins(queryDto: SearchAdminQueryDto) {
|
||||||
const { limit, skip } = PaginationUtils(queryDto);
|
const { limit, skip } = PaginationUtils(queryDto);
|
||||||
const queryBuilder = this.userRepository.createQueryBuilder("user");
|
const queryBuilder = this.userRepository.createQueryBuilder("user");
|
||||||
|
|||||||
@@ -40,5 +40,6 @@ export type TemplateParams =
|
|||||||
| "newBalance"
|
| "newBalance"
|
||||||
| "reason"
|
| "reason"
|
||||||
| "dueDate"
|
| "dueDate"
|
||||||
|
| "user"
|
||||||
| "subject"
|
| "subject"
|
||||||
| "message";
|
| "message";
|
||||||
|
|||||||
@@ -303,6 +303,37 @@ export class SmsService {
|
|||||||
this.logger.error("error in sending sms", error);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//************************************************* */
|
//************************************************* */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user