import type { QuoteRecord } from "@prisma/client"; import { filterQuotesForMotherShipUiDisplay } from "@/lib/constants/mothership-ui-tiers"; import { PRIORITY1_MANUAL_FOLLOWUP_ERROR_CODE } from "@/modules/priority1/constants"; import { readPriority1ShipmentMeta, resolvePriority1StoredQuotes, type Priority1DisplayLine, } from "@/modules/priority1/quote-storage"; import { getConfidenceScore } from "@/modules/quote/confidence"; import { formatQuoteErrorMessage } from "@/modules/quote/quote-error-messages"; type QuoteTierKey = { service_level: string; rate_option: string }; export type Priority1QuoteDetailPayload = { display_mode: "ltl_cards" | "ftl_calendar"; lines: Priority1DisplayLine[]; shipment_meta?: { shipment_type?: string; pickup_date?: string; commodity?: string; origin_zip?: string; destination_zip?: string; weight_lb?: number; }; }; export type QuoteDetailResponse = { quote_id: string; request_id: string; status: "processing" | "done" | "failed" | "expired"; valid_until?: string; source_type?: "rpa" | "cache" | "stale"; is_realtime?: boolean; confidence_score?: number; currency: string; error_code?: string; error_message?: string; quotes?: unknown[]; priority1?: Priority1QuoteDetailPayload; }; export type QuoteSummaryItem = { quote_id: string; request_id: string; status: string; source_type: string | null; is_realtime: boolean; created_at: string; valid_until: string | null; pallet_count: number; cargo_type: string; error_code: string | null; }; function resolveStatus(record: QuoteRecord): QuoteDetailResponse["status"] { if ( record.status === "done" && record.validUntil && record.validUntil.getTime() < Date.now() ) { return "expired"; } return record.status as QuoteDetailResponse["status"]; } /** 将 QuoteRecord 格式化为 GET /quotes/{id} 响应 */ export function serializeQuoteDetail(record: QuoteRecord): QuoteDetailResponse { const status = resolveStatus(record); const sourceType = record.sourceType as | "rpa" | "cache" | "stale" | null | undefined; const base: QuoteDetailResponse = { quote_id: record.quoteId, request_id: record.requestId, status, currency: record.currency, }; if (status === "processing") { return base; } if (status === "failed") { const errorCode = record.errorCode ?? "QUOTE_UNAVAILABLE"; return { ...base, error_code: errorCode, error_message: formatQuoteErrorMessage(errorCode, record.errorMessage), is_realtime: record.isRealtime, }; } if (status === "expired") { return { ...base, valid_until: record.validUntil?.toISOString(), source_type: sourceType ?? undefined, is_realtime: record.isRealtime, }; } if ( record.errorCode === PRIORITY1_MANUAL_FOLLOWUP_ERROR_CODE ) { const confidence = record.confidenceScore != null ? Number(record.confidenceScore) : getConfidenceScore("rpa"); return { ...base, source_type: sourceType ?? "rpa", is_realtime: record.isRealtime, confidence_score: confidence, error_code: PRIORITY1_MANUAL_FOLLOWUP_ERROR_CODE, error_message: formatQuoteErrorMessage( record.errorCode, record.errorMessage, ), quotes: [], }; } const confidence = record.confidenceScore != null ? Number(record.confidenceScore) : sourceType ? getConfidenceScore(sourceType) : 0.95; const priority1Stored = resolvePriority1StoredQuotes( record.quotesJson, record.pickupJson, ); const priority1Meta = readPriority1ShipmentMeta(record.pickupJson); if (priority1Stored) { const pickup = record.pickupJson as Record | null; const delivery = record.deliveryJson as Record | null; const meta = readPriority1ShipmentMeta(record.pickupJson); return { ...base, valid_until: record.validUntil?.toISOString(), source_type: sourceType ?? undefined, is_realtime: record.isRealtime, confidence_score: confidence, priority1: { display_mode: priority1Stored.display_mode, lines: priority1Stored.lines, shipment_meta: { shipment_type: meta.shipmentType, pickup_date: meta.pickupDate, commodity: meta.commodity, origin_zip: typeof pickup?.zip === "string" ? pickup.zip : undefined, destination_zip: typeof delivery?.zip === "string" ? delivery.zip : undefined, weight_lb: record.weightLb != null ? Number(record.weightLb) : undefined, }, }, }; } if (priority1Meta.shipmentType) { const errorCode = record.errorCode ?? "QUOTE_UNAVAILABLE"; return { ...base, status: "failed", error_code: errorCode, error_message: formatQuoteErrorMessage(errorCode, record.errorMessage), is_realtime: record.isRealtime, confidence_score: confidence, }; } return { ...base, valid_until: record.validUntil?.toISOString(), source_type: sourceType ?? undefined, is_realtime: record.isRealtime, confidence_score: confidence, quotes: filterQuotesForMotherShipUiDisplay( ((record.quotesJson as QuoteTierKey[]) ?? []) as QuoteTierKey[], ), }; } /** 历史列表摘要 */ export function serializeQuoteSummary(record: QuoteRecord): QuoteSummaryItem { const status = resolveStatus(record); return { quote_id: record.quoteId, request_id: record.requestId, status, source_type: record.sourceType, is_realtime: record.isRealtime, created_at: record.createdAt.toISOString(), valid_until: record.validUntil?.toISOString() ?? null, pallet_count: record.palletCount, cargo_type: record.cargoType, error_code: record.errorCode, }; }