update: add since to the query of invoice for admin
This commit is contained in:
@@ -391,6 +391,7 @@ export const enum InvoiceMessage {
|
|||||||
DISCOUNT_CANCELLED = "تخفیف با موفقیت لغو شد",
|
DISCOUNT_CANCELLED = "تخفیف با موفقیت لغو شد",
|
||||||
INVOICE_IS_REJECTED = "فاکتور قبلا رد شده است",
|
INVOICE_IS_REJECTED = "فاکتور قبلا رد شده است",
|
||||||
INVOICE_CAN_NOT_PAID = "فاکتور قابل پرداخت نیست",
|
INVOICE_CAN_NOT_PAID = "فاکتور قابل پرداخت نیست",
|
||||||
|
INVALID_DATE = "تاریخ وارد شده معتبر نیست",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum LearningMessage {
|
export const enum LearningMessage {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ApiPropertyOptional, PickType } from "@nestjs/swagger";
|
import { ApiPropertyOptional, PickType } from "@nestjs/swagger";
|
||||||
import { IsEnum, IsOptional, IsString, IsUUID } from "class-validator";
|
import { IsDateString, IsEnum, IsOptional, IsString, IsUUID } from "class-validator";
|
||||||
|
|
||||||
import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
||||||
import { InvoiceMessage, ServiceMessage, UserMessage } from "../../../common/enums/message.enum";
|
import { InvoiceMessage, ServiceMessage, UserMessage } from "../../../common/enums/message.enum";
|
||||||
@@ -9,22 +9,27 @@ export class InvoicesSearchQueryDto extends PaginationDto {
|
|||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString({ message: InvoiceMessage.SEARCH_QUERY_MUST_BE_A_STRING })
|
@IsString({ message: InvoiceMessage.SEARCH_QUERY_MUST_BE_A_STRING })
|
||||||
@ApiPropertyOptional({ description: "search query", example: "search query" })
|
@ApiPropertyOptional({ description: "search query", example: "search query" })
|
||||||
q: string;
|
q?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsUUID("4", { message: ServiceMessage.SERVICE_ID_SHOULD_BE_A_UUID })
|
@IsUUID("4", { message: ServiceMessage.SERVICE_ID_SHOULD_BE_A_UUID })
|
||||||
@ApiPropertyOptional({ description: "service id", example: "123e4567-e89b-12d3-a456-426614174000" })
|
@ApiPropertyOptional({ description: "service id", example: "123e4567-e89b-12d3-a456-426614174000" })
|
||||||
serviceId: string;
|
serviceId?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsUUID("4", { message: UserMessage.USER_ID_SHOULD_BE_A_UUID })
|
@IsUUID("4", { message: UserMessage.USER_ID_SHOULD_BE_A_UUID })
|
||||||
@ApiPropertyOptional({ description: "user id", example: "123e4567-e89b-12d3-a456-426614174000" })
|
@ApiPropertyOptional({ description: "user id", example: "123e4567-e89b-12d3-a456-426614174000" })
|
||||||
userId: string;
|
userId?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsEnum(InvoiceStatus)
|
@IsEnum(InvoiceStatus)
|
||||||
@ApiPropertyOptional({ enum: InvoiceStatus, description: "invoice status", example: InvoiceStatus.PAID })
|
@ApiPropertyOptional({ enum: InvoiceStatus, description: "invoice status", example: InvoiceStatus.PAID })
|
||||||
status: InvoiceStatus;
|
status?: InvoiceStatus;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsDateString({}, { message: InvoiceMessage.INVALID_DATE })
|
||||||
|
@ApiPropertyOptional({ description: "since query", example: "2025-01-27" })
|
||||||
|
since?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UserInvoicesSearchQueryDto extends PickType(InvoicesSearchQueryDto, ["status", "limit", "page"]) {}
|
export class UserInvoicesSearchQueryDto extends PickType(InvoicesSearchQueryDto, ["status", "limit", "page"]) {}
|
||||||
|
|||||||
@@ -161,42 +161,17 @@ export class InvoicesService {
|
|||||||
///********************************** */
|
///********************************** */
|
||||||
|
|
||||||
async getInvoices(queryDto: InvoicesSearchQueryDto) {
|
async getInvoices(queryDto: InvoicesSearchQueryDto) {
|
||||||
const { limit, skip } = PaginationUtils(queryDto);
|
const [invoices, count] = await this.invoiceRepository.getInvoicesForAdmin(queryDto);
|
||||||
|
|
||||||
const queryBuilder = this.invoiceRepository.createQueryBuilder("invoice");
|
const usersWithInvoices = await this.invoiceRepository
|
||||||
|
.createQueryBuilder("invoice")
|
||||||
queryBuilder
|
|
||||||
.leftJoinAndSelect("invoice.user", "user")
|
.leftJoinAndSelect("invoice.user", "user")
|
||||||
.leftJoinAndSelect("invoice.items", "items")
|
.select(["user.id", "user.firstName", "user.lastName", "user.email"])
|
||||||
.leftJoinAndSelect("items.subscriptionPlan", "subscriptionPlan", "subscriptionPlan.id IS NOT NULL")
|
.distinctOn(["user.id"])
|
||||||
.leftJoinAndSelect("subscriptionPlan.service", "service", "subscriptionPlan.id IS NOT NULL");
|
.getMany();
|
||||||
|
|
||||||
if (queryDto.q) {
|
|
||||||
queryBuilder
|
|
||||||
.orWhere("user.firstName ILIKE :search", { search: `%${queryDto.q}%` })
|
|
||||||
.orWhere("user.lastName ILIKE :search", { search: `%${queryDto.q}%` })
|
|
||||||
.orWhere("user.email ILIKE :search", { search: `%${queryDto.q}%` });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queryDto.status) {
|
|
||||||
queryBuilder.andWhere("invoice.status = :status", { status: queryDto.status });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queryDto.userId) {
|
|
||||||
queryBuilder.andWhere("invoice.user.id = :userId", { userId: queryDto.userId });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queryDto.serviceId) {
|
|
||||||
queryBuilder.andWhere("subscriptionPlan.serviceId = :serviceId", { serviceId: queryDto.serviceId });
|
|
||||||
}
|
|
||||||
|
|
||||||
queryBuilder.orderBy("invoice.createdAt", "DESC");
|
|
||||||
queryBuilder.skip(skip);
|
|
||||||
queryBuilder.take(limit);
|
|
||||||
|
|
||||||
const [invoices, count] = await queryBuilder.getManyAndCount();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
users: usersWithInvoices.map((inv) => inv.user),
|
||||||
invoices,
|
invoices,
|
||||||
count,
|
count,
|
||||||
paginate: true,
|
paginate: true,
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { Injectable } from "@nestjs/common";
|
|||||||
import { InjectRepository } from "@nestjs/typeorm";
|
import { InjectRepository } from "@nestjs/typeorm";
|
||||||
import { Repository } from "typeorm";
|
import { Repository } from "typeorm";
|
||||||
|
|
||||||
|
import { PaginationUtils } from "../../utils/providers/pagination.utils";
|
||||||
|
import { InvoicesSearchQueryDto } from "../DTO/invoices-search-query.dto";
|
||||||
import { Invoice } from "../entities/invoice.entity";
|
import { Invoice } from "../entities/invoice.entity";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -9,4 +11,47 @@ export class InvoicesRepository extends Repository<Invoice> {
|
|||||||
constructor(@InjectRepository(Invoice) invoicesRepository: Repository<Invoice>) {
|
constructor(@InjectRepository(Invoice) invoicesRepository: Repository<Invoice>) {
|
||||||
super(invoicesRepository.target, invoicesRepository.manager, invoicesRepository.queryRunner);
|
super(invoicesRepository.target, invoicesRepository.manager, invoicesRepository.queryRunner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getInvoicesForAdmin(queryDto: InvoicesSearchQueryDto) {
|
||||||
|
const { limit, skip } = PaginationUtils(queryDto);
|
||||||
|
|
||||||
|
const queryBuilder = this.createQueryBuilder("invoice");
|
||||||
|
|
||||||
|
queryBuilder
|
||||||
|
.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");
|
||||||
|
|
||||||
|
if (queryDto.q) {
|
||||||
|
queryBuilder
|
||||||
|
.orWhere("user.firstName ILIKE :search", { search: `%${queryDto.q}%` })
|
||||||
|
.orWhere("user.lastName ILIKE :search", { search: `%${queryDto.q}%` })
|
||||||
|
.orWhere("user.email ILIKE :search", { search: `%${queryDto.q}%` });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryDto.status) {
|
||||||
|
queryBuilder.andWhere("invoice.status = :status", { status: queryDto.status });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryDto.userId) {
|
||||||
|
queryBuilder.andWhere("invoice.user.id = :userId", { userId: queryDto.userId });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryDto.serviceId) {
|
||||||
|
queryBuilder.andWhere("subscriptionPlan.serviceId = :serviceId", { serviceId: queryDto.serviceId });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryDto.since) {
|
||||||
|
queryBuilder.andWhere("(invoice.createdAt >= :since OR invoice.dueDate >= :since OR invoice.paidAt >= :since)", {
|
||||||
|
since: new Date(queryDto.since),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
queryBuilder.orderBy("invoice.createdAt", "DESC");
|
||||||
|
queryBuilder.skip(skip);
|
||||||
|
queryBuilder.take(limit);
|
||||||
|
|
||||||
|
return await queryBuilder.getManyAndCount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user