Enhance contract and booking request handling

This commit is contained in:
Marshal
2026-06-30 02:20:32 +00:00
parent d91389daac
commit a072f04450
8 changed files with 735 additions and 62 deletions

View File

@@ -34,7 +34,17 @@ export class BookingRequestRepository extends BaseRepository<BookingRequest> {
async findById(id: string): Promise<BookingRequest | null> {
return this.repository.findOne({
where: { id },
relations: { contract: true },
// Load the contract with the bits the detail page surfaces: customer
// (company), service type (mile/customs flags), routes (with yard labels)
// and cargo scope.
relations: {
contract: {
company: true,
serviceType: true,
routes: { originYard: true, destinationYard: true },
cargoScope: true,
},
},
});
}

View File

@@ -17,12 +17,14 @@ import * as fs from "fs";
import * as path from "path";
import * as Handlebars from "handlebars";
import { Booking } from "../bookings/entities/booking.entity";
import { Invoice } from "../billing/entities/invoice.entity";
import {
ClientAction,
ProviderPaymentStatus,
} from "@edr/payment-providers";
import {
Freight,
PaymentService as PaymentServiceEnum,
PaymentReferenceType,
PaymentIntentSnapshot,
@@ -462,30 +464,37 @@ export class PaymentService {
failureCode?: string;
failureMessage?: string;
}): Promise<{ processed: boolean; alreadyFinalized?: boolean; reason?: string }> {
console.log(`Received payment event: ${JSON.stringify(event)}`);
if (event.eventType === "payment.succeeded") {
console.log(`Payment succeeded event received for reference ${event.referenceId}`);
const intent = await this.paymentRepo.findOneBy({ refId: event.referenceId });
if (!intent) {
console.warn(`No local intent found for reference ${event.referenceId}`);
return { processed: false, reason: `No local intent for reference ${event.referenceId}` };
}
console.log(`Processing payment succeeded event for intent: }`,intent);
const { alreadyFinalized } = await this.markIntentSucceeded(intent.id, {
providerTxnId: event.providerTxnId,
paidAt: event.paidAt ? new Date(event.paidAt) : undefined,
notify: true,
});
console.log(`Payment finalized for intent ${intent.id}, alreadyFinalized: ${alreadyFinalized}`);
console.log(`Payment intent ${intent.id} marked as succeeded (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) {
// The invoice the intent settled is the authority on what was paid for.
// Its `paymentId` links 1:1 to this intent; when its source is a booking,
// `sourceId` holds that booking id — flip the booking itself paid.
const invoice = await this.datasource.manager.findOneBy(Invoice, {
paymentId: intent.id,
});
console.log(`Invoice lookup for payment intent ${intent.id} returned invoice ${invoice?.id} (source=${invoice?.source}, sourceId=${invoice?.sourceId})`);
if (invoice?.source === Freight.InvoiceSource.Booking) {
console.log(`Marking booking ${invoice.sourceId} as PAID due to invoice ${invoice.id} settlement`);
await this.datasource.manager.update(
Booking,
{ id: intent.refId },
{ id: invoice.sourceId },
{ status: "PAID", paymentStatus: "PAID" },
);
}
// console.log(`Payment finalized for booking ${event.referenceId}, intent ${intent.id}, alreadyFinalized: ${alreadyFinalized}`);
return { processed: true, alreadyFinalized };
}