feat(platform): close AI expense value loop
Add tenant-safe value, telemetry, connector, commercial, and production-readiness foundations.
This commit is contained in:
@@ -71,10 +71,10 @@ test('claim delete flow invalidates the matching financial assistant session', (
|
||||
fileURLToPath(new URL('../src/views/AppShellRouteView.vue', import.meta.url)),
|
||||
'utf8'
|
||||
)
|
||||
const createViewScript = readFileSync(
|
||||
fileURLToPath(new URL('../src/views/scripts/TravelReimbursementCreateView.js', import.meta.url)),
|
||||
'utf8'
|
||||
)
|
||||
const createViewScript = [
|
||||
'../src/views/scripts/TravelReimbursementCreateView.js',
|
||||
'../src/views/scripts/useTravelReimbursementCreateViewSessionCleanup.js'
|
||||
].map((path) => readFileSync(fileURLToPath(new URL(path, import.meta.url)), 'utf8')).join('\n')
|
||||
|
||||
assert.match(appShellScript, /clearAssistantSessionSnapshotForDraftClaim/)
|
||||
assert.match(appShellScript, /async function handleRequestDeleted\(payload = \{\}\)/)
|
||||
@@ -194,8 +194,12 @@ test('saving a draft keeps the financial assistant open for continued work', ()
|
||||
})
|
||||
|
||||
test('detail smart entry is scoped to the current claim instead of the latest conversation', () => {
|
||||
const detailViewScript = readFileSync(
|
||||
fileURLToPath(new URL('../src/views/scripts/TravelRequestDetailView.js', import.meta.url)),
|
||||
const detailExpenseEditorScript = readFileSync(
|
||||
fileURLToPath(new URL('../src/views/scripts/useTravelRequestDetailExpenseEditor.js', import.meta.url)),
|
||||
'utf8'
|
||||
)
|
||||
const smartEntryRecognitionScript = readFileSync(
|
||||
fileURLToPath(new URL('../src/views/scripts/travelRequestDetailSmartEntryRecognition.js', import.meta.url)),
|
||||
'utf8'
|
||||
)
|
||||
const appShellScript = readFileSync(
|
||||
@@ -206,13 +210,17 @@ test('detail smart entry is scoped to the current claim instead of the latest co
|
||||
fileURLToPath(new URL('../src/views/scripts/useTravelReimbursementSessionState.js', import.meta.url)),
|
||||
'utf8'
|
||||
)
|
||||
const submitComposerScript = readFileSync(
|
||||
fileURLToPath(new URL('../src/views/scripts/useTravelReimbursementSubmitComposer.js', import.meta.url)),
|
||||
'utf8'
|
||||
)
|
||||
const submitComposerScript = [
|
||||
'../src/views/scripts/useTravelReimbursementSubmitComposer.js',
|
||||
'../src/views/scripts/travelReimbursementSubmitApplicationPreview.js'
|
||||
].map((path) => readFileSync(fileURLToPath(new URL(path, import.meta.url)), 'utf8')).join('\n')
|
||||
|
||||
assert.match(detailViewScript, /restoreLatestConversation:\s*false/)
|
||||
assert.match(detailViewScript, /scope:\s*claimId[\s\S]*type:\s*'claim'[\s\S]*claimId/)
|
||||
assert.match(detailExpenseEditorScript, /if \(!request\.value\.claimId\) \{[\s\S]*当前草稿缺少 claimId/)
|
||||
assert.match(detailExpenseEditorScript, /startSmartEntryRecognitionTask\(\{[\s\S]*claimId:\s*request\.value\.claimId/)
|
||||
assert.match(detailExpenseEditorScript, /bindSmartEntryRecognitionTask\(request\.value\.claimId\)/)
|
||||
assert.match(smartEntryRecognitionScript, /const normalizedClaimId = normalizeSmartEntryClaimId\(claimId\)/)
|
||||
assert.match(smartEntryRecognitionScript, /smartEntryRecognitionTasks\.set\(normalizedClaimId, task\)/)
|
||||
assert.doesNotMatch(detailExpenseEditorScript, /restoreLatestConversation/)
|
||||
assert.match(appShellScript, /function isDetailClaimScopedPayload\(payload = \{\}\)/)
|
||||
assert.match(appShellScript, /if \(isDetailClaimScopedPayload\(payload\)\) \{[\s\S]*return null[\s\S]*\}/)
|
||||
assert.match(sessionStateScript, /const shouldPersistLocalSnapshot = props\.entrySource !== 'detail'/)
|
||||
|
||||
Reference in New Issue
Block a user