feat: add support plan features and user support plan functionality
This commit is contained in:
@@ -286,6 +286,10 @@ export const enum TicketMessageEnum {
|
|||||||
TICKET_NOT_ASSIGNED = "تیکت به کارشناسی اختصاص داده نشده است",
|
TICKET_NOT_ASSIGNED = "تیکت به کارشناسی اختصاص داده نشده است",
|
||||||
TICKET_NOT_ASSIGNED_TO_USER = "تیکت به شما اختصاص داده نشده است",
|
TICKET_NOT_ASSIGNED_TO_USER = "تیکت به شما اختصاص داده نشده است",
|
||||||
REFERRED = "REFERRED",
|
REFERRED = "REFERRED",
|
||||||
|
NO_ACTIVE_SUPPORT_PLAN = "شما پلن پشتیبانی فعال ندارید",
|
||||||
|
TICKET_LIMIT_NOT_FOUND = "محدودیت تعداد تیکت در پلن پشتیبانی شما یافت نشد",
|
||||||
|
INVALID_TICKET_LIMIT = "محدودیت تعداد تیکت در پلن پشتیبانی شما نامعتبر است",
|
||||||
|
TICKET_LIMIT_EXCEEDED = "شما به محدودیت تعداد تیکت در پلن پشتیبانی خود رسیدهاید",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum WalletMessage {
|
export const enum WalletMessage {
|
||||||
|
|||||||
@@ -173,6 +173,15 @@ export class SupportPlansService {
|
|||||||
|
|
||||||
return { userSupportPlan };
|
return { userSupportPlan };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//***************************************** */
|
||||||
|
async getUsersOfSupportPlan(supportPlanId: string) {
|
||||||
|
const users = await this.userSupportPlanRepo.find({
|
||||||
|
where: { supportPlan: { id: supportPlanId }, status: UserSupportPlanStatus.ACTIVE },
|
||||||
|
relations: { user: true, supportPlan: true },
|
||||||
|
});
|
||||||
|
return users;
|
||||||
|
}
|
||||||
//***************************************** */
|
//***************************************** */
|
||||||
async upgradeSupportPlan(newPlanId: string, userId: string) {
|
async upgradeSupportPlan(newPlanId: string, userId: string) {
|
||||||
const queryRunner = this.dataSource.createQueryRunner();
|
const queryRunner = this.dataSource.createQueryRunner();
|
||||||
|
|||||||
@@ -30,7 +30,13 @@ export class SupportPlanRepository extends Repository<SupportPlan> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getSupportPlansListUser() {
|
async getSupportPlansListUser() {
|
||||||
return this.find({ where: { isActive: true, deletedAt: IsNull() }, order: { price: "ASC" }, relations: { features: true } });
|
return this.createQueryBuilder("supportPlan")
|
||||||
|
.leftJoinAndSelect("supportPlan.features", "features")
|
||||||
|
.where("supportPlan.isActive = :isActive", { isActive: true })
|
||||||
|
.andWhere("supportPlan.deletedAt IS NULL")
|
||||||
|
.orderBy("supportPlan.price", "ASC")
|
||||||
|
.addOrderBy("features.featureKey", "ASC")
|
||||||
|
.getMany();
|
||||||
}
|
}
|
||||||
//***************************************** */
|
//***************************************** */
|
||||||
async getSupportPlanById(id: string) {
|
async getSupportPlanById(id: string) {
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import { BadRequestException, HttpException, Injectable, InternalServerErrorException, Logger } from "@nestjs/common";
|
import { BadRequestException, HttpException, Injectable, InternalServerErrorException, Logger } from "@nestjs/common";
|
||||||
import { DataSource, Not, QueryRunner } from "typeorm";
|
import dayjs from "dayjs";
|
||||||
|
import { DataSource, MoreThanOrEqual, Not, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
import { ReferralService } from "./referral.service";
|
import { ReferralService } from "./referral.service";
|
||||||
import { ParamDto } from "../../../common/DTO/param.dto";
|
import { ParamDto } from "../../../common/DTO/param.dto";
|
||||||
import { CommonMessage, TicketMessageEnum, UserMessage } from "../../../common/enums/message.enum";
|
import { CommonMessage, TicketMessageEnum, UserMessage } from "../../../common/enums/message.enum";
|
||||||
import { DanakService } from "../../danak-services/entities/danak-service.entity";
|
import { DanakService } from "../../danak-services/entities/danak-service.entity";
|
||||||
import { NotificationQueue } from "../../notifications/queue/notification.queue";
|
import { NotificationQueue } from "../../notifications/queue/notification.queue";
|
||||||
|
import { SupportPlanFeatureKey } from "../../support-plans/enums/support-plan-feature-key.enum";
|
||||||
|
import { SupportPlansService } from "../../support-plans/providers/support-plans.service";
|
||||||
import { User } from "../../users/entities/user.entity";
|
import { User } from "../../users/entities/user.entity";
|
||||||
import { AdminsService } from "../../users/providers/admins.service";
|
import { AdminsService } from "../../users/providers/admins.service";
|
||||||
import { UsersService } from "../../users/providers/users.service";
|
import { UsersService } from "../../users/providers/users.service";
|
||||||
@@ -24,19 +27,23 @@ import { TicketStatus } from "../enums/ticket-status.enum";
|
|||||||
import { TicketCategoryRepository } from "../repositories/tickets-category.repository";
|
import { TicketCategoryRepository } from "../repositories/tickets-category.repository";
|
||||||
import { TicketMessagesRepository } from "../repositories/tickets-message.repository";
|
import { TicketMessagesRepository } from "../repositories/tickets-message.repository";
|
||||||
import { TicketsRepository } from "../repositories/tickets.repository";
|
import { TicketsRepository } from "../repositories/tickets.repository";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TicketsService {
|
export class TicketsService {
|
||||||
private readonly logger = new Logger(TicketsService.name);
|
private readonly logger = new Logger(TicketsService.name);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly notificationQueue: NotificationQueue,
|
|
||||||
private readonly ticketsCategoryRepository: TicketCategoryRepository,
|
|
||||||
private readonly ticketsRepository: TicketsRepository,
|
private readonly ticketsRepository: TicketsRepository,
|
||||||
|
private readonly ticketsCategoryRepository: TicketCategoryRepository,
|
||||||
private readonly ticketMessagesRepository: TicketMessagesRepository,
|
private readonly ticketMessagesRepository: TicketMessagesRepository,
|
||||||
private readonly usersService: UsersService,
|
private readonly usersService: UsersService,
|
||||||
private readonly adminsService: AdminsService,
|
private readonly adminsService: AdminsService,
|
||||||
|
private readonly notificationQueue: NotificationQueue,
|
||||||
private readonly referralService: ReferralService,
|
private readonly referralService: ReferralService,
|
||||||
private dataSource: DataSource,
|
private readonly dataSource: DataSource,
|
||||||
|
private readonly supportPlansService: SupportPlansService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
//******************************** */
|
//******************************** */
|
||||||
async getTicketCategories() {
|
async getTicketCategories() {
|
||||||
const ticketCategories = await this.ticketsCategoryRepository.find({});
|
const ticketCategories = await this.ticketsCategoryRepository.find({});
|
||||||
@@ -106,6 +113,36 @@ export class TicketsService {
|
|||||||
|
|
||||||
//******************************** */
|
//******************************** */
|
||||||
|
|
||||||
|
private async checkTicketLimit(userId: string, queryRunner: QueryRunner): Promise<void> {
|
||||||
|
const { userSupportPlan } = await this.supportPlansService.getUserSupportPlanOfUser(userId);
|
||||||
|
|
||||||
|
if (!userSupportPlan) throw new BadRequestException(TicketMessageEnum.NO_ACTIVE_SUPPORT_PLAN);
|
||||||
|
|
||||||
|
const ticketLimitFeature = userSupportPlan.supportPlan.features.find(
|
||||||
|
(feature) => feature.featureKey === SupportPlanFeatureKey.TICKET_LIMIT,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!ticketLimitFeature) throw new BadRequestException(TicketMessageEnum.TICKET_LIMIT_NOT_FOUND);
|
||||||
|
|
||||||
|
const ticketLimit = parseInt(ticketLimitFeature.featureValue);
|
||||||
|
if (isNaN(ticketLimit)) return;
|
||||||
|
|
||||||
|
if (isNaN(ticketLimit)) throw new BadRequestException(TicketMessageEnum.INVALID_TICKET_LIMIT);
|
||||||
|
|
||||||
|
const today = dayjs().startOf("day").toDate();
|
||||||
|
|
||||||
|
const ticketCount = await queryRunner.manager.count(this.ticketsRepository.target, {
|
||||||
|
where: {
|
||||||
|
user: { id: userId },
|
||||||
|
createdAt: MoreThanOrEqual(today),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ticketCount >= ticketLimit) throw new BadRequestException(TicketMessageEnum.TICKET_LIMIT_EXCEEDED);
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************** */
|
||||||
|
|
||||||
async createTicket(createDto: CreateTicketDto, userId: string) {
|
async createTicket(createDto: CreateTicketDto, userId: string) {
|
||||||
const queryRunner = this.dataSource.createQueryRunner();
|
const queryRunner = this.dataSource.createQueryRunner();
|
||||||
await queryRunner.connect();
|
await queryRunner.connect();
|
||||||
@@ -122,6 +159,8 @@ export class TicketsService {
|
|||||||
|
|
||||||
if (!ticketCategory) throw new BadRequestException(TicketMessageEnum.CATEGORY_NOT_FOUND);
|
if (!ticketCategory) throw new BadRequestException(TicketMessageEnum.CATEGORY_NOT_FOUND);
|
||||||
|
|
||||||
|
await this.checkTicketLimit(userId, queryRunner);
|
||||||
|
|
||||||
let service = null;
|
let service = null;
|
||||||
if (createDto.danakServiceId) {
|
if (createDto.danakServiceId) {
|
||||||
service = await queryRunner.manager.findOneBy(DanakService, {
|
service = await queryRunner.manager.findOneBy(DanakService, {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { NotificationModule } from "../notifications/notifications.module";
|
|||||||
import { ReferralService } from "./providers/referral.service";
|
import { ReferralService } from "./providers/referral.service";
|
||||||
import { GroupStrategy } from "./strategies/group.strategy";
|
import { GroupStrategy } from "./strategies/group.strategy";
|
||||||
import { RoundRobinStrategy } from "./strategies/round-robin.strategy";
|
import { RoundRobinStrategy } from "./strategies/round-robin.strategy";
|
||||||
|
import { SupportPlansModule } from "../support-plans/support-plans.module";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -25,6 +26,7 @@ import { RoundRobinStrategy } from "./strategies/round-robin.strategy";
|
|||||||
UsersModule,
|
UsersModule,
|
||||||
DanakServicesModule,
|
DanakServicesModule,
|
||||||
NotificationModule,
|
NotificationModule,
|
||||||
|
SupportPlansModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
GroupStrategy,
|
GroupStrategy,
|
||||||
|
|||||||
Reference in New Issue
Block a user