Files
LWLT-AI/archive/handoff/2026-07-12/legacy-erp-handoff/tools/tests/erp_operation_adapter.test.js
2026-07-13 19:57:46 +08:00

252 lines
9.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const adapter = require('../erp_operation_adapter');
function tempAuditDir() {
return fs.mkdtempSync(path.join(os.tmpdir(), 'erp-operation-audit-'));
}
test('defaults old order templates to create_order and delegates route parsing', () => {
const result = adapter.handleIncomingMessage(`下单模式:团队-单个下单
订单性质:测试
产品名称:遇见老挝
出发日期2026-10-03
人数:
成人2
小孩占床0
小孩不占床0
婴儿0
领队0
用房:
SGL0
TWN0
TRP0
DBL1
HNM0
TL0
单价:
成人500
小孩占床0
小孩不占床0
婴儿0
领队0
计调OP测试
销售人:琳琳
备注:确认真实保存 ERP`, { auditDir: tempAuditDir() });
assert.equal(result.status, 'ready');
assert.equal(result.operation, 'create_order');
assert.equal(result.task.operation, 'create_order');
assert.equal(result.task.route, 'team_single');
assert.equal(result.task.delivery.deferConfirmationExport, true);
assert.equal(result.task.delivery.sendPdfFollowUp, false);
});
test('treats order templates with supplemental and pdf wording as create_order', () => {
const result = adapter.handleIncomingMessage(`下单模式:散拼-拼单/录入子单
订单性质:测试
产品/线路:老挝行程-广东 8D7N
出发日期2026-09-19
渠道/预订客户LW云南七彩金桥国旅(昆明景腾)
人数:
成人2
小孩占床1
小孩不占床1
婴儿0
领队0
单价:
成人500
小孩占床300
小孩不占床200
婴儿0
领队0
计调OP测试
销售人:琳琳
航班信息:
去程2026-09-19CZ6091广州-万象08:20-10:10
回程2026-09-26CZ6092万象-广州18:30-22:10
酒店信息:
第1晚万象湄公河精品酒店2间双床房
接送机信息:
接机地点:万象机场到达口
送机地点:万象机场国际出发口
联系人:张三
电话13800138000
游客名单:
1. 张三 / 男 / 成人 / 护照 E12345678 / 电话 13800138000
特殊要求:
1. 确认书需要返回 PDF
备注:补充资料包含航班、酒店、游客名单和特殊要求。确认真实保存 ERP。`, { auditDir: tempAuditDir() });
assert.equal(result.status, 'ready');
assert.equal(result.operation, 'create_order');
assert.equal(result.task.operation, 'create_order');
assert.equal(result.task.route, 'split_child');
assert.equal(result.task.fields.supplemental.flights.length, 2);
assert.equal(result.task.fields.supplemental.hotels[0], '第1晚万象湄公河精品酒店2间双床房');
assert.equal(result.task.fields.supplemental.transfer.pickupPlace, '万象机场到达口');
assert.equal(result.task.fields.supplemental.travelers[0].name, '张三');
assert.deepEqual(result.task.fields.supplemental.specialRequests, ['确认书需要返回 PDF']);
});
test('parses update_order by ERP identifier without requiring a route', () => {
const result = adapter.handleIncomingMessage(`操作类型:补充/修改订单
订单编号D14079
修改内容:
航班信息:
去程2026-09-19CZ6091广州-万象08:20-10:10
特殊要求:
客人不吃牛肉`, { auditDir: tempAuditDir() });
assert.equal(result.status, 'ready');
assert.equal(result.operation, 'update_order');
assert.equal(result.task.operation, 'update_order');
assert.equal(result.task.identifier, 'D14079');
assert.match(result.task.updateText, /CZ6091/);
assert.equal(result.task.route, '');
});
test('adds structured update plan for update_order instructions', () => {
const result = adapter.handleIncomingMessage(`操作类型:修改订单
订单编号D14079
修改内容:
成人减少1
DBL减少1
备注增加:客人不吃牛肉`, { auditDir: tempAuditDir() });
assert.equal(result.status, 'ready');
assert.equal(result.operation, 'update_order');
assert.deepEqual(result.task.updatePlan.actions, [
{ target: 'pax.adult', operation: 'delta', value: -1, source: '成人减少1' },
{ target: 'rooms.DBL', operation: 'delta', value: -1, source: 'DBL减少1' },
{ target: 'remark', operation: 'append', value: '客人不吃牛肉', source: '备注增加:客人不吃牛肉' },
]);
});
test('attaches traveler-list files to update_order instructions and redacts audit rows', () => {
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'erp-operation-list-'));
const csvPath = path.join(tmp, 'travelers.csv');
fs.writeFileSync(
csvPath,
[
'序号,中文名,英文名,性别,身份证号码,出生日期,出生地,护照号码,签发日期,有效日期,签发地,备注',
'1,张三,ZHANG SAN,男,110101199001011234,1990-01-01,北京,E12345678,2025-01-01,2035-01-01,北京,',
'2,李四,LI SI,女,110101199201011234,1992-01-01,北京,E23456789,2025-01-01,2035-01-01,北京,',
].join('\n'),
'utf8'
);
const result = adapter.handleIncomingMessage(`操作类型:补充/修改订单
订单编号D14079`, {
auditDir: tempAuditDir(),
attachments: [csvPath],
});
const audit = JSON.parse(fs.readFileSync(result.auditPath, 'utf8'));
assert.equal(result.status, 'ready');
assert.equal(result.operation, 'update_order');
assert.equal(result.task.updatePlan.supplemental.travelerList.totalCount, 2);
assert.equal(result.task.updatePlan.supplemental.travelerList.validationStatus, 'pending_order_pax');
assert.equal(result.task.updatePlan.actions.at(-1).target, 'supplemental.travelerList');
assert.equal(audit.task.updatePlan.supplemental.travelerList.rows[0].chineseName, '[redacted]');
assert.equal(audit.task.updatePlan.supplemental.travelerList.rows[0].passportNo, '[redacted]');
});
test('treats natural traveler-list import phrase with an identifier as update_order', () => {
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'erp-operation-natural-list-'));
const csvPath = path.join(tmp, 'travelers.csv');
fs.writeFileSync(
csvPath,
[
'搴忓彿,涓枃鍚?鑻辨枃鍚?鎬у埆,韬唤璇佸彿鐮?鍑虹敓鏃ユ湡,鍑虹敓鍦?鎶ょ収鍙风爜,绛惧彂鏃ユ湡,鏈夋晥鏃ユ湡,绛惧彂鍦?澶囨敞',
'1,寮犱笁,ZHANG SAN,鐢?110101199001011234,1990-01-01,鍖椾含,E12345678,2025-01-01,2035-01-01,鍖椾含,',
'2,鏉庡洓,LI SI,濂?110101199201011234,1992-01-01,鍖椾含,E23456789,2025-01-01,2035-01-01,鍖椾含,',
].join('\n'),
'utf8'
);
const result = adapter.handleIncomingMessage('导入到 LLW-260805A-A', {
auditDir: tempAuditDir(),
attachments: [csvPath],
});
assert.equal(result.status, 'ready');
assert.equal(result.operation, 'update_order');
assert.equal(result.task.identifier, 'LLW-260805A-A');
assert.equal(result.task.updatePlan.supplemental.travelerList.sourceFile, csvPath);
assert.equal(result.task.updatePlan.supplemental.travelerList.validationStatus, 'pending_order_pax');
assert.equal(result.task.updatePlan.actions.at(-1).target, 'supplemental.travelerList');
});
test('asks clarification when update_order instructions are ambiguous', () => {
const result = adapter.handleIncomingMessage(`操作类型:修改订单
订单编号D14079
修改内容:
人数减1
房间减少1间`, { auditDir: tempAuditDir() });
assert.equal(result.status, 'needs_clarification');
assert.equal(result.operation, 'update_order');
assert.deepEqual(result.missingFields, ['人数类别', '房型']);
assert.equal(result.task, null);
assert.match(result.customerMessage, /人数类别/);
});
test('parses export_confirmation by ERP identifier', () => {
const result = adapter.handleIncomingMessage(`操作类型:导出确认件
订单编号LLW-260811A-A`, { auditDir: tempAuditDir() });
assert.equal(result.status, 'ready');
assert.equal(result.operation, 'export_confirmation');
assert.equal(result.task.operation, 'export_confirmation');
assert.equal(result.task.identifier, 'LLW-260811A-A');
assert.deepEqual(result.task.exportTypes, ['xingyou-confirm']);
});
test('parses explicit Liantai confirmation export request', () => {
const result = adapter.handleIncomingMessage(`操作类型:导出确认件
订单编号LW-260919A-A
需要联泰确认书`, { auditDir: tempAuditDir() });
assert.equal(result.status, 'ready');
assert.deepEqual(result.task.exportTypes, ['xingyou-confirm', 'liantai-confirm']);
});
test('blocks update_order when identifier is missing', () => {
const result = adapter.handleIncomingMessage(`操作类型:补充/修改订单
修改内容:备注:客人不吃牛肉`, { auditDir: tempAuditDir() });
assert.equal(result.status, 'needs_clarification');
assert.equal(result.operation, 'update_order');
assert.deepEqual(result.missingFields, ['订单编号']);
assert.match(result.customerMessage, /订单编号/);
});
test('parseArgs supports input audit-dir and json flags', () => {
const args = adapter.parseArgs(['node', 'tool', '--input', 'message.txt', '--audit-dir', 'audit', '--json']);
assert.equal(args.input, 'message.txt');
assert.equal(args.auditDir, 'audit');
assert.equal(args.json, true);
});