This commit is contained in:
2025-12-03 23:07:36 +03:30
parent ccabe04b60
commit 4e2bf34ab4
3 changed files with 21 additions and 36 deletions
@@ -26,18 +26,6 @@ export class PaymentsController {
return this.paymentMethodService.findByRestaurant(restId); return this.paymentMethodService.findByRestaurant(restId);
} }
@Post('public/payments/verify')
@ApiOperation({ summary: 'Verify a payment' })
@ApiBody({ type: VerifyPaymentDto })
@ApiNotFoundResponse({ description: 'Payment not found' })
verifyPayment(@Body() verifyPaymentDto: VerifyPaymentDto) {
return this.paymentsService.verifyPayment(
verifyPaymentDto.authority,
verifyPaymentDto.amount,
verifyPaymentDto.orderId,
);
}
// @UseGuards(AdminAuthGuard) // @UseGuards(AdminAuthGuard)
// @ApiBearerAuth() // @ApiBearerAuth()
// @Get('admin/payments') // @Get('admin/payments')
@@ -127,4 +115,12 @@ export class PaymentsController {
removeRestaurantPaymentMethod(@Param('paymentMethodId') paymentMethodId: string) { removeRestaurantPaymentMethod(@Param('paymentMethodId') paymentMethodId: string) {
return this.paymentMethodService.remove(paymentMethodId); return this.paymentMethodService.remove(paymentMethodId);
} }
@Post('public/payments/verify')
@ApiOperation({ summary: 'Verify a payment' })
@ApiBody({ type: VerifyPaymentDto })
@ApiNotFoundResponse({ description: 'Payment not found' })
verifyPayment(@Body() verifyPaymentDto: VerifyPaymentDto) {
return this.paymentsService.verifyPayment(verifyPaymentDto.authority, verifyPaymentDto.orderId);
}
} }
@@ -1,16 +1,11 @@
import { IsNumber, IsOptional, IsString } from 'class-validator'; import { IsString } from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
export class VerifyPaymentDto { export class VerifyPaymentDto {
@ApiProperty({ description: 'Payment authority token' }) @ApiProperty({ description: 'Payment authority token' })
@IsString() @IsString()
authority: string; authority: string;
@ApiPropertyOptional({ description: 'Payment amount (optional, will use payment amount if not provided)' })
@IsOptional()
@IsNumber()
amount?: number;
@ApiProperty({ description: 'Payment order id' }) @ApiProperty({ description: 'Payment order id' })
@IsString() @IsString()
orderId: string; orderId: string;
@@ -150,7 +150,7 @@ export class PaymentsService {
return null; return null;
} }
async verifyPayment(authority: string, amount: number | undefined, orderId: string): Promise<Payment> { async verifyPayment(authority: string, orderId: string): Promise<Payment> {
// Find payment by authority and orderId // Find payment by authority and orderId
const payment = await this.em.findOne( const payment = await this.em.findOne(
Payment, Payment,
@@ -177,12 +177,12 @@ export class PaymentsService {
} }
// For non-online payments, mark as paid directly // For non-online payments, mark as paid directly
if (paymentMethod.method !== PaymentMethodEnum.Online) { // if (paymentMethod.method !== PaymentMethodEnum.Online) {
payment.status = PaymentStatusEnum.Paid; // payment.status = PaymentStatusEnum.Paid;
payment.paidAt = new Date(); // payment.paidAt = new Date();
await this.em.persistAndFlush(payment); // await this.em.persistAndFlush(payment);
return payment; // return payment;
} // }
// Online payments require gateway verification // Online payments require gateway verification
if (!paymentMethod.merchantId) { if (!paymentMethod.merchantId) {
@@ -193,13 +193,12 @@ export class PaymentsService {
throw new BadRequestException('Payment gateway is required for online payment verification'); throw new BadRequestException('Payment gateway is required for online payment verification');
} }
// Use provided amount or payment amount // Use payment amount
const verifyAmount = amount || payment.amount; const verifyAmount = payment.amount;
// Handle ZarinPal gateway verification // Handle ZarinPal gateway verification
if (payment.gateway === PaymentGatewayEnum.ZarinPal) { if (payment.gateway === PaymentGatewayEnum.ZarinPal) {
try { try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const verifyResponse = await this.verifyZarinPalPayment({ const verifyResponse = await this.verifyZarinPalPayment({
merchantId: paymentMethod.merchantId, merchantId: paymentMethod.merchantId,
amount: verifyAmount, amount: verifyAmount,
@@ -211,18 +210,13 @@ export class PaymentsService {
throw new BadRequestException('Invalid verification response from payment gateway'); throw new BadRequestException('Invalid verification response from payment gateway');
} }
// Type assertion after type guard const response = verifyResponse;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const response: IPaymentVerifyResponse = verifyResponse as IPaymentVerifyResponse;
// Check verification response code (100 means success for ZarinPal)
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (response.code === 100) { if (response.code === 100) {
// Payment successful // Payment successful
payment.status = PaymentStatusEnum.Paid; payment.status = PaymentStatusEnum.Paid;
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
payment.refId = String(response.refId); payment.refId = String(response.refId);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment
payment.cardPan = response.cardPan; payment.cardPan = response.cardPan;
payment.verifyResponse = response as unknown as Record<string, any>; payment.verifyResponse = response as unknown as Record<string, any>;
payment.paidAt = new Date(); payment.paidAt = new Date();