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.
chajia/lib/frontend/mothership-logged-in-quote-...

129 lines
4.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* 登录后一级 payload → 现有 QuoteRequestBody复用匿名询价 API
*/
import { applyMothershipCandidate } from "@/lib/frontend/mothership-address";
import { uuidV4 } from "@/lib/frontend/format";
import type {
AddressInput,
MothershipAddressCandidate,
QuoteRequestBody,
} from "@/lib/frontend/types";
import type { MothershipLoggedInShipmentPayload } from "@/components/mothership/mothership-logged-in-shipment-form";
import type { MothershipLoggedInDetailsPayload } from "@/components/mothership/mothership-logged-in-details-form";
import { normalizeMothershipReadyDateIso } from "@/lib/mothership/logged-in-constraints";
function candidateToAddress(
candidate: MothershipAddressCandidate,
): AddressInput {
return applyMothershipCandidate(
{
street: candidate.street,
city: candidate.city,
state: candidate.state,
zip: candidate.zip || "",
place_id: candidate.option_id,
formatted_address:
candidate.formatted_address || candidate.display_label,
selected_from_suggestions: true,
},
candidate,
);
}
/** 托盘数:各行 quantity 合计(登录后官网可多行) */
export function resolveLoggedInPalletCount(
payload: MothershipLoggedInShipmentPayload,
): number {
const sum = payload.cargo.reduce((acc, row) => acc + row.quantity, 0);
return Math.max(1, Math.round(sum));
}
/**
* 用一级货件 + 已确认联想地址组询价请求。
* 托盘数取 quantity 合计;重量/尺寸保留首行供匿名路径兼容;
* cargo_lines 供登录态 RPA 按行填官网cargo-add-button
*/
export function buildQuoteRequestBodyFromLoggedIn(
payload: MothershipLoggedInShipmentPayload,
customerId: string,
details?: MothershipLoggedInDetailsPayload,
): QuoteRequestBody {
const primary = payload.cargo[0];
if (!primary) {
throw new Error("货物明细不能为空");
}
return {
request_id: uuidV4(),
customer_id: customerId,
pickup_address: candidateToAddress(payload.pickupConfirmed),
delivery_address: candidateToAddress(payload.deliveryConfirmed),
weight: { value: primary.weightLb, unit: "lb" },
dimensions: {
length: primary.lengthIn,
width: primary.widthIn,
height: primary.heightIn,
unit: "in",
},
pallet_count: resolveLoggedInPalletCount(payload),
cargo_type: "general_freight",
service_level: "standard",
rate_option: "lowest",
display_unit: "imperial",
pickup_accessorials: [...payload.pickupAccessorials],
delivery_accessorials: [...payload.deliveryAccessorials],
ready_date: normalizeMothershipReadyDateIso(payload.readyDate),
ready_time: payload.readyTime || undefined,
cargo_lines: payload.cargo.map((row) => ({
cargo_type: row.cargoType,
quantity: row.quantity,
weight_lb: row.weightLb,
length_in: row.lengthIn,
width_in: row.widthIn,
height_in: row.heightIn,
})),
mothership_details: details
? {
pickup: {
company_name: details.pickup.companyName || undefined,
suite: details.pickup.suite || undefined,
contact_first: details.pickup.contactFirst || undefined,
contact_last: details.pickup.contactLast || undefined,
contact_email: details.pickup.contactEmail || undefined,
contact_phone: details.pickup.contactPhone || undefined,
reference: details.pickup.reference || undefined,
notes: details.pickup.notes || undefined,
opens_at: details.pickup.opensAt || undefined,
closes_at: details.pickup.closesAt || undefined,
},
delivery: {
company_name: details.delivery.companyName || undefined,
suite: details.delivery.suite || undefined,
contact_first: details.delivery.contactFirst || undefined,
contact_last: details.delivery.contactLast || undefined,
contact_email: details.delivery.contactEmail || undefined,
contact_phone: details.delivery.contactPhone || undefined,
reference: details.delivery.reference || undefined,
notes: details.delivery.notes || undefined,
opens_at: details.delivery.opensAt || undefined,
closes_at: details.delivery.closesAt || undefined,
},
request_delivery_appointment: details.requestDeliveryAppointment,
fba_number: details.fbaNumber || undefined,
fba_po_number: details.fbaPoNumber || undefined,
cargo: details.cargo.map((line) => ({
piece_count_type: line.pieceCountType || undefined,
piece_count_qty: Number.isFinite(line.pieceCountQty)
? line.pieceCountQty
: undefined,
description: line.description || undefined,
nmfc: line.nmfc || undefined,
hazmat: line.hazmat,
alcohol: line.alcohol,
tobacco: line.tobacco,
})),
}
: undefined,
};
}