mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 16:28:12 +00:00
telebirr out in the payment
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { IsOptional, IsString } from "class-validator";
|
||||
|
||||
export class TelebirrDto {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
merch_order_id!: string;
|
||||
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
payment_order_id!: string;
|
||||
|
||||
@ApiProperty({ default: "SUCCEEDED"})
|
||||
@IsString()
|
||||
trade_status!: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
trans_id?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
total_amount?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
trans_currency?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
notify_time?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
trans_end_time?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
sign!: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
sign_type?: string;
|
||||
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { TelebirrDto } from '../dto/telebirr.dto';
|
||||
import { PaymentRepository } from '../../payment.repository';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { Booking } from '../../../bookings/entities/booking.entity';
|
||||
import { TelebirrProvider, ProviderPaymentStatus } from '@edr/payment-providers';
|
||||
|
||||
@Injectable()
|
||||
export class TelebirrWebhookService {
|
||||
private readonly logger = new Logger(TelebirrWebhookService.name);
|
||||
|
||||
constructor(
|
||||
private readonly datasource: DataSource,
|
||||
private readonly paymentRepo: PaymentRepository,
|
||||
private readonly telebirrProvider: TelebirrProvider,
|
||||
) { }
|
||||
|
||||
verifyTelebirrNotification(payload: TelebirrDto) {
|
||||
return this.telebirrProvider.verifyWebhookSignature(payload as unknown as Record<string, unknown>);
|
||||
}
|
||||
|
||||
async handle(payload: TelebirrDto): Promise<void> {
|
||||
const payment = await this.paymentRepo.findOneBy({ merchantOrderId: payload.merch_order_id })
|
||||
if (!payment) {
|
||||
this.logger.warn(`Webhook received for unknown merchantOrderId: ${payload.merch_order_id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const mapped = this.telebirrProvider.mapWebhookTradeStatus(payload.trade_status);
|
||||
|
||||
switch (mapped) {
|
||||
case ProviderPaymentStatus.SUCCEEDED:
|
||||
await this.paymentRepo.update(
|
||||
{ id: payment.id },
|
||||
{ status: "success", paidAt: new Date() },
|
||||
);
|
||||
if (payment.type === "booking") {
|
||||
await this.datasource.manager.update(
|
||||
Booking,
|
||||
{ id: payment.refId },
|
||||
{ paymentStatus: "PAID" },
|
||||
);
|
||||
}
|
||||
break;
|
||||
case ProviderPaymentStatus.FAILED:
|
||||
await this.paymentRepo.update({ id: payment.id }, { status: "failed" });
|
||||
break;
|
||||
case ProviderPaymentStatus.PROCESSING:
|
||||
await this.paymentRepo.update({ id: payment.id }, { status: "processing" });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Body, Controller, HttpCode, HttpStatus, Logger, Post, } from '@nestjs/common';
|
||||
import { TelebirrWebhookService } from './providers/telebirr.service';
|
||||
import { ApiOperation } from '@nestjs/swagger';
|
||||
import { TelebirrDto } from './dto/telebirr.dto';
|
||||
import { Public } from '@edr/api-common';
|
||||
|
||||
@Controller("payments-webhooks")
|
||||
@Public()
|
||||
export class WebhookController {
|
||||
constructor(private readonly telebirr: TelebirrWebhookService) { }
|
||||
private readonly logger = new Logger(WebhookController.name);
|
||||
|
||||
@Post('telebirr')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({
|
||||
summary: 'Telebirr payment notification callback (Ethiopia)',
|
||||
description: 'Webhook endpoint for Telebirr payment status updates. Used by Ethiopian passengers.'
|
||||
})
|
||||
async receiveTelebirr(@Body() payload: TelebirrDto) {
|
||||
this.logger.log(
|
||||
`Telebirr webhook Called`,
|
||||
);
|
||||
|
||||
try {
|
||||
const verified = this.telebirr.verifyTelebirrNotification(payload)
|
||||
if (!verified) {
|
||||
throw new Error("Telebirr webhook signature verification failed")
|
||||
}
|
||||
await this.telebirr.handle(payload);
|
||||
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
this.logger.error(`Telebirr webhook handler threw: ${message}`);
|
||||
}
|
||||
return { code: '0', message: 'OK' };
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user