115 lines
3.9 KiB
TypeScript
115 lines
3.9 KiB
TypeScript
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
|
|
import { RestaurantPaymentMethod } from '../entities/restaurant-payment-method.entity';
|
|
import axios from 'axios';
|
|
import { IPaymentRequest, IPaymentResponse, PaymentStatus } from '../interface/payment-status';
|
|
import { Payment } from '../entities/payment.entity';
|
|
import { EntityManager, RequiredEntityData } from '@mikro-orm/core';
|
|
import { Order } from '../../orders/entities/order.entity';
|
|
|
|
@Injectable()
|
|
export class PaymentsService {
|
|
constructor(private readonly em: EntityManager) {}
|
|
|
|
async initializePayment(
|
|
restaurantPaymentMethodId: string,
|
|
amount: number,
|
|
orderId: string,
|
|
): Promise<{ paymentUrl: string | null }> {
|
|
// Validate amount
|
|
if (amount <= 0) {
|
|
throw new BadRequestException('Amount must be greater than zero');
|
|
}
|
|
|
|
// Validate order exists
|
|
const order = await this.em.findOne(Order, { id: orderId });
|
|
if (!order) {
|
|
throw new NotFoundException('Order not found');
|
|
}
|
|
|
|
// Load restaurant payment method with payment method relationship
|
|
const restaurantPaymentMethod = await this.em.findOne(
|
|
RestaurantPaymentMethod,
|
|
{ id: restaurantPaymentMethodId },
|
|
{ populate: ['paymentMethod'] },
|
|
);
|
|
if (!restaurantPaymentMethod) {
|
|
throw new NotFoundException('Restaurant payment method not found');
|
|
}
|
|
|
|
if (!restaurantPaymentMethod.paymentMethod?.isOnline) {
|
|
return { paymentUrl: null };
|
|
}
|
|
|
|
if (!restaurantPaymentMethod.callbackUrl) {
|
|
throw new BadRequestException('Callback URL is not configured');
|
|
}
|
|
|
|
if (!restaurantPaymentMethod.merchantId) {
|
|
throw new BadRequestException('Merchant ID is not provided');
|
|
}
|
|
|
|
if (!restaurantPaymentMethod.paymentMethod?.paymentUrl) {
|
|
throw new BadRequestException('Payment URL is not configured');
|
|
}
|
|
|
|
// Request to payment gateway with error handling
|
|
let gatewayResponse: IPaymentResponse;
|
|
try {
|
|
gatewayResponse = await this.requestToPaymentGateway(restaurantPaymentMethod.paymentMethod.paymentUrl, {
|
|
amount,
|
|
callbackUrl: restaurantPaymentMethod.callbackUrl,
|
|
merchantId: restaurantPaymentMethod.merchantId,
|
|
description: `Payment for order #${orderId}`,
|
|
});
|
|
} catch (error) {
|
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
throw new BadRequestException(`Failed to connect to payment gateway: ${errorMessage}`);
|
|
}
|
|
|
|
// Check gateway response code (typically 100 means success for Iranian gateways)
|
|
if (gatewayResponse.code !== 100 && gatewayResponse.code !== 0) {
|
|
throw new BadRequestException(`Payment gateway error: ${gatewayResponse.message || 'Unknown error'}`);
|
|
}
|
|
|
|
if (!gatewayResponse.authority) {
|
|
throw new BadRequestException('Payment gateway did not return an authority token');
|
|
}
|
|
|
|
// Create payment record and save authority
|
|
const payment = this.em.create(Payment, {
|
|
amount,
|
|
authority: gatewayResponse.authority,
|
|
order: this.em.getReference(Order, orderId),
|
|
gateway: restaurantPaymentMethod.paymentMethod.name,
|
|
status: PaymentStatus.Pending,
|
|
} as RequiredEntityData<Payment>);
|
|
|
|
await this.em.persistAndFlush(payment);
|
|
|
|
// Return payment URL
|
|
const paymentUrl = `${restaurantPaymentMethod.paymentMethod.paymentUrl}/${gatewayResponse.authority}`;
|
|
return { paymentUrl };
|
|
}
|
|
|
|
private async requestToPaymentGateway(
|
|
gatewayPaymentUrl: string,
|
|
requestPayment: IPaymentRequest,
|
|
): Promise<IPaymentResponse> {
|
|
const response = await axios.post<IPaymentResponse>(gatewayPaymentUrl, requestPayment);
|
|
return response.data;
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
update(_id: number, _updatePaymentDto: unknown) {
|
|
return `This action updates a #${_id} payment`;
|
|
}
|
|
|
|
findAll() {
|
|
return this.em.find(Payment, {});
|
|
}
|
|
|
|
remove(id: number) {
|
|
return `This action removes a #${id} payment`;
|
|
}
|
|
}
|