add GL operations for customs risk assignment, duty advising, and incident reporting

This commit is contained in:
Marshal
2026-06-28 16:09:45 +00:00
parent 7c744352d1
commit e1d54746c2
31 changed files with 1879 additions and 29 deletions

View File

@@ -297,3 +297,106 @@ export function useCompleteMilestone(bookingId: string) {
onError: () => toast.error("Failed to complete milestone"),
});
}
function invalidateMilestones(qc: QueryClient, bookingId: string) {
void qc.invalidateQueries({
queryKey: QUERY_KEYS.CONTRACTS.bookingMilestones(bookingId),
});
}
/** Assign a customs risk level (completes RISK_ASSIGNED). */
export function useAssignRisk(bookingId: string) {
const qc = useQueryClient();
return useMutation({
mutationFn: (payload: {
riskLevel: Freight.CustomsRiskLevel;
note?: string;
}) => contractsService.assignRisk(bookingId, payload),
onSuccess: () => {
toast.success("Customs risk assigned");
invalidateMilestones(qc, bookingId);
},
onError: () => toast.error("Failed to assign risk"),
});
}
/** Advise duty & tax (completes DUTY_TAXES_ADVISED). */
export function useAdviseDuty(bookingId: string) {
const qc = useQueryClient();
return useMutation({
mutationFn: (payload: {
amount: number;
currency: string;
declarationSerial?: string;
note?: string;
}) => contractsService.adviseDuty(bookingId, payload),
onSuccess: () => {
toast.success("Duty & tax advised to customer");
invalidateMilestones(qc, bookingId);
},
onError: () => toast.error("Failed to advise duty & tax"),
});
}
/** Route the shipment to a station + bind GL staff. */
export function useAssignStation(bookingId: string) {
const qc = useQueryClient();
return useMutation({
mutationFn: (payload: { stationYardId: string; staffId?: string }) =>
contractsService.assignStation(bookingId, payload),
onSuccess: () => {
toast.success("Shipment routed to station");
void qc.invalidateQueries({
queryKey: QUERY_KEYS.BOOKINGS.byId(bookingId),
});
},
onError: () => toast.error("Failed to assign station"),
});
}
/** Upload GL post-booking documents (DO/RO/T1/…); auto-completes milestones. */
export function useUploadGlDocuments(bookingId: string) {
const qc = useQueryClient();
return useMutation({
mutationFn: (files: Record<string, File | null>) =>
contractsService.uploadGlDocuments(bookingId, files),
onSuccess: (res) => {
const n = res.completedMilestones.length;
toast.success(
n > 0
? `Uploaded — ${n} milestone${n === 1 ? "" : "s"} advanced`
: "Documents uploaded",
);
invalidateMilestones(qc, bookingId);
},
onError: () => toast.error("Failed to upload documents"),
});
}
/** Incidents for a shipment (damage / exceptions). */
export function useBookingIncidents(bookingId: string | undefined) {
return useQuery({
queryKey: QUERY_KEYS.CONTRACTS.bookingIncidents(bookingId ?? ""),
queryFn: () => contractsService.listIncidents(bookingId!),
enabled: !!bookingId,
});
}
/** Report a cargo exception with photos. */
export function useReportIncident(bookingId: string) {
const qc = useQueryClient();
return useMutation({
mutationFn: (payload: {
incidentType: Freight.IncidentType;
description: string;
photos: File[];
}) => contractsService.reportIncident(bookingId, payload),
onSuccess: () => {
toast.success("Incident reported");
void qc.invalidateQueries({
queryKey: QUERY_KEYS.CONTRACTS.bookingIncidents(bookingId),
});
},
onError: () => toast.error("Failed to report incident"),
});
}