|
|
import type { QuoteItem } from "@/modules/providers/quote-provider";
|
|
|
import type { RawQuoteTier } from "@/modules/pricing/engine";
|
|
|
import type { NormalizedCargo } from "@/modules/quote/types";
|
|
|
import type { QuoteRequest } from "@/modules/providers/quote-provider";
|
|
|
|
|
|
/** NormalizedCargo → QuoteProvider 入参 */
|
|
|
export function cargoToQuoteRequest(cargo: NormalizedCargo): QuoteRequest {
|
|
|
return {
|
|
|
cargoHash: cargo.cargoHash,
|
|
|
quoteSessionId: cargo.quoteSessionId,
|
|
|
pickup: {
|
|
|
street: cargo.pickupAddress.street,
|
|
|
city: cargo.pickupAddress.city,
|
|
|
state: cargo.pickupAddress.state,
|
|
|
zip: cargo.pickupAddress.zip,
|
|
|
placeId: cargo.pickupAddress.place_id,
|
|
|
formattedAddress: cargo.pickupAddress.formatted_address,
|
|
|
selectedFromSuggestions: cargo.pickupAddress.selected_from_suggestions,
|
|
|
mothershipOptionId: cargo.pickupAddress.mothership_option_id ?? "",
|
|
|
mothershipDisplayLabel: cargo.pickupAddress.mothership_display_label ?? "",
|
|
|
selectedFromMothership: cargo.pickupAddress.selected_from_mothership === true,
|
|
|
},
|
|
|
delivery: {
|
|
|
street: cargo.deliveryAddress.street,
|
|
|
city: cargo.deliveryAddress.city,
|
|
|
state: cargo.deliveryAddress.state,
|
|
|
zip: cargo.deliveryAddress.zip,
|
|
|
placeId: cargo.deliveryAddress.place_id,
|
|
|
formattedAddress: cargo.deliveryAddress.formatted_address,
|
|
|
selectedFromSuggestions: cargo.deliveryAddress.selected_from_suggestions,
|
|
|
mothershipOptionId: cargo.deliveryAddress.mothership_option_id ?? "",
|
|
|
mothershipDisplayLabel:
|
|
|
cargo.deliveryAddress.mothership_display_label ?? "",
|
|
|
selectedFromMothership:
|
|
|
cargo.deliveryAddress.selected_from_mothership === true,
|
|
|
},
|
|
|
weightLb: cargo.weightLb,
|
|
|
dimsIn: {
|
|
|
l: cargo.dimLIn,
|
|
|
w: cargo.dimWIn,
|
|
|
h: cargo.dimHIn,
|
|
|
},
|
|
|
palletCount: cargo.palletCount,
|
|
|
cargoType: cargo.cargoType,
|
|
|
pickupAccessorials: cargo.pickupAccessorials,
|
|
|
deliveryAccessorials: cargo.deliveryAccessorials,
|
|
|
readyDate: cargo.readyDate,
|
|
|
readyTime: cargo.readyTime,
|
|
|
cargoLines: cargo.cargoLines,
|
|
|
mothershipDetails: cargo.mothershipDetails,
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/** QuoteItem → L2/L3 缓存档位结构 */
|
|
|
export function quoteItemsToRawTiers(items: QuoteItem[]): RawQuoteTier[] {
|
|
|
return items.map((item) => ({
|
|
|
service_level: item.serviceLevel,
|
|
|
rate_option: item.rateOption,
|
|
|
carrier: item.carrier,
|
|
|
transit_days: item.transitDays,
|
|
|
transit_description: item.transitDescription,
|
|
|
raw_freight: item.rawFreight,
|
|
|
surcharges: item.surcharges,
|
|
|
raw_total: item.rawTotal,
|
|
|
}));
|
|
|
}
|
|
|
|
|
|
/** 取 standard 档「最低价格」基准(absolute lowest 优先) */
|
|
|
export function getStandardLowestTotal(quotes: RawQuoteTier[]): number | null {
|
|
|
const std = quotes.filter((q) => q.service_level === "standard");
|
|
|
const tier =
|
|
|
std.find((q) => q.rate_option === "lowest") ??
|
|
|
std.find((q) => q.rate_option === "bestValue");
|
|
|
return tier ? tier.raw_total : null;
|
|
|
}
|