import { describe, expect, it } from "vitest"; import { extractBlPlusFromMail, mapBlModulesToHeader, parseBlPlusTemplate, } from "@/services/parse/bl-plus-template"; import { extractContainerHeaderFromText, shippingLineHintFromBl, } from "@/services/parse/extract-container-header"; const SAMPLE = "新辰泽+WHLC027G597465+WHSU8127240+洛杉矶+40HQ+EDT2026.04-25 ETA2026.05-15船名航次HMM EMERALD 013E+提拆派组合柜-不带托架"; describe("parseBlPlusTemplate", () => { it("parses standard plus template modules", () => { const m = parseBlPlusTemplate(SAMPLE); expect(m).not.toBeNull(); expect(m!.customer_name).toBe("新辰泽"); expect(m!.bl_no).toBe("WHLC027G597465"); expect(m!.shipping_line_hint).toBe("WHLC"); expect(m!.container_no).toBe("WHSU8127240"); expect(m!.port).toBe("洛杉矶"); expect(m!.cabinet_type).toBe("40HQ"); expect(m!.etd).toBe("2026-04-25"); expect(m!.eta).toBe("2026-05-15"); expect(m!.vessel_voyage).toContain("HMM EMERALD"); expect(m!.service).toContain("提拆派"); expect(m!.classis).toBe(0); expect(m!.ops_hints).toEqual( expect.arrayContaining(["提柜", "拆柜", "派送"]), ); }); it("maps modules onto SaveContainer-aligned header fields", () => { const m = parseBlPlusTemplate(SAMPLE)!; const header = mapBlModulesToHeader( { F_ContainerNo: "", container_no_valid: false }, m, ); expect(header.F_ContainerNo).toBe("WHSU8127240"); expect(header.F_BLCopyCode).toBe("WHLC027G597465"); expect(header.F_Dock).toBe("洛杉矶"); expect(header.F_CabinetType).toBe("40HQ"); expect(header.F_ETD).toBe("2026-04-25"); expect(header.F_ETA).toBe("2026-05-15"); expect(header.F_Classis).toBe(0); expect(header.F_OperationType).toBe(0); expect(header.F_TransMode).toBe(0); expect(header.F_Instruction).toMatch(/船名航次.*HMM EMERALD/); expect(header.F_MemoRemark).toContain("新辰泽"); }); it("extracts from subject + body like template mail", () => { const r = extractBlPlusFromMail( `新增预报136:${SAMPLE}`, `Dear,\n请查收新增预报:${SAMPLE}DO也同步上传至附件请注意查收!`, ); expect(r).not.toBeNull(); expect(r!.modules.container_no).toBe("WHSU8127240"); expect(r!.modules.bl_no).toBe("WHLC027G597465"); expect(r!.modules.shipping_line_hint).toBe("WHLC"); expect(r!.modules.customer_name).toBe("新辰泽"); }); it("strips Fw/转发/新增预报N from subject customer segment", () => { const r = extractBlPlusFromMail( `Fw: 转发:新增预报136:${SAMPLE}`, "", ); expect(r).not.toBeNull(); expect(r!.modules.customer_name).toBe("新辰泽"); expect(r!.modules.bl_no).toBe("WHLC027G597465"); expect(r!.modules.shipping_line_hint).toBe("WHLC"); }); it("parses mail2 transfer subject (4 segments)", () => { const subject = "Fw: 转发:LINK EVER INC + MATS4583030000+ 柜号:MATU2745683+ ETA : 7/13"; const r = extractBlPlusFromMail(subject, "新增转仓,请留意"); expect(r).not.toBeNull(); expect(r!.modules.customer_name).toBe("LINK EVER INC"); expect(r!.modules.bl_no).toBe("MATS4583030000"); expect(r!.modules.container_no).toBe("MATU2745683"); expect(r!.modules.vessel_voyage).toBeUndefined(); }); }); describe("shipping line hint priority", () => { it("BL prefix WHLC beats vessel HMM", () => { expect(shippingLineHintFromBl("WHLC027G597465")).toBe("WHLC"); const h = extractContainerHeaderFromText(SAMPLE); expect(h.shipping_line_hint).toBe("WHLC"); expect(h.F_OperationType).toBe(0); expect(h.F_TransMode).toBe(0); expect(h.F_Classis).toBe(0); }); it("提拆派 wins over 直送 when both present", () => { const h = extractContainerHeaderFromText("提拆派组合柜,说明:另有直送类型"); expect(h.F_OperationType).toBe(0); }); it("explicit 船司 still preferred over BL prefix", () => { const h = extractContainerHeaderFromText( "船司:MSC\n提单:WHLC027G597465\n柜型:40HQ", ); expect(h.shipping_line_hint).toBe("MSC"); }); });