2026-05-20 21:00:47 +08:00
|
|
|
import assert from 'node:assert/strict'
|
|
|
|
|
import test from 'node:test'
|
|
|
|
|
|
|
|
|
|
import { mapExpenseClaimToRequest } from '../src/composables/useRequests.js'
|
|
|
|
|
|
|
|
|
|
test('progress steps show approval operator time and current stay duration', () => {
|
|
|
|
|
const originalNow = Date.now
|
|
|
|
|
Date.now = () => new Date('2026-05-20T05:00:00.000Z').getTime()
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const request = mapExpenseClaimToRequest({
|
|
|
|
|
id: 'claim-1',
|
|
|
|
|
claim_no: 'EXP-202605-001',
|
|
|
|
|
employee_name: '张三',
|
|
|
|
|
department_name: '市场部',
|
|
|
|
|
expense_type: 'transport',
|
|
|
|
|
reason: '交通报销',
|
|
|
|
|
location: '上海',
|
|
|
|
|
amount: 88,
|
|
|
|
|
invoice_count: 1,
|
|
|
|
|
occurred_at: '2026-05-20T01:00:00.000Z',
|
|
|
|
|
submitted_at: '2026-05-20T02:00:00.000Z',
|
|
|
|
|
created_at: '2026-05-20T01:30:00.000Z',
|
|
|
|
|
updated_at: '2026-05-20T03:30:00.000Z',
|
|
|
|
|
status: 'submitted',
|
|
|
|
|
approval_stage: '财务审批',
|
|
|
|
|
risk_flags_json: [
|
|
|
|
|
{
|
|
|
|
|
source: 'manual_approval',
|
|
|
|
|
operator: '李经理',
|
|
|
|
|
previous_approval_stage: '直属领导审批',
|
|
|
|
|
next_approval_stage: '财务审批',
|
|
|
|
|
created_at: '2026-05-20T03:30:00.000Z'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
items: []
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const leaderStep = request.progressSteps.find((step) => step.label === '直属领导审批')
|
|
|
|
|
const financeStep = request.progressSteps.find((step) => step.label === '财务审批')
|
|
|
|
|
const aiStep = request.progressSteps.find((step) => step.label === 'AI预审')
|
2026-05-21 09:28:33 +08:00
|
|
|
const firstStep = request.progressSteps[0]
|
2026-05-20 21:00:47 +08:00
|
|
|
|
2026-05-21 09:28:33 +08:00
|
|
|
assert.equal(firstStep.label, '创建单据')
|
2026-05-20 21:00:47 +08:00
|
|
|
assert.equal(leaderStep.time, '李经理通过')
|
|
|
|
|
assert.match(leaderStep.detail, /2026-05-20/)
|
|
|
|
|
assert.match(leaderStep.title, /李经理审批通过/)
|
|
|
|
|
assert.equal(aiStep.time, 'AI预审通过')
|
|
|
|
|
assert.match(aiStep.detail, /2026-05-20/)
|
|
|
|
|
assert.equal(financeStep.current, true)
|
|
|
|
|
assert.equal(financeStep.time, '停留 1小时30分钟')
|
|
|
|
|
} finally {
|
|
|
|
|
Date.now = originalNow
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
2026-05-21 09:28:33 +08:00
|
|
|
test('progress steps do not expose approver email when manager name is available', () => {
|
|
|
|
|
const originalNow = Date.now
|
|
|
|
|
Date.now = () => new Date('2026-05-20T05:00:00.000Z').getTime()
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const request = mapExpenseClaimToRequest({
|
|
|
|
|
id: 'claim-email-operator',
|
|
|
|
|
claim_no: 'EXP-202605-003',
|
|
|
|
|
employee_name: '张三',
|
|
|
|
|
department_name: '市场部',
|
|
|
|
|
manager_name: '李经理',
|
|
|
|
|
expense_type: 'transport',
|
|
|
|
|
reason: '交通报销',
|
|
|
|
|
location: '上海',
|
|
|
|
|
amount: 88,
|
|
|
|
|
invoice_count: 1,
|
|
|
|
|
occurred_at: '2026-05-20T01:00:00.000Z',
|
|
|
|
|
submitted_at: '2026-05-20T02:00:00.000Z',
|
|
|
|
|
created_at: '2026-05-20T01:30:00.000Z',
|
|
|
|
|
updated_at: '2026-05-20T03:30:00.000Z',
|
|
|
|
|
status: 'submitted',
|
|
|
|
|
approval_stage: '财务审批',
|
|
|
|
|
risk_flags_json: [
|
|
|
|
|
{
|
|
|
|
|
source: 'manual_approval',
|
|
|
|
|
operator: 'manager@example.com',
|
|
|
|
|
operator_username: 'manager@example.com',
|
|
|
|
|
previous_approval_stage: '直属领导审批',
|
|
|
|
|
next_approval_stage: '财务审批',
|
|
|
|
|
created_at: '2026-05-20T03:30:00.000Z'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
items: []
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const leaderStep = request.progressSteps.find((step) => step.label === '直属领导审批')
|
|
|
|
|
|
|
|
|
|
assert.equal(leaderStep.time, '李经理通过')
|
|
|
|
|
assert.ok(!leaderStep.title.includes('manager@example.com'))
|
|
|
|
|
} finally {
|
|
|
|
|
Date.now = originalNow
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('completed finance approval marks finance and archive progress steps', () => {
|
|
|
|
|
const request = mapExpenseClaimToRequest({
|
|
|
|
|
id: 'claim-finance-completed',
|
|
|
|
|
claim_no: 'EXP-202605-004',
|
|
|
|
|
employee_name: '张三',
|
|
|
|
|
department_name: '市场部',
|
|
|
|
|
expense_type: 'transport',
|
|
|
|
|
reason: '交通报销',
|
|
|
|
|
location: '上海',
|
|
|
|
|
amount: 88,
|
|
|
|
|
invoice_count: 1,
|
|
|
|
|
occurred_at: '2026-05-20T01:00:00.000Z',
|
|
|
|
|
submitted_at: '2026-05-20T02:00:00.000Z',
|
|
|
|
|
created_at: '2026-05-20T01:30:00.000Z',
|
|
|
|
|
updated_at: '2026-05-20T04:00:00.000Z',
|
|
|
|
|
status: 'approved',
|
|
|
|
|
approval_stage: '归档入账',
|
|
|
|
|
risk_flags_json: [
|
|
|
|
|
{
|
|
|
|
|
source: 'manual_approval',
|
|
|
|
|
operator: '李经理',
|
|
|
|
|
previous_approval_stage: '直属领导审批',
|
|
|
|
|
next_approval_stage: '财务审批',
|
|
|
|
|
created_at: '2026-05-20T03:00:00.000Z'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
source: 'finance_approval',
|
|
|
|
|
operator: '财务复核',
|
|
|
|
|
previous_approval_stage: '财务审批',
|
|
|
|
|
next_approval_stage: '归档入账',
|
|
|
|
|
created_at: '2026-05-20T04:00:00.000Z'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
items: []
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const financeStep = request.progressSteps.find((step) => step.label === '财务审批')
|
|
|
|
|
const archiveStep = request.progressSteps.find((step) => step.label === '归档入账')
|
|
|
|
|
|
|
|
|
|
assert.equal(request.workflowNode, '归档入账')
|
|
|
|
|
assert.equal(financeStep.time, '财务复核通过')
|
|
|
|
|
assert.match(financeStep.detail, /2026-05-20/)
|
|
|
|
|
assert.equal(archiveStep.time, '归档入账')
|
|
|
|
|
assert.equal(archiveStep.done, true)
|
|
|
|
|
})
|
|
|
|
|
|
2026-05-20 21:00:47 +08:00
|
|
|
test('current direct manager step shows how long the claim has stayed there', () => {
|
|
|
|
|
const originalNow = Date.now
|
|
|
|
|
Date.now = () => new Date('2026-05-20T05:15:00.000Z').getTime()
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const request = mapExpenseClaimToRequest({
|
|
|
|
|
id: 'claim-2',
|
|
|
|
|
claim_no: 'EXP-202605-002',
|
|
|
|
|
employee_name: '王五',
|
|
|
|
|
department_name: '市场部',
|
|
|
|
|
expense_type: 'office',
|
|
|
|
|
reason: '办公用品',
|
|
|
|
|
location: '上海',
|
|
|
|
|
amount: 128,
|
|
|
|
|
invoice_count: 1,
|
|
|
|
|
occurred_at: '2026-05-20T01:00:00.000Z',
|
|
|
|
|
submitted_at: '2026-05-20T02:00:00.000Z',
|
|
|
|
|
created_at: '2026-05-20T01:30:00.000Z',
|
|
|
|
|
updated_at: '2026-05-20T02:00:00.000Z',
|
|
|
|
|
status: 'submitted',
|
|
|
|
|
approval_stage: '直属领导审批',
|
|
|
|
|
risk_flags_json: [],
|
|
|
|
|
items: []
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const leaderStep = request.progressSteps.find((step) => step.label === '直属领导审批')
|
|
|
|
|
const submitStep = request.progressSteps.find((step) => step.label === '待提交')
|
|
|
|
|
|
|
|
|
|
assert.equal(submitStep.time, '王五提交')
|
|
|
|
|
assert.match(submitStep.detail, /2026-05-20/)
|
|
|
|
|
assert.equal(leaderStep.current, true)
|
|
|
|
|
assert.equal(leaderStep.time, '停留 3小时15分钟')
|
|
|
|
|
} finally {
|
|
|
|
|
Date.now = originalNow
|
|
|
|
|
}
|
|
|
|
|
})
|