import { compareUiTierSortOrder } from "@/lib/constants/quote"; import type { QuoteItem } from "@/modules/providers/quote-provider"; import { RpaError } from "@/modules/rpa/errors"; function tierKey(item: QuoteItem): string { const carrier = (item.carrier ?? "").trim().toLowerCase(); return `${item.serviceLevel}/${item.rateOption}/${carrier}`; } /** 保留 MotherShip 实际返回的全部 UI 档位;同档不同承运商不去重挤掉 */ export function normalizeQuoteItems(items: QuoteItem[]): QuoteItem[] { const map = new Map(); for (const item of items) { map.set(tierKey(item), item); } const normalized = [...map.values()].sort((a, b) => { const byTier = compareUiTierSortOrder( a.serviceLevel, a.rateOption, b.serviceLevel, b.rateOption, ); if (byTier !== 0) return byTier; return (a.carrier ?? "").localeCompare(b.carrier ?? ""); }); if (normalized.length === 0) { throw new RpaError( "RPA_DATA_INVALID", "未解析到有效报价档位", { retryable: false }, ); } return normalized; } /** 网络层报价严格校验(唯一验收入口) */ export function validateQuoteSchema(items: QuoteItem[]): QuoteItem[] { const normalized = normalizeQuoteItems(items); for (const tier of normalized) { if (tier.rawFreight <= 0) { throw new RpaError( "RPA_DATA_INVALID", `档位 ${tier.serviceLevel}/${tier.rateOption} 运费无效`, { retryable: false }, ); } if (!tier.transitDays?.trim() || tier.transitDays === "—") { throw new RpaError( "RPA_DATA_INVALID", `档位 ${tier.serviceLevel}/${tier.rateOption} 时效为空`, { retryable: false }, ); } } return normalized; }