feat: 细化差旅票据费用明细分类并自动计算出差补贴

将差旅费用明细拆分为火车票、机票、住宿票、乘车等细分类
型,根据票据字段自动生成行程/事由描述,结合规则引擎自
动计算出差补贴金额,前端适配费用明细编辑和差旅票据审
核交互,补充单元测试覆盖。
This commit is contained in:
caoxiaozhu
2026-05-21 10:57:06 +08:00
parent 8f65661809
commit b183b0bd5e
26 changed files with 2588 additions and 362 deletions

View File

@@ -98,6 +98,71 @@ test('progress steps do not expose approver email when manager name is available
}
})
test('travel expense items describe departure return and lodging time below the date', () => {
const request = mapExpenseClaimToRequest({
id: 'claim-travel-time-labels',
claim_no: 'EXP-202605-TRAVEL',
employee_name: '张三',
department_name: '市场部',
expense_type: 'travel',
reason: '北京客户现场出差',
location: '北京',
amount: 1108,
invoice_count: 3,
occurred_at: '2026-05-13T01:00:00.000Z',
created_at: '2026-05-13T01:30:00.000Z',
updated_at: '2026-05-13T03:30:00.000Z',
status: 'draft',
approval_stage: '待提交',
risk_flags_json: [],
items: [
{
id: 'outbound-train',
item_type: 'train_ticket',
item_reason: '从广州南到北京南',
item_location: '北京',
item_date: '2026-05-13',
item_amount: 354,
invoice_id: 'outbound.png'
},
{
id: 'hotel',
item_type: 'hotel_ticket',
item_reason: '北京全季酒店',
item_location: '北京',
item_date: '2026-05-14',
item_amount: 100,
invoice_id: 'hotel.png'
},
{
id: 'return-train',
item_type: 'train_ticket',
item_reason: '从北京南到广州南',
item_location: '广州',
item_date: '2026-05-15',
item_amount: 354,
invoice_id: 'return.png'
},
{
id: 'allowance',
item_type: 'travel_allowance',
item_reason: '系统自动计算出差补贴',
item_location: '北京',
item_date: '2026-05-15',
item_amount: 300,
invoice_id: '',
is_system_generated: true
}
]
})
assert.equal(request.expenseItems.find((item) => item.id === 'outbound-train')?.dayLabel, '出发时间')
assert.equal(request.expenseItems.find((item) => item.id === 'return-train')?.dayLabel, '返回时间')
assert.equal(request.expenseItems.find((item) => item.id === 'hotel')?.dayLabel, '住宿时间')
assert.equal(request.expenseItems.at(-1)?.id, 'allowance')
assert.equal(request.expenseItems.at(-1)?.dayLabel, '系统自动计算')
})
test('completed finance approval marks finance and archive progress steps', () => {
const request = mapExpenseClaimToRequest({
id: 'claim-finance-completed',