From f0eae8034238ba3d2735ed61680d8c3c83f89bc0 Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Mon, 5 Jan 2026 20:40:18 +0330 Subject: [PATCH] add : subscription list --- .../DTO/admin-user-subscriptions-query.dto.ts | 53 +++++++++++++++++ .../providers/subscriptions.service.ts | 57 +++++++++++++++++++ .../subscriptions/subscriptions.controller.ts | 8 +++ 3 files changed, 118 insertions(+) create mode 100644 src/modules/subscriptions/DTO/admin-user-subscriptions-query.dto.ts diff --git a/src/modules/subscriptions/DTO/admin-user-subscriptions-query.dto.ts b/src/modules/subscriptions/DTO/admin-user-subscriptions-query.dto.ts new file mode 100644 index 0000000..64f7ab0 --- /dev/null +++ b/src/modules/subscriptions/DTO/admin-user-subscriptions-query.dto.ts @@ -0,0 +1,53 @@ +import { ApiPropertyOptional } from "@nestjs/swagger"; +import { Type } from "class-transformer"; +import { IsEnum, IsOptional, IsString, IsUUID } from "class-validator"; + +import { PaginationDto } from "../../../common/DTO/pagination.dto"; +import { SubscriptionMessage } from "../../../common/enums/message.enum"; +import { SubscriptionStatus } from "../enums/subscription-status.enum"; + +export class AdminUserSubscriptionsQueryDto extends PaginationDto { + @IsOptional() + @IsString({ message: SubscriptionMessage.SEARCH_QUERY_STRING }) + @ApiPropertyOptional({ description: "Search query (business name, description, etc.)" }) + q?: string; + + @IsOptional() + @IsUUID() + @ApiPropertyOptional({ description: "Filter by user ID" }) + userId?: string; + + @IsOptional() + @IsUUID() + @ApiPropertyOptional({ description: "Filter by service ID" }) + serviceId?: string; + + @IsOptional() + @IsEnum(SubscriptionStatus) + @ApiPropertyOptional({ + description: "Filter by subscription status", + + enum: SubscriptionStatus + }) + status?: SubscriptionStatus; + + @IsOptional() + @Type(() => Date) + @ApiPropertyOptional({ description: "Filter by start date (from)", }) + startDateFrom?: Date; + + @IsOptional() + @Type(() => Date) + @ApiPropertyOptional({ description: "Filter by start date (to)" }) + startDateTo?: Date; + + @IsOptional() + @Type(() => Date) + @ApiPropertyOptional({ description: "Filter by end date (from)", }) + endDateFrom?: Date; + + @IsOptional() + @Type(() => Date) + @ApiPropertyOptional({ description: "Filter by end date (to)", }) + endDateTo?: Date; +} diff --git a/src/modules/subscriptions/providers/subscriptions.service.ts b/src/modules/subscriptions/providers/subscriptions.service.ts index a22693e..e7c9b0f 100755 --- a/src/modules/subscriptions/providers/subscriptions.service.ts +++ b/src/modules/subscriptions/providers/subscriptions.service.ts @@ -16,6 +16,7 @@ import { UsersService } from "../../users/providers/users.service"; import { PaginationUtils } from "../../utils/providers/pagination.utils"; import { SUBSCRIPTIONS } from "../constants"; import { AddSubscriptionsToServiceDto } from "../DTO/create-subscription.dto"; +import { AdminUserSubscriptionsQueryDto } from "../DTO/admin-user-subscriptions-query.dto"; import { SearchUserSubsQueryDto } from "../DTO/search-user-subs-query.dto"; import { ServiceSubsQueryDto } from "../DTO/service-subs-query.dto"; import { ExtendUSerSubscribeServiceDto, SubscribeServiceDto } from "../DTO/subscribe-service.dto"; @@ -589,5 +590,61 @@ export class SubscriptionsService { ); } + //************************************ */ + async getAllUserSubscriptions(queryDto: AdminUserSubscriptionsQueryDto) { + const { limit, skip } = PaginationUtils(queryDto); + + const queryBuilder = this.userSubscriptionsRepository + .createQueryBuilder("userSubscription") + .leftJoinAndSelect("userSubscription.user", "user") + .leftJoinAndSelect("userSubscription.plan", "plan") + .leftJoinAndSelect("plan.service", "service"); + + if (queryDto.q) { + queryBuilder.andWhere( + "(userSubscription.businessName ILIKE :query OR userSubscription.description ILIKE :query OR user.email ILIKE :query OR user.firstName ILIKE :query OR user.lastName ILIKE :query OR service.name ILIKE :query OR service.title ILIKE :query)", + { query: `%${queryDto.q}%` } + ); + } + + if (queryDto.userId) { + queryBuilder.andWhere("user.id = :userId", { userId: queryDto.userId }); + } + + if (queryDto.serviceId) { + queryBuilder.andWhere("service.id = :serviceId", { serviceId: queryDto.serviceId }); + } + + if (queryDto.status) { + queryBuilder.andWhere("userSubscription.status = :status", { status: queryDto.status }); + } + + if (queryDto.startDateFrom) { + queryBuilder.andWhere("userSubscription.startDate >= :startDateFrom", { startDateFrom: queryDto.startDateFrom }); + } + + if (queryDto.startDateTo) { + queryBuilder.andWhere("userSubscription.startDate <= :startDateTo", { startDateTo: queryDto.startDateTo }); + } + + if (queryDto.endDateFrom) { + queryBuilder.andWhere("userSubscription.endDate >= :endDateFrom", { endDateFrom: queryDto.endDateFrom }); + } + + if (queryDto.endDateTo) { + queryBuilder.andWhere("userSubscription.endDate <= :endDateTo", { endDateTo: queryDto.endDateTo }); + } + + queryBuilder.orderBy("userSubscription.createdAt", "DESC"); + + const [userSubscriptions, count] = await queryBuilder.skip(skip).take(limit).getManyAndCount(); + + return { + userSubscriptions, + count, + pagination: true, + }; + } + //************************************ */ } diff --git a/src/modules/subscriptions/subscriptions.controller.ts b/src/modules/subscriptions/subscriptions.controller.ts index 6342489..fce5cc7 100755 --- a/src/modules/subscriptions/subscriptions.controller.ts +++ b/src/modules/subscriptions/subscriptions.controller.ts @@ -2,6 +2,7 @@ import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query } from "@ import { ApiOperation } from "@nestjs/swagger"; import { AddSubscriptionsToServiceDto } from "./DTO/create-subscription.dto"; +import { AdminUserSubscriptionsQueryDto } from "./DTO/admin-user-subscriptions-query.dto"; import { SearchUserSubsQueryDto } from "./DTO/search-user-subs-query.dto"; import { ServiceIdParamDto } from "./DTO/service-id.param.dto"; import { ServiceSubsQueryDto } from "./DTO/service-subs-query.dto"; @@ -132,4 +133,11 @@ export class SubscriptionsController { getUserServiceAccess(@Param() serviceIdParamDto: ServiceIdParamDto, @UserDec("id") userId: string) { return this.subscriptionService.getUserSubscriptionsForService(userId, serviceIdParamDto.serviceId); } + + @ApiOperation({ summary: "get all user subscriptions with pagination and filters ==> admin route" }) + @PermissionsDec(PermissionEnum.SERVICES) + @Get("admin/user-subscriptions/all") + getAllUserSubscriptions(@Query() queryDto: AdminUserSubscriptionsQueryDto) { + return this.subscriptionService.getAllUserSubscriptions(queryDto); + } }