import { Injectable, NotFoundException } from '@nestjs/common'; import { Freight } from '@edr/types'; import { BookingsRepository } from './bookings.repository'; import { Booking } from './entities/booking.entity'; import { assertBookingStatus } from './booking-status.util'; import { InAppPaymentReceiptDto } from './dto/pay-booking.dto'; import { BillingService } from '../billing/billing.service'; import { PaymentMethodTypeEnum } from '../payment/payments.dto'; export interface InAppPaymentReceipt extends InAppPaymentReceiptDto { } @Injectable() export class BookingPaymentService { constructor( private readonly bookingsRepository: BookingsRepository, private readonly billing: BillingService, ) { } /** * Start payment for a booking. The booking never touches the payment gateway * directly — it charges its invoice through billing, which resolves the amount * and drives the provider. Returns the provider redirect URL (empty when none). */ async pay(bookingId: string): Promise<{ redirectUrl: string }> { const booking = await this.requireBooking(bookingId); assertBookingStatus(booking, ['FULLY_EXECUTED', 'SELECTED_FOR_BATCH', 'AWAITING_PAYMENT', '']); const resp = await this.billing.payInvoice(Freight.InvoiceSource.Booking, bookingId, { method: PaymentMethodTypeEnum.TELEBIRR, platform: 'web', }); const action = resp.clientAction as { type?: string; url?: string } | undefined; return { redirectUrl: action?.type === 'REDIRECT' ? (action.url ?? '') : '', }; } private async requireBooking(id: string): Promise { const booking = await this.bookingsRepository.findById(id); if (!booking) throw new NotFoundException(`Booking ${id} not found`); return booking; } }