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

@@ -1,6 +1,6 @@
import type { ReactNode } from "react";
import { Badge, Stack, Tabs, Text } from "@mantine/core";
import { AlertTriangle, FileText, Share2, ShieldAlert } from "lucide-react";
import { AlertTriangle, FileText, Receipt, Share2, ShieldAlert } from "lucide-react";
import type { Freight } from "@edr/types";
import { useAuth } from "@/auth/useAuth";
@@ -9,6 +9,7 @@ import { SectionCard } from "@/components/bookings/detail/SectionCard";
import { AssignRiskCard } from "@/components/contracts/gl-actions/AssignRiskCard";
import { IncidentReportCard } from "@/components/contracts/gl-actions/IncidentReportCard";
import { ClearanceUploadedDocumentsPanel } from "@/components/contracts/ClearanceUploadedDocumentsPanel";
import { ClearanceChargesTab } from "@/components/contracts/ClearanceChargesTab";
import { GlExchangePanel } from "@/components/contracts/GlExchangePanel";
export interface ClearanceOpsTabsProps {
@@ -68,6 +69,12 @@ export function ClearanceOpsTabs({
Boolean(exchangeEntityId) &&
(hasPermission(user, FREIGHT_PERMS.contracts.clearanceEtActions) ||
hasPermission(user, FREIGHT_PERMS.contracts.clearanceDjActions));
// Post-finalization customer billing. This layout is only rendered on the ET
// clearance pages — the DJ page (GlClearanceDetailPage) mounts its own tab.
const showCharges =
Boolean(bookingId) &&
Boolean(onViewFile) &&
hasPermission(user, FREIGHT_PERMS.contracts.clearanceEtActions);
// Risk assignment + incident reporting hit bookings:operations endpoints.
const canOps = hasPermission(user, FREIGHT_PERMS.bookings.operations);
const hasTabs = (showOpsTabs && hasOps) || showDocuments || showExchange;
@@ -100,6 +107,11 @@ export function ClearanceOpsTabs({
Document exchange
</Tabs.Tab>
) : null}
{showCharges ? (
<Tabs.Tab value="charges" leftSection={<Receipt size={14} />}>
Customer charges
</Tabs.Tab>
) : null}
{showOpsTabs && canOps && riskMs ? (
<Tabs.Tab value="risk" leftSection={<ShieldAlert size={14} />}>
Risk assignment
@@ -131,6 +143,16 @@ export function ClearanceOpsTabs({
</Tabs.Panel>
) : null}
{showCharges ? (
<Tabs.Panel value="charges">
<ClearanceChargesTab
bookingId={bookingId!}
roleMode="ET"
onViewFile={onViewFile!}
/>
</Tabs.Panel>
) : null}
{showOpsTabs && canOps && riskMs && bookingId ? (
<Tabs.Panel value="risk">
<SectionCard icon={ShieldAlert} title="Customs risk" accent="edr-green">