diff --git a/src/modules/order/controllers/order.controller.ts b/src/modules/order/controllers/order.controller.ts index 16df8ff..2be5043 100644 --- a/src/modules/order/controllers/order.controller.ts +++ b/src/modules/order/controllers/order.controller.ts @@ -61,6 +61,13 @@ export class OrderController { return this.orderService.findOrdersAsAdmin(adminId, dto); } + @Get('admin/orders/tab-counts') + @UseGuards(AdminAuthGuard) + @ApiOperation({ summary: 'Get order tab counts for admin order list' }) + getAdminOrderTabCounts(@Query() dto: FindOrdersDto, @AdminId() adminId: string) { + return this.orderService.getAdminOrderTabCounts(adminId, dto); + } + @Get('admin/orders/:id') @UseGuards(AdminAuthGuard) @Permissions(PermissionEnum.VIEW_ORDERS) diff --git a/src/modules/order/providers/order.service.ts b/src/modules/order/providers/order.service.ts index 600b5ec..bdb831c 100644 --- a/src/modules/order/providers/order.service.ts +++ b/src/modules/order/providers/order.service.ts @@ -30,6 +30,27 @@ import { OrderCreatedEvent } from '../events/order.events'; import { InvoiceConfirmStatusEnum } from 'src/modules/invoice/enum/invoice-confirm-status.enum'; import { ChattService } from 'src/modules/chat/providers/chat.service'; +type AdminOrderTabCounts = { + inProgress: number; + finished: number; + canceled: number; + invoiced: number; +}; + +const IN_PROGRESS_STATUSES: OrderStatusEnum[] = [ + OrderStatusEnum.CREATED, + OrderStatusEnum.DESIGN_INITIATED, + OrderStatusEnum.DESIGN_FINISHED, + OrderStatusEnum.DESIGN_REVISION, + OrderStatusEnum.READY_TO_PRINTING, + OrderStatusEnum.IN_PRINTING, + OrderStatusEnum.READY_FOR_DELIVERY, + OrderStatusEnum.DELIVERED, + OrderStatusEnum.AFTER_PRINT_COVER, + OrderStatusEnum.AFTER_PRINT_BOXING, + OrderStatusEnum.AFTER_PRINT_CARTONING, +]; + @Injectable() export class OrderService { private readonly logger = new Logger(OrderService.name); @@ -159,6 +180,49 @@ export class OrderService { } } + async getAdminOrderTabCounts(adminId: string, dto: FindOrdersDto): Promise { + const permissions = await this.adminService.ownedPermissions(adminId, [ + PermissionEnum.VIEW_ORDERS, + PermissionEnum.VIEW_ASSIGNED_ORDERS, + ]); + + const canViewAnyOrder = permissions.includes(PermissionEnum.VIEW_ORDERS); + const canViewAssignedOrder = permissions.includes(PermissionEnum.VIEW_ASSIGNED_ORDERS); + + if (!canViewAnyOrder && !canViewAssignedOrder) { + throw new ForbiddenException("You don't have permission to view orders"); + } + + const baseFilter: FindOrdersDto = { + ...dto, + designerId: + canViewAnyOrder + ? dto.designerId + : adminId, + }; + + const [inProgress, finished, canceled, invoiced] = await Promise.all([ + this.orderRepository.countByFilters({ + ...baseFilter, + statuses: IN_PROGRESS_STATUSES, + }), + this.orderRepository.countByFilters({ + ...baseFilter, + statuses: [OrderStatusEnum.FINISHED], + }), + this.orderRepository.countByFilters({ + ...baseFilter, + statuses: [OrderStatusEnum.CANCELED], + }), + this.orderRepository.countByFilters({ + ...baseFilter, + statuses: [OrderStatusEnum.INVOICED], + }), + ]); + + return { inProgress, finished, canceled, invoiced }; + } + async getOrderAsUser(userId: string, orderId: string): Promise { const order = await this.findOrderOrFail(orderId) if (order.user.id !== userId) { @@ -254,18 +318,9 @@ export class OrderService { return order; } - const inProgressStatuses = [ - OrderStatusEnum.DESIGN_INITIATED, - OrderStatusEnum.DESIGN_FINISHED, - OrderStatusEnum.DESIGN_REVISION, - OrderStatusEnum.READY_TO_PRINTING, - OrderStatusEnum.IN_PRINTING, - OrderStatusEnum.READY_FOR_DELIVERY, - OrderStatusEnum.DELIVERED, - OrderStatusEnum.AFTER_PRINT_COVER, - OrderStatusEnum.AFTER_PRINT_BOXING, - OrderStatusEnum.AFTER_PRINT_CARTONING, - ]; + const inProgressStatuses: OrderStatusEnum[] = IN_PROGRESS_STATUSES.filter( + (status) => status !== OrderStatusEnum.CREATED, + ); const canChangeToCancelled = toStatus === OrderStatusEnum.CANCELED && diff --git a/src/modules/order/repositories/order.repository.ts b/src/modules/order/repositories/order.repository.ts index 90a707e..62b7e73 100644 --- a/src/modules/order/repositories/order.repository.ts +++ b/src/modules/order/repositories/order.repository.ts @@ -12,23 +12,8 @@ export class OrderRepository extends EntityRepository { super(em, Order); } - async findAllPaginated(opts: FindOrdersDto): Promise> { - const { - page = 1, - limit = 10, - statuses, - search, - orderBy = 'createdAt', - order = 'desc', - userId, - from, - to, - categoryId, - designerId, - } = opts; - - const offset = (page - 1) * limit; - + private buildWhere(opts: FindOrdersDto): FilterQuery { + const { statuses, search, userId, from, to, categoryId, designerId } = opts; const where: FilterQuery = {}; // Filter by statuses @@ -89,6 +74,14 @@ export class OrderRepository extends EntityRepository { where.$or = searchConditions; } + return where; + } + + async findAllPaginated(opts: FindOrdersDto): Promise> { + const { page = 1, limit = 10, orderBy = 'createdAt', order = 'desc' } = opts; + const offset = (page - 1) * limit; + const where = this.buildWhere(opts); + // First, fetch orders without reviews const [data, total] = await this.findAndCount(where, { limit, @@ -110,4 +103,9 @@ export class OrderRepository extends EntityRepository { }, }; } + + async countByFilters(opts: FindOrdersDto): Promise { + const where = this.buildWhere(opts); + return this.count(where); + } }