feat: 新增预算后端服务与差旅风险规则库
后端新增预算模型、端点和服务模块,支持预算 CRUD 和余额 查询,清理旧生成规则文件并替换为按严重等级分类的差旅风 险规则库,优化认证权限和报销单访问策略,新增财务规则目 录和演示数据构建脚本,前端预算中心增加对话框交互,完善 审计页面运行时模型和元数据展示,补充单元测试。
This commit is contained in:
@@ -5,8 +5,10 @@ import {
|
||||
canApproveLeaderExpenseClaims,
|
||||
canAccessAppView,
|
||||
canDeleteArchivedExpenseClaims,
|
||||
canEditBudgetCenter,
|
||||
canManageExpenseClaims,
|
||||
canReturnExpenseClaims
|
||||
canReturnExpenseClaims,
|
||||
canSwitchBudgetDepartments
|
||||
} from '../src/utils/accessControl.js'
|
||||
import { canProcessApprovalRequest } from '../src/utils/approvalInbox.js'
|
||||
|
||||
@@ -45,6 +47,25 @@ test('legacy reimbursement approval and archive centers are no longer accessible
|
||||
assert.equal(canAccessAppView(adminUser, 'documents'), true)
|
||||
})
|
||||
|
||||
test('budget center is visible to platform admin, budget monitor, and executive roles only', () => {
|
||||
assert.equal(canAccessAppView({ isAdmin: true, roleCodes: ['manager'] }, 'budget'), true)
|
||||
assert.equal(canAccessAppView({ username: 'admin', roleCodes: ['manager'] }, 'budget'), true)
|
||||
assert.equal(canAccessAppView({ roleCodes: ['budget_monitor'] }, 'budget'), true)
|
||||
assert.equal(canAccessAppView({ roleCodes: ['auditor'] }, 'budget'), true)
|
||||
assert.equal(canAccessAppView({ roleCodes: ['executive'] }, 'budget'), true)
|
||||
assert.equal(canAccessAppView({ roleCodes: ['finance'] }, 'budget'), false)
|
||||
assert.equal(canAccessAppView({ roleCodes: ['manager'] }, 'budget'), false)
|
||||
})
|
||||
|
||||
test('budget edit and department switching are limited to admin and senior finance', () => {
|
||||
assert.equal(canEditBudgetCenter({ username: 'admin', roleCodes: ['manager'] }), true)
|
||||
assert.equal(canSwitchBudgetDepartments({ username: 'admin', roleCodes: ['manager'] }), true)
|
||||
assert.equal(canEditBudgetCenter({ roleCodes: ['executive'] }), true)
|
||||
assert.equal(canSwitchBudgetDepartments({ roleCodes: ['executive'] }), true)
|
||||
assert.equal(canEditBudgetCenter({ roleCodes: ['budget_monitor'] }), false)
|
||||
assert.equal(canSwitchBudgetDepartments({ roleCodes: ['budget_monitor'] }), false)
|
||||
})
|
||||
|
||||
test('finance approval inbox only processes finance-stage requests', () => {
|
||||
const financeUser = { roleCodes: ['finance'], name: '财务' }
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
BUDGET_EXPENSE_TYPE_OPTIONS,
|
||||
BUDGET_ONTOLOGY_FIELDS,
|
||||
BUDGET_QUARTER_OPTIONS,
|
||||
BUDGET_VISIBLE_EXPENSE_TYPE_OPTIONS,
|
||||
BUDGET_YEAR_OPTIONS,
|
||||
buildBudgetOntologyContext
|
||||
} from '../src/utils/budgetOntology.js'
|
||||
@@ -44,7 +45,7 @@ test('budget ontology context maps dialog fields to ontology payload', () => {
|
||||
],
|
||||
rows: [
|
||||
{
|
||||
budgetSubject: '差旅费',
|
||||
budgetSubject: '差旅',
|
||||
budgetSubjectCode: 'travel',
|
||||
budgetAmount: '600,000.00',
|
||||
warningThreshold: '80%',
|
||||
@@ -63,7 +64,7 @@ test('budget ontology context maps dialog fields to ontology payload', () => {
|
||||
assert.equal(context.budget_header.cost_center, 'CC-4100')
|
||||
assert.equal(context.budget_details[0].budget_subject_code, 'travel')
|
||||
assert.equal(context.budget_details[0].expense_type, 'travel')
|
||||
assert.equal(context.budget_details[0].expense_type_label, '差旅费')
|
||||
assert.equal(context.budget_details[0].expense_type_label, '差旅')
|
||||
assert.equal(context.budget_details[0].warning_threshold, '80%')
|
||||
})
|
||||
|
||||
@@ -85,6 +86,12 @@ test('budget expense type options expose real expense type codes', () => {
|
||||
])
|
||||
})
|
||||
|
||||
test('budget center visible expense type options only expose current supported budget subjects', () => {
|
||||
const optionLabels = BUDGET_VISIBLE_EXPENSE_TYPE_OPTIONS.map((item) => item.label)
|
||||
|
||||
assert.deepEqual(optionLabels, ['差旅', '通信', '招待费', '办公用品'])
|
||||
})
|
||||
|
||||
test('budget center exposes separate year and quarter dimensions', () => {
|
||||
assert.deepEqual(BUDGET_YEAR_OPTIONS, ['2026', '2027', '2028'])
|
||||
assert.deepEqual(BUDGET_QUARTER_OPTIONS, ['Q1', 'Q2', 'Q3', 'Q4'])
|
||||
|
||||
@@ -24,7 +24,7 @@ test('expense application submit uses rich text link and confirm dialog', () =>
|
||||
)
|
||||
assert.match(createViewTemplate, /:open="applicationSubmitConfirmDialog\.open"/)
|
||||
assert.match(createViewTemplate, /title="确认提交当前费用申请?"/)
|
||||
assert.match(createViewTemplate, /description="提交后申请将进入领导审核流程,并同步纳入预算管理口径/)
|
||||
assert.match(createViewTemplate, /description="提交后申请将进入领导审核流程,请确认关键申请信息和预计费用已经核对无误。"/)
|
||||
assert.match(createViewTemplate, /@confirm="confirmApplicationSubmit"/)
|
||||
assert.match(createViewScript, /const APPLICATION_SUBMIT_HREF = '#application-submit'/)
|
||||
assert.match(
|
||||
|
||||
@@ -29,7 +29,7 @@ test('application claims are mapped as application documents', () => {
|
||||
assert.equal(request.typeLabel, '差旅费用申请')
|
||||
assert.equal(request.secondaryStatusLabel, '申请材料')
|
||||
assert.equal(request.secondaryStatusValue, '已进入审批流程')
|
||||
assert.equal(request.expenseTableSummary, '预计金额已纳入预算管理口径')
|
||||
assert.equal(request.expenseTableSummary, '预计金额已随申请提交')
|
||||
assert.deepEqual(
|
||||
request.progressSteps.map((step) => step.label),
|
||||
['创建申请', '直属领导审批', '审批完成']
|
||||
|
||||
Reference in New Issue
Block a user