From 6e8e2cd5273aca6f6965f5ef4a77d26165c1e514 Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Wed, 15 Apr 2026 15:37:40 +0330 Subject: [PATCH] reseller : update --- src/common/decorators/reseller.decorator.ts | 3 +- src/modules/auth/guards/reseller.guard.ts | 11 +-- .../referrals/providers/referrals.service.ts | 4 +- .../referral-rewards.repository.ts | 4 +- ...dto.ts => search-withdraw-requests.dto.ts} | 2 +- .../withdraw-request.repository.ts | 8 +-- src/modules/reseller/reseller.controller.ts | 71 +++++++++++-------- src/modules/reseller/reseller.service.ts | 44 ++++++++++-- 8 files changed, 98 insertions(+), 49 deletions(-) rename src/modules/reseller/dto/{search-reward-requests.dto.ts => search-withdraw-requests.dto.ts} (52%) diff --git a/src/common/decorators/reseller.decorator.ts b/src/common/decorators/reseller.decorator.ts index 089073b..4d80c7f 100755 --- a/src/common/decorators/reseller.decorator.ts +++ b/src/common/decorators/reseller.decorator.ts @@ -1,4 +1,5 @@ export const RESELLER_ROUTE = "shouldReseller"; import { SetMetadata } from "@nestjs/common"; +import { ResellerType } from "../../modules/auth/DTO/verify-reseller-otp.dto"; -export const ResellerRoute = (isResellerRoute: boolean = true) => SetMetadata(RESELLER_ROUTE, isResellerRoute); +export const ResellerRoute = (type:ResellerType[]) => SetMetadata(RESELLER_ROUTE, type); diff --git a/src/modules/auth/guards/reseller.guard.ts b/src/modules/auth/guards/reseller.guard.ts index 4477a53..0587364 100755 --- a/src/modules/auth/guards/reseller.guard.ts +++ b/src/modules/auth/guards/reseller.guard.ts @@ -4,6 +4,7 @@ import { FastifyRequest } from "fastify"; import { AuthMessage } from "../../../common/enums/message.enum"; import { Reflector } from "@nestjs/core"; import { RESELLER_ROUTE } from "../../../common/decorators/reseller.decorator"; +import { ResellerType } from "../DTO/verify-reseller-otp.dto"; @Injectable() export class ResellerRouteGuard implements CanActivate { @@ -11,18 +12,20 @@ export class ResellerRouteGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { - const requiredReseller = this.reflector.getAllAndOverride(RESELLER_ROUTE, + const allowedTypes = this.reflector.getAllAndOverride(RESELLER_ROUTE, [context.getHandler(), context.getClass()]); - if (!requiredReseller) return true; + console.log(allowedTypes) + + if (!allowedTypes) return true; const req = context.switchToHttp().getRequest(); const user = req.user; - if (!user) throw new ForbiddenException(AuthMessage.UNAUTHORIZED_ACCESS); + if (!user || !user.resellerType) throw new ForbiddenException(AuthMessage.UNAUTHORIZED_ACCESS); - if (!user.resellerType) throw new ForbiddenException(AuthMessage.UNAUTHORIZED_ACCESS); + if (!allowedTypes.includes(user.resellerType)) throw new ForbiddenException(AuthMessage.UNAUTHORIZED_ACCESS); return true; } diff --git a/src/modules/referrals/providers/referrals.service.ts b/src/modules/referrals/providers/referrals.service.ts index 6d58b93..537d2f8 100755 --- a/src/modules/referrals/providers/referrals.service.ts +++ b/src/modules/referrals/providers/referrals.service.ts @@ -12,7 +12,7 @@ import { ReferralCodesRepository } from "../repositories/referral-codes.reposito import { ReferralRewardsRepository } from "../repositories/referral-rewards.repository"; import { ReferralsRepository } from "../repositories/referrals.repository"; import { SearchCustomersDto } from "../../users/DTO/search-customers.dto"; -import { SearchRewardsRequestQueryDto } from "../../reseller/dto/search-reward-requests.dto"; +import { SearchWithdrawRequestQueryDto } from "../../reseller/dto/search-withdraw-requests.dto"; @Injectable() export class ReferralsService { private MAX_ATTEMPTS = 10; @@ -150,7 +150,7 @@ export class ReferralsService { //*********************************** */ - async findRewards(userIds: string[], query: SearchRewardsRequestQueryDto) { + async findRewards(userIds: string[], query: SearchWithdrawRequestQueryDto) { const [data, count] = await this.referralRewardsRepository.findPaginatedList(userIds, query); diff --git a/src/modules/referrals/repositories/referral-rewards.repository.ts b/src/modules/referrals/repositories/referral-rewards.repository.ts index 268ddf2..4848d20 100755 --- a/src/modules/referrals/repositories/referral-rewards.repository.ts +++ b/src/modules/referrals/repositories/referral-rewards.repository.ts @@ -4,7 +4,7 @@ import { Repository } from "typeorm"; import { ReferralReward } from "../entities/referral-reward.entity"; import { PaginationUtils } from "../../utils/providers/pagination.utils"; -import { SearchRewardsRequestQueryDto } from "../../reseller/dto/search-reward-requests.dto"; +import { SearchWithdrawRequestQueryDto } from "../../reseller/dto/search-withdraw-requests.dto"; @Injectable() export class ReferralRewardsRepository extends Repository { @@ -12,7 +12,7 @@ export class ReferralRewardsRepository extends Repository { super(repository.target, repository.manager, repository.queryRunner); } - async findPaginatedList(userIds: string[], queryDto: SearchRewardsRequestQueryDto) { + async findPaginatedList(userIds: string[], queryDto: SearchWithdrawRequestQueryDto) { const { limit, skip } = PaginationUtils(queryDto); console.log(userIds) const qb = this.createQueryBuilder("rr") diff --git a/src/modules/reseller/dto/search-reward-requests.dto.ts b/src/modules/reseller/dto/search-withdraw-requests.dto.ts similarity index 52% rename from src/modules/reseller/dto/search-reward-requests.dto.ts rename to src/modules/reseller/dto/search-withdraw-requests.dto.ts index 6613c89..8bb0a9b 100644 --- a/src/modules/reseller/dto/search-reward-requests.dto.ts +++ b/src/modules/reseller/dto/search-withdraw-requests.dto.ts @@ -1,5 +1,5 @@ import { PaginationDto } from "../../../common/DTO/pagination.dto"; -export class SearchRewardsRequestQueryDto extends PaginationDto { +export class SearchWithdrawRequestQueryDto extends PaginationDto { } diff --git a/src/modules/reseller/repositories/withdraw-request.repository.ts b/src/modules/reseller/repositories/withdraw-request.repository.ts index d81eda3..6c063bd 100755 --- a/src/modules/reseller/repositories/withdraw-request.repository.ts +++ b/src/modules/reseller/repositories/withdraw-request.repository.ts @@ -2,7 +2,7 @@ import { Injectable } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { Repository } from "typeorm"; import { RewardWithdrawRequest } from "../entities/rewards-withdraw-request.entity"; -import { SearchRewardsRequestQueryDto } from "../dto/search-reward-requests.dto"; +import { SearchWithdrawRequestQueryDto } from "../dto/search-withdraw-requests.dto"; import { PaginationUtils } from "../../utils/providers/pagination.utils"; @Injectable() @@ -11,7 +11,7 @@ export class WithdrawRequestRepository extends Repository super(repository.target, repository.manager, repository.queryRunner); } - async findPaginatedListForAdmin(queryDto: SearchRewardsRequestQueryDto) { + async findPaginatedListForAdmin(queryDto: SearchWithdrawRequestQueryDto) { const { limit, skip } = PaginationUtils(queryDto); const queryBuilder = this.createQueryBuilder("request") @@ -21,13 +21,13 @@ export class WithdrawRequestRepository extends Repository return queryBuilder.skip(skip).take(limit).getManyAndCount(); } - async findPaginatedList(userId: string, queryDto: SearchRewardsRequestQueryDto) { + async findPaginatedList(userId: string, queryDto: SearchWithdrawRequestQueryDto) { const { limit, skip } = PaginationUtils(queryDto); const queryBuilder = this.createQueryBuilder("request") .where("request.user.id = :userId", { userId }) .leftJoinAndSelect("request.user", "user") - .orderBy("ticket.createdAt", "DESC"); + .orderBy("request.createdAt", "DESC"); return queryBuilder.skip(skip).take(limit).getManyAndCount(); } diff --git a/src/modules/reseller/reseller.controller.ts b/src/modules/reseller/reseller.controller.ts index 49ea9c9..050c6fc 100644 --- a/src/modules/reseller/reseller.controller.ts +++ b/src/modules/reseller/reseller.controller.ts @@ -9,13 +9,14 @@ import { AdminRoute } from '../../common/decorators/admin.decorator'; import { ResellerRoute } from '../../common/decorators/reseller.decorator'; import { UserDec } from '../../common/decorators/user.decorator'; import { CreateResellerAgentDto } from './dto/create-reseller-agent.dto'; -import { SearchRewardsRequestQueryDto } from './dto/search-reward-requests.dto'; +import { SearchWithdrawRequestQueryDto } from './dto/search-withdraw-requests.dto'; import { SearchCustomersDto } from '../users/DTO/search-customers.dto'; import { SearchResellerInvoicesQueryDto } from './dto/search-reseller-invoices.dto'; import { PaginationDto } from '../../common/DTO/pagination.dto'; import { WalletsService } from '../wallets/providers/wallets.service'; import { CreateWithdrawRequestDto } from './dto/create-withdraw-request.dto'; import { CreateUserBankAccountDto } from './dto/create-user-bank-account.dto'; +import { ResellerType } from '../auth/DTO/verify-reseller-otp.dto'; @Controller('reseller') @AuthGuards() @@ -25,7 +26,7 @@ export class ResellerController { private readonly walletsService: WalletsService, ) { } - + //***************** DSC Endpoints **************** */ @ApiOperation({ summary: "create Reseller ==> admin route" }) @AdminRoute() @PermissionsDec(PermissionEnum.RESELLER) @@ -52,24 +53,26 @@ export class ResellerController { return this.resellerService.findAll() } + // ************** Reseller Panel Endpoints *********** + // =========== Reseller-->Agent ============= @ApiOperation({ summary: "get Reseller agents ==> reseller route" }) - @ResellerRoute() + @ResellerRoute([ResellerType.agent, ResellerType.reseller]) @Get('agents') getResellerAgents(@UserDec("id") userId: string) { return this.resellerService.finResellerAgents(userId) } @ApiOperation({ summary: "Create Reseller agent ==> reseller route" }) - @ResellerRoute() + @ResellerRoute([ResellerType.reseller]) @Post('agents') createResellerAgent(@UserDec("id") userId: string, @Body() dto: CreateResellerAgentDto) { return this.resellerService.createResellerAgent(userId, dto.phone) } @ApiOperation({ summary: "Remove Reseller agent ==> reseller route" }) - @ResellerRoute() + @ResellerRoute([ResellerType.reseller]) @Delete('agents/:agentId') deleteResellerAgent(@UserDec("id") userId: string, @Param('agentId') agentId: string) { return this.resellerService.removeResellerAgent(userId, agentId) @@ -77,31 +80,39 @@ export class ResellerController { // ============ Customers ============= @ApiOperation({ summary: "get Reseller Customers ==> reseller route" }) - @ResellerRoute() + @ResellerRoute([ResellerType.reseller]) @Get('customers') getCustomers(@UserDec("id") userId: string, @Query() dto: SearchCustomersDto) { return this.resellerService.findResellerCustomers(userId, dto) } - // ============ Invoice ============= + // ============ Invoice =============ok @ApiOperation({ summary: "get Reseller Customers Invoices==> reseller route" }) - @ResellerRoute() + @ResellerRoute([ResellerType.agent, ResellerType.reseller]) @Get('invoices') - getCustomerInvoices(@UserDec("id") userId: string, @Query() query: SearchResellerInvoicesQueryDto) { - return this.resellerService.findResellerCustomersInvoices(userId, query) + getCustomerInvoices( + @UserDec("id") userId: string, + @Query() query: SearchResellerInvoicesQueryDto, + @UserDec("resellerType") type: ResellerType + ) { + return this.resellerService.findInvoices(userId, type, query) } // ============ Rewards ============= @ApiOperation({ summary: "get Reseller Agents Rewards==> reseller route" }) - @ResellerRoute() + @ResellerRoute([ResellerType.agent, ResellerType.reseller]) @Get('rewards') - getResellerAgentsRewards(@UserDec("id") userId: string, @Query() query: SearchRewardsRequestQueryDto) { - return this.resellerService.findResellerAgentsRewards(userId, query) + getResellerAgentsRewards( + @UserDec("id") userId: string, + @Query() query: SearchWithdrawRequestQueryDto, + @UserDec("resellerType") type: ResellerType + ) { + return this.resellerService.findRewards(userId, type, query) } // ============ Wallet Transactions ============= @ApiOperation({ summary: "get Reseller/Agent Wallet Transactions ==> reseller route" }) - @ResellerRoute() + @ResellerRoute([ResellerType.agent, ResellerType.reseller]) @Get('wallet/transaction') getWalletTransactionss(@UserDec("id") userId: string, @Query() query: PaginationDto) { return this.walletsService.getTransaction(userId, query); @@ -110,39 +121,39 @@ export class ResellerController { // ============ Wallet Balance ============= @ApiOperation({ summary: "get Reseller/Agent Wallet Balance ==> reseller route" }) - @ResellerRoute() + @ResellerRoute([ResellerType.agent, ResellerType.reseller]) @Get('wallet/balance') getWalletBalance(@UserDec("id") userId: string) { return this.walletsService.getBalance(userId) } - // ============Payment WithDraw Request ============= + // ============Create WithDraw Request ============= @ApiOperation({ summary: "Create Reseller/Agent withdraw request ==> reseller route" }) - @ResellerRoute() - @Post('payment/withdraw') + @ResellerRoute([ResellerType.agent]) + @Post('withdraw-request') withdrawRequest(@UserDec("id") userId: string, @Body() dto: CreateWithdrawRequestDto) { return this.resellerService.createWithdrawRequest(userId, dto.amount) } - // ============ Remove payment WithDraw Request ============= + // ============ Remove WithDraw Request ============= @ApiOperation({ summary: "remove Reseller/Agent withdraw request ==> reseller route" }) - @ResellerRoute() - @Delete('paymant/withdraw/:id') + @ResellerRoute([ResellerType.agent]) + @Delete('withdraw-request/:id') removeWithdrawRequest(@UserDec("id") userId: string, @Param('id') id: string) { return this.resellerService.removeWithdrawRequest(userId, id) } - // ============ Payment list============= - @ApiOperation({ summary: "Get Payment list ==> reseller route" }) - @ResellerRoute() - @Get('payment') - getPayments(@UserDec("id") userId: string, @Body() dto: SearchRewardsRequestQueryDto) { + // ============ withdraw list============= + @ApiOperation({ summary: "Get withdraw-request list ==> reseller route" }) + @ResellerRoute([ResellerType.agent, ResellerType.reseller]) + @Get('withdraw-request') + getPayments(@UserDec("id") userId: string, @Body() dto: SearchWithdrawRequestQueryDto) { return this.resellerService.getRewrdsRequests(userId, dto) } - // ============ Bank Account ============= + // ============ Create Bank Account ============= @ApiOperation({ summary: "Create Bank Account ==> reseller route" }) - @ResellerRoute() + @ResellerRoute([ResellerType.agent, ResellerType.reseller]) @Post('bank-account') createBankAccount(@UserDec("id") userId: string, @Body() dto: CreateUserBankAccountDto) { return this.resellerService.createUserBankAccount(userId, dto) @@ -151,7 +162,7 @@ export class ResellerController { // ============ Get Bank Account ============= @ApiOperation({ summary: "Get Bank Account ==> reseller route" }) - @ResellerRoute() + @ResellerRoute([ResellerType.agent, ResellerType.reseller]) @Get('bank-account') getBankAccount(@UserDec("id") userId: string) { return this.resellerService.getUserBankAccount(userId) @@ -159,7 +170,7 @@ export class ResellerController { // ============ Remove Bank Account ============= @ApiOperation({ summary: "remove User Bank account ==> reseller route" }) - @ResellerRoute() + @ResellerRoute([ResellerType.agent, ResellerType.reseller]) @Delete('bank-account/:id') removeBankAccount(@UserDec("id") userId: string, @Param('id') id: string) { return this.resellerService.deleteUserBankAccount(userId, id) diff --git a/src/modules/reseller/reseller.service.ts b/src/modules/reseller/reseller.service.ts index eb3fe5d..760cd09 100644 --- a/src/modules/reseller/reseller.service.ts +++ b/src/modules/reseller/reseller.service.ts @@ -5,12 +5,13 @@ import { ResellerRepository } from './repositories/reseller.repository'; import { AuthMessage } from '../../common/enums/message.enum'; import { ReferralsService } from '../referrals/providers/referrals.service'; import { InvoicesService } from '../invoices/providers/invoices.service'; -import { SearchRewardsRequestQueryDto } from './dto/search-reward-requests.dto'; +import { SearchWithdrawRequestQueryDto } from './dto/search-withdraw-requests.dto'; import { WithdrawRequestRepository } from './repositories/withdraw-request.repository'; import { SearchCustomersQueryDto } from './dto/search-customers.dto'; import { SearchResellerInvoicesQueryDto } from './dto/search-reseller-invoices.dto'; import { CreateUserBankAccountDto } from './dto/create-user-bank-account.dto'; import { UserBankAccountRepository } from './repositories/user-bank-account.repository'; +import { ResellerType } from '../auth/DTO/verify-reseller-otp.dto'; @Injectable() export class ResellerService { @@ -105,8 +106,16 @@ export class ResellerService { return this.referralService.findPaginatedReferedUsers(agentIds, query) } + // *************** Invoice *************** + async findInvoices(userId: string, type: ResellerType, query: SearchResellerInvoicesQueryDto) { + if (type == ResellerType.agent) { + return this.findResellerCustomersInvoices(userId, query) + } else if (type == ResellerType.reseller) { + return this.findAgentCustomersInvoices(userId, query) + } + } - async findResellerCustomersInvoices(userId: string, query: SearchResellerInvoicesQueryDto) { + private async findResellerCustomersInvoices(userId: string, query: SearchResellerInvoicesQueryDto) { const reselller = await this.FindOneOrFailByUserId(userId) const agentIds = reselller.agents.map(ag => ag.id) @@ -119,7 +128,27 @@ export class ResellerService { } - async findResellerAgentsRewards(userId: string, query: SearchRewardsRequestQueryDto) { + private async findAgentCustomersInvoices(userId: string, query: SearchResellerInvoicesQueryDto) { + + const agentIds = [userId] + + const customerIds = await this.referralService.findReferedUsersIds(agentIds) + + const [invoices, count] = await this.invoicesService.findInvoicesByCustomerIds(customerIds, query) + + return { invoices, count, paginate: true }; + + } + + // *********** Rewards ********************* + async findRewards(userId: string, type: ResellerType, query: SearchWithdrawRequestQueryDto) { + if (type == ResellerType.agent) { + return this.findAgentRewards(userId, query) + } else if (type == ResellerType.reseller) { + return this.findResellerAgentsRewards(userId, query) + } + } + async findResellerAgentsRewards(userId: string, query: SearchWithdrawRequestQueryDto) { const reselller = await this.FindOneOrFailByUserId(userId) const agentIds = reselller.agents.map(ag => ag.id) @@ -127,14 +156,19 @@ export class ResellerService { return this.referralService.findRewards(agentIds, query) } - async getRewrdsRequestsForAdmin(queryDto: SearchRewardsRequestQueryDto) { + async findAgentRewards(userId: string, query: SearchWithdrawRequestQueryDto) { + return this.referralService.findRewards([userId], query) + } + + //************* withdraw request ***********/ + async getRewrdsRequestsForAdmin(queryDto: SearchWithdrawRequestQueryDto) { const [requests, count] = await this.withdrawRequestRepository.findPaginatedListForAdmin(queryDto); return { requests, count, paginate: true }; } - async getRewrdsRequests(userId: string, queryDto: SearchRewardsRequestQueryDto) { + async getRewrdsRequests(userId: string, queryDto: SearchWithdrawRequestQueryDto) { const [requests, count] = await this.withdrawRequestRepository.findPaginatedList(userId, queryDto);