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.
106 lines
3.7 KiB
106 lines
3.7 KiB
import type { Priority1DemoInput } from "@/workers/rpa/priority1/demo-input";
|
|
import { validatePriority1FormConstraints } from "@/workers/rpa/priority1/form-constraints";
|
|
import { findPhoneCountry } from "@/lib/priority1/phone-countries";
|
|
import { pickupDateValidationMessage } from "@/lib/priority1/pickup-date";
|
|
import { ValidationError } from "@/modules/quote/types";
|
|
|
|
const ZIP_RE = /^\d{5}$/;
|
|
const DATE_RE = /^\d{2}\/\d{2}\/\d{4}$/;
|
|
|
|
function req(value: string | undefined, label: string): string {
|
|
const v = value?.trim();
|
|
if (!v) throw new ValidationError(`请填写${label}`);
|
|
return v;
|
|
}
|
|
|
|
/** 校验 Priority1 模拟表单提交 */
|
|
export function validatePriority1QuoteInput(
|
|
body: unknown,
|
|
): Priority1DemoInput & { request_id: string; customer_id: string } {
|
|
if (!body || typeof body !== "object") {
|
|
throw new ValidationError("请求体格式无效");
|
|
}
|
|
const o = body as Record<string, unknown>;
|
|
const requestId = req(o.request_id as string | undefined, "请求标识");
|
|
const customerId = req(o.customer_id as string | undefined, "客户标识");
|
|
const input = o.priority1_input;
|
|
if (!input || typeof input !== "object") {
|
|
throw new ValidationError("请填写 Priority1 表单参数");
|
|
}
|
|
const p = input as Priority1DemoInput;
|
|
|
|
if (!["ltl", "ftl", "expedited"].includes(p.shipmentType)) {
|
|
throw new ValidationError("请选择运输类型");
|
|
}
|
|
if (!ZIP_RE.test(req(p.originZip, "起运邮编"))) {
|
|
throw new ValidationError("起运邮编须为 5 位数字");
|
|
}
|
|
if (!ZIP_RE.test(req(p.destinationZip, "目的邮编"))) {
|
|
throw new ValidationError("目的邮编须为 5 位数字");
|
|
}
|
|
if (p.originZip === p.destinationZip) {
|
|
throw new ValidationError("起运与目的邮编不能相同");
|
|
}
|
|
if (!DATE_RE.test(req(p.pickupDate, "提货日"))) {
|
|
throw new ValidationError("提货日格式须为 MM/DD/YYYY");
|
|
}
|
|
const pickupDateError = pickupDateValidationMessage(p.pickupDate);
|
|
if (pickupDateError) {
|
|
throw new ValidationError(pickupDateError);
|
|
}
|
|
const phoneDigits = req(p.phone, "电话").replace(/\D/g, "");
|
|
const country = findPhoneCountry(p.phoneCountry ?? "US");
|
|
if (country.code === "US" || country.code === "CA") {
|
|
if (phoneDigits.length !== 10) {
|
|
throw new ValidationError("美国/加拿大电话须为 10 位数字");
|
|
}
|
|
} else if (phoneDigits.length < 6 || phoneDigits.length > 15) {
|
|
throw new ValidationError("请填写有效电话号码");
|
|
}
|
|
req(p.email, "商务邮箱");
|
|
|
|
if (p.shipmentType === "ltl") {
|
|
req(p.lengthIn, "长度");
|
|
req(p.widthIn, "宽度");
|
|
req(p.heightIn, "高度");
|
|
req(p.weightLb, "总重量");
|
|
req(p.packaging, "包装类型");
|
|
req(p.palletCount, "托盘数");
|
|
req(p.freightClass, "货运等级");
|
|
req(p.pickupLocation, "提货地点类型");
|
|
req(p.deliveryLocation, "派送地点类型");
|
|
}
|
|
|
|
if (p.shipmentType === "ftl") {
|
|
req(p.commodity, "货描");
|
|
req(p.weightLb, "总重量");
|
|
if (p.ftlTrailer !== "ftl_expedited") {
|
|
req(p.palletCount, "托盘数");
|
|
}
|
|
if (p.ftlTrailer === "open_deck") req(p.openDeckSubtype, "Open Deck 子类型");
|
|
if (p.ftlTrailer === "temperature_controlled") {
|
|
req(p.tempMinF, "最低温度");
|
|
req(p.tempMaxF, "最高温度");
|
|
}
|
|
}
|
|
|
|
if (p.shipmentType === "expedited") {
|
|
req(p.commodity, "货描");
|
|
req(p.weightLb, "总重量");
|
|
}
|
|
|
|
const constraintErrors = validatePriority1FormConstraints(p).filter(
|
|
(v) => v.severity === "error",
|
|
);
|
|
if (constraintErrors.length > 0) {
|
|
throw new ValidationError(constraintErrors[0]!.message);
|
|
}
|
|
|
|
return {
|
|
...p,
|
|
phone: p.phone.replace(/\D/g, "").slice(-10),
|
|
request_id: requestId,
|
|
customer_id: customerId,
|
|
};
|
|
}
|