feat(bookings): two-level clearance charges (port + misc) billed to customer with invoices

This commit is contained in:
Marshal
2026-08-20 05:24:57 +00:00
parent 4adb53b486
commit c138da6137
14 changed files with 1281 additions and 53 deletions

View File

@@ -432,6 +432,69 @@ export const bookingsService = {
return unwrap(response.data) as Freight.ClearanceView;
},
// ── Clearance charges (post-finalization customer billing) ──
getClearanceCharges: async (id: string): Promise<Freight.ClearanceCharge[]> => {
const response = await client.get(`/bookings/${id}/clearance/charges`);
return unwrap(response.data) as Freight.ClearanceCharge[];
},
/** GL Djibouti uploads (or replaces, until billed) the port-charges document. */
uploadPortChargeDocument: async (
id: string,
file: File,
): Promise<Freight.ClearanceCharge[]> => {
const form = new FormData();
form.append("file", file);
const response = await client.post(
`/bookings/${id}/clearance/charges/port-document`,
form,
{ headers: { "Content-Type": "multipart/form-data" } },
);
return unwrap(response.data) as Freight.ClearanceCharge[];
},
/** GL Ethiopia sets or revises a charge's amount + currency. */
billClearanceCharge: async (
id: string,
chargeId: string,
payload: { amount: number; currency: string },
): Promise<Freight.ClearanceCharge[]> => {
const response = await client.patch(
`/bookings/${id}/clearance/charges/${chargeId}/bill`,
payload,
);
return unwrap(response.data) as Freight.ClearanceCharge[];
},
/** GL Ethiopia issues the charge's payable invoice to the customer. */
sendClearanceCharge: async (
id: string,
chargeId: string,
): Promise<Freight.ClearanceCharge[]> => {
const response = await client.post(
`/bookings/${id}/clearance/charges/${chargeId}/send`,
);
return unwrap(response.data) as Freight.ClearanceCharge[];
},
/** GL Ethiopia creates the miscellaneous charge (document + amount + currency). */
createMiscellaneousCharge: async (
id: string,
file: File,
payload: { amount: number; currency: string },
): Promise<Freight.ClearanceCharge[]> => {
const form = new FormData();
form.append("file", file);
form.append("amount", String(payload.amount));
form.append("currency", payload.currency);
const response = await client.post(
`/bookings/${id}/clearance/charges/miscellaneous`,
form,
{ headers: { "Content-Type": "multipart/form-data" } },
);
return unwrap(response.data) as Freight.ClearanceCharge[];
},
/** GL ET asks Djibouti to name the officer handling the shipment in transit. */
requestTransitAssignee: (id: string, note?: string) =>
postBooking<BookingDetail>(B.CLEARANCE_TRANSIT_ASSIGNEE_REQUEST(id), {