You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
3.8 KiB
135 lines
3.8 KiB
import type { FlockQuoteLine } from "@/workers/rpa/flock/types";
|
|
|
|
export type FlockFulfillmentOption = {
|
|
fulfillmentCategory?: string;
|
|
transportMode?: string;
|
|
rateUsd?: string | number;
|
|
transitTimeDaysMin?: number;
|
|
transitTimeDaysMax?: number;
|
|
transitSupportedOnWeekendsAndHolidays?: boolean;
|
|
carrierName?: string;
|
|
guid?: string;
|
|
};
|
|
|
|
export type FlockQuotesApiResponse = {
|
|
guid?: string;
|
|
referenceNumber?: string;
|
|
status?: string;
|
|
fulfillmentOptions?: FlockFulfillmentOption[];
|
|
};
|
|
|
|
function parseRateUsd(raw: string | number | undefined): number | null {
|
|
if (typeof raw === "number" && Number.isFinite(raw) && raw > 0) {
|
|
return Math.round(raw * 100) / 100;
|
|
}
|
|
if (typeof raw === "string") {
|
|
const n = Number(raw.replace(/,/g, "").trim());
|
|
if (Number.isFinite(n) && n > 0) return Math.round(n * 100) / 100;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function formatTransit(
|
|
min?: number,
|
|
max?: number,
|
|
weekends?: boolean,
|
|
): { transitDays: string; transitDescription: string } {
|
|
const hasMin = typeof min === "number" && Number.isFinite(min);
|
|
const hasMax = typeof max === "number" && Number.isFinite(max);
|
|
let transitDays = "—";
|
|
if (hasMin && hasMax) {
|
|
transitDays = min === max ? String(min) : `${min}-${max}`;
|
|
} else if (hasMin) {
|
|
transitDays = String(min);
|
|
} else if (hasMax) {
|
|
transitDays = String(max);
|
|
}
|
|
const transitDescription = weekends
|
|
? `${transitDays} 天(含周末)`
|
|
: `${transitDays} 个工作日(预估)`;
|
|
return { transitDays, transitDescription };
|
|
}
|
|
|
|
function pickCheapest(
|
|
options: FlockFulfillmentOption[],
|
|
predicate: (o: FlockFulfillmentOption) => boolean,
|
|
): { option: FlockFulfillmentOption; rate: number } | null {
|
|
let best: { option: FlockFulfillmentOption; rate: number } | null = null;
|
|
for (const option of options) {
|
|
if (!predicate(option)) continue;
|
|
const rate = parseRateUsd(option.rateUsd);
|
|
if (rate == null) continue;
|
|
if (!best || rate < best.rate) {
|
|
best = { option, rate };
|
|
}
|
|
}
|
|
return best;
|
|
}
|
|
|
|
/**
|
|
* 将 API fulfillmentOptions 映射为 UI 两档:
|
|
* - FlockDirect® ← GUARANTEED_HUBLESS 最低价
|
|
* - Standard ← STANDARD 最低价
|
|
*/
|
|
export function mapFlockFulfillmentOptionsToLines(
|
|
body: FlockQuotesApiResponse,
|
|
): { quotes: FlockQuoteLine[]; reference: string | null } {
|
|
const reference =
|
|
typeof body.referenceNumber === "string" && body.referenceNumber.trim()
|
|
? body.referenceNumber.trim()
|
|
: null;
|
|
const options = Array.isArray(body.fulfillmentOptions)
|
|
? body.fulfillmentOptions
|
|
: [];
|
|
|
|
const quotes: FlockQuoteLine[] = [];
|
|
|
|
const direct = pickCheapest(
|
|
options,
|
|
(o) => /GUARANTEED_HUBLESS/i.test(o.fulfillmentCategory ?? ""),
|
|
);
|
|
if (direct) {
|
|
const { transitDays, transitDescription } = formatTransit(
|
|
direct.option.transitTimeDaysMin,
|
|
direct.option.transitTimeDaysMax,
|
|
direct.option.transitSupportedOnWeekendsAndHolidays === true,
|
|
);
|
|
quotes.push({
|
|
tier: "flock_direct",
|
|
serviceLevel: "guaranteed",
|
|
rateOption: "fastest",
|
|
carrier: "Flock Freight",
|
|
label: "FlockDirect®",
|
|
totalUsd: direct.rate,
|
|
transitDays,
|
|
transitDescription,
|
|
reference,
|
|
});
|
|
}
|
|
|
|
const standard = pickCheapest(
|
|
options,
|
|
(o) => /^STANDARD$/i.test(o.fulfillmentCategory ?? ""),
|
|
);
|
|
if (standard) {
|
|
const { transitDays, transitDescription } = formatTransit(
|
|
standard.option.transitTimeDaysMin,
|
|
standard.option.transitTimeDaysMax,
|
|
standard.option.transitSupportedOnWeekendsAndHolidays === true,
|
|
);
|
|
quotes.push({
|
|
tier: "standard",
|
|
serviceLevel: "standard",
|
|
rateOption: "lowest",
|
|
carrier: "Flock Freight",
|
|
label: "Standard",
|
|
totalUsd: standard.rate,
|
|
transitDays,
|
|
transitDescription,
|
|
reference,
|
|
});
|
|
}
|
|
|
|
return { quotes, reference };
|
|
}
|