|
|
/**
|
|
|
* One-shot writer for fixtures/emails spec.json + expected.json
|
|
|
*/
|
|
|
import fs from "fs/promises";
|
|
|
import path from "path";
|
|
|
|
|
|
const ROOT = path.join(process.cwd(), "fixtures", "emails");
|
|
|
|
|
|
const PACKING_TWO = [
|
|
|
{
|
|
|
仓库ID: "LAS1",
|
|
|
渠道: "卡派",
|
|
|
件数: 10,
|
|
|
总体积: 2.5,
|
|
|
毛重: 100,
|
|
|
"FBA ID": "FBA16SQQ7PTF",
|
|
|
"Amazon reference ID": "REF-001",
|
|
|
分货标识: "MK-1",
|
|
|
派送地址: "/",
|
|
|
备注: "/",
|
|
|
柜号: "WHSU8127240",
|
|
|
最早送仓日期: "2026-05-20",
|
|
|
最晚送仓日期: "2026-05-25",
|
|
|
},
|
|
|
{
|
|
|
仓库ID: "FTW1",
|
|
|
渠道: "TRUCK",
|
|
|
件数: 4,
|
|
|
总体积: 1.2,
|
|
|
毛重: 40,
|
|
|
"FBA ID": "FBA16AAAAAAA",
|
|
|
"Amazon reference ID": "REF-002",
|
|
|
分货标识: "MK-2",
|
|
|
派送地址: "/",
|
|
|
备注: "/",
|
|
|
柜号: "WHSU8127240",
|
|
|
最早送仓日期: "2026-05-20",
|
|
|
最晚送仓日期: "2026-05-25",
|
|
|
},
|
|
|
];
|
|
|
|
|
|
const fixtures: Array<{ spec: Record<string, unknown>; expected: Record<string, unknown> }> = [
|
|
|
{
|
|
|
spec: {
|
|
|
id: "01-normal-forecast",
|
|
|
category: "normal",
|
|
|
from: "ops@example.com",
|
|
|
subject: "请查收新增预报 智鸿2+WHLC027G597465+WHSU8127240+洛杉矶+40HQ",
|
|
|
text: "请查收新增预报:WHSU8127240 40HQ EDT2026.04-25 ETA2026.05-15 船名航次HMM EMERALD 013E+提拆派",
|
|
|
messageId: "<01-normal-forecast@fixtures.local>",
|
|
|
date: "2026-04-14T00:00:00.000Z",
|
|
|
attachments: [
|
|
|
{ filename: "数据模版-WHSU8127240.xlsx", kind: "packing_xlsx", rows: PACKING_TWO },
|
|
|
],
|
|
|
},
|
|
|
expected: {
|
|
|
mail_type: "NEW_CONTAINER",
|
|
|
status: "PENDING_CONFIRM",
|
|
|
last_error: null,
|
|
|
container_no: "WHSU8127240",
|
|
|
container_no_valid: true,
|
|
|
selected_attachment: "数据模版-WHSU8127240.xlsx",
|
|
|
shipment_count: 2,
|
|
|
valid_shipment_count: 2,
|
|
|
shipments: [
|
|
|
{ F_FBACode: "LAS1", F_Transporter: "TRUCK", F_CTNS: 10, row_status: "VALID" },
|
|
|
{ F_FBACode: "FTW1", F_Transporter: "TRUCK", F_CTNS: 4, row_status: "VALID" },
|
|
|
],
|
|
|
idempotent_with: null,
|
|
|
pull: true,
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
spec: {
|
|
|
id: "02-normal-transfer",
|
|
|
category: "normal",
|
|
|
from: "ops@example.com",
|
|
|
subject: "MATU2745683 转仓指令",
|
|
|
text: "Dear, 请将 MATU2745683 新增转仓:原仓 ABQ2 转到 FTW1,谢谢。",
|
|
|
messageId: "<02-normal-transfer@fixtures.local>",
|
|
|
date: "2026-04-14T01:00:00.000Z",
|
|
|
attachments: [
|
|
|
{
|
|
|
filename: "柜号:MATU2745683卡派资料.xlsx",
|
|
|
kind: "packing_xlsx",
|
|
|
rows: [
|
|
|
{
|
|
|
仓库ID: "FTW1",
|
|
|
渠道: "卡派",
|
|
|
件数: 8,
|
|
|
总体积: 3,
|
|
|
毛重: 80,
|
|
|
柜号: "MATU2745683",
|
|
|
},
|
|
|
],
|
|
|
},
|
|
|
],
|
|
|
},
|
|
|
expected: {
|
|
|
mail_type: "TRANSFER",
|
|
|
status: "PENDING_CONFIRM",
|
|
|
last_error: null,
|
|
|
container_no: "MATU2745683",
|
|
|
container_no_valid: true,
|
|
|
selected_attachment: "柜号:MATU2745683卡派资料.xlsx",
|
|
|
shipment_count: 1,
|
|
|
valid_shipment_count: 1,
|
|
|
pull: true,
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
spec: {
|
|
|
id: "03-normal-do-upload",
|
|
|
category: "normal",
|
|
|
from: "ops@example.com",
|
|
|
subject: "WHSU8127240 DO请查收",
|
|
|
text: "DO也同步上传至附件请注意查收!",
|
|
|
messageId: "<03-normal-do-upload@fixtures.local>",
|
|
|
date: "2026-04-14T02:00:00.000Z",
|
|
|
attachments: [
|
|
|
{ filename: "WHSU8127240-DO.pdf", kind: "pdf", text: "DELIVERY ORDER WHSU8127240" },
|
|
|
],
|
|
|
},
|
|
|
expected: {
|
|
|
mail_type: "DO_UPLOAD",
|
|
|
status: "PENDING_CONFIRM",
|
|
|
last_error: null,
|
|
|
container_no: "WHSU8127240",
|
|
|
container_no_valid: true,
|
|
|
selected_attachment: "WHSU8127240-DO.pdf",
|
|
|
shipment_count: 0,
|
|
|
pull: true,
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
spec: {
|
|
|
id: "04-keyword-subject",
|
|
|
category: "boundary",
|
|
|
from: "ops@example.com",
|
|
|
subject: "新增预报 WHSU8127240",
|
|
|
text: "附件是数据模版,请处理。",
|
|
|
messageId: "<04-keyword-subject@fixtures.local>",
|
|
|
date: "2026-04-14T03:00:00.000Z",
|
|
|
attachments: [
|
|
|
{ filename: "数据模版.xlsx", kind: "packing_xlsx", rows: PACKING_TWO },
|
|
|
],
|
|
|
},
|
|
|
expected: {
|
|
|
mail_type: "NEW_CONTAINER",
|
|
|
status: "PENDING_CONFIRM",
|
|
|
last_error: null,
|
|
|
container_no: "WHSU8127240",
|
|
|
selected_attachment: "数据模版.xlsx",
|
|
|
shipment_count: 2,
|
|
|
valid_shipment_count: 2,
|
|
|
pull: true,
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
spec: {
|
|
|
id: "05-keyword-body",
|
|
|
category: "boundary",
|
|
|
from: "ops@example.com",
|
|
|
subject: "WHSU8127240 资料",
|
|
|
text: "请查收新增预报,柜号 WHSU8127240,40HQ。",
|
|
|
messageId: "<05-keyword-body@fixtures.local>",
|
|
|
date: "2026-04-14T04:00:00.000Z",
|
|
|
attachments: [
|
|
|
{ filename: "数据模版.xlsx", kind: "packing_xlsx", rows: PACKING_TWO },
|
|
|
],
|
|
|
},
|
|
|
expected: {
|
|
|
mail_type: "NEW_CONTAINER",
|
|
|
status: "PENDING_CONFIRM",
|
|
|
last_error: null,
|
|
|
container_no: "WHSU8127240",
|
|
|
selected_attachment: "数据模版.xlsx",
|
|
|
shipment_count: 2,
|
|
|
pull: true,
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
spec: {
|
|
|
id: "06-mixed-en-zh",
|
|
|
category: "boundary",
|
|
|
from: "ops@example.com",
|
|
|
subject: "Please check 新增预报 WHSU8127240 / 40HQ ETA 2026-05-15",
|
|
|
text: "Hi team, 请查收新增预报 packing list attached. Vessel HMM EMERALD 013E.",
|
|
|
messageId: "<06-mixed-en-zh@fixtures.local>",
|
|
|
date: "2026-04-14T05:00:00.000Z",
|
|
|
attachments: [
|
|
|
{ filename: "数据模版.xlsx", kind: "packing_xlsx", rows: PACKING_TWO },
|
|
|
],
|
|
|
},
|
|
|
expected: {
|
|
|
mail_type: "NEW_CONTAINER",
|
|
|
status: "PENDING_CONFIRM",
|
|
|
last_error: null,
|
|
|
container_no: "WHSU8127240",
|
|
|
selected_attachment: "数据模版.xlsx",
|
|
|
shipment_count: 2,
|
|
|
pull: true,
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
spec: {
|
|
|
id: "07-gbk-body",
|
|
|
category: "boundary",
|
|
|
from: "ops@example.com",
|
|
|
subject: "Forecast WHSU8127240",
|
|
|
text: "请查收新增预报 WHSU8127240",
|
|
|
charset: "gbk",
|
|
|
messageId: "<07-gbk-body@fixtures.local>",
|
|
|
date: "2026-04-14T06:00:00.000Z",
|
|
|
attachments: [
|
|
|
{ filename: "数据模版.xlsx", kind: "packing_xlsx", rows: PACKING_TWO },
|
|
|
],
|
|
|
},
|
|
|
expected: {
|
|
|
mail_type: "NEW_CONTAINER",
|
|
|
status: "PENDING_CONFIRM",
|
|
|
last_error: null,
|
|
|
container_no: "WHSU8127240",
|
|
|
selected_attachment: "数据模版.xlsx",
|
|
|
shipment_count: 2,
|
|
|
pull: true,
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
spec: {
|
|
|
id: "08-oversized-attachment",
|
|
|
category: "boundary",
|
|
|
from: "ops@example.com",
|
|
|
subject: "请查收新增预报 WHSU8127240",
|
|
|
text: "请查收新增预报,附件较大。",
|
|
|
messageId: "<08-oversized-attachment@fixtures.local>",
|
|
|
date: "2026-04-14T07:00:00.000Z",
|
|
|
attachments: [
|
|
|
{ filename: "数据模版.xlsx", kind: "oversized", bytes: 20971521 },
|
|
|
],
|
|
|
},
|
|
|
expected: {
|
|
|
mail_type: "NEW_CONTAINER",
|
|
|
status: "REJECTED_VALIDATION",
|
|
|
last_error: "ATTACHMENT_TOO_LARGE",
|
|
|
container_no: "WHSU8127240",
|
|
|
selected_attachment: null,
|
|
|
pull: true,
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
spec: {
|
|
|
id: "09-no-attachment",
|
|
|
category: "abnormal",
|
|
|
from: "ops@example.com",
|
|
|
subject: "请查收新增预报 WHSU8127240 40HQ",
|
|
|
text: "请查收新增预报,稍后补附件。",
|
|
|
messageId: "<09-no-attachment@fixtures.local>",
|
|
|
date: "2026-04-14T08:00:00.000Z",
|
|
|
attachments: [],
|
|
|
},
|
|
|
expected: {
|
|
|
mail_type: "NEW_CONTAINER",
|
|
|
status: "REJECTED_VALIDATION",
|
|
|
last_error: "NO_SHIPMENT_ROWS",
|
|
|
container_no: "WHSU8127240",
|
|
|
selected_attachment: null,
|
|
|
shipment_count: 0,
|
|
|
pull: true,
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
spec: {
|
|
|
id: "10-corrupt-xlsx",
|
|
|
category: "abnormal",
|
|
|
from: "ops@example.com",
|
|
|
subject: "请查收新增预报 WHSU8127240",
|
|
|
text: "请查收新增预报,附件已损坏。",
|
|
|
messageId: "<10-corrupt-xlsx@fixtures.local>",
|
|
|
date: "2026-04-14T09:00:00.000Z",
|
|
|
attachments: [{ filename: "数据模版.xlsx", kind: "corrupt_xlsx" }],
|
|
|
},
|
|
|
expected: {
|
|
|
mail_type: "NEW_CONTAINER",
|
|
|
pipeline_mail_type: "UNKNOWN",
|
|
|
status: "PARSE_FAILED",
|
|
|
last_error: "MIME_PARSE_ERROR",
|
|
|
container_no: "WHSU8127240",
|
|
|
selected_attachment: "数据模版.xlsx",
|
|
|
pull: true,
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
spec: {
|
|
|
id: "11-wrong-format",
|
|
|
category: "abnormal",
|
|
|
from: "ops@example.com",
|
|
|
subject: "请查收新增预报 WHSU8127240",
|
|
|
text: "请查收新增预报,附件是说明文档。",
|
|
|
messageId: "<11-wrong-format@fixtures.local>",
|
|
|
date: "2026-04-14T10:00:00.000Z",
|
|
|
attachments: [
|
|
|
{
|
|
|
filename: "说明.docx",
|
|
|
kind: "raw",
|
|
|
content: "this is not a spreadsheet",
|
|
|
contentType:
|
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
|
},
|
|
|
],
|
|
|
},
|
|
|
expected: {
|
|
|
mail_type: "NEW_CONTAINER",
|
|
|
status: "PARSE_FAILED",
|
|
|
last_error: "NO_SUPPORTED_SPREADSHEET",
|
|
|
container_no: "WHSU8127240",
|
|
|
selected_attachment: null,
|
|
|
pull: true,
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
spec: {
|
|
|
id: "12-missing-required",
|
|
|
category: "abnormal",
|
|
|
from: "ops@example.com",
|
|
|
subject: "请查收新增预报 WHSU8127240",
|
|
|
text: "请查收新增预报。",
|
|
|
messageId: "<12-missing-required@fixtures.local>",
|
|
|
date: "2026-04-14T11:00:00.000Z",
|
|
|
attachments: [
|
|
|
{
|
|
|
filename: "数据模版.xlsx",
|
|
|
kind: "packing_xlsx",
|
|
|
headers: ["备注", "柜号"],
|
|
|
rows: [{ 备注: "只有备注没有必填列", 柜号: "WHSU8127240" }],
|
|
|
},
|
|
|
],
|
|
|
},
|
|
|
expected: {
|
|
|
mail_type: "NEW_CONTAINER",
|
|
|
status: "PARSE_FAILED",
|
|
|
last_error: "missing_columns",
|
|
|
container_no: "WHSU8127240",
|
|
|
selected_attachment: "数据模版.xlsx",
|
|
|
missing_columns: true,
|
|
|
shipment_count: 0,
|
|
|
pull: true,
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
spec: {
|
|
|
id: "13-illegal-date",
|
|
|
category: "abnormal",
|
|
|
from: "ops@example.com",
|
|
|
subject: "请查收新增预报 WHSU8127240",
|
|
|
text: "请查收新增预报。",
|
|
|
messageId: "<13-illegal-date@fixtures.local>",
|
|
|
date: "2026-04-14T12:00:00.000Z",
|
|
|
attachments: [
|
|
|
{
|
|
|
filename: "数据模版.xlsx",
|
|
|
kind: "packing_xlsx",
|
|
|
rows: [
|
|
|
{
|
|
|
仓库ID: "LAS1",
|
|
|
渠道: "卡派",
|
|
|
件数: 2,
|
|
|
总体积: 1,
|
|
|
毛重: 20,
|
|
|
柜号: "WHSU8127240",
|
|
|
最早送仓日期: "not-a-date",
|
|
|
最晚送仓日期: "99/99/99",
|
|
|
},
|
|
|
],
|
|
|
},
|
|
|
],
|
|
|
},
|
|
|
expected: {
|
|
|
mail_type: "NEW_CONTAINER",
|
|
|
status: "PENDING_CONFIRM",
|
|
|
last_error: null,
|
|
|
container_no: "WHSU8127240",
|
|
|
selected_attachment: "数据模版.xlsx",
|
|
|
shipment_count: 1,
|
|
|
valid_shipment_count: 1,
|
|
|
shipments: [
|
|
|
{
|
|
|
F_FBACode: "LAS1",
|
|
|
F_Transporter: "TRUCK",
|
|
|
F_CTNS: 2,
|
|
|
row_status: "VALID",
|
|
|
F_Expected_DeliveryDateB: null,
|
|
|
},
|
|
|
],
|
|
|
pull: true,
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
spec: {
|
|
|
id: "14-duplicate-pull",
|
|
|
category: "duplicate",
|
|
|
from: "ops@example.com",
|
|
|
subject: "请查收新增预报 智鸿2+WHLC027G597465+WHSU8127240+洛杉矶+40HQ",
|
|
|
text: "请查收新增预报:WHSU8127240 40HQ EDT2026.04-25 ETA2026.05-15 船名航次HMM EMERALD 013E+提拆派",
|
|
|
messageId: "<01-normal-forecast@fixtures.local>",
|
|
|
date: "2026-04-14T00:00:00.000Z",
|
|
|
attachments: [
|
|
|
{ filename: "数据模版-WHSU8127240.xlsx", kind: "packing_xlsx", rows: PACKING_TWO },
|
|
|
],
|
|
|
},
|
|
|
expected: {
|
|
|
mail_type: "NEW_CONTAINER",
|
|
|
status: "PENDING_CONFIRM",
|
|
|
last_error: null,
|
|
|
container_no: "WHSU8127240",
|
|
|
selected_attachment: "数据模版-WHSU8127240.xlsx",
|
|
|
idempotent_with: "01-normal-forecast",
|
|
|
pull: true,
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
spec: {
|
|
|
id: "15-multi-attachment",
|
|
|
category: "multi_attachment",
|
|
|
from: "ops@example.com",
|
|
|
subject: "请查收新增预报 WHSU8127240,DO请查收",
|
|
|
text: "请查收新增预报。DO也同步上传至附件。",
|
|
|
messageId: "<15-multi-attachment@fixtures.local>",
|
|
|
date: "2026-04-14T13:00:00.000Z",
|
|
|
attachments: [
|
|
|
{
|
|
|
filename: "YT2604021091=76件换标走HIA1卡派出库操作指令.xlsx",
|
|
|
kind: "packing_xlsx",
|
|
|
rows: [
|
|
|
{ 仓库ID: "HIA1", 渠道: "换标", 件数: 76, 柜号: "XXXX0000000" },
|
|
|
],
|
|
|
},
|
|
|
{ filename: "WHSU8127240-DO.pdf", kind: "pdf", text: "DO" },
|
|
|
{ filename: "数据模版-WHSU8127240.xlsx", kind: "packing_xlsx", rows: PACKING_TWO },
|
|
|
{ filename: "4邮箱.pdf", kind: "pdf", text: "screenshot" },
|
|
|
],
|
|
|
},
|
|
|
expected: {
|
|
|
// 附件名含「换标」走硬工单分(45+30=75),压过新增预报(65)与 DO(70);不改生产分类
|
|
|
mail_type: "WORK_ORDER",
|
|
|
status: "PENDING_CONFIRM",
|
|
|
last_error: null,
|
|
|
container_no: "WHSU8127240",
|
|
|
selected_attachment: "数据模版-WHSU8127240.xlsx",
|
|
|
selected_attachments: [
|
|
|
"YT2604021091=76件换标走HIA1卡派出库操作指令.xlsx",
|
|
|
"WHSU8127240-DO.pdf",
|
|
|
"数据模版-WHSU8127240.xlsx",
|
|
|
"4邮箱.pdf",
|
|
|
],
|
|
|
shipment_count: 2,
|
|
|
valid_shipment_count: 2,
|
|
|
pull: true,
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
spec: {
|
|
|
id: "16-unknown-format",
|
|
|
category: "abnormal",
|
|
|
from: "random@example.com",
|
|
|
subject: "Weekly newsletter",
|
|
|
text: "Hello, this is a marketing newsletter about office snacks.",
|
|
|
messageId: "<16-unknown-format@fixtures.local>",
|
|
|
date: "2026-04-14T14:00:00.000Z",
|
|
|
attachments: [],
|
|
|
},
|
|
|
expected: {
|
|
|
mail_type: "UNKNOWN",
|
|
|
status: "IGNORED",
|
|
|
last_error: "SKIP_FILTER",
|
|
|
selected_attachment: null,
|
|
|
pull: false,
|
|
|
},
|
|
|
},
|
|
|
];
|
|
|
|
|
|
async function main() {
|
|
|
await fs.mkdir(ROOT, { recursive: true });
|
|
|
for (const { spec, expected } of fixtures) {
|
|
|
const id = String(spec.id);
|
|
|
const dir = path.join(ROOT, id);
|
|
|
await fs.mkdir(dir, { recursive: true });
|
|
|
await fs.writeFile(path.join(dir, "spec.json"), JSON.stringify(spec, null, 2) + "\n");
|
|
|
await fs.writeFile(
|
|
|
path.join(dir, "expected.json"),
|
|
|
JSON.stringify(expected, null, 2) + "\n",
|
|
|
);
|
|
|
}
|
|
|
console.log(`wrote ${fixtures.length} fixtures under ${ROOT}`);
|
|
|
}
|
|
|
|
|
|
main().catch((err) => {
|
|
|
console.error(err);
|
|
|
process.exit(1);
|
|
|
});
|