空运人工价锁舱现拉补全舱位并拦清缺参;成交/报价填表与工单陆运费率展示同步收紧。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
linmianxun
2026-10-07 23:35:24 +08:00
co-authored by Cursor
parent 419b4a1bf7
commit e197ecea10
31 changed files with 1607 additions and 150 deletions
@@ -253,9 +253,88 @@ function parseQuoteFees(q: any): TicketQuoteFee[] {
pushRows(asFeeArray(payload[key] || payload[bucket]));
}
}
// 陆运 TMS:燃油附加费率 / 税率挂在线路段上,不是金额费目行。
for (const extra of parseLandRateFees(payload)) {
if (!out.some((x) => x.name === extra.name && x.amount === extra.amount)) {
out.push(extra);
}
}
return out;
}
/**
* 陆运线路:fuelSurchargeRate=燃油附加费率;rate=税率;rateFlag=是否含税(1是0否)。
* 只读 payload,不写库。海运/空运没有这些键则不出行。
*/
function parseLandRateFees(payload: Record<string, any>): TicketQuoteFee[] {
const rows = asFeeArray(payload.route_rows || payload.landSegments || payload.land_segments);
const out: TicketQuoteFee[] = [];
const seen = new Set<string>();
for (const row of rows) {
if (!row || typeof row !== "object") continue;
const fuel = formatLandPercent(row.fuel_surcharge_rate ?? row.fuelSurchargeRate);
const tax = formatLandTaxRate(row.tax_rate ?? row.taxRate ?? row.rate);
const included = formatLandTaxIncluded(
row.tax_included ?? row.rateFlag ?? row.rate_flag
);
if (fuel) {
const key = `fuel:${fuel}`;
if (!seen.has(key)) {
seen.add(key);
out.push({ name: "燃油附加费率", amount: fuel });
}
}
if (tax) {
const key = `tax:${tax}`;
if (!seen.has(key)) {
seen.add(key);
out.push({ name: "税率", amount: tax });
}
}
if (included) {
const key = `inc:${included}`;
if (!seen.has(key)) {
seen.add(key);
out.push({ name: "是否含税", amount: included });
}
}
}
return out;
}
/** 燃油附加费率:数字带 %。 */
function formatLandPercent(raw: unknown): string {
const s = String(raw ?? "").trim();
if (!s || s === "-" || s.toLowerCase() === "null") return "";
if (s.includes("%")) return s;
if (/^-?\d+(\.\d+)?$/.test(s)) {
return `${s.replace(/(\.\d*?)0+$/, "$1").replace(/\.$/, "")}%`;
}
return s;
}
/** 税率 rate:0.09→9%;大于 1 按百分点。 */
function formatLandTaxRate(raw: unknown): string {
const s = String(raw ?? "").trim();
if (!s || s === "-" || s.toLowerCase() === "null") return "";
if (s.includes("%")) return s;
if (!/^-?\d+(\.\d+)?$/.test(s)) return s;
const n = Number(s);
if (!Number.isFinite(n)) return s;
const abs = Math.abs(n);
const pct = abs > 0 && abs <= 1 ? n * 100 : n;
return `${String(pct).replace(/(\.\d*?)0+$/, "$1").replace(/\.$/, "")}%`;
}
/** rateFlag:1=含税,0=不含税。 */
function formatLandTaxIncluded(raw: unknown): string {
const s = String(raw ?? "").trim();
if (!s || s === "-" || s.toLowerCase() === "null") return "";
if (s === "1" || s.toLowerCase() === "true" || s === "是" || s === "含税") return "含税";
if (s === "0" || s.toLowerCase() === "false" || s === "否" || s === "不含税") return "不含税";
return s;
}
/**
* 主账 inq_ticket_status_log.action 是内部码,禁止当备注展示。
* transition 与「已报价」等 toStatus 重复,无用户备注时不再跟一段英文。