feat(ai): add expense application feedback ledger
This commit is contained in:
@@ -1916,6 +1916,14 @@ test('application preview editor recalculates days and subsidy after date range
|
||||
assert.equal(message.applicationPreview.fields.lodgingDailyCap, '450\u5143/\u5929')
|
||||
assert.equal(message.applicationPreview.fields.subsidyDailyCap, '100\u5143/\u5929')
|
||||
assert.match(message.applicationPreview.fields.policyEstimate, /\u8865\u8d34 400\u5143/)
|
||||
assert.deepEqual(message.applicationPreview.aiDecisionFeedback.changedFields, [
|
||||
{ fieldKey: 'days', suggestedValue: '1\u5929', finalValue: '4\u5929' },
|
||||
{
|
||||
fieldKey: 'time',
|
||||
suggestedValue: '2026-05-25',
|
||||
finalValue: '2026-02-20 \u81f3 2026-02-23'
|
||||
}
|
||||
])
|
||||
})
|
||||
|
||||
test('application preview editor can edit return date from table row', async () => {
|
||||
@@ -1981,6 +1989,14 @@ test('application preview editor can edit return date from table row', async ()
|
||||
})
|
||||
assert.equal(message.applicationPreview.fields.time, '2026-02-20 \u81f3 2026-02-24')
|
||||
assert.equal(message.applicationPreview.fields.days, '5\u5929')
|
||||
assert.deepEqual(message.applicationPreview.aiDecisionFeedback.changedFields, [
|
||||
{ fieldKey: 'days', suggestedValue: '4\u5929', finalValue: '5\u5929' },
|
||||
{
|
||||
fieldKey: 'time',
|
||||
suggestedValue: '2026-02-20 \u81f3 2026-02-23',
|
||||
finalValue: '2026-02-20 \u81f3 2026-02-24'
|
||||
}
|
||||
])
|
||||
})
|
||||
|
||||
test('application preview editor can edit return date from inline table input', async () => {
|
||||
@@ -2185,3 +2201,210 @@ test('application preview editor estimates after shorthand return date input', a
|
||||
assert.equal(message.applicationPreview.fields.amount, '1,650\u5143\uff08\u4e0d\u542b\u4ea4\u901a\uff09')
|
||||
assert.match(message.applicationPreview.fields.policyEstimate, /\u4ea4\u901a\u5f85\u8865\u5145/)
|
||||
})
|
||||
|
||||
test('application preview editor ignores stale out-of-order estimate responses', async () => {
|
||||
const message = {
|
||||
id: 'application-preview-stale-estimate-message',
|
||||
applicationPreview: normalizeApplicationPreview({
|
||||
fields: {
|
||||
applicationType: '差旅费用申请',
|
||||
time: '2026-07-20 至 2026-07-21',
|
||||
location: '上海',
|
||||
reason: '客户现场实施',
|
||||
days: '2天',
|
||||
transportMode: '火车',
|
||||
grade: 'P5'
|
||||
}
|
||||
}),
|
||||
text: ''
|
||||
}
|
||||
const pendingEstimates = []
|
||||
const editor = useApplicationPreviewEditor({
|
||||
persistSessionState: () => {},
|
||||
toast: () => {},
|
||||
currentUser: ref({ grade: 'P5' }),
|
||||
calculateTravelReimbursement: (payload) => new Promise((resolve) => {
|
||||
pendingEstimates.push({ payload, resolve })
|
||||
})
|
||||
})
|
||||
|
||||
editor.openApplicationPreviewEditor(message, 'location', '上海')
|
||||
editor.applicationPreviewEditor.value.draftValue = '北京'
|
||||
const firstCommit = editor.commitApplicationPreviewEditor(message)
|
||||
|
||||
editor.openApplicationPreviewEditor(message, 'location', '北京')
|
||||
editor.applicationPreviewEditor.value.draftValue = '广州'
|
||||
const secondCommit = editor.commitApplicationPreviewEditor(message)
|
||||
|
||||
assert.equal(pendingEstimates.length, 2)
|
||||
pendingEstimates[1].resolve({
|
||||
days: 2,
|
||||
location: '广州',
|
||||
matched_city: '广州',
|
||||
grade: 'P5',
|
||||
hotel_rate: 600,
|
||||
hotel_amount: 1200,
|
||||
total_allowance_rate: 100,
|
||||
allowance_amount: 200,
|
||||
total_amount: 1400,
|
||||
rule_name: '第二次估算规则',
|
||||
rule_version: 'v2'
|
||||
})
|
||||
await secondCommit
|
||||
pendingEstimates[0].resolve({
|
||||
days: 2,
|
||||
location: '北京',
|
||||
matched_city: '北京',
|
||||
grade: 'P5',
|
||||
hotel_rate: 300,
|
||||
hotel_amount: 600,
|
||||
total_allowance_rate: 80,
|
||||
allowance_amount: 160,
|
||||
total_amount: 760,
|
||||
rule_name: '过期估算规则',
|
||||
rule_version: 'v1'
|
||||
})
|
||||
await firstCommit
|
||||
|
||||
assert.equal(message.applicationPreview.fields.location, '广州')
|
||||
assert.equal(message.applicationPreview.fields.ruleName, '第二次估算规则')
|
||||
assert.deepEqual(message.applicationPreview.aiDecisionFeedback.changedFields, [
|
||||
{ fieldKey: 'location', suggestedValue: '上海', finalValue: '广州' }
|
||||
])
|
||||
})
|
||||
|
||||
test('application type edit starts a fresh estimate instead of leaving pending state', async () => {
|
||||
const message = {
|
||||
id: 'application-preview-type-estimate-message',
|
||||
applicationPreview: normalizeApplicationPreview({
|
||||
fields: {
|
||||
applicationType: '差旅费用申请',
|
||||
time: '2026-07-20 至 2026-07-21',
|
||||
location: '上海',
|
||||
reason: '客户现场实施',
|
||||
days: '2天',
|
||||
transportMode: '火车',
|
||||
grade: 'P5'
|
||||
}
|
||||
}),
|
||||
text: ''
|
||||
}
|
||||
const pendingEstimates = []
|
||||
const editor = useApplicationPreviewEditor({
|
||||
persistSessionState: () => {},
|
||||
toast: () => {},
|
||||
currentUser: ref({ grade: 'P5' }),
|
||||
calculateTravelReimbursement: (payload) => new Promise((resolve) => {
|
||||
pendingEstimates.push({ payload, resolve })
|
||||
})
|
||||
})
|
||||
|
||||
editor.openApplicationPreviewEditor(message, 'location', '上海')
|
||||
editor.applicationPreviewEditor.value.draftValue = '北京'
|
||||
const firstCommit = editor.commitApplicationPreviewEditor(message)
|
||||
|
||||
editor.openApplicationPreviewEditor(message, 'applicationType', '差旅费用申请')
|
||||
editor.applicationPreviewEditor.value.draftValue = '出差费用申请'
|
||||
const secondCommit = editor.commitApplicationPreviewEditor(message)
|
||||
|
||||
assert.equal(pendingEstimates.length, 2)
|
||||
pendingEstimates[1].resolve({
|
||||
days: 2,
|
||||
location: '北京',
|
||||
matched_city: '北京',
|
||||
grade: 'P5',
|
||||
hotel_rate: 600,
|
||||
hotel_amount: 1200,
|
||||
total_allowance_rate: 100,
|
||||
allowance_amount: 200,
|
||||
total_amount: 1400,
|
||||
rule_name: '申请类型更新规则',
|
||||
rule_version: 'v2'
|
||||
})
|
||||
await secondCommit
|
||||
pendingEstimates[0].resolve({
|
||||
days: 2,
|
||||
location: '北京',
|
||||
matched_city: '北京',
|
||||
grade: 'P5',
|
||||
hotel_rate: 300,
|
||||
hotel_amount: 600,
|
||||
total_allowance_rate: 80,
|
||||
allowance_amount: 160,
|
||||
total_amount: 760,
|
||||
rule_name: '过期申请类型规则',
|
||||
rule_version: 'v1'
|
||||
})
|
||||
await firstCommit
|
||||
|
||||
assert.equal(message.applicationPreview.fields.applicationType, '出差费用申请')
|
||||
assert.equal(message.applicationPreview.fields.ruleName, '申请类型更新规则')
|
||||
assert.equal(message.applicationPreview.policyEstimateStatus, 'completed')
|
||||
assert.doesNotMatch(message.applicationPreview.fields.policyEstimate, /正在/)
|
||||
assert.deepEqual(message.applicationPreview.aiDecisionFeedback.changedFields, [
|
||||
{
|
||||
fieldKey: 'applicationType',
|
||||
suggestedValue: '差旅费用申请',
|
||||
finalValue: '出差费用申请'
|
||||
},
|
||||
{ fieldKey: 'location', suggestedValue: '上海', finalValue: '北京' }
|
||||
])
|
||||
})
|
||||
|
||||
test('application preview editor merges estimate without dropping later edits', async () => {
|
||||
const message = {
|
||||
id: 'application-preview-merge-estimate-message',
|
||||
applicationPreview: normalizeApplicationPreview({
|
||||
fields: {
|
||||
applicationType: '差旅费用申请',
|
||||
time: '2026-07-20 至 2026-07-21',
|
||||
location: '上海',
|
||||
reason: '客户拜访',
|
||||
days: '2天',
|
||||
transportMode: '火车',
|
||||
grade: 'P5'
|
||||
}
|
||||
}),
|
||||
text: ''
|
||||
}
|
||||
let resolveEstimate
|
||||
const editor = useApplicationPreviewEditor({
|
||||
persistSessionState: () => {},
|
||||
toast: () => {},
|
||||
currentUser: ref({ grade: 'P5' }),
|
||||
calculateTravelReimbursement: () => new Promise((resolve) => {
|
||||
resolveEstimate = resolve
|
||||
})
|
||||
})
|
||||
|
||||
editor.openApplicationPreviewEditor(message, 'location', '上海')
|
||||
editor.applicationPreviewEditor.value.draftValue = '北京'
|
||||
const estimateCommit = editor.commitApplicationPreviewEditor(message)
|
||||
|
||||
editor.openApplicationPreviewEditor(message, 'reason', '客户拜访')
|
||||
editor.applicationPreviewEditor.value.draftValue = '客户现场实施'
|
||||
await editor.commitApplicationPreviewEditor(message)
|
||||
|
||||
resolveEstimate({
|
||||
days: 2,
|
||||
location: '北京',
|
||||
matched_city: '北京',
|
||||
grade: 'P5',
|
||||
hotel_rate: 500,
|
||||
hotel_amount: 1000,
|
||||
total_allowance_rate: 100,
|
||||
allowance_amount: 200,
|
||||
total_amount: 1200,
|
||||
rule_name: '并发合并规则',
|
||||
rule_version: 'v1'
|
||||
})
|
||||
await estimateCommit
|
||||
|
||||
assert.equal(message.applicationPreview.fields.location, '北京')
|
||||
assert.equal(message.applicationPreview.fields.reason, '客户现场实施')
|
||||
assert.equal(message.applicationPreview.fields.ruleName, '并发合并规则')
|
||||
assert.deepEqual(message.applicationPreview.aiDecisionFeedback.changedFields, [
|
||||
{ fieldKey: 'location', suggestedValue: '上海', finalValue: '北京' },
|
||||
{ fieldKey: 'reason', suggestedValue: '客户拜访', finalValue: '客户现场实施' }
|
||||
])
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user