receipt template

This commit is contained in:
Tria
2026-06-05 17:23:21 +03:00
parent 620607e50c
commit 6786bdd210
12 changed files with 381 additions and 112 deletions

View File

@@ -1,13 +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;
}

View File

@@ -2,12 +2,17 @@ import { Injectable, } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as crypto from "crypto"
import { TelebirrDto } from '../dto/telebirr.dto';
import { BookingsRepository } from 'src/modules/bookings/bookings.repository';
import { PaymentRepository } from '../../payment.repository';
@Injectable()
export class TelebirrWebhookService {
// private readonly logger = new Logger(TelebirrWebhookService.name);
constructor(
private readonly config: ConfigService
private readonly config: ConfigService,
private readonly bookingRepo: BookingsRepository,
private readonly paymentRepo: PaymentRepository,
) { }
verifyTelebirrNotification(payload: TelebirrDto) {
@@ -43,7 +48,34 @@ export class TelebirrWebhookService {
}
async handle(payload: TelebirrDto): Promise<void> {
console.log(payload)
const payment = await this.paymentRepo.findOneBy({ merchantOrderId: payload.merch_order_id })
if (!payment) {
throw new Error("payment not found")
}
switch (payload.trade_status) {
case "SUCCEEDED":
console.log(payment.id)
await this.paymentRepo.update({ id: payment.id }, { status: "success" })
switch (payment.type) {
case "booking":
await this.bookingRepo.update(payment.refId, { paymentStatus: "PAID" })
break;
}
break;
case "FAILED":
await this.paymentRepo.update({ id: payment.id }, { status: "failed" })
break;
case "CANCELLED":
await this.paymentRepo.update({ id: payment.id }, { status: "canceled" })
break;
case "PROCESSING":
await this.paymentRepo.update({ id: payment.id }, { status: "processing" })
break;
case "REFUNDED":
await this.paymentRepo.update({ id: payment.id }, { status: "refunded" })
break;
}
}
}

View File

@@ -1,14 +1,16 @@
import { All, Body, Controller, HttpCode, HttpStatus, Logger, } from '@nestjs/common';
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")
@Controller("payments-webhooks")
@Public()
export class WebhookController {
constructor(private readonly telebirr: TelebirrWebhookService) { }
private readonly logger = new Logger(WebhookController.name);
@All('telebirr')
@Post('telebirr')
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: 'Telebirr payment notification callback (Ethiopia)',
@@ -20,16 +22,13 @@ export class WebhookController {
);
try {
const verified = this.telebirr.verifyTelebirrNotification(payload)
if (!verified) {
throw new Error("not valid")
}
const merchantOrderId = payload.merch_order_id;
if (merchantOrderId.startsWith("freight")) {
await this.telebirr.handle(payload);
} else if (merchantOrderId.startsWith("passagner")) {
//todo: handle else where
}
// const verified = this.telebirr.verifyTelebirrNotification(payload)
// if (!verified) {
// throw new Error("not valid")
// }
// const merchantOrderId = payload.merch_order_id;
await this.telebirr.handle(payload);
} catch (err) {
const message = err instanceof Error ? err.message : String(err);