style: clean up the invoice and setup event for warehouse.

This commit is contained in:
Nathnael
2026-06-30 13:28:14 +00:00
parent fa3138f2ac
commit 0056dec924
5 changed files with 30 additions and 68 deletions

View File

@@ -6,8 +6,6 @@ import {
ParseUUIDPipe,
Query,
Res,
Body,
Post,
} from "@nestjs/common";
import {
ApiTags,
@@ -18,9 +16,9 @@ import {
} from "@nestjs/swagger";
import { Response } from "express";
import { Public } from "@edr/api-common";
import { BookingView, FreightAdmin } from "../../common/booking-guards";
import { BookingView } from "../../common/booking-guards";
import { PaymentService } from "./payment.service";
import { IntentStatusDto, RefundDto } from "./payments.dto";
import { IntentStatusDto } from "./payments.dto";
@ApiTags("Payment")
@Controller("payments")
@@ -73,13 +71,6 @@ export class PaymentController {
return this.paymentService.getIntentByBookingId(bookingId);
}
@Post("refund")
@FreightAdmin()
@ApiOperation({ summary: "Refund a paid booking (staff/admin only)" })
refund(@Body() dto: RefundDto) {
return this.paymentService.refund(dto);
}
@Get("receipt/:orderId")
@Public()
@ApiOperation({ summary: "Generate a payment receipt HTML page" })

View File

@@ -7,7 +7,6 @@ import {
Logger,
NotFoundException,
} from "@nestjs/common";
import { DataSource } from "typeorm";
import { PaymentEntity } from "./entities/payment.entity";
import { PaymentRepository } from "./payment.repository";
import { PaymentClientService } from "./payment-client.service";
@@ -16,7 +15,6 @@ import { BillingService } from "../billing/billing.service";
import * as fs from "fs";
import * as path from "path";
import * as Handlebars from "handlebars";
import { Booking } from "../bookings/entities/booking.entity";
import { ClientAction, ProviderPaymentStatus } from "@edr/payment-providers";
import {
@@ -29,7 +27,6 @@ import {
InitiateResponseDto,
IntentStatusDto,
PaymentPlatformDto,
RefundDto,
} from "./payments.dto";
/** Everything the gateway needs to open an intent. Amount/currency are supplied by
@@ -96,7 +93,6 @@ export class PaymentService {
private readonly logger = new Logger(PaymentService.name);
constructor(
private readonly datasource: DataSource,
private readonly paymentRepo: PaymentRepository,
private readonly paymentClient: PaymentClientService,
@Inject(forwardRef(() => BillingService))
@@ -404,34 +400,6 @@ export class PaymentService {
);
}
async refund(dto: RefundDto) {
const intent = await this.paymentRepo.findOneBy({
refId: dto.bookingId,
type: "booking",
});
if (!intent || intent.status !== "success") {
throw new BadRequestException("No successful payment to refund");
}
// NOTE: refunding still mutates the booking directly — left intact pending
// the refund redesign. TODO: route refunds through billing.refundPayable +
// a `${source}.invoice.refunded` reaction, like settlement.
await this.datasource.transaction(async (mg) => {
await mg.update(
PaymentEntity,
{ id: intent.id },
{ status: "refunded", refundedAt: new Date() },
);
await mg.update(
Booking,
{ id: dto.bookingId },
{ paymentStatus: "FAILED", status: "CANCELLED" },
);
});
return { refunded: true, bookingId: dto.bookingId };
}
async getActivePaymentByOrderIdAndMethod(
orderId: string,
method: PaymentEntity["method"],
@@ -527,16 +495,10 @@ export class PaymentService {
`Payment finalized for intent ${intent.id}, alreadyFinalized: ${alreadyFinalized}`,
);
// When the intent references a booking, flip the booking itself paid.
// refId holds the booking id (the domain reference the intent opened with).
if (intent.referenceType === PaymentReferenceType.BOOKING) {
await this.datasource.manager.update(
Booking,
{ id: intent.refId },
{ status: "PAID", paymentStatus: "PAID" },
);
}
// console.log(`Payment finalized for booking ${event.referenceId}, intent ${intent.id}, alreadyFinalized: ${alreadyFinalized}`);
// The payment service stays domain-agnostic: it settles the intent and
// lets billing settle the invoice (markIntentSucceeded → settleByPaymentId),
// which emits `${source}.invoice.paid`. Per-source advances (booking → PAID,
// warehouse → release, …) live in the domain services that listen for it.
return { processed: true, alreadyFinalized };
}