clean
This commit is contained in:
@@ -30,238 +30,293 @@ export class ResellerService {
|
||||
private readonly userBankAccountRepository: UserBankAccountRepository,
|
||||
private readonly walletsService: WalletsService,
|
||||
private readonly dataSource: DataSource,
|
||||
) { }
|
||||
) {}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Create a reseller record for an existing user.
|
||||
// ---------------------------------------------------------------------------
|
||||
async create(dto: CreateResellerDto) {
|
||||
const { name, phone } = dto
|
||||
const { name, phone } = dto;
|
||||
|
||||
const user = await this.usersService.findOneWithPhone(phone)
|
||||
const user = await this.usersService.findOneWithPhone(phone);
|
||||
|
||||
if (!user) {
|
||||
throw new BadRequestException(AuthMessage.USER_NOT_FOUND)
|
||||
throw new BadRequestException(AuthMessage.USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
const reseller = this.resellerRepository.create({
|
||||
name,
|
||||
owner: user
|
||||
})
|
||||
owner: user,
|
||||
});
|
||||
|
||||
await this.resellerRepository.save(reseller)
|
||||
await this.resellerRepository.save(reseller);
|
||||
|
||||
return reseller
|
||||
return reseller;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Return all resellers with their owners.
|
||||
// ---------------------------------------------------------------------------
|
||||
async findAll() {
|
||||
return this.resellerRepository.find({
|
||||
relations: {
|
||||
owner: true
|
||||
}
|
||||
})
|
||||
owner: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Return agents assigned to the reseller owner.
|
||||
// ---------------------------------------------------------------------------
|
||||
async finResellerAgents(userId: string) {
|
||||
const reseller = await this.FindOneOrFailByUserId(userId)
|
||||
const reseller = await this.FindOneOrFailByUserId(userId);
|
||||
|
||||
return reseller.agents
|
||||
return reseller.agents;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Find a reseller by owner user id and fail if it does not exist.
|
||||
// ---------------------------------------------------------------------------
|
||||
async FindOneOrFailByUserId(userId: string) {
|
||||
const reseller = await this.resellerRepository.findOne({
|
||||
where: { owner: { id: userId } },
|
||||
relations: { agents: true }
|
||||
})
|
||||
relations: { agents: true },
|
||||
});
|
||||
|
||||
if (!reseller) {
|
||||
throw new NotFoundException()
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
return reseller
|
||||
return reseller;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Attach an existing user to the reseller as an agent.
|
||||
// ---------------------------------------------------------------------------
|
||||
async createResellerAgent(userId: string, userTobeAgentPhone: string) {
|
||||
const reseller = await this.FindOneOrFailByUserId(userId)
|
||||
const reseller = await this.FindOneOrFailByUserId(userId);
|
||||
|
||||
const user = await this.usersService.findOneWithPhone(userTobeAgentPhone)
|
||||
const user = await this.usersService.findOneWithPhone(userTobeAgentPhone);
|
||||
|
||||
if (!user) {
|
||||
throw new NotFoundException(AuthMessage.USER_NOT_FOUND)
|
||||
throw new NotFoundException(AuthMessage.USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
user.reseller = reseller
|
||||
user.reseller = reseller;
|
||||
|
||||
await this.usersService.save(user)
|
||||
await this.usersService.save(user);
|
||||
|
||||
return user
|
||||
return user;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Remove an agent from the reseller if it belongs to them.
|
||||
// ---------------------------------------------------------------------------
|
||||
async removeResellerAgent(userId: string, agentId: string) {
|
||||
const reseller = await this.FindOneOrFailByUserId(userId)
|
||||
|
||||
const { user } = await this.usersService.findOneById(agentId)
|
||||
const reseller = await this.FindOneOrFailByUserId(userId);
|
||||
|
||||
const { user } = await this.usersService.findOneById(agentId);
|
||||
|
||||
if (!user) {
|
||||
throw new NotFoundException(AuthMessage.USER_NOT_FOUND)
|
||||
throw new NotFoundException(AuthMessage.USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (user.reseller?.id !== reseller.id) {
|
||||
throw new BadRequestException("بازاریاب به این نمایندگی تعلق ندارد")
|
||||
throw new BadRequestException('بازاریاب به این نمایندگی تعلق ندارد');
|
||||
}
|
||||
|
||||
user.reseller = undefined
|
||||
user.reseller = undefined;
|
||||
|
||||
await this.usersService.save(user)
|
||||
await this.usersService.save(user);
|
||||
|
||||
return user
|
||||
return user;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Return customers referred by all agents of the reseller.
|
||||
// ---------------------------------------------------------------------------
|
||||
async findResellerCustomers(userId: string, query: SearchCustomersQueryDto) {
|
||||
const reselller = await this.FindOneOrFailByUserId(userId)
|
||||
const reseller = await this.FindOneOrFailByUserId(userId);
|
||||
|
||||
const agentIds = reselller.agents.map(ag => ag.id)
|
||||
const agentIds = reseller.agents.map((agent) => agent.id);
|
||||
|
||||
if (!agentIds.length) {
|
||||
return { customers: [], count: 0, paginate: true };
|
||||
}
|
||||
|
||||
return this.referralService.findPaginatedReferedUsers(agentIds, query)
|
||||
return this.referralService.findPaginatedReferedUsers(agentIds, query);
|
||||
}
|
||||
|
||||
// *************** Invoice ***************
|
||||
// ---------------------------------------------------------------------------
|
||||
// Resolve invoice lookup based on reseller or agent role.
|
||||
// ---------------------------------------------------------------------------
|
||||
async findInvoices(userId: string, type: ResellerType, query: SearchResellerInvoicesQueryDto) {
|
||||
if (type == ResellerType.agent) {
|
||||
return this.findAgentCustomersInvoices(userId, query)
|
||||
} else if (type == ResellerType.reseller) {
|
||||
return this.findResellerCustomersInvoices(userId, query)
|
||||
if (type === ResellerType.agent) {
|
||||
return this.findAgentCustomersInvoices(userId, query);
|
||||
}
|
||||
|
||||
if (type === ResellerType.reseller) {
|
||||
return this.findResellerCustomersInvoices(userId, query);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Return invoices for customers referred by the reseller's agents.
|
||||
// ---------------------------------------------------------------------------
|
||||
private async findResellerCustomersInvoices(userId: string, query: SearchResellerInvoicesQueryDto) {
|
||||
const reselller = await this.FindOneOrFailByUserId(userId)
|
||||
const reseller = await this.FindOneOrFailByUserId(userId);
|
||||
|
||||
const agentIds = reselller.agents.map(ag => ag.id)
|
||||
const agentIds = reseller.agents.map((agent) => agent.id);
|
||||
|
||||
if (!agentIds.length) {
|
||||
return { invoices: [], count: 0, paginate: true };
|
||||
}
|
||||
|
||||
const customerIds = await this.referralService.findReferedUsersIds(agentIds)
|
||||
const customerIds = await this.referralService.findReferedUsersIds(agentIds);
|
||||
|
||||
const [invoices, count] = await this.invoicesService.findInvoicesByCustomerIds(customerIds, query)
|
||||
const [invoices, count] = await this.invoicesService.findInvoicesByCustomerIds(customerIds, query);
|
||||
|
||||
return { invoices, count, paginate: true };
|
||||
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Return invoices for customers referred by a single agent.
|
||||
// ---------------------------------------------------------------------------
|
||||
private async findAgentCustomersInvoices(userId: string, query: SearchResellerInvoicesQueryDto) {
|
||||
const agentIds = [userId];
|
||||
|
||||
const agentIds = [userId]
|
||||
const customerIds = await this.referralService.findReferedUsersIds(agentIds);
|
||||
|
||||
const customerIds = await this.referralService.findReferedUsersIds(agentIds)
|
||||
|
||||
const [invoices, count] = await this.invoicesService.findInvoicesByCustomerIds(customerIds, query)
|
||||
const [invoices, count] = await this.invoicesService.findInvoicesByCustomerIds(customerIds, query);
|
||||
|
||||
return { invoices, count, paginate: true };
|
||||
|
||||
}
|
||||
|
||||
// *********** Rewards *********************
|
||||
// ---------------------------------------------------------------------------
|
||||
// Resolve reward lookup based on reseller or agent role.
|
||||
// ---------------------------------------------------------------------------
|
||||
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)
|
||||
if (type === ResellerType.agent) {
|
||||
return this.findAgentRewards(userId, query);
|
||||
}
|
||||
|
||||
if (type === ResellerType.reseller) {
|
||||
return this.findResellerAgentsRewards(userId, query);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Return rewards earned by all agents under a reseller.
|
||||
// ---------------------------------------------------------------------------
|
||||
async findResellerAgentsRewards(userId: string, query: SearchWithdrawRequestQueryDto) {
|
||||
const reselller = await this.FindOneOrFailByUserId(userId)
|
||||
const reseller = await this.FindOneOrFailByUserId(userId);
|
||||
|
||||
const agentIds = reselller.agents.map(ag => ag.id)
|
||||
const agentIds = reseller.agents.map((agent) => agent.id);
|
||||
|
||||
if (!agentIds.length) {
|
||||
return { rewards: [], count: 0, paginate: true };
|
||||
}
|
||||
|
||||
return this.referralService.findRewards(agentIds, query)
|
||||
return this.referralService.findRewards(agentIds, query);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Return rewards earned by a single agent.
|
||||
// ---------------------------------------------------------------------------
|
||||
async findAgentRewards(userId: string, query: SearchWithdrawRequestQueryDto) {
|
||||
return this.referralService.findRewards([userId], query)
|
||||
return this.referralService.findRewards([userId], query);
|
||||
}
|
||||
|
||||
//************* withdraw request ***********/
|
||||
// ---------------------------------------------------------------------------
|
||||
// Return paginated withdraw requests for admin review.
|
||||
// ---------------------------------------------------------------------------
|
||||
async getwithdrawRequestsForAdmin(queryDto: SearchWithdrawRequestQueryDto) {
|
||||
|
||||
const [requests, count] = await this.withdrawRequestRepository.findPaginatedListForAdmin(queryDto);
|
||||
|
||||
return { requests, count, paginate: true };
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Return paginated withdraw requests for a specific user.
|
||||
// ---------------------------------------------------------------------------
|
||||
async getWithdrawRequests(userId: string, queryDto: SearchWithdrawRequestQueryDto) {
|
||||
|
||||
const [requests, count] = await this.withdrawRequestRepository.findPaginatedList(userId, queryDto);
|
||||
|
||||
return { requests, count, paginate: true };
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Create a withdraw request after validating balance and pending requests.
|
||||
// ---------------------------------------------------------------------------
|
||||
async createWithdrawRequest(userId: string, requestedAmount: number) {
|
||||
const { user } = await this.usersService.findOneById(userId)
|
||||
const { user } = await this.usersService.findOneById(userId);
|
||||
|
||||
if (!user) {
|
||||
throw new NotFoundException(AuthMessage.USER_NOT_FOUND)
|
||||
throw new NotFoundException(AuthMessage.USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
const pendingWithdrawRequest = await this.withdrawRequestRepository.findOne({
|
||||
where: {
|
||||
user: { id: userId },
|
||||
paidAt: IsNull()
|
||||
}
|
||||
})
|
||||
paidAt: IsNull(),
|
||||
},
|
||||
});
|
||||
|
||||
if (pendingWithdrawRequest) {
|
||||
throw new BadRequestException("امکان ایجاد درخواست برداشت جدید نیست")
|
||||
throw new BadRequestException('امکان ایجاد درخواست برداشت جدید نیست');
|
||||
}
|
||||
|
||||
const { balance } = await this.walletsService.getBalance(userId)
|
||||
const { balance } = await this.walletsService.getBalance(userId);
|
||||
|
||||
if (new Decimal(balance).lessThan(requestedAmount)) {
|
||||
throw new BadRequestException("برداشت بیشتر از موجودی ممکن نیست")
|
||||
throw new BadRequestException('برداشت بیشتر از موجودی ممکن نیست');
|
||||
}
|
||||
|
||||
const request = this.withdrawRequestRepository.create({
|
||||
requestedAmount,
|
||||
user
|
||||
})
|
||||
user,
|
||||
});
|
||||
|
||||
return this.withdrawRequestRepository.save(request)
|
||||
return this.withdrawRequestRepository.save(request);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Delete a pending withdraw request owned by the user.
|
||||
// ---------------------------------------------------------------------------
|
||||
async removeWithdrawRequest(userId: string, withdrawRequestId: string) {
|
||||
|
||||
const request = await this.withdrawRequestRepository.findOne({
|
||||
where: {
|
||||
id: withdrawRequestId,
|
||||
user: { id: userId }
|
||||
}
|
||||
})
|
||||
user: { id: userId },
|
||||
},
|
||||
});
|
||||
|
||||
if (!request) {
|
||||
throw new NotFoundException()
|
||||
}
|
||||
if (request.paidAt) {
|
||||
throw new BadRequestException("درخواست پرداخت شده قابل حذف نیست")
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
return this.withdrawRequestRepository.remove(request)
|
||||
if (request.paidAt) {
|
||||
throw new BadRequestException('درخواست پرداخت شده قابل حذف نیست');
|
||||
}
|
||||
|
||||
return this.withdrawRequestRepository.remove(request);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Confirm a withdraw request and create its wallet transaction atomically.
|
||||
// ---------------------------------------------------------------------------
|
||||
async confirmWithdrawRequest(requestId: string, transactionId: string) {
|
||||
const request = await this.withdrawRequestRepository.findOne({ where: { id: requestId }, relations: ['user'] })
|
||||
const request = await this.withdrawRequestRepository.findOne({
|
||||
where: { id: requestId },
|
||||
relations: ['user'],
|
||||
});
|
||||
|
||||
if (!request) {
|
||||
throw new BadRequestException("درخواست برداشت یافت نشد .")
|
||||
throw new BadRequestException('درخواست برداشت یافت نشد .');
|
||||
}
|
||||
|
||||
if (request.paidAt) {
|
||||
throw new BadRequestException("قبلا تایید شده است")
|
||||
throw new BadRequestException('قبلا تایید شده است');
|
||||
}
|
||||
|
||||
this.logger.log(`confirm withdraw request for request id ${requestId} `);
|
||||
@@ -272,14 +327,14 @@ export class ResellerService {
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
|
||||
const amount = new Decimal(request.requestedAmount)
|
||||
const amount = new Decimal(request.requestedAmount);
|
||||
|
||||
await this.walletsService.createWithdrawTransaction(request.user.id, amount, request, queryRunner)
|
||||
await this.walletsService.createWithdrawTransaction(request.user.id, amount, request, queryRunner);
|
||||
|
||||
request.paidAt = new Date()
|
||||
request.transactionId = transactionId
|
||||
request.paidAt = new Date();
|
||||
request.transactionId = transactionId;
|
||||
|
||||
await queryRunner.manager.save(request)
|
||||
await queryRunner.manager.save(request);
|
||||
|
||||
await queryRunner.commitTransaction();
|
||||
return true;
|
||||
@@ -292,69 +347,86 @@ export class ResellerService {
|
||||
}
|
||||
}
|
||||
|
||||
//********* Bank Account ***********/
|
||||
// ---------------------------------------------------------------------------
|
||||
// Return all bank accounts registered for a user.
|
||||
// ---------------------------------------------------------------------------
|
||||
async getUserBankAccount(userId: string) {
|
||||
|
||||
return this.userBankAccountRepository.find({
|
||||
where: { user: { id: userId } }
|
||||
})
|
||||
where: { user: { id: userId } },
|
||||
});
|
||||
}
|
||||
|
||||
//********* Bank Account ***********/
|
||||
// ---------------------------------------------------------------------------
|
||||
// Create a bank account if the iban and user record are not duplicated.
|
||||
// ---------------------------------------------------------------------------
|
||||
async createUserBankAccount(userId: string, dto: CreateUserBankAccountDto) {
|
||||
const { user } = await this.usersService.findOneById(userId)
|
||||
const { user } = await this.usersService.findOneById(userId);
|
||||
|
||||
const exitingBankAccount = await this.userBankAccountRepository.findOne({
|
||||
where: {
|
||||
IBan: dto.IBan
|
||||
}
|
||||
})
|
||||
where: [
|
||||
{
|
||||
IBan: dto.IBan,
|
||||
},
|
||||
{
|
||||
user: { id: userId },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (exitingBankAccount) {
|
||||
throw new BadRequestException("شماره شبا موجود می باشد .")
|
||||
throw new BadRequestException('شماره شبا موجود می باشد .');
|
||||
}
|
||||
|
||||
const account = this.userBankAccountRepository.create({
|
||||
user,
|
||||
...dto
|
||||
})
|
||||
...dto,
|
||||
});
|
||||
|
||||
return this.userBankAccountRepository.save(account)
|
||||
return this.userBankAccountRepository.save(account);
|
||||
}
|
||||
|
||||
//********* Remove Bank Account ***********/
|
||||
// ---------------------------------------------------------------------------
|
||||
// Delete a bank account that belongs to the user.
|
||||
// ---------------------------------------------------------------------------
|
||||
async deleteUserBankAccount(userId: string, bankAccountId: string) {
|
||||
|
||||
return this.userBankAccountRepository.delete({
|
||||
user: { id: userId },
|
||||
id: bankAccountId
|
||||
})
|
||||
|
||||
id: bankAccountId,
|
||||
});
|
||||
}
|
||||
|
||||
//*********** Referral Code ************/
|
||||
// ---------------------------------------------------------------------------
|
||||
// Resolve referral code lookup based on reseller or agent role.
|
||||
// ---------------------------------------------------------------------------
|
||||
async getReferralCodes(userId: string, type: ResellerType, query: PaginationDto) {
|
||||
if (type == ResellerType.agent) {
|
||||
return this.findAgentReferralCodes(userId, query)
|
||||
} else if (type == ResellerType.reseller) {
|
||||
return this.findResellerAgentsReferralCodes(userId, query)
|
||||
if (type === ResellerType.agent) {
|
||||
return this.findAgentReferralCodes(userId, query);
|
||||
}
|
||||
|
||||
if (type === ResellerType.reseller) {
|
||||
return this.findResellerAgentsReferralCodes(userId, query);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Return referral codes created by all agents under a reseller.
|
||||
// ---------------------------------------------------------------------------
|
||||
private async findResellerAgentsReferralCodes(userId: string, query: SearchWithdrawRequestQueryDto) {
|
||||
const reselller = await this.FindOneOrFailByUserId(userId)
|
||||
const reseller = await this.FindOneOrFailByUserId(userId);
|
||||
|
||||
const agentIds = reselller.agents.map(ag => ag.id)
|
||||
const agentIds = reseller.agents.map((agent) => agent.id);
|
||||
|
||||
if (!agentIds.length) {
|
||||
return { codes: [], count: 0, paginate: true };
|
||||
}
|
||||
|
||||
return this.referralService.getReferralCodesByUserIds(agentIds, query)
|
||||
return this.referralService.getReferralCodesByUserIds(agentIds, query);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Return referral codes created by a single agent.
|
||||
// ---------------------------------------------------------------------------
|
||||
private async findAgentReferralCodes(userId: string, query: SearchWithdrawRequestQueryDto) {
|
||||
return this.referralService.getReferralCodesByUserIds([userId], query)
|
||||
return this.referralService.getReferralCodesByUserIds([userId], query);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user