reseller
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { IsNotEmpty, IsString } from "class-validator";
|
||||
import { IsMobilePhone, IsNotEmpty, Length } from "class-validator";
|
||||
import { AuthMessage } from "../../../common/enums/message.enum";
|
||||
|
||||
export class CreateResellerAgentDto {
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
@ApiProperty()
|
||||
userId: string;
|
||||
@IsNotEmpty({ message: AuthMessage.PHONE_NOT_EMPTY })
|
||||
@IsMobilePhone("fa-IR", {}, { message: AuthMessage.INVALID_PHONE_FORMAT })
|
||||
@Length(11, 11, { message: AuthMessage.PHONE_SHOULD_BE_11_DIGIT })
|
||||
@ApiProperty({ description: "phone number", default: "09922320740" })
|
||||
phone: string;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
||||
|
||||
export class SearchCustomersQueryDto extends PaginationDto { }
|
||||
@@ -0,0 +1,3 @@
|
||||
import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
||||
|
||||
export class SearchResellerInvoicesQueryDto extends PaginationDto { }
|
||||
@@ -0,0 +1,5 @@
|
||||
import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
||||
|
||||
export class SearchRewardsRequestQueryDto extends PaginationDto {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import Decimal from "decimal.js";
|
||||
import { Column, Entity, ManyToOne } from "typeorm";
|
||||
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||
import { DecimalTransformer } from "../../../common/transformers/decimal.transformer";
|
||||
import { User } from "../../users/entities/user.entity";
|
||||
|
||||
@Entity()
|
||||
export class RewardWithdrawRequest extends BaseEntity {
|
||||
@ManyToOne(() => User, (user) => user.referralRewards)
|
||||
user: User;
|
||||
|
||||
@Column({ type: "decimal", precision: 10, scale: 2, nullable: true, transformer: new DecimalTransformer() })
|
||||
requestedAmount?: Decimal;
|
||||
|
||||
@Column({ type: "timestamp", nullable: true })
|
||||
paidAt: Date;
|
||||
|
||||
@Column({ type: "varchar", length: 255, nullable: true })
|
||||
transactionId?: string;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
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 { PaginationUtils } from "../../utils/providers/pagination.utils";
|
||||
|
||||
@Injectable()
|
||||
export class WithdrawRequestRepository extends Repository<RewardWithdrawRequest> {
|
||||
constructor(@InjectRepository(RewardWithdrawRequest) repository: Repository<RewardWithdrawRequest>) {
|
||||
super(repository.target, repository.manager, repository.queryRunner);
|
||||
}
|
||||
|
||||
async findPaginatedList(queryDto: SearchRewardsRequestQueryDto) {
|
||||
const { limit, skip } = PaginationUtils(queryDto);
|
||||
|
||||
const queryBuilder = this.createQueryBuilder("request")
|
||||
.leftJoinAndSelect("request.user", "user")
|
||||
.orderBy("ticket.createdAt", "DESC");
|
||||
|
||||
return queryBuilder.skip(skip).take(limit).getManyAndCount();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Controller, Get, Post, Body, Delete } from '@nestjs/common';
|
||||
import { Controller, Get, Post, Body, Delete, Param, Query } from '@nestjs/common';
|
||||
import { ResellerService } from './reseller.service';
|
||||
import { ApiOperation } from '@nestjs/swagger';
|
||||
import { PermissionsDec } from '../../common/decorators/permission.decorator';
|
||||
@@ -9,6 +9,9 @@ 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 { SearchCustomersDto } from '../users/DTO/search-customers.dto';
|
||||
import { SearchResellerInvoicesQueryDto } from './dto/search-reseller-invoices.dto';
|
||||
|
||||
@Controller('reseller')
|
||||
@AuthGuards()
|
||||
@@ -34,6 +37,16 @@ export class ResellerController {
|
||||
return this.resellerService.findAll()
|
||||
}
|
||||
|
||||
//=========== Reward Requests =========
|
||||
|
||||
@ApiOperation({ summary: "get reseller reward requests ==> admin route" })
|
||||
@AdminRoute()
|
||||
@PermissionsDec(PermissionEnum.RESELLER)
|
||||
@Get('reward/request')
|
||||
getRewardRequests() {
|
||||
return this.resellerService.findAll()
|
||||
}
|
||||
|
||||
// =========== Reseller-->Agent =============
|
||||
|
||||
@ApiOperation({ summary: "get Reseller agents ==> reseller route" })
|
||||
@@ -47,14 +60,38 @@ export class ResellerController {
|
||||
@ResellerRoute()
|
||||
@Post('agents')
|
||||
createResellerAgent(@UserDec("id") userId: string, @Body() dto: CreateResellerAgentDto) {
|
||||
return this.resellerService.createResellerAgent(userId, dto.userId)
|
||||
return this.resellerService.createResellerAgent(userId, dto.phone)
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: "Remove Reseller agent ==> reseller route" })
|
||||
@ResellerRoute()
|
||||
@Delete('agents')
|
||||
deleteResellerAgent(@UserDec("id") userId: string, @Body() dto: CreateResellerAgentDto) {
|
||||
return this.resellerService.removeResellerAgent(userId, dto.userId)
|
||||
@Delete('agents/:agentId')
|
||||
deleteResellerAgent(@UserDec("id") userId: string, @Param('agentId') agentId: string) {
|
||||
return this.resellerService.removeResellerAgent(userId, agentId)
|
||||
}
|
||||
|
||||
// ============ Customers =============
|
||||
@ApiOperation({ summary: "get Reseller Customers ==> reseller route" })
|
||||
@ResellerRoute()
|
||||
@Get('customers')
|
||||
getCustomers(@UserDec("id") userId: string, @Query() dto: SearchCustomersDto) {
|
||||
return this.resellerService.findResellerCustomers(userId, dto)
|
||||
}
|
||||
|
||||
// ============ Invoice =============
|
||||
@ApiOperation({ summary: "get Reseller Customers Invoices==> reseller route" })
|
||||
@ResellerRoute()
|
||||
@Get('invoices')
|
||||
getCustomerInvoices(@UserDec("id") userId: string, @Query() query: SearchResellerInvoicesQueryDto) {
|
||||
return this.resellerService.findResellerCustomersInvoices(userId, query)
|
||||
}
|
||||
|
||||
// ============ Rewards =============
|
||||
@ApiOperation({ summary: "get Reseller Agents Rewards==> reseller route" })
|
||||
@ResellerRoute()
|
||||
@Get('rewards')
|
||||
getResellerAgentsRewards(@UserDec("id") userId: string, @Query() query: SearchRewardsRequestQueryDto) {
|
||||
return this.resellerService.findResellerAgentsRewards(userId, query)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,10 +5,17 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { Reseller } from './entities/reseller.entity';
|
||||
import { ResellerRepository } from './repositories/reseller.repository';
|
||||
import { UsersModule } from '../users/users.module';
|
||||
import { ReferralsModule } from '../referrals/referrals.module';
|
||||
import { InvoicesModule } from '../invoices/invoices.module';
|
||||
import { RewardWithdrawRequest } from "../reseller/entities/rewards-withdraw-request.entity";
|
||||
import { WithdrawRequestRepository } from './repositories/withdraw-request.repository';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Reseller]), UsersModule],
|
||||
imports: [TypeOrmModule.forFeature([Reseller, RewardWithdrawRequest]),
|
||||
UsersModule,
|
||||
ReferralsModule,
|
||||
InvoicesModule],
|
||||
controllers: [ResellerController],
|
||||
providers: [ResellerService, ResellerRepository],
|
||||
providers: [ResellerService, ResellerRepository, WithdrawRequestRepository],
|
||||
})
|
||||
export class ResellerModule { }
|
||||
|
||||
@@ -3,12 +3,21 @@ import { UsersService } from '../users/providers/users.service';
|
||||
import { CreateResellerDto } from './dto/create-reseller.dto';
|
||||
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 { WithdrawRequestRepository } from './repositories/withdraw-request.repository';
|
||||
import { SearchCustomersQueryDto } from './dto/search-customers.dto';
|
||||
import { SearchResellerInvoicesQueryDto } from './dto/search-reseller-invoices.dto';
|
||||
|
||||
@Injectable()
|
||||
export class ResellerService {
|
||||
constructor(
|
||||
private readonly usersService: UsersService,
|
||||
private readonly referralService: ReferralsService,
|
||||
private readonly resellerRepository: ResellerRepository,
|
||||
private readonly invoicesService: InvoicesService,
|
||||
private readonly withdrawRequestRepository: WithdrawRequestRepository,
|
||||
) { }
|
||||
|
||||
async create(dto: CreateResellerDto) {
|
||||
@@ -44,6 +53,7 @@ export class ResellerService {
|
||||
return reseller.agents
|
||||
}
|
||||
|
||||
|
||||
async FindOneOrFailByUserId(userId: string) {
|
||||
const reseller = await this.resellerRepository.findOne({
|
||||
where: { owner: { id: userId } },
|
||||
@@ -57,10 +67,14 @@ export class ResellerService {
|
||||
return reseller
|
||||
}
|
||||
|
||||
async createResellerAgent(userId: string, userTobeAgent: string) {
|
||||
async createResellerAgent(userId: string, userTobeAgentPhone: string) {
|
||||
const reseller = await this.FindOneOrFailByUserId(userId)
|
||||
|
||||
const { user } = await this.usersService.findOneById(userTobeAgent)
|
||||
const user = await this.usersService.findOneWithPhone(userTobeAgentPhone)
|
||||
|
||||
if (!user) {
|
||||
throw new NotFoundException(AuthMessage.USER_NOT_FOUND)
|
||||
}
|
||||
|
||||
user.reseller = reseller
|
||||
|
||||
@@ -80,4 +94,37 @@ export class ResellerService {
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
async findResellerCustomers(userId: string, query: SearchCustomersQueryDto) {
|
||||
const reselller = await this.FindOneOrFailByUserId(userId)
|
||||
|
||||
const agentIds = reselller.agents.map(ag => ag.id)
|
||||
|
||||
return this.referralService.findPaginatedReferedUsers(agentIds, query)
|
||||
}
|
||||
|
||||
async findResellerCustomersInvoices(userId: string, query: SearchResellerInvoicesQueryDto) {
|
||||
const reselller = await this.FindOneOrFailByUserId(userId)
|
||||
|
||||
const agentIds = reselller.agents.map(ag => ag.id)
|
||||
|
||||
const customerIds = await this.referralService.findReferedUsersIds(agentIds)
|
||||
|
||||
return this.invoicesService.findInvoicesByCustomerIds(customerIds, query)
|
||||
}
|
||||
|
||||
async findResellerAgentsRewards(userId: string, query: SearchRewardsRequestQueryDto) {
|
||||
const reselller = await this.FindOneOrFailByUserId(userId)
|
||||
|
||||
const agentIds = reselller.agents.map(ag => ag.id)
|
||||
|
||||
return this.referralService.findRewards(agentIds, query)
|
||||
}
|
||||
|
||||
async getRewrdsRequests(queryDto: SearchRewardsRequestQueryDto) {
|
||||
|
||||
const [requests, count] = await this.withdrawRequestRepository.findPaginatedList(queryDto);
|
||||
|
||||
return { requests, count, paginate: true };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user