mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
94 lines
3.0 KiB
TypeScript
94 lines
3.0 KiB
TypeScript
import { Injectable, Logger } from '@nestjs/common';
|
|
import {
|
|
WaafiProvider,
|
|
WaafiWebhookPayload,
|
|
ProviderPaymentStatus,
|
|
} from '@edr/payment-providers';
|
|
import { PaymentIntentStatus, PaymentMethodType } from '@prisma/client';
|
|
import { PrismaService } from '../../../common/prisma.service';
|
|
import { PaymentsService } from '../payments.service';
|
|
|
|
@Injectable()
|
|
export class WaafiWebhookService {
|
|
private readonly logger = new Logger(WaafiWebhookService.name);
|
|
|
|
constructor(
|
|
private prisma: PrismaService,
|
|
private paymentsService: PaymentsService,
|
|
private waafiProvider: WaafiProvider,
|
|
) {}
|
|
|
|
async handleWebhook(payload: WaafiWebhookPayload): Promise<{ received: boolean }> {
|
|
this.logger.log(
|
|
`Waafi webhook received: event=${payload.eventType} ref=${payload.params?.referenceId}`,
|
|
);
|
|
|
|
const signatureValid = this.waafiProvider.verifyWebhookSignature(
|
|
payload as unknown as Record<string, unknown>,
|
|
);
|
|
|
|
const merchantOrderId = payload.params?.referenceId;
|
|
const transactionId = payload.params?.transactionId;
|
|
const state = payload.params?.state;
|
|
|
|
await this.prisma.paymentWebhookEvent.create({
|
|
data: {
|
|
provider: PaymentMethodType.WAAFI,
|
|
externalEventId: payload.requestId,
|
|
merchantOrderId,
|
|
providerTxnId: transactionId,
|
|
signatureValid,
|
|
status: state || 'UNKNOWN',
|
|
payload: payload as any,
|
|
},
|
|
});
|
|
|
|
if (!signatureValid) {
|
|
this.logger.warn(`Waafi webhook signature invalid for ref=${merchantOrderId}`);
|
|
return { received: true };
|
|
}
|
|
|
|
if (!merchantOrderId) {
|
|
this.logger.error('Waafi webhook missing referenceId');
|
|
return { received: true };
|
|
}
|
|
|
|
const intent = await this.prisma.paymentIntent.findFirst({
|
|
where: { merchantOrderId },
|
|
});
|
|
|
|
if (!intent) {
|
|
this.logger.warn(`No PaymentIntent found for merchantOrderId=${merchantOrderId}`);
|
|
return { received: true };
|
|
}
|
|
|
|
const mappedStatus = this.waafiProvider.mapState(state);
|
|
|
|
if (mappedStatus === ProviderPaymentStatus.SUCCEEDED) {
|
|
await this.paymentsService.finalizePaymentSuccess({
|
|
intentId: intent.id,
|
|
providerTxnId: transactionId,
|
|
});
|
|
this.logger.log(`Waafi payment succeeded: intent=${intent.id} txn=${transactionId}`);
|
|
} else if (mappedStatus === ProviderPaymentStatus.FAILED) {
|
|
await this.paymentsService.markPaymentFailed({
|
|
intentId: intent.id,
|
|
failureCode: state,
|
|
failureMessage: payload.params?.description,
|
|
});
|
|
this.logger.log(`Waafi payment failed: intent=${intent.id} state=${state}`);
|
|
} else {
|
|
await this.prisma.paymentIntent.update({
|
|
where: { id: intent.id },
|
|
data: {
|
|
status: mappedStatus as unknown as PaymentIntentStatus,
|
|
providerTxnId: transactionId,
|
|
},
|
|
});
|
|
this.logger.log(`Waafi payment status updated: intent=${intent.id} status=${mappedStatus}`);
|
|
}
|
|
|
|
return { received: true };
|
|
}
|
|
}
|