import { describe, expect, it } from "vitest"; import { applyServiceFromModules, applyServiceFromText, normalizeCabinetType, stripOrChoiceNoise, } from "@/services/parse/header-service-hints"; import { extractContainerHeaderFromText } from "@/services/parse/extract-container-header"; import { mapBlModulesToHeader } from "@/services/parse/bl-plus-template"; import { extractOpsSubjectFromMail } from "@/services/parse/ops-subject-template"; import { buildCcForecastFormValue } from "@/components/CcForecastFormOrder"; describe("header-service-hints (AI assistant parity)", () => { it("strips 海运或空运 / 提拆派或直送 option noise", () => { const t = stripOrChoiceNoise("运输方式(海运或空运)操作类型(提拆派或直送)"); expect(t).not.toMatch(/海运或空运|提拆派或直送/); }); it("normalizeCabinetType 40HC → 40HQ", () => { expect(normalizeCabinetType("40HC")).toBe("40HQ"); expect(normalizeCabinetType("40HQ")).toBe("40HQ"); }); it("拆柜清单 / 提拆派 / 直送 / 只清关", () => { expect(applyServiceFromText("拆柜清单").F_OperationType).toBe(0); expect(applyServiceFromText("提拆派组合柜-不带托架")).toMatchObject({ F_OperationType: 0, F_Classis: 0, F_Instruction: "提拆派", }); expect(applyServiceFromText("本票直送").F_OperationType).toBe(2); expect(applyServiceFromText("只清关").F_OperationType).toBe(4); expect( applyServiceFromText("提拆派,说明另有直送类型").F_OperationType, ).toBe(0); }); it("ops_hints 拆柜清单 → modules path", () => { expect( applyServiceFromModules({ ops_hints: ["拆柜清单", "派送要求"] }) .F_OperationType, ).toBe(0); expect( applyServiceFromModules({ ops_hints: ["直送"] }).F_OperationType, ).toBe(2); }); }); describe("extractContainerHeaderFromText assistant parity", () => { it("mail3 channel summary → 拆柜 + 海运 + OOCL 船司别名", () => { const h = extractContainerHeaderFromText( "WHSU5574991+WHL063G550810+船名航次:OOCL SINGAPORE / 065W+ETA:6/28+FedEx-29件+UPS-102件+亚马逊卡派-289件+私人地址-166件+拦截-209件+拆柜清单", ); expect(h.F_OperationType).toBe(0); expect(h.F_TransMode).toBe(0); expect(h.F_ETA).toBe("2026-06-28"); expect(h.F_BLCopyCode).toBe("WHL063G550810"); expect(h.shipping_line_hint).toMatch(/WHL/i); expect(h.F_Instruction).toMatch(/船名航次.*OOCL SINGAPORE/); // 禁止 WAN/OOCL 船名首词误当船司时:有提单前缀则用 WHL }); it("does not take vessel first token as shipping line (WAN HAI)", () => { const h = extractContainerHeaderFromText( "船名航次:WAN HAI 511-V.E110 柜号 TCNU4412465", ); expect(h.shipping_line_hint?.toUpperCase()).not.toBe("WAN"); expect(h.shipping_line_hint?.toUpperCase()).toMatch(/WAN\s*HAI|WHL|WAN HAI/i); }); it("ignores 提拆派或直送 as selected operation", () => { const h = extractContainerHeaderFromText( "请选择操作类型(提拆派或直送)柜号 WHSU8127240", ); expect(h.F_OperationType).toBeUndefined(); }); }); describe("ops subject → form full chain", () => { it("mail3 subject fills OperationType via map + form", () => { const subject = "Fw: 转发:派送要求更新: 拆柜清单更新: DO请查收+拆柜清单更新: WHSU5574991+WHL063G550810+船名航次:OOCL SINGAPORE / 065W+ETA:6/28+FedEx-29件+UPS-102件+亚马逊卡派-289件+私人地址-166件+拦截-209件+拆柜清单"; const ops = extractOpsSubjectFromMail(subject, { defaultYear: 2026 })!; const header = mapBlModulesToHeader( { F_ContainerNo: ops.modules.container_no || "", container_no_valid: true, }, ops.modules, ); expect(header.F_OperationType).toBe(0); expect(header.F_TransMode).toBe(0); expect(header.F_ETA).toBe("2026-06-28"); const form = buildCcForecastFormValue({ header: {}, modules: ops.modules, }); expect(form.F_OperationType).toBe(0); expect(form.F_TransMode).toBe(0); expect(form.F_ETA).toBe("2026-06-28"); expect(form.F_Instruction).toMatch(/船名航次/); }); });