import assert from 'node:assert/strict'; import test from 'node:test'; import { parseProgramInput } from '../src/program-parser.js'; const hotel = (start: string, end: string, directive = '安排酒店变更') => `${directive}\n团号:LW-260901VIP-A\n入住日期:${start}\n离店日期:${end}\n酒店搜索:测试酒店TWN\n间数:12`; const parse = (rawText: string, receivedAt = '2026-09-14T13:16:07+08:00') => parseProgramInput({ rawText, receivedAt }); test('original hotel dates never roll forward with the submission date or group number', async () => { for (const now of ['2026-09-14T13:16:07+08:00', '2027-01-01T00:00:00+08:00']) { const result = await parse(hotel('9-4', '9-5'), now); assert.equal(result.status, 'agent_parse_passed', JSON.stringify(result)); assert.deepEqual((result.operation as any).data.arrangement.selection, { start_date: '09-04', end_date: '09-05' }); assert.equal((result.operation as any).data.arrangement.changes.end_date, undefined); } const local = await parse(hotel('9-12', '9-13').replace('LW-260901VIP-A', 'LLW-270911A-A')); assert.deepEqual((local.operation as any).data.arrangement.selection, { start_date: '09-12', end_date: '09-13' }); }); test('original dates retain explicit years and allow cross-year, mixed-year and leap-day selectors', async () => { for (const [start, end, expected] of [ ['2026-9-4', '2026-9-5', ['2026-09-04', '2026-09-05']], ['12月31日', '1月2日', ['12-31', '01-02']], ['2026-12-31', '1-2', ['2026-12-31', '01-02']], ['2/29', '3/1', ['02-29', '03-01']] ] as const) { const result = await parse(hotel(start, end)); assert.equal(result.status, 'agent_parse_passed', JSON.stringify(result)); assert.deepEqual((result.operation as any).data.arrangement.selection, { start_date: expected[0], end_date: expected[1] }); } for (const [start, end] of [['2-30', '3-1'], ['2026-2-29', '2026-3-1'], ['2026-9-5', '2026-9-4'], ['2026-9-4', '2026-9-4']]) { const result = await parse(hotel(start, end)); assert.ok(['agent_parse_blocked', 'agent_parse_needs_input'].includes(result.status)); assert.equal(result.operation, null); } }); test('vehicle, transport and other original dates also preserve month/day including filing date', async () => { const group = '\n团号:LW-260901VIP-A\n结算单位搜索:测试新供应商\n数量:2'; for (const [input, selection] of [ [`安排用车变更${group}\n用车日期:12-31到1-2`, { start_date: '12-31', end_date: '01-02' }], [`安排大交通变更${group}\n交通日期:9-4`, { date: '09-04' }], [`安排其他/备案变更${group}\n业务日期:9-4\n备案日期:9-3`, { date: '09-04', filing_date: '09-03' }] ] as const) { const result = await parse(input); assert.equal(result.status, 'agent_parse_passed', JSON.stringify(result)); assert.deepEqual((result.operation as any).data.arrangement.selection, selection); } }); test('hotel creation and legacy target-date changes retain their existing year semantics', async () => { const create = await parse(hotel('9-4', '9-5', '安排酒店')); assert.equal((create.operation as any).data.arrangement.start_date, '2026-09-04'); assert.equal((create.operation as any).data.arrangement.end_date, '2026-09-05'); const legacy = await parse('安排变更\n团号:LW-260901VIP-A\n目标变更:离店日期改为9-5\n安排类型:酒店'); assert.equal(legacy.status, 'agent_parse_passed', JSON.stringify(legacy)); assert.equal((legacy.operation as any).data.arrangement.changes.end_date, '2027-09-05'); });