mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 09:42:53 +00:00
89 lines
3.2 KiB
TypeScript
89 lines
3.2 KiB
TypeScript
import { randomUUID } from "node:crypto";
|
|
import { Body, Controller, Inject, Logger, Post } from "@nestjs/common";
|
|
import { ApiOperation, ApiTags } from "@nestjs/swagger";
|
|
import {
|
|
PaymentEvent,
|
|
PaymentReferenceType,
|
|
PaymentService,
|
|
ProviderMethod,
|
|
paymentRoutingKey,
|
|
} from "@edr/types";
|
|
import {
|
|
PAYMENT_EVENT_PUBLISHER,
|
|
PaymentEventPublisher,
|
|
} from "./publisher/payment-event-publisher";
|
|
import { TestPaymentEventDto } from "./dto/test-payment-event.dto";
|
|
|
|
/**
|
|
* DEV-ONLY test harness. Publishes a synthetic payment event through the real
|
|
* PaymentEventPublisher (RabbitMQ in dev), so the passenger/freight consumer receives it
|
|
* exactly as in production — without creating an intent or going through a booking + provider
|
|
* flow. Registered only when NODE_ENV !== "production" (see OutboxModule); never reachable in prod.
|
|
*
|
|
* Quick check (no body): POST /test/payment-event -> publishes payment.passenger.succeeded.
|
|
* Real side effects: pass a real bookingId as `referenceId`.
|
|
*/
|
|
@ApiTags("Dev test (non-production)")
|
|
@Controller("test")
|
|
export class TestEventsController {
|
|
private readonly logger = new Logger(TestEventsController.name);
|
|
|
|
constructor(
|
|
@Inject(PAYMENT_EVENT_PUBLISHER)
|
|
private readonly publisher: PaymentEventPublisher,
|
|
) {}
|
|
|
|
@Post("payment-event")
|
|
@ApiOperation({
|
|
summary:
|
|
"DEV ONLY: publish a synthetic payment event to the broker (passenger/freight consumes it)",
|
|
description:
|
|
"Bypasses intents/booking. Empty body publishes a payment.succeeded for PASSENGER. " +
|
|
"Set referenceId to a real bookingId to trigger the consumer's seat/ticket side effects.",
|
|
})
|
|
async publishTestEvent(
|
|
@Body() dto: TestPaymentEventDto,
|
|
): Promise<{ published: true; routingKey: string; event: PaymentEvent }> {
|
|
const eventType = dto.eventType ?? "payment.succeeded";
|
|
const service = dto.service ?? PaymentService.PASSENGER;
|
|
const now = new Date().toISOString();
|
|
|
|
const base = {
|
|
version: 1 as const,
|
|
eventId: randomUUID(),
|
|
occurredAt: now,
|
|
service,
|
|
intentId: dto.intentId ?? randomUUID(),
|
|
referenceType: dto.referenceType ?? PaymentReferenceType.BOOKING,
|
|
referenceId: dto.referenceId ?? randomUUID(),
|
|
merchantOrderId: dto.merchantOrderId ?? `test-${randomUUID().slice(0, 8)}`,
|
|
provider: dto.provider ?? ProviderMethod.WAAFI,
|
|
amountMinor: dto.amountMinor ?? 10_000,
|
|
currency: dto.currency ?? "ETB",
|
|
};
|
|
|
|
const event: PaymentEvent =
|
|
eventType === "payment.failed"
|
|
? {
|
|
...base,
|
|
eventType: "payment.failed",
|
|
failureCode: dto.failureCode ?? "TEST_DECLINED",
|
|
failureMessage: dto.failureMessage ?? "Synthetic test failure",
|
|
}
|
|
: {
|
|
...base,
|
|
eventType: "payment.succeeded",
|
|
providerTxnId: dto.providerTxnId ?? `TEST-${randomUUID().slice(0, 8)}`,
|
|
paidAt: now,
|
|
};
|
|
|
|
await this.publisher.publish(event);
|
|
|
|
const routingKey = paymentRoutingKey(event.service, event.eventType);
|
|
this.logger.log(
|
|
`published TEST ${event.eventType} (${event.eventId}) ref=${event.referenceId} -> ${routingKey}`,
|
|
);
|
|
return { published: true, routingKey, event };
|
|
}
|
|
}
|