import { describe, expect, it } from "vitest"; import { detectUiKindsFromText, extractForecastInstructionText, extractMailInstructions, splitBodySegments, } from "@/services/parse/split-instructions"; import { evaluateTransferGate } from "@/services/cc/container-status"; import { buildCcWorkOrderFormValue } from "@/components/CcWorkOrderForm"; import { buildCcDoUploadFormValue } from "@/components/CcDoUploadPanel"; const MAIL4_SUBJECT = "Fw: 转发:新增预报136:新辰泽+WHLC027G597465+WHSU8127240+洛杉矶+40HQ+EDT2026.04-25 ETA2026.05-15船名航次HMM EMERALD 013E+提拆派组合柜-不带托架"; const MAIL4_BODY = [ "Dear,", "原箱号YT2604021091=FBA199R49LD6-MDW2=76件操作指令", "换标后单号:FBA19HW52S0L-2G1MCB6X-HIA1=76件", "1:覆盖贴FBA标签,一箱贴两张", "3:贴好拍照回传", ].join("\n"); describe("four-business extractMailInstructions", () => { it("mail4: forecast + work_order + maybe do", () => { const units = extractMailInstructions({ subject: MAIL4_SUBJECT, body: MAIL4_BODY, filenames: ["YT2604021091=76件换标走HIA1卡派出库操作指令.xlsx"], }); const kinds = units.map((u) => u.uiKind); expect(kinds).toContain("forecast"); expect(kinds).toContain("work_order"); }); it("transfer-only body → transfer", () => { const units = extractMailInstructions({ subject: "MATU2745683", body: "新增转仓,请留意", filenames: [], }); expect(units.some((u) => u.uiKind === "transfer")).toBe(true); }); it("DO filename → do_upload", () => { expect( detectUiKindsFromText("WHSU5574991", "", ["柜DO.pdf"]), ).toContain("do_upload"); }); }); describe("extractForecastInstructionText P4", () => { it("does not use 换标 body as forecast instruction", () => { const text = extractForecastInstructionText({ subject: MAIL4_SUBJECT, body: MAIL4_BODY, }); expect(text).not.toMatch(/覆盖贴/); expect(text).toMatch(/船名航次|HMM|EMERALD|/); }); }); describe("splitBodySegments", () => { it("splits on quote header", () => { const segs = splitBodySegments( "当前换标\n------------------ 原始电子邮件 ------------------\n主题:新增预报\n历史", ); expect(segs.length).toBeGreaterThanOrEqual(2); }); }); describe("buildCcWorkOrderFormValue", () => { it("mail actions stay in tags; 贴标映射 CC 留言类型「操作指令」", () => { const v = buildCcWorkOrderFormValue({ subject: "操作", body: "请贴标并拍照", containerNo: "WHSU8127240", }); expect(v.F_MessageType).toBe("操作指令"); expect(v.F_MessageType).not.toBe("贴标"); expect(v.mailActions).toEqual(expect.arrayContaining(["贴标", "拍照"])); expect(v.F_Remark).toContain("邮件动作:"); expect(v.F_ReferCode).toBe("WHSU8127240"); }); it("拦截 → CC 留言类型「货件拦截」", () => { const v = buildCcWorkOrderFormValue({ subject: "请拦截", body: "柜号 WHSU8127240 拦截货件", }); expect(v.F_MessageType).toBe("货件拦截"); expect(v.mailActions).toContain("拦截"); }); it("mail3 渠道拦截-N件 → 备注为拆柜清单而非拦截", () => { const subject = "Fw: 转发:派送要求更新: 拆柜清单更新: DO请查收+拆柜清单更新: WHSU5574991+WHL063G550810+船名航次:OOCL SINGAPORE / 065W+ETA:6/28+FedEx-29件+UPS-102件+亚马逊卡派-289件+私人地址-166件+拦截-209件+拆柜清单"; const v = buildCcWorkOrderFormValue({ subject, body: "派送要求更新,请查收 DO 与拆柜清单。", containerNo: "WHSU5574991", actions: [], }); expect(v.F_Remark).toContain("邮件动作:拆柜清单"); expect(v.F_Remark).not.toContain("拦截"); expect(v.F_MessageType).not.toBe("货件拦截"); expect(v.mailActions).toContain("拆柜清单"); expect(v.mailActions).not.toContain("拦截"); }); it("mail85 76件换标挂对应附件;833件历史轮不误挂", () => { const files = [ "YT2604021091=76件换标走HIA1卡派出库操作指令.xlsx", "FBA19HW52S0L-76CTN-HIA1-覆盖贴1箱贴2张.pdf", "X003UHDF7B-304PCS-覆盖贴1箱贴1张.pdf", ]; const current = buildCcWorkOrderFormValue({ subject: "Re:新增预报136", body: [ "Dear,", "原箱号 YT2604021091=FBA199R49LD6-MDW2=76 件操作指令", "换标后单号: FBA19HW52S0L-2G1MCB6X-HIA1=76 件", "1:覆盖贴FBA 标签,一箱贴两张", "2:覆盖贴SKU 标签,一箱 1 张( FNSKU : X003UHDF7B ( 304PCS ))", ].join("\n"), filenames: files, containerNo: "WHSU8127240", }); expect(current.F_AttachFile).toContain("YT2604021091"); expect(current.F_AttachFile).toContain("FBA19HW52S0L"); expect(current.F_AttachFile).toContain("X003UHDF7B"); const hist833 = buildCcWorkOrderFormValue({ subject: "Fw: 新增预报136", body: [ "Dear,", "WHSU8127240= 原箱号 YT2604021486- 剩余 540 件", "两个柜子共计 833 件操作指令", "换标后单号:FBA19DS6CXV4-2G1XD81L-LGB8=87 件", ].join("\n"), filenames: files, containerNo: "WHSU8127240", isCurrent: false, }); expect(hist833.F_AttachFile).toBe(""); }); it("strips forward headers; keeps Dear instruction as F_MessageContent", () => { const v = buildCcWorkOrderFormValue({ subject: "Fw: 新增预报136", body: [ "---- 转发的邮件 ----", "发件人新辰泽", "主题 Re:Re:新增预报136", "Dear,", "原箱号 YT2604021091=FBA199R49LD6-MDW2=76 件操作指令", "1:覆盖贴FBA标签,一箱贴两张", "3:贴好拍照回传", ].join("\n"), containerNo: "WHSU8127240", }); expect(v.F_MessageContent).toMatch(/^Dear,/); expect(v.F_MessageContent).toContain("覆盖贴"); expect(v.F_MessageContent).not.toContain("转发的邮件"); expect(v.mailActions).toEqual(expect.arrayContaining(["贴标", "拍照"])); }); }); describe("buildCcDoUploadFormValue", () => { it("keeps DO pdf filenames", () => { const v = buildCcDoUploadFormValue({ subject: "DO请查收 WHSU5574991", filenames: ["WHSU5574991-DO.pdf", "其他.xlsx"], }); expect(v.filenames.some((f) => /DO/i.test(f))).toBe(true); }); }); describe("evaluateTransferGate mock", () => { it("ARRIVED container → work_order fallback", async () => { const g = await evaluateTransferGate("ARRIVED1234567"); expect(g.canTransfer).toBe(false); if (!g.canTransfer) expect(g.fallback).toBe("work_order"); }); it("normal container → can transfer in mock", async () => { const g = await evaluateTransferGate("WHSU8127240"); // depends on CC_MOCK; if live empty list may fallback expect(typeof g.canTransfer).toBe("boolean"); }); });