mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
113 lines
4.4 KiB
TypeScript
113 lines
4.4 KiB
TypeScript
import { Injectable, NotFoundException } from "@nestjs/common";
|
|
import { DataSource, QueryRunner } from "typeorm";
|
|
import { PaymentEntity } from "./entities/payment.entity";
|
|
import { PaymentStrategy } from "./strategies/payment.strategy";
|
|
import { PaymentTelebirrStrategy } from "./strategies/payment.telebirr.strategy";
|
|
import { PaymentRepository } from "./payment.repository";
|
|
import { ClientAction, PaymentPlatform } from "./strategies/payments.types";
|
|
import * as crypto from 'crypto';
|
|
import { PaymentStatus, UpdatePaymentStatusDto } from "./dto/update-payment-status.dto";
|
|
|
|
type PaymentMethod = PaymentEntity["method"]
|
|
type CurrencyType = PaymentEntity["currency"]
|
|
|
|
@Injectable()
|
|
export class PaymentService {
|
|
private strategies: Map<PaymentMethod, PaymentStrategy>;
|
|
|
|
constructor(
|
|
private readonly datasource: DataSource,
|
|
private readonly paymentRepo: PaymentRepository,
|
|
private readonly telebirrPaymentStategy: PaymentTelebirrStrategy) {
|
|
this.strategies = new Map([
|
|
["telebirr", this.telebirrPaymentStategy as PaymentStrategy]
|
|
])
|
|
}
|
|
|
|
async pay(amount: number, currency: CurrencyType, method: PaymentMethod, cb: (qr: QueryRunner) => Promise<{ id: string, type: PaymentEntity["type"] }>, payform: PaymentPlatform = "web"): Promise<{
|
|
refId: string,
|
|
clientAction: ClientAction,
|
|
status: PaymentEntity["status"],
|
|
paidAt?: string,
|
|
failureCode?: string,
|
|
failureMessage?: string,
|
|
}> {
|
|
|
|
const strategy = this.strategies.get(method)
|
|
if (!strategy) {
|
|
throw new NotFoundException("strategy not found")
|
|
}
|
|
|
|
const orderId = `freigh${Date.now()}${crypto.randomBytes(4).toString('hex')}` //todo: make it dynamic
|
|
const paymentResp = await strategy.pay({
|
|
amountMinor: amount,
|
|
currency: currency,
|
|
merchantOrderId: orderId,
|
|
platform: payform,
|
|
});
|
|
|
|
const queryRunner = this.datasource.createQueryRunner()
|
|
await queryRunner.connect()
|
|
await queryRunner.startTransaction()
|
|
|
|
console.log(paymentResp.expiresAt)
|
|
try {
|
|
const resp = await cb(queryRunner)
|
|
const payment = await this.paymentRepo.createTr(queryRunner, {
|
|
amount,
|
|
currency,
|
|
method,
|
|
refId: resp.id,
|
|
type: resp.type,
|
|
merchantOrderId: orderId,
|
|
rawInitiation: paymentResp.rawInitiation,
|
|
clientAction: paymentResp.clientAction,
|
|
expiresAt: paymentResp.expiresAt
|
|
|
|
})
|
|
await queryRunner.commitTransaction()
|
|
return {
|
|
refId: payment.refId,
|
|
clientAction: paymentResp.clientAction,
|
|
status: payment.status,
|
|
paidAt: payment.paidAt?.toISOString(),
|
|
failureCode: payment.failerCode ?? undefined,
|
|
failureMessage: payment.failureMessage ?? undefined,
|
|
}
|
|
} catch (err) {
|
|
await queryRunner.rollbackTransaction()
|
|
throw new Error("payment failed")
|
|
} finally {
|
|
await queryRunner.release()
|
|
}
|
|
|
|
}
|
|
|
|
|
|
async getActivePaymentByRefIdAndMethod(refId: string, method: PaymentEntity["method"]): Promise<PaymentEntity | null> {
|
|
return this.paymentRepo.getActivePaymentByRefIdAndMethod(refId, method)
|
|
}
|
|
|
|
|
|
async handleTelebirrPaymentCb(dto: UpdatePaymentStatusDto): Promise<void> {
|
|
switch (dto.status) {
|
|
case PaymentStatus.SUCCEEDED:
|
|
await this.paymentRepo.update({ merchantOrderId: dto.orderId }, { status: "success" })
|
|
break;
|
|
case PaymentStatus.FAILED:
|
|
await this.paymentRepo.update({ merchantOrderId: dto.orderId }, { status: "failed", failureMessage: dto.failureMessage })
|
|
break;
|
|
case PaymentStatus.CANCELLED:
|
|
await this.paymentRepo.update({ merchantOrderId: dto.orderId }, { status: "canceled" })
|
|
break;
|
|
case PaymentStatus.PROCESSING:
|
|
await this.paymentRepo.update({ merchantOrderId: dto.orderId }, { status: "canceled" })
|
|
break;
|
|
case PaymentStatus.REFUNDED:
|
|
await this.paymentRepo.update({ merchantOrderId: dto.orderId }, { status: "canceled" })
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
} |