payment module refactoring

master
aliMohtarami 1 month ago
parent 112e0598b5
commit 79a36d2b82
  1. 41
      src/products/entities/payment.entity.ts
  2. 63
      src/products/products.controller.ts
  3. 3
      src/products/products.module.ts
  4. 47
      src/products/products.service.ts

@ -0,0 +1,41 @@
import { BelongsTo, Column, DataType, ForeignKey, Model, Table } from "sequelize-typescript";
import { User } from "src/users/entities/user.entity";
import { Wallet } from "src/wallet/entities/wallet.entity";
@Table
export class Payment extends Model<Payment> {
@ForeignKey(() => User)
@Column
userId: number;
@BelongsTo(() => User, { onDelete: "CASCADE" })
user: User;
@ForeignKey(() => Wallet)
@Column
walletId: number;
@BelongsTo(() => Wallet, { onDelete: "CASCADE" })
wallet: Wallet;
@Column({
type: DataType.INTEGER,
allowNull: false,
})
paymentAmount: number;
@Column({
type: DataType.ENUM( "completed", "failed",),
allowNull: false,
defaultValue: "failed",
})
status: string;
@Column({
type: DataType.DATE,
allowNull: false,
defaultValue: DataType.NOW,
})
paymentDate: Date;
}

@ -8,13 +8,19 @@ import { AddToCartDto } from "./dto/cart/add-to-cart.dto";
import { JwtAuthGuard } from "src/guard/auth.guard";
import { UpdateCartDto } from "./dto/cart/update-cart.dto";
import { PaymentService } from "src/payment/payment.service";
import { InvoiceService } from "src/invoice/invoice.service";
import { InjectModel } from "@nestjs/sequelize";
import { Transaction } from "./entities/transaction.entity";
import { Payment } from "./entities/payment.entity";
@Controller("shop")
export class ProductsController {
constructor(
private readonly productsService: ProductsService,
private paymentService: PaymentService,
private readonly invoiceService: InvoiceService,
@InjectModel(Transaction) private readonly transactionModel: typeof Transaction,
@InjectModel(Payment) private readonly paymentModel: typeof Payment,
) {}
////////////////////////////////////////products////////////////////////////////////////
@ -111,7 +117,7 @@ export class ProductsController {
////////////////////////////////////////wallet////////////////////////////////////////
//getting wallet balance (user)
@UseGuards(JwtAuthGuard)
@Get('wallet')
@Get("wallet")
async getBalance(@Request() req) {
const userId = req.user.id;
return this.productsService.getBalance(userId);
@ -138,6 +144,59 @@ export class ProductsController {
async getTransactionByIdForAdmin(@Param("id") id: number) {
return this.productsService.getTransactionByIdForAdmin(id);
}
////////////////////////////////////////payment////////////////////////////////////////
//payment request
@UseGuards(JwtAuthGuard)
@Get("payment/request")
async requestPayment(@Request() req) {
const userId = req.user.id;
const invoice = await this.invoiceService.getInvoicePendingByUser(userId);
const totalAmount = invoice.totalPaymentAmount;
if (totalAmount < 1000) {
return { message: "please enter amount above 1000" };
}
const callbackUrl = `http://localhost:3000/payment/verify?userId=${userId}&amount=${totalAmount}`;
const paymentUrl = await this.paymentService.requestPayment(totalAmount, "Purchase products", callbackUrl);
return { url: paymentUrl };
}
//payment verify
@Get("verify")
async verifyPayment(@Query() query: { Authority: string; Status: string; userId: number; amount: number }): Promise<any> {
const { Authority, Status, userId, amount } = query;
if (Status !== "OK") {
throw new Error("Payment failed");
}
if (!userId) {
throw new Error("User ID is required.");
}
const wallet = this.productsService.getWalletInfo(userId);
try {
const refId = await this.paymentService.verifyPayment(Authority, amount);
await this.productsService.addBalance(userId, amount);
const wallet = this.productsService.getWalletInfo(userId);
await this.paymentModel.create({
userId,
walletId: (await wallet).walletId,
paymentAmount: amount,
status: "completed",
});
await this.transactionModel.create({
walletId: (await wallet).walletId,
amount: String(amount).startsWith("+") ? String(amount) : `+${amount}`,
});
return { message: "Payment successful", refId };
} catch (error) {
console.log(error);
await this.paymentModel.create({
userId,
walletId: (await wallet).walletId,
paymentAmount: amount,
status: "failed",
});
throw new Error(`Error during payment verification: ${error.message}`);
}
}
}

@ -13,9 +13,10 @@ import { WalletModule } from "src/wallet/wallet.module";
import { Wallet } from "./entities/wallet.entity";
import { Transaction } from "./entities/transaction.entity";
import { PaymentService } from "src/payment/payment.service";
import { Payment } from "./entities/payment.entity";
@Module({
imports: [SequelizeModule.forFeature([Product,Cart,Invoice,Wallet, Transaction]),
imports: [SequelizeModule.forFeature([Product,Cart,Invoice,Wallet, Transaction,Payment]),
JwtModule.register({
secret: process.env.JWT_SECRET,
signOptions: { expiresIn: '1h' },

@ -11,9 +11,12 @@ import { InvoiceService } from "src/invoice/invoice.service";
import { WalletService } from "src/wallet/WalletService";
import { Wallet } from "./entities/wallet.entity";
import { Transaction } from "./entities/transaction.entity";
import { InternalServerErrorException } from "@nestjs/common";
const ZarinpalCheckout = require("zarinpal-checkout");
@Injectable()
export class ProductsService {
private zarinpal;
constructor(
@InjectModel(Product) private readonly productModel: typeof Product,
@InjectModel(Cart) private readonly cartModel: typeof Cart,
@ -22,7 +25,14 @@ export class ProductsService {
@InjectModel(Transaction) private transactionModel: typeof Transaction,
private invoiceService: InvoiceService,
private walletService: WalletService,
) {}
) {
this.zarinpal = this.initializeZarinpal();
}
private initializeZarinpal() {
const merchantId = "00000000-0000-0000-0000-000000000000"; // Merchant ID should be valid
const sandboxMode = true;
return ZarinpalCheckout.create(merchantId, sandboxMode);
}
///////////////////////////////////////////products//////////////////////////////////////////////
// create a new product
async create(createProductDto: CreateProductDto): Promise<Product> {
@ -437,4 +447,39 @@ export class ProductsService {
where: { walletId: wallet.walletId },
});
}
//charge balance of wallet by user
async addBalance(userId: number, amount: number) {
try {
const wallet = await this.walletModel.findOne({ where: { userId } });
if (wallet) {
wallet.balance += Number(amount);
await wallet.save();
return { message: "Balance updated successfully.", balance: wallet.balance };
} else {
const newWallet = await this.walletModel.create({ userId, balance: amount });
return { message: "Wallet created and balance added successfully.", balance: newWallet.balance };
}
} catch (error) {
throw new HttpException("An error occurred while adding balance to the wallet.", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
///////////////////////////////////////////payment//////////////////////////////////////////////
async requestPayment(amount: number, description: string, callbackUrl: string): Promise<string> {
try {
const result = await this.zarinpal.PaymentRequest({
Amount: amount,
CallbackURL: callbackUrl,
Description: description,
});
if (result.status === 100) {
return result.url;
} else {
throw new Error(`Payment request failed with status: ${result.status}`);
}
} catch (error) {
console.log("Error in PaymentRequest:", error.message || error);
throw new InternalServerErrorException(`Error in payment request: ${error.message}`);
}
}
}

Loading…
Cancel
Save