From 0abac00bdec1db5471a4500162b1ae791fb3b996 Mon Sep 17 00:00:00 2001 From: mahyargdz Date: Mon, 3 Mar 2025 09:31:23 +0330 Subject: [PATCH] fix: bug in the customer and tikcet for admin panel --- src/common/enums/message.enum.ts | 1 + .../repositories/invoices.repository.ts | 6 ++- .../tickets/DTO/search-ticket-query.dto.ts | 10 ++++- .../tickets/providers/tickets.service.ts | 35 ++++++++-------- src/modules/tickets/tickets.controller.ts | 2 +- src/modules/users/DTO/search-customers.dto.ts | 20 ++++----- src/modules/users/entities/user.entity.ts | 2 +- src/modules/users/providers/users.service.ts | 41 ++++++++++--------- src/modules/users/users.controller.ts | 15 +++---- 9 files changed, 72 insertions(+), 60 deletions(-) diff --git a/src/common/enums/message.enum.ts b/src/common/enums/message.enum.ts index 608f2e4..c5a3e0c 100755 --- a/src/common/enums/message.enum.ts +++ b/src/common/enums/message.enum.ts @@ -507,6 +507,7 @@ export const enum FinancialMessage { NATIONAL_ID_STRING = "شناسه ملی باید یک رشته باشد", ECONOMIC_CODE_NUMBER_STRING = "کد اقتصادی باید یک رشته عددی باشد", REGISTRATION_ID_NUMBER_STRING = "شناسه ثبت باید یک رشته عددی باشد", + SEARCH_QUERY_MUST_BE_A_STRING = "رشته جستجو باید یک رشته باشد", } export const enum AdminMessage { diff --git a/src/modules/invoices/repositories/invoices.repository.ts b/src/modules/invoices/repositories/invoices.repository.ts index e016589..eca5094 100755 --- a/src/modules/invoices/repositories/invoices.repository.ts +++ b/src/modules/invoices/repositories/invoices.repository.ts @@ -21,7 +21,9 @@ export class InvoicesRepository extends Repository { .leftJoinAndSelect("invoice.user", "user") .leftJoinAndSelect("invoice.items", "items") .leftJoinAndSelect("items.subscriptionPlan", "subscriptionPlan", "subscriptionPlan.id IS NOT NULL") - .leftJoinAndSelect("subscriptionPlan.service", "service", "subscriptionPlan.id IS NOT NULL"); + .leftJoinAndSelect("subscriptionPlan.plan", "plan", "subscriptionPlan.id IS NOT NULL") + .leftJoin("plan.service", "service", "subscriptionPlan.id IS NOT NULL") + .addSelect(["service.name", "service.id"]); if (queryDto.q) { queryBuilder @@ -39,7 +41,7 @@ export class InvoicesRepository extends Repository { } if (queryDto.serviceId) { - queryBuilder.andWhere("subscriptionPlan.serviceId = :serviceId", { serviceId: queryDto.serviceId }); + queryBuilder.andWhere("plan.serviceId = :serviceId", { serviceId: queryDto.serviceId }); } if (queryDto.since) { diff --git a/src/modules/tickets/DTO/search-ticket-query.dto.ts b/src/modules/tickets/DTO/search-ticket-query.dto.ts index 020bc28..8a53620 100755 --- a/src/modules/tickets/DTO/search-ticket-query.dto.ts +++ b/src/modules/tickets/DTO/search-ticket-query.dto.ts @@ -1,12 +1,18 @@ import { ApiPropertyOptional } from "@nestjs/swagger"; -import { IsEnum, IsOptional } from "class-validator"; +import { IsEnum, IsOptional, IsUUID } from "class-validator"; import { PaginationDto } from "../../../common/DTO/pagination.dto"; +import { UserMessage } from "../../../common/enums/message.enum"; import { TicketStatus } from "../enums/ticket-status.enum"; export class SearchTicketQueryDto extends PaginationDto { @IsOptional() @IsEnum(TicketStatus) @ApiPropertyOptional({ enum: TicketStatus, description: "ticket status", example: TicketStatus.PENDING }) - status: TicketStatus; + status?: TicketStatus; + + @IsOptional() + @IsUUID("4", { message: UserMessage.USER_ID_SHOULD_BE_A_UUID }) + @ApiPropertyOptional({ description: "user id", example: "123e4567-e89b-12d3-a456-426614174000" }) + userId?: string; } diff --git a/src/modules/tickets/providers/tickets.service.ts b/src/modules/tickets/providers/tickets.service.ts index a008674..d594af7 100755 --- a/src/modules/tickets/providers/tickets.service.ts +++ b/src/modules/tickets/providers/tickets.service.ts @@ -1,5 +1,5 @@ import { BadRequestException, HttpException, Injectable, InternalServerErrorException, Logger } from "@nestjs/common"; -import { DataSource, FindManyOptions, Not } from "typeorm"; +import { DataSource, Not } from "typeorm"; import { ParamDto } from "../../../common/DTO/param.dto"; import { CommonMessage, TicketMessageEnum, UserMessage } from "../../../common/enums/message.enum"; @@ -220,25 +220,26 @@ export class TicketsService { } //******************************** */ //TODO: get for admin with group of category - async getAllTickets(queryDto: SearchTicketQueryDto) { + async getTicketForAdmin(queryDto: SearchTicketQueryDto) { const { limit, skip } = PaginationUtils(queryDto); - const findOptions: FindManyOptions = { - where: { - ...(queryDto.status && { status: queryDto.status }), - }, - relations: { - category: true, - user: true, - assignedTo: true, - danakService: true, - }, - order: { createdAt: "DESC" as const }, - skip, - take: limit, - }; + const queryBuilder = this.ticketsRepository + .createQueryBuilder("ticket") + .leftJoinAndSelect("ticket.category", "category") + .leftJoinAndSelect("ticket.user", "user") + .leftJoinAndSelect("ticket.assignedTo", "assignedTo") + .leftJoinAndSelect("ticket.danakService", "danakService") + .orderBy("ticket.createdAt", "DESC"); - const [tickets, count] = await this.ticketsRepository.findAndCount(findOptions); + if (queryDto.status) { + queryBuilder.andWhere("ticket.status = :status", { status: queryDto.status }); + } + + if (queryDto.userId) { + queryBuilder.andWhere("user.id = :userId", { userId: queryDto.userId }); + } + + const [tickets, count] = await queryBuilder.skip(skip).take(limit).getManyAndCount(); return { tickets, count, paginate: true }; } diff --git a/src/modules/tickets/tickets.controller.ts b/src/modules/tickets/tickets.controller.ts index 49abdab..70a65dd 100755 --- a/src/modules/tickets/tickets.controller.ts +++ b/src/modules/tickets/tickets.controller.ts @@ -87,7 +87,7 @@ export class TicketsController { @Pagination() @Get("admin") getAllTickets(@Query() queryDto: SearchTicketQueryDto) { - return this.ticketsService.getAllTickets(queryDto); + return this.ticketsService.getTicketForAdmin(queryDto); } @ApiOperation({ summary: "create ticket messages" }) diff --git a/src/modules/users/DTO/search-customers.dto.ts b/src/modules/users/DTO/search-customers.dto.ts index 7e8e13e..1bef363 100755 --- a/src/modules/users/DTO/search-customers.dto.ts +++ b/src/modules/users/DTO/search-customers.dto.ts @@ -1,12 +1,12 @@ -// import { ApiPropertyOptional } from "@nestjs/swagger"; -// import { IsOptional, IsString } from "class-validator"; +import { ApiPropertyOptional } from "@nestjs/swagger"; +import { IsOptional, IsString } from "class-validator"; -// import { PaginationDto } from "../../../common/DTO/pagination.dto"; -// import { FinancialMessage } from "../../../common/enums/message.enum"; +import { PaginationDto } from "../../../common/DTO/pagination.dto"; +import { FinancialMessage } from "../../../common/enums/message.enum"; -// export class SearchCustomersDto extends PaginationDto { -// @IsOptional() -// @IsString({ message: FinancialMessage.SEARCH_QUERY_MUST_BE_A_STRING }) -// @ApiPropertyOptional({ description: "search query", example: "search query" }) -// q: string; -// } +export class SearchCustomersDto extends PaginationDto { + @IsOptional() + @IsString({ message: FinancialMessage.SEARCH_QUERY_MUST_BE_A_STRING }) + @ApiPropertyOptional({ description: "search query", example: "search query" }) + q?: string; +} diff --git a/src/modules/users/entities/user.entity.ts b/src/modules/users/entities/user.entity.ts index ac2e767..df4f523 100755 --- a/src/modules/users/entities/user.entity.ts +++ b/src/modules/users/entities/user.entity.ts @@ -56,7 +56,7 @@ export class User extends BaseEntity { @Column({ type: "boolean", default: false }) emailVerified: boolean; - @Column({ type: "enum", enum: FinancialType, nullable: true }) + @Column({ type: "enum", enum: FinancialType, nullable: true, default: null }) financialType: FinancialType | null; //----------------------------------------- diff --git a/src/modules/users/providers/users.service.ts b/src/modules/users/providers/users.service.ts index 3911773..3751084 100755 --- a/src/modules/users/providers/users.service.ts +++ b/src/modules/users/providers/users.service.ts @@ -26,6 +26,7 @@ import { CreateLegalUserDto } from "../DTO/create-legal-user.dto"; import { CreateRealUserDto } from "../DTO/create-real-user.dto"; import { CreateRoleDto } from "../DTO/create-role.dto"; import { SearchAdminQueryDto } from "../DTO/search-admins-query.dto"; +import { SearchCustomersDto } from "../DTO/search-customers.dto"; import { SearchRolesQueryDto } from "../DTO/search-roles.dto"; import { UpdateProfileDto } from "../DTO/update-profile.dto"; import { CreateUserGroupDto } from "../DTO/user-group.dto"; @@ -398,30 +399,30 @@ export class UsersService { /************************************************************ */ - // async findAllCustomers(queryDto: SearchCustomersDto) { - // const { limit, skip } = PaginationUtils(queryDto); + async getCustomers(queryDto: SearchCustomersDto) { + const { limit, skip } = PaginationUtils(queryDto); - // const queryBuilder = this.userRepository - // .createQueryBuilder("user") - // .leftJoin("user.roles", "role") - // .where("role.name = :roleName", { roleName: RoleEnum.USER }) - // .leftJoin("user.groups", "groups") - // .addSelect(["groups.id", "groups.name"]) - // .loadRelationCountAndMap("user.invoicesCount", "user.invoices") - // .loadRelationCountAndMap("user.subscriptionsCount", "user.subscriptions") - // .loadRelationCountAndMap("user.ticketsCount", "user.tickets"); + const queryBuilder = this.userRepository + .createQueryBuilder("user") + .leftJoin("user.roles", "role") + .where("role.name = :roleName", { roleName: RoleEnum.USER }) + .leftJoin("user.groups", "groups") + .addSelect(["groups.id", "groups.name"]) + .loadRelationCountAndMap("user.invoicesCount", "user.invoices") + .loadRelationCountAndMap("user.subscriptionsCount", "user.subscriptions") + .loadRelationCountAndMap("user.ticketsCount", "user.tickets"); - // if (queryDto.q) { - // queryBuilder - // .orWhere("user.firstName ILIKE :search", { search: `%${queryDto.q}%` }) - // .orWhere("user.lastName ILIKE :search", { search: `%${queryDto.q}%` }) - // .orWhere("user.userName ILIKE :search", { search: `%${queryDto.q}%` }); - // } + if (queryDto.q) { + queryBuilder + .orWhere("user.firstName ILIKE :search", { search: `%${queryDto.q}%` }) + .orWhere("user.lastName ILIKE :search", { search: `%${queryDto.q}%` }) + .orWhere("user.userName ILIKE :search", { search: `%${queryDto.q}%` }); + } - // const [customers, count] = await queryBuilder.skip(skip).take(limit).getManyAndCount(); + const [customers, count] = await queryBuilder.skip(skip).take(limit).getManyAndCount(); - // return { customers, count }; - // } + return { customers, count }; + } /************************************************************ */ diff --git a/src/modules/users/users.controller.ts b/src/modules/users/users.controller.ts index 3d4e2f2..cf1ccf1 100755 --- a/src/modules/users/users.controller.ts +++ b/src/modules/users/users.controller.ts @@ -9,6 +9,7 @@ import { CreateLegalUserDto } from "./DTO/create-legal-user.dto"; import { CreateRealUserDto } from "./DTO/create-real-user.dto"; import { CreateRoleDto } from "./DTO/create-role.dto"; import { SearchAdminQueryDto } from "./DTO/search-admins-query.dto"; +import { SearchCustomersDto } from "./DTO/search-customers.dto"; import { SearchRolesQueryDto } from "./DTO/search-roles.dto"; import { UpdateProfileDto } from "./DTO/update-profile.dto"; import { CreateUserGroupDto } from "./DTO/user-group.dto"; @@ -117,13 +118,13 @@ export class UsersController { return this.usersService.findAllUsers(); } - // @ApiOperation({ summary: "get all customers ==> admin route" }) - // @AuthGuards() - // @PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS) - // @Get("customers") - // customers(@Query() queryDto: SearchCustomersDto) { - // return this.usersService.findAllCustomers(queryDto); - // } + @ApiOperation({ summary: "get all customers ==> admin route" }) + @AuthGuards() + @PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS) + @Get("customers") + getCustomers(@Query() queryDto: SearchCustomersDto) { + return this.usersService.getCustomers(queryDto); + } @ApiOperation({ summary: "get all customers ==> admin route" }) @AuthGuards()