feat: 同步报销流程与工作台改动
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
const CREATE_APPLICATION = '\u521b\u5efa\u7533\u8bf7'
|
||||
const DIRECT_MANAGER_APPROVAL = '\u76f4\u5c5e\u9886\u5bfc\u5ba1\u6279'
|
||||
const BUDGET_MANAGER_APPROVAL = '\u9884\u7b97\u7ba1\u7406\u8005\u5ba1\u6279'
|
||||
const FINANCE_APPROVAL = '\u8d22\u52a1\u5ba1\u6279'
|
||||
const APPROVAL_COMPLETED = '\u5ba1\u6279\u5b8c\u6210'
|
||||
const APPLICATION_LINK_STATUS = '\u5173\u8054\u5355\u636e\u72b6\u6001'
|
||||
const APPLICATION_ARCHIVE = '\u7533\u8bf7\u5f52\u6863'
|
||||
@@ -21,6 +22,7 @@ const ARCHIVED = '\u5df2\u5f52\u6863'
|
||||
const WAIT_LEADER_LI_APPROVAL = '\u7b49\u5f85 Leader Li \u6279\u590d'
|
||||
const WAIT_BUDGET_ZHAO_APPROVAL = '\u7b49\u5f85 \u8d75\u9884\u7b97 \u6279\u590d'
|
||||
const WAIT_BUDGET_P8_EXECUTIVE_APPROVAL = '\u7b49\u5f85 P8 Executive \u6279\u590d'
|
||||
const WAIT_FINANCE_FIONA_APPROVAL = '\u7b49\u5f85 Fiona Finance \u6279\u590d'
|
||||
const LEADER_RETURNED_STATUS = '\u9886\u5bfc\u5df2\u9000\u56de\uff0c\u5f85\u91cd\u65b0\u63d0\u4ea4'
|
||||
|
||||
test('claim mapper exposes employee identifier for reviewer risk profile lookup', () => {
|
||||
@@ -158,7 +160,7 @@ test('application claims are mapped as application documents', () => {
|
||||
assert.equal(request.expenseTableSummary, '预计金额已随申请提交')
|
||||
assert.deepEqual(
|
||||
request.progressSteps.map((step) => step.label),
|
||||
[CREATE_APPLICATION, WAIT_LEADER_LI_APPROVAL, APPROVAL_COMPLETED, APPLICATION_LINK_STATUS, ARCHIVED]
|
||||
[CREATE_APPLICATION, WAIT_LEADER_LI_APPROVAL, APPLICATION_LINK_STATUS, ARCHIVED]
|
||||
)
|
||||
assert.equal(request.progressSteps.some((step) => step.label === 'AI预审'), false)
|
||||
assert.equal(request.progressSteps.some((step) => step.label === '财务审批'), false)
|
||||
@@ -252,7 +254,7 @@ test('application claims wait for department P8 budget monitor after leader appr
|
||||
|
||||
assert.deepEqual(
|
||||
request.progressSteps.map((step) => step.label),
|
||||
[CREATE_APPLICATION, DIRECT_MANAGER_APPROVAL, WAIT_BUDGET_ZHAO_APPROVAL, APPROVAL_COMPLETED, APPLICATION_LINK_STATUS, ARCHIVED]
|
||||
[CREATE_APPLICATION, DIRECT_MANAGER_APPROVAL, WAIT_BUDGET_ZHAO_APPROVAL, APPLICATION_LINK_STATUS, ARCHIVED]
|
||||
)
|
||||
assert.equal(request.progressSteps.find((step) => step.label === WAIT_BUDGET_ZHAO_APPROVAL)?.current, true)
|
||||
assert.equal(request.progressSteps.find((step) => step.label === DIRECT_MANAGER_APPROVAL)?.time, 'Leader Li通过')
|
||||
@@ -295,7 +297,7 @@ test('application budget wait label uses claim-level budget approver snapshot',
|
||||
assert.equal(request.budgetApproverName, 'P8 Executive')
|
||||
assert.deepEqual(
|
||||
request.progressSteps.map((step) => step.label),
|
||||
[CREATE_APPLICATION, DIRECT_MANAGER_APPROVAL, WAIT_BUDGET_P8_EXECUTIVE_APPROVAL, APPROVAL_COMPLETED, APPLICATION_LINK_STATUS, ARCHIVED]
|
||||
[CREATE_APPLICATION, DIRECT_MANAGER_APPROVAL, WAIT_BUDGET_P8_EXECUTIVE_APPROVAL, APPLICATION_LINK_STATUS, ARCHIVED]
|
||||
)
|
||||
assert.equal(request.progressSteps.find((step) => step.label === WAIT_BUDGET_P8_EXECUTIVE_APPROVAL)?.current, true)
|
||||
})
|
||||
@@ -391,7 +393,7 @@ test('approved application claims complete after budget approval', () => {
|
||||
assert.equal(request.workflowNode, APPLICATION_LINK_STATUS)
|
||||
assert.deepEqual(
|
||||
request.progressSteps.map((step) => step.label),
|
||||
[CREATE_APPLICATION, DIRECT_MANAGER_APPROVAL, BUDGET_MANAGER_APPROVAL, APPROVAL_COMPLETED, APPLICATION_LINK_STATUS, ARCHIVED]
|
||||
[CREATE_APPLICATION, DIRECT_MANAGER_APPROVAL, BUDGET_MANAGER_APPROVAL, APPLICATION_LINK_STATUS, ARCHIVED]
|
||||
)
|
||||
assert.equal(request.progressSteps.find((step) => step.label === APPLICATION_LINK_STATUS)?.current, true)
|
||||
assert.equal(request.progressSteps.find((step) => step.label === APPLICATION_LINK_STATUS)?.time, '未关联')
|
||||
@@ -417,15 +419,40 @@ test('application claims hide budget step when leader approval also covers budge
|
||||
created_at: '2026-05-25T01:30:00.000Z',
|
||||
updated_at: '2026-05-25T03:00:00.000Z',
|
||||
status: 'approved',
|
||||
approval_stage: APPROVAL_COMPLETED,
|
||||
approval_stage: APPLICATION_LINK_STATUS,
|
||||
risk_flags_json: [
|
||||
{
|
||||
source: 'approval_routing',
|
||||
event_type: 'expense_application_route_decision',
|
||||
requires_budget_review: true,
|
||||
route: 'budget_manager',
|
||||
budget_result: {
|
||||
metrics: {
|
||||
after_usage_rate: '99.27',
|
||||
claim_amount_ratio: '1.27',
|
||||
over_budget_amount: '0.00'
|
||||
}
|
||||
},
|
||||
created_at: '2026-05-25T03:00:00.000Z'
|
||||
},
|
||||
{
|
||||
source: 'manual_approval',
|
||||
event_type: 'expense_application_approval',
|
||||
operator: '李预算经理',
|
||||
previous_approval_stage: DIRECT_MANAGER_APPROVAL,
|
||||
next_approval_stage: APPROVAL_COMPLETED,
|
||||
next_approval_stage: APPLICATION_LINK_STATUS,
|
||||
budget_approval_merged: true,
|
||||
route_decision: {
|
||||
requires_budget_review: true,
|
||||
route: 'budget_manager',
|
||||
budget_result: {
|
||||
metrics: {
|
||||
after_usage_rate: '99.27',
|
||||
claim_amount_ratio: '1.27',
|
||||
over_budget_amount: '0.00'
|
||||
}
|
||||
}
|
||||
},
|
||||
created_at: '2026-05-25T03:00:00.000Z'
|
||||
}
|
||||
],
|
||||
@@ -434,7 +461,7 @@ test('application claims hide budget step when leader approval also covers budge
|
||||
|
||||
assert.deepEqual(
|
||||
request.progressSteps.map((step) => step.label),
|
||||
[CREATE_APPLICATION, DIRECT_MANAGER_APPROVAL, APPROVAL_COMPLETED, APPLICATION_LINK_STATUS, ARCHIVED]
|
||||
[CREATE_APPLICATION, DIRECT_MANAGER_APPROVAL, APPLICATION_LINK_STATUS, ARCHIVED]
|
||||
)
|
||||
assert.equal(request.progressSteps.find((step) => step.label === APPLICATION_LINK_STATUS)?.current, true)
|
||||
assert.equal(request.progressSteps.find((step) => step.label === ARCHIVED)?.done, false)
|
||||
@@ -486,7 +513,7 @@ test('approved application claims hide budget step when dynamic route skipped bu
|
||||
|
||||
assert.deepEqual(
|
||||
request.progressSteps.map((step) => step.label),
|
||||
[CREATE_APPLICATION, DIRECT_MANAGER_APPROVAL, APPROVAL_COMPLETED, APPLICATION_LINK_STATUS, ARCHIVED]
|
||||
[CREATE_APPLICATION, DIRECT_MANAGER_APPROVAL, APPLICATION_LINK_STATUS, ARCHIVED]
|
||||
)
|
||||
assert.equal(request.progressSteps.find((step) => step.label === APPLICATION_LINK_STATUS)?.current, true)
|
||||
assert.equal(request.progressSteps.find((step) => step.label === ARCHIVED)?.done, false)
|
||||
@@ -494,6 +521,69 @@ test('approved application claims hide budget step when dynamic route skipped bu
|
||||
assert.equal(request.progressSteps.find((step) => step.label === DIRECT_MANAGER_APPROVAL)?.time, 'Leader Li通过')
|
||||
})
|
||||
|
||||
test('approved application claims hide stale budget route below 90 percent threshold', () => {
|
||||
const request = mapExpenseClaimToRequest({
|
||||
id: 'claim-application-stale-budget-route',
|
||||
claim_no: 'APP-20260525-STALE-BUDGET',
|
||||
employee_name: '张三',
|
||||
department_name: '交付部',
|
||||
manager_name: 'Leader Li',
|
||||
expense_type: 'travel_application',
|
||||
reason: 'Project onsite support',
|
||||
location: 'Shanghai',
|
||||
amount: 8500,
|
||||
invoice_count: 0,
|
||||
occurred_at: '2026-05-25T00:00:00.000Z',
|
||||
submitted_at: '2026-05-25T02:00:00.000Z',
|
||||
created_at: '2026-05-25T01:30:00.000Z',
|
||||
updated_at: '2026-05-25T03:00:00.000Z',
|
||||
status: 'approved',
|
||||
approval_stage: APPROVAL_COMPLETED,
|
||||
risk_flags_json: [
|
||||
{
|
||||
source: 'approval_routing',
|
||||
event_type: 'expense_application_route_decision',
|
||||
requires_budget_review: true,
|
||||
route: 'budget_manager',
|
||||
budget_result: {
|
||||
metrics: {
|
||||
after_usage_rate: '85.00',
|
||||
claim_amount_ratio: '85.00',
|
||||
over_budget_amount: '0.00'
|
||||
}
|
||||
},
|
||||
created_at: '2026-05-25T03:00:00.000Z'
|
||||
},
|
||||
{
|
||||
source: 'manual_approval',
|
||||
event_type: 'expense_application_approval',
|
||||
operator: 'Leader Li',
|
||||
previous_approval_stage: DIRECT_MANAGER_APPROVAL,
|
||||
next_approval_stage: BUDGET_MANAGER_APPROVAL,
|
||||
route_decision: {
|
||||
requires_budget_review: true,
|
||||
route: 'budget_manager',
|
||||
budget_result: {
|
||||
metrics: {
|
||||
after_usage_rate: '85.00',
|
||||
claim_amount_ratio: '85.00',
|
||||
over_budget_amount: '0.00'
|
||||
}
|
||||
}
|
||||
},
|
||||
created_at: '2026-05-25T03:00:00.000Z'
|
||||
}
|
||||
],
|
||||
items: []
|
||||
})
|
||||
|
||||
assert.deepEqual(
|
||||
request.progressSteps.map((step) => step.label),
|
||||
[CREATE_APPLICATION, DIRECT_MANAGER_APPROVAL, APPLICATION_LINK_STATUS, ARCHIVED]
|
||||
)
|
||||
assert.equal(request.progressSteps.some((step) => step.label === BUDGET_MANAGER_APPROVAL), false)
|
||||
})
|
||||
|
||||
test('approved application claims show linked reimbursement status before archive', () => {
|
||||
const request = mapExpenseClaimToRequest({
|
||||
id: 'claim-application-linked-draft',
|
||||
@@ -566,7 +656,7 @@ test('application claims are archived only after linked reimbursement is paid',
|
||||
assert.equal(request.workflowNode, APPLICATION_ARCHIVE)
|
||||
assert.deepEqual(
|
||||
request.progressSteps.map((step) => step.label),
|
||||
[CREATE_APPLICATION, DIRECT_MANAGER_APPROVAL, APPROVAL_COMPLETED, APPLICATION_LINK_STATUS, ARCHIVED]
|
||||
[CREATE_APPLICATION, DIRECT_MANAGER_APPROVAL, APPLICATION_LINK_STATUS, ARCHIVED]
|
||||
)
|
||||
assert.equal(request.progressSteps.every((step) => step.done), true)
|
||||
assert.equal(request.secondaryStatusValue, '已归档')
|
||||
@@ -582,6 +672,8 @@ test('progress steps show approval operator time and current stay duration', ()
|
||||
claim_no: 'EXP-202605-001',
|
||||
employee_name: '张三',
|
||||
department_name: '市场部',
|
||||
finance_owner_name: 'Wang Finance Group',
|
||||
finance_approver_name: 'Fiona Finance',
|
||||
expense_type: 'transport',
|
||||
reason: '交通报销',
|
||||
location: '上海',
|
||||
@@ -592,21 +684,21 @@ test('progress steps show approval operator time and current stay duration', ()
|
||||
created_at: '2026-05-20T01:30:00.000Z',
|
||||
updated_at: '2026-05-20T03:30:00.000Z',
|
||||
status: 'submitted',
|
||||
approval_stage: '财务审批',
|
||||
approval_stage: FINANCE_APPROVAL,
|
||||
risk_flags_json: [
|
||||
{
|
||||
source: 'manual_approval',
|
||||
operator: '李经理',
|
||||
previous_approval_stage: '直属领导审批',
|
||||
next_approval_stage: '财务审批',
|
||||
previous_approval_stage: DIRECT_MANAGER_APPROVAL,
|
||||
next_approval_stage: FINANCE_APPROVAL,
|
||||
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 leaderStep = request.progressSteps.find((step) => step.label === DIRECT_MANAGER_APPROVAL)
|
||||
const financeStep = request.progressSteps.find((step) => step.rawLabel === FINANCE_APPROVAL)
|
||||
const firstStep = request.progressSteps[0]
|
||||
|
||||
assert.equal(request.riskSummary, '无')
|
||||
@@ -615,6 +707,10 @@ test('progress steps show approval operator time and current stay duration', ()
|
||||
assert.match(leaderStep.detail, /2026-05-20/)
|
||||
assert.match(leaderStep.title, /李经理审批通过/)
|
||||
assert.equal(request.progressSteps.some((step) => step.label === 'AI预审'), false)
|
||||
assert.equal(request.financeOwnerName, 'Wang Finance Group')
|
||||
assert.equal(request.financeApproverName, 'Fiona Finance')
|
||||
assert.equal(financeStep.label, WAIT_FINANCE_FIONA_APPROVAL)
|
||||
assert.equal(financeStep.rawLabel, FINANCE_APPROVAL)
|
||||
assert.equal(financeStep.current, true)
|
||||
assert.equal(financeStep.time, '停留 1小时30分钟')
|
||||
} finally {
|
||||
@@ -1124,6 +1220,7 @@ test('current direct manager step shows how long the claim has stayed there', ()
|
||||
claim_no: 'EXP-202605-002',
|
||||
employee_name: '王五',
|
||||
department_name: '市场部',
|
||||
manager_name: '李经理',
|
||||
expense_type: 'office',
|
||||
reason: '办公用品',
|
||||
location: '上海',
|
||||
@@ -1139,11 +1236,13 @@ test('current direct manager step shows how long the claim has stayed there', ()
|
||||
items: []
|
||||
})
|
||||
|
||||
const leaderStep = request.progressSteps.find((step) => step.label === '直属领导审批')
|
||||
const leaderStep = request.progressSteps.find((step) => step.rawLabel === '直属领导审批')
|
||||
const submitStep = request.progressSteps.find((step) => step.label === '待提交')
|
||||
|
||||
assert.equal(submitStep.time, '王五提交')
|
||||
assert.match(submitStep.detail, /2026-05-20/)
|
||||
assert.equal(leaderStep.label, '等待 李经理 批复')
|
||||
assert.equal(leaderStep.rawLabel, '直属领导审批')
|
||||
assert.equal(leaderStep.current, true)
|
||||
assert.equal(leaderStep.time, '停留 3小时15分钟')
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user