You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

106 lines
4.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { describe, expect, it } from "vitest";
import { classifyMail } from "@/services/parse/classify";
import {
extractOpsSubjectFromMail,
parseOpsSubjectTemplate,
} from "@/services/parse/ops-subject-template";
import { buildMailRecord } from "@/services/parse/work-order-record";
/** 邮件3 真实主题(3邮箱.pdf) */
const MAIL3_SUBJECT =
"Fw: 转发:派送要求更新: 拆柜清单更新: DO请查收+拆柜清单更新: WHSU5574991+WHL063G550810+船名航次:OOCL SINGAPORE / 065W+ETA:6/28+FedEx-29件+UPS-102件+亚马逊卡派-289件+私人地址-166件+拦截-209件+拆柜清单";
const PAYLOAD =
"WHSU5574991+WHL063G550810+船名航次:OOCL SINGAPORE / 065W+ETA:6/28+FedEx-29件+UPS-102件+亚马逊卡派-289件+私人地址-166件+拦截-209件+拆柜清单";
describe("ops-subject-template mail3", () => {
it("parses subject payload fields", () => {
const r = parseOpsSubjectTemplate(PAYLOAD, { defaultYear: 2026 });
expect(r).not.toBeNull();
expect(r!.modules.container_no).toBe("WHSU5574991");
expect(r!.modules.bl_no).toBe("WHL063G550810");
expect(r!.modules.shipping_line_hint).toBe("WHL");
expect(r!.modules.vessel_voyage).toMatch(/OOCL SINGAPORE/);
expect(r!.modules.vessel_voyage).toMatch(/065W/);
expect(r!.modules.eta).toBe("2026-06-28");
expect(r!.channels).toEqual(
expect.arrayContaining([
{ channel: "FedEx", ctns: 29 },
{ channel: "UPS", ctns: 102 },
{ channel: "亚马逊卡派", ctns: 289 },
{ channel: "私人地址", ctns: 166 },
{ channel: "拦截", ctns: 209 },
]),
);
expect(r!.modules.ops_hints).toEqual(
expect.arrayContaining(["拆柜清单"]),
);
expect(r!.modules.ops_hints).not.toContain("拦截");
});
it("extracts from full forwarded subject", () => {
const r = extractOpsSubjectFromMail(MAIL3_SUBJECT, { defaultYear: 2026 });
expect(r).not.toBeNull();
expect(r!.modules.container_no).toBe("WHSU5574991");
expect(r!.modules.bl_no).toBe("WHL063G550810");
expect(r!.modules.eta).toBe("2026-06-28");
});
it("拆柜清单 ops_hints → mapBlModulesToHeader OperationType 0", async () => {
const { mapBlModulesToHeader } = await import(
"@/services/parse/bl-plus-template"
);
const r = extractOpsSubjectFromMail(MAIL3_SUBJECT, { defaultYear: 2026 })!;
const header = mapBlModulesToHeader(
{
F_ContainerNo: r.modules.container_no || "",
container_no_valid: true,
},
r.modules,
);
expect(r.modules.ops_hints).toEqual(
expect.arrayContaining(["拆柜清单"]),
);
expect(header.F_OperationType).toBe(0);
});
it("classifies as WORK_ORDER and builds subject-only mail_record", () => {
const evidence = classifyMail({
subject: MAIL3_SUBJECT,
body: "",
filenames: [],
});
expect(evidence.mail_type).toBe("WORK_ORDER");
const ops = extractOpsSubjectFromMail(MAIL3_SUBJECT, {
defaultYear: 2026,
})!;
const record = buildMailRecord({
mailType: "WORK_ORDER",
subject: MAIL3_SUBJECT,
body: "这票需要开箱拍照……不应进入记录",
filenames: ["WL103276-SBD1(1).pdf"],
opsSubject: {
modules: ops.modules,
channels: ops.channels,
},
});
expect(record.kind).toBe("WORK_ORDER");
expect(record.lineage.subject_only).toBe(true);
expect(record.modules.container_no).toBe("WHSU5574991");
expect(record.modules.bl_no).toBe("WHL063G550810");
expect(record.modules.eta).toBe("2026-06-28");
expect(record.table.rows.length).toBe(5);
expect(record.table.rows.every((r) => r.动作 === "拆柜清单")).toBe(true);
expect(record.table.rows.some((r) => String(r.备注).includes("FedEx"))).toBe(
true,
);
expect(record.work_order_actions || []).not.toContain("拦截");
expect(record.summary).toMatch(/拆柜清单/);
expect(record.summary).not.toMatch(/主题):拦截/);
// 正文/附件未混入
expect(record.summary).not.toMatch(/开箱拍照/);
});
});