import type { MarkupRule } from "@/modules/pricing/engine"; import { applyMarkup } from "@/modules/pricing/engine"; import type { Priority1QuoteLine } from "@/workers/rpa/priority1/quote-extract"; export type Priority1DisplayMode = "ltl_cards" | "ftl_calendar"; export type Priority1DisplayLine = Priority1QuoteLine & { markup_amount: number; final_total_usd: number; }; export type Priority1StoredQuotes = { provider: "priority1"; display_mode: Priority1DisplayMode; lines: Priority1DisplayLine[]; }; export function inferPriority1DisplayMode( lines: Priority1QuoteLine[], shipmentType?: string, ): Priority1DisplayMode { if (shipmentType === "ftl") { return "ftl_calendar"; } if ( lines.some( (l) => l.source === "ftl-calendar" || /ftl\s*calendar/i.test(l.serviceLevel) || l.carrier.includes("FTL 日历"), ) ) { return "ftl_calendar"; } return "ltl_cards"; } export function applyMarkupToPriority1Lines( lines: Priority1QuoteLine[], rule: MarkupRule, ): Priority1DisplayLine[] { return lines.map((line) => { const { markupAmount, finalTotal } = applyMarkup( line.totalUsd, line.totalUsd, rule, ); return { ...line, markup_amount: markupAmount, final_total_usd: finalTotal, }; }); } export function buildPriority1StoredQuotes( lines: Priority1QuoteLine[], rule: MarkupRule, shipmentType?: string, ): Priority1StoredQuotes { const marked = applyMarkupToPriority1Lines(lines, rule); return { provider: "priority1", display_mode: inferPriority1DisplayMode(lines, shipmentType), lines: marked, }; } export function parsePriority1StoredQuotes( json: unknown, ): Priority1StoredQuotes | null { if (!json || typeof json !== "object" || Array.isArray(json)) { return null; } const o = json as Record; if (o.provider !== "priority1" || !Array.isArray(o.lines)) { return null; } return o as unknown as Priority1StoredQuotes; } /** 从 pickupJson 读取 Priority1 填单上下文 */ export function readPriority1ShipmentMeta( pickupJson: unknown, ): { shipmentType?: string; pickupDate?: string; commodity?: string } { if (!pickupJson || typeof pickupJson !== "object") { return {}; } const o = pickupJson as Record; return { shipmentType: typeof o.priority1_shipment_type === "string" ? o.priority1_shipment_type : undefined, pickupDate: typeof o.priority1_pickup_date === "string" ? o.priority1_pickup_date : undefined, commodity: typeof o.priority1_commodity === "string" ? o.priority1_commodity : undefined, }; } type LegacyQuoteTierRow = { service_level?: string; rate_option?: string; carrier?: string; transit_days?: string; raw_total?: number; final_total?: number; markup_amount?: number; }; /** 旧版 MotherShip tier 数组 → Priority1 展示行(兼容未升级的 worker / stale 降级) */ export function legacyTiersToPriority1StoredQuotes( tiers: LegacyQuoteTierRow[], shipmentType?: string, ): Priority1StoredQuotes | null { const lines: Priority1DisplayLine[] = []; for (const tier of tiers) { const raw = Number(tier.raw_total ?? tier.final_total ?? 0); const final = Number(tier.final_total ?? tier.raw_total ?? 0); if (!Number.isFinite(raw) || raw <= 0) continue; lines.push({ rank: lines.length + 1, carrier: String(tier.carrier ?? "Unknown").trim() || "Unknown", carrierCode: "", totalUsd: raw, markup_amount: Number(tier.markup_amount ?? Math.max(0, final - raw)) || 0, final_total_usd: final > 0 ? final : raw, transitDays: Number.parseInt(String(tier.transit_days ?? ""), 10) || 0, deliveryDate: null, expirationDate: null, serviceLevel: "STANDARD LTL", quoteId: null, caboUrl: null, source: "legacy-tier", }); } if (lines.length === 0) return null; return { provider: "priority1", display_mode: inferPriority1DisplayMode(lines, shipmentType), lines, }; } function isLegacyQuoteTierArray(json: unknown): json is LegacyQuoteTierRow[] { if (!Array.isArray(json) || json.length === 0) return false; const row = json[0]; if (!row || typeof row !== "object") return false; const o = row as Record; return ( typeof o.service_level === "string" && (typeof o.raw_total === "number" || typeof o.final_total === "number") ); } /** 从 DB quotesJson 解析 Priority1 展示数据(含旧 tier 兼容) */ export function resolvePriority1StoredQuotes( quotesJson: unknown, pickupJson?: unknown, ): Priority1StoredQuotes | null { const stored = parsePriority1StoredQuotes(quotesJson); if (stored && stored.lines.length > 0) { return stored; } const meta = readPriority1ShipmentMeta(pickupJson); // MotherShip tier 数组与 Priority1 旧 tier 结构相似;仅 Priority1 询价上下文才做 legacy 转换 if (!meta.shipmentType) { return null; } if (isLegacyQuoteTierArray(quotesJson)) { return legacyTiersToPriority1StoredQuotes(quotesJson, meta.shipmentType); } return null; }