import assert from 'node:assert/strict' import test from 'node:test' import { AI_APPLICATION_ACTION_SAVE_DRAFT, AI_APPLICATION_ACTION_SUBMIT, buildAiApplicationPreviewActionPayload } from '../src/services/aiApplicationPreviewActions.js' import { applyApplicationPolicyEstimateResult, buildApplicationPolicyEstimateRequest, buildLocalApplicationPreview } from '../src/utils/expenseApplicationPreview.js' const applicationPreview = { fields: { applicationType: '差旅费用申请', applicant: '曹笑竹', grade: 'P5', department: '技术部', position: '财务智能化产品经理', managerName: '向万红', time: '2026-02-20 至 2026-02-23', location: '上海', reason: '辅助国网仿生产服务器部署', days: '4天', transportMode: '火车', lodgingDailyCap: '250元/天', subsidyDailyCap: '100元/天', transportPolicy: '按交通费用预估表暂估', policyEstimate: '交通 720元 + 住宿 1,000元 + 补贴 400元 = 2,120元(4天)', amount: '2,120元' } } const currentUser = { username: 'caoxiaozhu@xf.com', name: '曹笑竹', departmentName: '技术部', position: '财务智能化产品经理', grade: 'P5', managerName: '向万红', roleCodes: ['employee'] } test('save application preview payload uses save draft action without submit wording', () => { const payload = buildAiApplicationPreviewActionPayload({ actionType: AI_APPLICATION_ACTION_SAVE_DRAFT, applicationPreview, currentUser, conversationId: 'inline-1' }) assert.equal(payload.user_id, 'caoxiaozhu@xf.com') assert.equal(payload.conversation_id, 'inline-1') assert.equal(payload.context_json.session_type, 'application') assert.equal(payload.context_json.review_action, undefined) assert.equal(payload.context_json.application_action, 'save_draft') assert.equal(payload.context_json.application_preview.fields.transportMode, '火车') assert.match(payload.message, /费用申请保存草稿/) assert.match(payload.message, /保存草稿/) assert.doesNotMatch(payload.message, /确认提交/) }) test('submit application preview payload keeps existing draft id for resubmission', () => { const payload = buildAiApplicationPreviewActionPayload({ actionType: AI_APPLICATION_ACTION_SUBMIT, applicationPreview, currentUser, conversationId: 'inline-1', draftPayload: { claim_id: 'draft-001', claim_no: 'AP-202602200001' } }) assert.equal(payload.context_json.review_action, undefined) assert.equal(payload.context_json.application_edit_claim_id, 'draft-001') assert.equal(payload.context_json.draft_claim_id, 'draft-001') assert.match(payload.message, /费用申请确认提交/) assert.match(payload.message, /确认提交/) }) test('travel application preview calculates base standards before transport mode is selected', () => { const preview = buildLocalApplicationPreview( '2月20-23日去上海出差,辅助国网仿生产服务器部署', { name: '曹笑竹', grade: 'P5', location: '武汉' }, { today: '2026-06-20' } ) const request = buildApplicationPolicyEstimateRequest(preview, { grade: 'P5', location: '武汉' }) assert.equal(request.canCalculate, true) assert.deepEqual(request.payload, { days: 4, location: '上海', grade: 'P5', transport_mode: null, origin_location: '武汉', travel_date: '2026-02-20' }) const estimatedPreview = applyApplicationPolicyEstimateResult(preview, { days: 4, location: '上海', matched_city: '上海', grade: 'P5', hotel_rate: 450, hotel_amount: 1800, total_allowance_rate: 100, allowance_amount: 400, transport_mode: '火车', transport_origin: '武汉', transport_destination: '上海', transport_estimated_amount: 720, total_amount: 2200, rule_name: '公司差旅费报销规则', rule_version: 'v1.0.0' }, { grade: 'P5', location: '武汉' }) assert.equal(estimatedPreview.fields.transportMode, '') assert.equal(estimatedPreview.missingFields.includes('出行方式'), true) assert.equal(estimatedPreview.fields.lodgingDailyCap, '450元/天') assert.equal(estimatedPreview.fields.subsidyDailyCap, '100元/天') assert.equal(estimatedPreview.fields.transportPolicy, '选择火车、飞机或轮船后自动预估交通费用') assert.equal(estimatedPreview.fields.policyEstimate, '交通待补充 + 住宿 1,800元 + 补贴 400元 = 2,200元(4天,不含交通)') assert.equal(estimatedPreview.fields.amount, '2,200元(不含交通)') })