import { describe, expect, it } from "vitest"; import { parseTransferInstructionTable, splitTaggedOcrBlocks, transferRowsToPairs, } from "@/services/parse/transfer-instruction-table"; import { buildTransferSegmentContexts } from "@/services/parse/match-transfer-segment-ocr"; import type { MailInstructionUnit } from "@/services/parse/split-instructions"; describe("parseTransferInstructionTable", () => { it("parses 地址/箱数/仓库重定向 row", () => { const rows = parseTransferInstructionTable( "柜号 ZCSU6581068 ETA 2026/7/7 地址 PSC2 箱数 7 提柜时间 仓库重定向 POC2", ); expect(rows).toEqual([ { containerNo: "ZCSU6581068", eta: "2026/7/7", from: "PSC2", to: "POC2", ctns: 7, }, ]); expect(transferRowsToPairs(rows)).toEqual([ { from: "PSC2", to: "POC2", rows: 7 }, ]); }); it("parses FWA4 → VGT2", () => { const rows = parseTransferInstructionTable( "地址 FWA4 箱数 17 仓库重定向 VGT2 柜号 ZCSU6581068", ); expect(rows[0]?.from).toBe("FWA4"); expect(rows[0]?.to).toBe("VGT2"); expect(rows[0]?.ctns).toBe(17); }); it("parses noisy OCR table row", () => { const rows = parseTransferInstructionTable( "ZCSU6581068 20267777 PSC2 7 POC2", ); expect(rows[0]?.from).toBe("PSC2"); expect(rows[0]?.to).toBe("POC2"); }); it("uses fallback header fields and ignores OCR noise codes", () => { const rows = parseTransferInstructionTable( "HES ETA Ek BH ZCSUB581068 2026/7/7 PSC2 7 POC2", { containerNo: "ZCSU6581068", }, ); expect(rows).toEqual([ { containerNo: "ZCSU6581068", eta: "2026/7/7", from: "PSC2", to: "POC2", ctns: 7, }, ]); }); it("normalizes fuzzy FWA4 OCR row", () => { const rows = parseTransferInstructionTable( "155 EH ETA Spit AE RABE CEEEE zcsuessioes ozoze/r/7 Ewad 17 VGT2", { containerNo: "ZCSU6581068", }, ); expect(rows).toEqual([ { containerNo: "ZCSU6581068", from: "FWA4", to: "VGT2", ctns: 17, }, ]); }); }); describe("splitTaggedOcrBlocks", () => { it("splits per attachment tag", () => { const blocks = splitTaggedOcrBlocks( "【OCR:a.jpg】\n地址 PSC2 箱数 7 仓库重定向 POC2\n\n【OCR:b.jpg】\n地址 FWA4 箱数 17 仓库重定向 VGT2", ); expect(blocks).toHaveLength(2); expect(blocks[0].tag).toBe("a.jpg"); expect(blocks[1].text).toMatch(/FWA4/); }); }); describe("buildTransferSegmentContexts", () => { it("assigns oldest transfer unit to first image OCR block", () => { const units: MailInstructionUnit[] = [ { id: "t-new", uiKind: "transfer", mailType: "TRANSFER", label: "批量转仓", summary: "", keywords: [], source: "body_segment", segmentIndex: 3, isCurrent: true, segmentText: "新增转仓,请留意", roundAt: "2026-07-07", }, { id: "t-old", uiKind: "transfer", mailType: "TRANSFER", label: "批量转仓", summary: "", keywords: [], source: "body_segment", segmentIndex: 4, isCurrent: false, segmentText: "新增转仓,请留意", roundAt: "2026-07-06", }, ]; const ctx = buildTransferSegmentContexts({ transferUnits: units, imageFilenames: ["img-fwa.jpg", "img-psc.jpg"], containerNo: "ZCSU6581068", ocrText: "【OCR:img-fwa.jpg】\n地址 FWA4 箱数 17 仓库重定向 VGT2\n【OCR:img-psc.jpg】\n地址 PSC2 箱数 7 仓库重定向 POC2", }); expect(ctx.get("t-old")?.rows[0]?.from).toBe("FWA4"); expect(ctx.get("t-new")?.rows[0]?.from).toBe("PSC2"); }); });