chore: add new route for get single transaction for user
This commit is contained in:
@@ -268,6 +268,7 @@ export const enum WalletMessage {
|
||||
INSUFFICIENT_BALANCE = "موجودی کیف پول کافی نیست",
|
||||
SUBSCRIPTION_WALLET_TRANSFER = "پرداخت اشتراک از طریق کیف پول",
|
||||
INVOICE_WALLET_TRANSFER = "پرداخت صورت حساب از طریق کیف پول",
|
||||
TRANSACTION_NOT_FOUND = "تراکنش پیدا نشد",
|
||||
}
|
||||
|
||||
export const enum PaymentMessage {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import Decimal from "decimal.js";
|
||||
import { Column, Entity, ManyToOne } from "typeorm";
|
||||
import { Column, Entity, ManyToOne, OneToMany } from "typeorm";
|
||||
|
||||
import { BankAccount } from "./bank-account.entity";
|
||||
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||
import { DecimalTransformer } from "../../../common/transformers/decimal.transformer";
|
||||
import { User } from "../../users/entities/user.entity";
|
||||
import { WalletTransaction } from "../../wallets/entities/transaction.entity";
|
||||
import { DepositRequestStatus } from "../enums/deposit-request-status.enum";
|
||||
import { TransferType } from "../enums/payment-type.enum";
|
||||
|
||||
@@ -30,4 +31,7 @@ export class DepositRequest extends BaseEntity {
|
||||
|
||||
@Column({ type: "enum", enum: DepositRequestStatus, default: DepositRequestStatus.PENDING })
|
||||
status: DepositRequestStatus;
|
||||
|
||||
@OneToMany(() => WalletTransaction, (transaction) => transaction.depositRequest)
|
||||
transactions: WalletTransaction[];
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { GatewayEnum } from "../enums/gateway.enum";
|
||||
|
||||
@Entity()
|
||||
export class PaymentGateway extends BaseEntity {
|
||||
@Column({ type: "enum", enum: GatewayEnum, nullable: false })
|
||||
@Column({ type: "enum", enum: GatewayEnum, nullable: false, unique: true })
|
||||
name: GatewayEnum;
|
||||
|
||||
@Column({ type: "varchar", length: 150, nullable: false })
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
// eslint-disable-next-line import/no-named-as-default
|
||||
import Decimal from "decimal.js";
|
||||
import { Column, Entity, ManyToOne } from "typeorm";
|
||||
import { Column, Entity, ManyToOne, OneToMany } from "typeorm";
|
||||
|
||||
import { PaymentGateway } from "./payment-gateway.entity";
|
||||
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||
import { DecimalTransformer } from "../../../common/transformers/decimal.transformer";
|
||||
import { User } from "../../users/entities/user.entity";
|
||||
import { WalletTransaction } from "../../wallets/entities/transaction.entity";
|
||||
import { PaymentStatus } from "../enums/payment-status.enum";
|
||||
|
||||
@Entity()
|
||||
@@ -27,4 +28,7 @@ export class Payment extends BaseEntity {
|
||||
|
||||
@ManyToOne(() => PaymentGateway, { nullable: false, onDelete: "RESTRICT" })
|
||||
paymentGateway: PaymentGateway;
|
||||
|
||||
@OneToMany(() => WalletTransaction, (transaction) => transaction.payment)
|
||||
transactions: WalletTransaction[];
|
||||
}
|
||||
|
||||
@@ -139,10 +139,17 @@ export class PaymentsService {
|
||||
|
||||
try {
|
||||
const paymentGateway = this.gatewayFactory.getPaymentGateway(gateway);
|
||||
const payment = await queryRunner.manager.findOne(Payment, {
|
||||
where: { reference: queryDto.Authority },
|
||||
relations: ["user"],
|
||||
});
|
||||
// const payment = await queryRunner.manager.findOne(Payment, {
|
||||
// where: { reference: queryDto.Authority },
|
||||
// relations: ["user"],
|
||||
// });
|
||||
|
||||
const payment = await queryRunner.manager
|
||||
.createQueryBuilder(Payment, "payment")
|
||||
.innerJoinAndSelect("payment.user", "user")
|
||||
.where("payment.reference = :reference", { reference: queryDto.Authority })
|
||||
.setLock("pessimistic_write")
|
||||
.getOne();
|
||||
|
||||
if (!payment) throw new BadRequestException(PaymentMessage.PAYMENT_NOT_FOUND_WITH_REF);
|
||||
if (payment.status === PaymentStatus.COMPLETED) throw new BadRequestException(PaymentMessage.VALIDATED_BEFORE);
|
||||
@@ -162,7 +169,7 @@ export class PaymentsService {
|
||||
|
||||
if (verifyData.code === 100) {
|
||||
const { wallet } = await this.handleSuccessfulPayment(
|
||||
payment.id,
|
||||
payment,
|
||||
payment.user.id,
|
||||
payment.amount,
|
||||
`${verifyData.ref_id}`,
|
||||
@@ -248,9 +255,9 @@ export class PaymentsService {
|
||||
}
|
||||
|
||||
//*********************************** */
|
||||
async handleSuccessfulPayment(paymentId: string, userId: string, amount: Decimal, transactionId: string, queryRunner: QueryRunner) {
|
||||
await queryRunner.manager.update(Payment, { id: paymentId }, { status: PaymentStatus.COMPLETED, transactionId });
|
||||
return this.walletsService.createPaymentTransaction(userId, amount, queryRunner);
|
||||
async handleSuccessfulPayment(payment: Payment, userId: string, amount: Decimal, transactionId: string, queryRunner: QueryRunner) {
|
||||
await queryRunner.manager.update(Payment, { id: payment.id }, { status: PaymentStatus.COMPLETED, transactionId });
|
||||
return this.walletsService.createPaymentTransaction(userId, amount, payment, queryRunner);
|
||||
}
|
||||
|
||||
//*********************************** */
|
||||
@@ -399,7 +406,7 @@ export class PaymentsService {
|
||||
|
||||
await queryRunner.manager.update(DepositRequest, { id: depositRequest.id }, { status: DepositRequestStatus.APPROVED });
|
||||
|
||||
await this.walletsService.createDepositTransaction(depositRequest.amount, depositRequest.user.id, queryRunner);
|
||||
await this.walletsService.createDepositTransaction(depositRequest.user.id, depositRequest.amount, depositRequest, queryRunner);
|
||||
|
||||
await queryRunner.commitTransaction();
|
||||
return {
|
||||
|
||||
@@ -5,6 +5,8 @@ import { Column, Entity, ManyToOne } from "typeorm";
|
||||
import { Wallet } from "./wallet.entity";
|
||||
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||
import { DecimalTransformer } from "../../../common/transformers/decimal.transformer";
|
||||
import { DepositRequest } from "../../payments/entities/deposit-request.entity";
|
||||
import { Payment } from "../../payments/entities/payment.entity";
|
||||
import { TransactionType } from "../enums/transaction-type.enum";
|
||||
|
||||
@Entity()
|
||||
@@ -23,4 +25,10 @@ export class WalletTransaction extends BaseEntity {
|
||||
|
||||
@Column({ type: "text", nullable: false })
|
||||
description: string;
|
||||
|
||||
@ManyToOne(() => Payment, (payment) => payment.transactions, { onDelete: "CASCADE", nullable: true })
|
||||
payment: Payment | null;
|
||||
|
||||
@ManyToOne(() => DepositRequest, (depositRequest) => depositRequest.transactions, { onDelete: "CASCADE", nullable: true })
|
||||
depositRequest: DepositRequest | null;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
||||
import { WalletMessage } from "../../../common/enums/message.enum";
|
||||
import { decimal } from "../../../common/transformers/decimal.transformer";
|
||||
import { SearchTransactionQueryDto } from "../../payments/DTO/search-transaction-query.dto";
|
||||
import { DepositRequest } from "../../payments/entities/deposit-request.entity";
|
||||
import { Payment } from "../../payments/entities/payment.entity";
|
||||
import { PaginationUtils } from "../../utils/providers/pagination.utils";
|
||||
import { WalletTransaction } from "../entities/transaction.entity";
|
||||
import { Wallet } from "../entities/wallet.entity";
|
||||
@@ -39,7 +41,7 @@ export class WalletsService {
|
||||
return wallet;
|
||||
}
|
||||
//*********************************** */
|
||||
async createPaymentTransaction(userId: string, amount: Decimal, queryRunner: QueryRunner) {
|
||||
async createPaymentTransaction(userId: string, amount: Decimal, payment: Payment, queryRunner: QueryRunner) {
|
||||
const wallet = await queryRunner.manager.findOne(Wallet, { where: { user: { id: userId } }, lock: { mode: "pessimistic_write" } });
|
||||
if (!wallet) throw new BadRequestException(WalletMessage.WALLET_NOT_FOUND);
|
||||
|
||||
@@ -48,6 +50,7 @@ export class WalletsService {
|
||||
wallet: { id: wallet.id },
|
||||
type: TransactionType.DEPOSIT,
|
||||
description: WalletMessage.DEPOSIT_WALLET_IPG,
|
||||
payment,
|
||||
});
|
||||
|
||||
wallet.balance = new Decimal(wallet.balance).add(transaction.amount);
|
||||
@@ -59,7 +62,7 @@ export class WalletsService {
|
||||
}
|
||||
//*********************************** */
|
||||
|
||||
async createDepositTransaction(amount: Decimal, userId: string, queryRunner: QueryRunner) {
|
||||
async createDepositTransaction(userId: string, amount: Decimal, depositRequest: DepositRequest, queryRunner: QueryRunner) {
|
||||
const wallet = await queryRunner.manager.findOne(Wallet, { where: { user: { id: userId } }, lock: { mode: "pessimistic_write" } });
|
||||
if (!wallet) throw new BadRequestException(WalletMessage.WALLET_NOT_FOUND);
|
||||
|
||||
@@ -68,6 +71,7 @@ export class WalletsService {
|
||||
wallet: { id: wallet.id },
|
||||
type: TransactionType.DEPOSIT,
|
||||
description: WalletMessage.DEPOSIT_WALLET_TRANSFER,
|
||||
depositRequest,
|
||||
});
|
||||
|
||||
wallet.balance = new Decimal(wallet.balance).add(transaction.amount);
|
||||
@@ -149,13 +153,29 @@ export class WalletsService {
|
||||
count,
|
||||
totalDeposits: decimal(totals.totalDeposits) || 0,
|
||||
totalWithdrawals: decimal(totals.totalWithdrawals) || 0,
|
||||
//TODO:fix this
|
||||
balancePercentChange: 5,
|
||||
totalDepositsPercentChange: 4,
|
||||
totalWithdrawalsPercentChange: 10,
|
||||
paginate: true,
|
||||
};
|
||||
}
|
||||
//*********************************** */
|
||||
|
||||
async getTransactionById(transactionId: string, userId: string) {
|
||||
const transaction = await this.walletsTransactionRepo
|
||||
.createQueryBuilder("transaction")
|
||||
.leftJoinAndSelect("transaction.wallet", "wallet")
|
||||
.leftJoin("wallet.user", "user")
|
||||
.addSelect(["user.id", "user.firstName", "user.lastName"])
|
||||
.leftJoinAndSelect("transaction.payment", "payment", "payment.id IS NOT NULL")
|
||||
.leftJoinAndSelect("payment.paymentGateway", "paymentGateway", "payment.id IS NOT NULL")
|
||||
.leftJoinAndSelect("transaction.depositRequest", "depositRequest", "depositRequest.id IS NOT NULL")
|
||||
.leftJoinAndSelect("depositRequest.bankAccount", "bankAccount", "depositRequest.id IS NOT NULL")
|
||||
.where("transaction.id = :transactionId", { transactionId })
|
||||
.andWhere("wallet.userId = :userId", { userId })
|
||||
.getOne();
|
||||
|
||||
if (!transaction) throw new BadRequestException(WalletMessage.TRANSACTION_NOT_FOUND);
|
||||
|
||||
return { transaction };
|
||||
}
|
||||
|
||||
//*********************************** */
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Controller, Get, Query } from "@nestjs/common";
|
||||
import { Controller, Get, Param, Query } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags } from "@nestjs/swagger";
|
||||
|
||||
import { WalletsService } from "./providers/wallets.service";
|
||||
@@ -6,6 +6,7 @@ import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
|
||||
import { Pagination } from "../../common/decorators/pagination.decorator";
|
||||
import { UserDec } from "../../common/decorators/user.decorator";
|
||||
import { PaginationDto } from "../../common/DTO/pagination.dto";
|
||||
import { ParamDto } from "../../common/DTO/param.dto";
|
||||
|
||||
@Controller("wallets")
|
||||
@ApiTags("wallets")
|
||||
@@ -26,4 +27,11 @@ export class WalletsController {
|
||||
getTransactions(@UserDec("id") userId: string, @Query() paginationDto: PaginationDto) {
|
||||
return this.walletsService.getTransaction(userId, paginationDto);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: "get transaction by id" })
|
||||
@AuthGuards()
|
||||
@Get("transactions/:id")
|
||||
getTransactionById(@Param() paramDto: ParamDto, @UserDec("id") userId: string) {
|
||||
return this.walletsService.getTransactionById(paramDto.id, userId);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user