|
|
import { normalizeToFourTiers } from "@/modules/quote/quote-completeness";
|
|
|
import type { QuoteItem } from "@/modules/providers/quote-provider";
|
|
|
|
|
|
const CORE_TIER_KEYS = [
|
|
|
"standard/lowest",
|
|
|
"standard/fastest",
|
|
|
"guaranteed/lowest",
|
|
|
"guaranteed/fastest",
|
|
|
] as const;
|
|
|
|
|
|
const OPTIONAL_TIER_KEYS = [
|
|
|
"standard/bestValue",
|
|
|
"guaranteed/bestValue",
|
|
|
] as const;
|
|
|
|
|
|
export type ProbeValidationResult =
|
|
|
| { ok: true }
|
|
|
| { ok: false; message: string };
|
|
|
|
|
|
function resolveProbeItem(
|
|
|
map: Map<string, QuoteItem>,
|
|
|
key: string,
|
|
|
): QuoteItem | undefined {
|
|
|
const direct = map.get(key);
|
|
|
if (direct) {
|
|
|
return direct;
|
|
|
}
|
|
|
if (key.endsWith("/fastest")) {
|
|
|
return map.get(key.replace("/fastest", "/lowest"));
|
|
|
}
|
|
|
return undefined;
|
|
|
}
|
|
|
|
|
|
/** TC-601:至少 standard/guaranteed lowest;缺失 fastest 可复用 lowest */
|
|
|
export function validateProbeItems(
|
|
|
items: QuoteItem[],
|
|
|
): ProbeValidationResult {
|
|
|
const map = new Map<string, QuoteItem>();
|
|
|
for (const item of items) {
|
|
|
map.set(`${item.serviceLevel}/${item.rateOption}`, item);
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
normalizeToFourTiers(
|
|
|
items.map((item) => ({
|
|
|
service_level: item.serviceLevel,
|
|
|
rate_option: item.rateOption,
|
|
|
})),
|
|
|
);
|
|
|
} catch (error) {
|
|
|
return {
|
|
|
ok: false,
|
|
|
message: error instanceof Error ? error.message : "档位不足",
|
|
|
};
|
|
|
}
|
|
|
|
|
|
for (const key of CORE_TIER_KEYS) {
|
|
|
const item = resolveProbeItem(map, key);
|
|
|
if (!item) {
|
|
|
return { ok: false, message: `缺少档位 ${key}` };
|
|
|
}
|
|
|
if (item.rawFreight <= 0) {
|
|
|
return {
|
|
|
ok: false,
|
|
|
message: `档位 ${key} rawFreight 无效`,
|
|
|
};
|
|
|
}
|
|
|
if (!item.transitDescription?.trim()) {
|
|
|
return {
|
|
|
ok: false,
|
|
|
message: `档位 ${key} transit_description 为空`,
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
for (const key of OPTIONAL_TIER_KEYS) {
|
|
|
const item = map.get(key);
|
|
|
if (!item) {
|
|
|
continue;
|
|
|
}
|
|
|
if (item.rawFreight <= 0) {
|
|
|
return {
|
|
|
ok: false,
|
|
|
message: `档位 ${key} rawFreight 无效`,
|
|
|
};
|
|
|
}
|
|
|
if (!item.transitDescription?.trim()) {
|
|
|
return {
|
|
|
ok: false,
|
|
|
message: `档位 ${key} transit_description 为空`,
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return { ok: true };
|
|
|
}
|