feat(bookings): add ad-hoc additional-charge module

New freight.additional_charge table, independent of BookingClearanceCharge
(unbounded per booking, free-text reason). Draft -> send issues an invoice
and notifies the customer in-app/SMS/email; settles via the standard
.invoice.paid event. Adds the Additional charges row-menu entry
next to Cancel booking, permission-gated.

Not included: the Additional Payments tab UI, add-charge modal, portal pay
flow.
This commit is contained in:
Hagernesh
2026-08-20 12:35:19 +00:00
parent 8e2bab27cf
commit 0ceb595714
12 changed files with 622 additions and 1 deletions

View File

@@ -13,6 +13,7 @@ import { logCtx } from "@edr/api-common";
import { DataSource, EntityManager, In, SelectQueryBuilder } from "typeorm";
import { Booking } from "../bookings/entities/booking.entity";
import { AdditionalCharge } from "../bookings/entities/additional-charge.entity";
// Entity-only import (no module edge): portal reads resolve shipping-line
// payers straight off the table.
import { ShippingLineCompany } from "../shipping-lines/entities/shipping-line-company.entity";
@@ -1958,6 +1959,14 @@ export class BillingService {
.getRepository(Booking)
.update({ id: invoice.sourceId }, { pnrCode: billReference });
}
// Same reference, for an ad-hoc additional charge — its own column, since
// an AdditionalCharge doesn't own a Booking-scoped `pnrCode` and a booking
// can carry many of these at once.
if (billReference && invoice.source === Freight.InvoiceSource.AdditionalCharge) {
await this.dataSource
.getRepository(AdditionalCharge)
.update({ id: invoice.sourceId }, { paymentReference: billReference });
}
// Settlement is driven by the payment API (webhook/outbox → payment.succeeded);
// billing must not simulate it. Kept for local demos only.