Files
LWLT-AIBOT/control-plane/test/reply-contract.test.ts
T

194 lines
6.7 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import {
buildCustomerSuccessReply,
buildCustomerSuccessReceipt,
replyAttachmentsFromReceipt,
replyTextFromReceipt
} from '../src/reply-contract.js';
test('hotel arrangement uses the customer bilingual booking template', () => {
const operation = {
action: 'arrangement_hotel',
data: {
customer: { name: '老挝联泰' },
existing_refs: { kind: 'independent_order', identifier: 'LW-260603Z-A' },
arrangement: {
mode: 'create',
start_date: '2026-06-03',
end_date: '2026-06-04',
room_count: 6
}
}
};
const result = {
report: {
requery: {
subpage: {
arrangement_target: {
item_value: 'TWN',
quantity_value: '6'
}
}
}
}
};
const receipt = { success: true, group_number: 'LW-260603Z-A' };
const reply = buildCustomerSuccessReply(receipt, result, operation);
assert.ok(reply);
assert.equal(reply.profile, 'hotel-arrangement-lwlt-v1');
assert.equal(reply.text, [
'①NEW BOOKING',
'GROUP CODE: LW-260603Z-A',
'IN. 03/06/2026',
'OUT 04/06/2026',
'1Night. 6Twin',
'②新订单',
'团号:LW-260603Z-A 老挝联泰',
'入住日期:2026.06.03',
'退房日期:2026.06.04',
'几 晚:1晚',
'房型/房数:标间 6间'
].join('\n'));
});
test('hotel clear and update replies stay business-readable when the booking template is not applicable', () => {
const clearReply = buildCustomerSuccessReply(
{ success: true, group_number: 'LW-260603Z-A' },
{},
{
action: 'arrangement_hotel',
data: {
existing_refs: { identifier: 'LW-260603Z-A' },
arrangement: { mode: 'clear' }
}
}
);
assert.ok(clearReply);
assert.equal(clearReply.text, '酒店安排已清除\n团号:LW-260603Z-A');
const updateReply = buildCustomerSuccessReply(
{ success: true, group_number: 'LW-260603Z-A' },
{ report: { changes: [{ target: 'room_count', after: 9 }] } },
{
action: 'arrangement_hotel',
data: {
existing_refs: { identifier: 'LW-260603Z-A' },
arrangement: { mode: 'update', end_date: '2026-06-05', room_count: 9 }
}
}
);
assert.ok(updateReply);
assert.equal(updateReply.text, '酒店安排成功\n团号:LW-260603Z-A\n退房日期:2026-06-05\n房数:9间');
});
test('batch newbooking receipt preserves every group number', () => {
const reply = buildCustomerSuccessReply(
{ success: true, group_number: 'LW-260603A-A', group_numbers: ['LW-260603A-A', 'LW-260605A-A'] },
{},
{ action: 'team_order_batch_create', data: {} }
);
assert.ok(reply);
assert.equal(reply.text, '批量下单成功\n团号:LW-260603A-A、LW-260605A-A');
});
test('update and file replies expose business fields without technical evidence', () => {
const updateReply = buildCustomerSuccessReply(
{ success: true, group_number: 'LW-260603A-A' },
{ report: { changes: [{ target: 'planned_capacity', after: 45 }] } },
{
action: 'order_update_shared_plan',
data: {
existing_refs: { identifier: 'LW-260603A-A' },
updates: { actions: [{ target: 'planned_capacity', operation: 'set', value: 45 }] }
}
}
);
assert.ok(updateReply);
assert.equal(updateReply.text, '散拼母团信息修改成功\n团号:LW-260603A-A\n计划收客数:45');
assert.doesNotMatch(updateReply.text, /sha256|verification|blocker|execution/iu);
const baseReceipt = buildCustomerSuccessReceipt(
{ success: true, group_number: 'LW-260603A-A' },
{
report: {
artifacts: [{
file_name: 'liantai-confirm.docx',
content_type: 'application/msword',
bytes: 28892,
download_url: '/api/tasks/TASK-1/artifacts/ART-1',
sha256: 'secret-hash'
}]
}
},
{ action: 'confirmation_export', data: { existing_refs: { identifier: 'LW-260603A-A' } } }
);
assert.equal(replyTextFromReceipt(baseReceipt), '团队文件已准备\n团号:LW-260603A-A\n文件:liantai-confirm.docx');
assert.deepEqual(replyAttachmentsFromReceipt(baseReceipt), [{
name: 'liantai-confirm.docx',
content_type: 'application/msword',
size: 28892,
download_url: '/api/tasks/TASK-1/artifacts/ART-1'
}]);
assert.doesNotMatch(JSON.stringify(baseReceipt), /secret-hash/);
});
test('visitor export reply exposes only the mobile XLSX delivery artifact', () => {
const receipt = buildCustomerSuccessReceipt(
{ success: true, group_number: 'LW-260816Z-A' },
{
report: {
artifacts: [
{
file_name: 'LW-260816Z-A Visitor.xls',
content_type: 'application/vnd.ms-excel',
bytes: 9377,
agentbus_visible: false,
download_url: '/api/tasks/TASK-VISITOR/artifacts/ART-XLS'
},
{
file_name: 'LW-260816Z-A Visitor.xlsx',
content_type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
bytes: 5211,
agentbus_visible: true,
download_url: '/api/tasks/TASK-VISITOR/artifacts/ART-XLSX'
}
]
}
},
{ action: 'confirmation_export', data: { existing_refs: { identifier: 'LW-260816Z-A' } } }
);
assert.equal(replyTextFromReceipt(receipt!), '团队文件已准备\n团号:LW-260816Z-A\n文件:LW-260816Z-A Visitor.xlsx');
assert.deepEqual(replyAttachmentsFromReceipt(receipt!), [{
name: 'LW-260816Z-A Visitor.xlsx',
content_type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
size: 5211,
download_url: '/api/tasks/TASK-VISITOR/artifacts/ART-XLSX'
}]);
assert.doesNotMatch(JSON.stringify(receipt), /Visitor\.xls(?!x)/u);
});
test('legacy ERP mojibake filenames are repaired when a stored receipt is read', () => {
const receipt = buildCustomerSuccessReceipt(
{ success: true, group_number: 'LW-261202A-A' },
{
report: {
artifacts: [{
file_name: 'LLW-261202A-A 客户确认书.doc',
content_type: 'application/msword',
bytes: 30649,
download_url: '/api/tasks/TASK-LEGACY/artifacts/ART-LEGACY'
}]
}
},
{ action: 'confirmation_export', data: { existing_refs: { identifier: 'LW-261202A-A' } } }
);
assert.equal(replyTextFromReceipt(receipt), '团队文件已准备\n团号:LW-261202A-A\n文件:LLW-261202A-A 客户确认书.doc');
assert.deepEqual(replyAttachmentsFromReceipt(receipt), [{
name: 'LLW-261202A-A 客户确认书.doc',
content_type: 'application/msword',
size: 30649,
download_url: '/api/tasks/TASK-LEGACY/artifacts/ART-LEGACY'
}]);
});