diff --git a/database/migrations/1776232939010-AddUSerBAnkAccount.ts b/database/migrations/1776232939010-AddUSerBAnkAccount.ts new file mode 100644 index 0000000..f1cbfbd --- /dev/null +++ b/database/migrations/1776232939010-AddUSerBAnkAccount.ts @@ -0,0 +1,16 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddUSerBAnkAccount1776232939010 implements MigrationInterface { + name = 'AddUSerBAnkAccount1776232939010' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE "user_bank_account" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "cardNumber" character varying(100), "IBan" character varying(100), "bankName" character varying(100) NOT NULL, "accountOwnerName" character varying(150) NOT NULL, "userId" uuid, CONSTRAINT "UQ_731c0d4523b22914c22236d471d" UNIQUE ("cardNumber"), CONSTRAINT "UQ_5fc918bd3726009307a7c5f07a3" UNIQUE ("IBan"), CONSTRAINT "REL_17640f868ef97b2f53b7f7ab0c" UNIQUE ("userId"), CONSTRAINT "PK_080d426b06188408bc1cc508c84" PRIMARY KEY ("id"))`); + await queryRunner.query(`ALTER TABLE "user_bank_account" ADD CONSTRAINT "FK_17640f868ef97b2f53b7f7ab0cb" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "user_bank_account" DROP CONSTRAINT "FK_17640f868ef97b2f53b7f7ab0cb"`); + await queryRunner.query(`DROP TABLE "user_bank_account"`); + } + +} diff --git a/src/modules/referrals/repositories/referral-rewards.repository.ts b/src/modules/referrals/repositories/referral-rewards.repository.ts index 150c7dd..bb05b12 100755 --- a/src/modules/referrals/repositories/referral-rewards.repository.ts +++ b/src/modules/referrals/repositories/referral-rewards.repository.ts @@ -10,16 +10,14 @@ import { SearchRewardsRequestQueryDto } from "../../reseller/dto/search-reward-r export class ReferralRewardsRepository extends Repository { constructor(@InjectRepository(ReferralReward) repository: Repository) { super(repository.target, repository.manager, repository.queryRunner); - } + } async findPaginatedList(userIds: string[], queryDto: SearchRewardsRequestQueryDto) { const { limit, skip } = PaginationUtils(queryDto); - - const qb = this.createQueryBuilder("referral") - .where("referral.referrerId IN (:...userIds)", { userIds }) - .leftJoinAndSelect("referral.referrer", "referrer") - .leftJoinAndSelect("referral.referredUser", "referred") - .orderBy("referral.createdAt", "DESC") + const qb = this.createQueryBuilder("rr") + .where("rr.userId IN (:...userIds)", { userIds }) + .leftJoinAndSelect("rr.user", "user") + .orderBy("rr.createdAt", "DESC") .skip(skip) .take(limit); diff --git a/src/modules/reseller/dto/create-user-bank-account.dto.ts b/src/modules/reseller/dto/create-user-bank-account.dto.ts new file mode 100755 index 0000000..346eafb --- /dev/null +++ b/src/modules/reseller/dto/create-user-bank-account.dto.ts @@ -0,0 +1,32 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { IsNotEmpty, IsNumberString, IsString, Length } from "class-validator"; + +import { PaymentMessage } from "../../../common/enums/message.enum"; + +export class CreateUserBankAccountDto { + @IsNotEmpty({ message: PaymentMessage.CARD_NUMBER_REQUIRED }) + @IsNumberString({ no_symbols: true }, { message: PaymentMessage.CARD_NUMBER_NUMBER_STRING }) + @Length(16, 16, { message: PaymentMessage.CARD_NUMBER_LENGTH }) + @ApiProperty({ description: "card number", example: "1234567812345678" }) + cardNumber: string; + + @IsNotEmpty({ message: PaymentMessage.IBAN_REQUIRED }) + @IsNumberString({ no_symbols: true }, { message: PaymentMessage.IBAN_NUMBER_STRING }) + // @IsIBAN({ message: PaymentMessage.IBAN_INVALID }) + @Length(24, 24, { message: PaymentMessage.IBAN_INVALID }) + @ApiProperty({ description: "IBAN number", example: "123456789012345678901234" }) + IBan: string; + + @IsNotEmpty({ message: PaymentMessage.BANK_NAME_REQUIRED }) + @IsString({ message: PaymentMessage.BANK_NAME_STRING }) + @Length(2, 100, { message: PaymentMessage.BANK_NAME_LENGTH }) + @ApiProperty({ description: "bank name", example: "Example Bank" }) + bankName: string; + + @IsNotEmpty({ message: PaymentMessage.ACCOUNT_OWNER_NAME_REQUIRED }) + @IsString({ message: PaymentMessage.ACCOUNT_OWNER_NAME_STRING }) + @Length(3, 150, { message: PaymentMessage.ACCOUNT_OWNER_NAME_LENGTH }) + @ApiProperty({ description: "account owner name", example: "John Doe" }) + accountOwnerName: string; + +} diff --git a/src/modules/reseller/entities/user-bank-account.entity.ts b/src/modules/reseller/entities/user-bank-account.entity.ts new file mode 100755 index 0000000..e802dd7 --- /dev/null +++ b/src/modules/reseller/entities/user-bank-account.entity.ts @@ -0,0 +1,25 @@ +import { Column, Entity, JoinColumn, OneToOne } from "typeorm"; +import { BaseEntity } from "../../../common/entities/base.entity"; +import { User } from "../../users/entities/user.entity"; + +@Entity() +export class UserBankAccount extends BaseEntity { + @Column({ type: "varchar", length: 100, unique: true, nullable: true }) + cardNumber?: string; + + @Column({ type: "varchar", length: 100, unique: true, nullable: true }) + IBan?: string; + + @Column({ type: "varchar", length: 100, nullable: false }) + bankName: string; + + @Column({ type: "varchar", length: 150, nullable: false }) + accountOwnerName: string; + + //---------------------- + + @OneToOne(() => User, (user) => user.bankAckount) + @JoinColumn() + user?: User + +} diff --git a/src/modules/reseller/repositories/user-bank-account.repository.ts b/src/modules/reseller/repositories/user-bank-account.repository.ts new file mode 100755 index 0000000..f203318 --- /dev/null +++ b/src/modules/reseller/repositories/user-bank-account.repository.ts @@ -0,0 +1,12 @@ +import { Injectable } from "@nestjs/common"; +import { InjectRepository } from "@nestjs/typeorm"; +import { Repository } from "typeorm"; + import { UserBankAccount } from "../entities/user-bank-account.entity"; + + +@Injectable() +export class UserBankAccountRepository extends Repository { + constructor(@InjectRepository(UserBankAccount) repository: Repository) { + super(repository.target, repository.manager, repository.queryRunner); + } +} diff --git a/src/modules/reseller/reseller.controller.ts b/src/modules/reseller/reseller.controller.ts index 7b551f3..a15f0d9 100644 --- a/src/modules/reseller/reseller.controller.ts +++ b/src/modules/reseller/reseller.controller.ts @@ -15,6 +15,7 @@ import { SearchResellerInvoicesQueryDto } from './dto/search-reseller-invoices.d 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'; @Controller('reseller') @AuthGuards() @@ -127,8 +128,24 @@ export class ResellerController { @ApiOperation({ summary: "remove Reseller/Agent withdraw request ==> reseller route" }) @ResellerRoute() @Delete('wallet/withdraw/:id') - removeWithdrawRequest(@UserDec("id") userId: string) { - return this.walletsService.getBalance(userId) + removeWithdrawRequest(@UserDec("id") userId: string, @Param('id') id: string) { + return this.resellerService.removeWithdrawRequest(userId, id) + } + + // ============ Bank Account ============= + @ApiOperation({ summary: "Create Bank Account ==> reseller route" }) + @ResellerRoute() + @Post('bank-account') + createBankAccount(@UserDec("id") userId: string, @Body() dto: CreateUserBankAccountDto) { + return this.resellerService.createUserBankAccount(userId, dto) + } + + // ============ Remove Bank Account ============= + @ApiOperation({ summary: "remove User Bank account ==> reseller route" }) + @ResellerRoute() + @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.module.ts b/src/modules/reseller/reseller.module.ts index 3f8815a..a4900c1 100644 --- a/src/modules/reseller/reseller.module.ts +++ b/src/modules/reseller/reseller.module.ts @@ -10,15 +10,17 @@ import { InvoicesModule } from '../invoices/invoices.module'; import { RewardWithdrawRequest } from "../reseller/entities/rewards-withdraw-request.entity"; import { WithdrawRequestRepository } from './repositories/withdraw-request.repository'; import { WalletsModule } from '../wallets/wallets.module'; +import { UserBankAccount } from './entities/user-bank-account.entity'; +import { UserBankAccountRepository } from './repositories/user-bank-account.repository'; @Module({ - imports: [TypeOrmModule.forFeature([Reseller, RewardWithdrawRequest]), + imports: [TypeOrmModule.forFeature([Reseller, RewardWithdrawRequest, UserBankAccount]), UsersModule, ReferralsModule, InvoicesModule, WalletsModule ], controllers: [ResellerController], - providers: [ResellerService, ResellerRepository, WithdrawRequestRepository], + providers: [ResellerService, ResellerRepository, WithdrawRequestRepository, UserBankAccountRepository], }) export class ResellerModule { } diff --git a/src/modules/reseller/reseller.service.ts b/src/modules/reseller/reseller.service.ts index 34576e4..52d0d75 100644 --- a/src/modules/reseller/reseller.service.ts +++ b/src/modules/reseller/reseller.service.ts @@ -9,6 +9,8 @@ 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'; +import { CreateUserBankAccountDto } from './dto/create-user-bank-account.dto'; +import { UserBankAccountRepository } from './repositories/user-bank-account.repository'; @Injectable() export class ResellerService { @@ -18,6 +20,7 @@ export class ResellerService { private readonly resellerRepository: ResellerRepository, private readonly invoicesService: InvoicesService, private readonly withdrawRequestRepository: WithdrawRequestRepository, + private readonly userBankAccountRepository: UserBankAccountRepository, ) { } async create(dto: CreateResellerDto) { @@ -148,20 +151,42 @@ export class ResellerService { async removeWithdrawRequest(userId: string, withdrawRequestId: string) { - const request =await this.withdrawRequestRepository.findOne({ + const request = await this.withdrawRequestRepository.findOne({ where: { id: withdrawRequestId, user: { id: userId } } }) - if(!request){ + if (!request) { throw new NotFoundException() } - if(request.paidAt){ + if (request.paidAt) { throw new BadRequestException("درخواست پرداخت شده قابل حذف نیست") } return this.withdrawRequestRepository.remove(request) } + + //********* Bank Account ***********/ + async createUserBankAccount(userId: string, dto: CreateUserBankAccountDto) { + const { user } = await this.usersService.findOneById(userId) + + const account = this.userBankAccountRepository.create({ + user, + ...dto + }) + + return this.userBankAccountRepository.save(account) + } + + //********* Remove Bank Account ***********/ + async deleteUserBankAccount(userId: string, bankAccountId: string) { + + return this.userBankAccountRepository.delete({ + user: { id: userId }, + id: bankAccountId + }) + + } } diff --git a/src/modules/users/entities/user.entity.ts b/src/modules/users/entities/user.entity.ts index 0c487f3..2237188 100755 --- a/src/modules/users/entities/user.entity.ts +++ b/src/modules/users/entities/user.entity.ts @@ -31,6 +31,7 @@ import { Ticket } from "../../tickets/entities/ticket.entity"; import { Wallet } from "../../wallets/entities/wallet.entity"; import { FinancialType } from "../enums/financial-type.enum"; import { Reseller } from "../../reseller/entities/reseller.entity"; +import { UserBankAccount } from "../../reseller/entities/user-bank-account.entity"; @Entity() export class User extends BaseEntity { @@ -171,4 +172,9 @@ export class User extends BaseEntity { @OneToOne(() => Reseller, reseller => reseller.owner, { nullable: true }) ownedReseller?: Reseller + + //------------------------ + + @OneToOne(() => UserBankAccount, (account) => account.user, { nullable: true }) + bankAckount: UserBankAccount }