fix: handle risk explanation standard adjustment

This commit is contained in:
caoxiaozhu
2026-06-03 17:31:40 +08:00
parent 67b81a1bd8
commit 8e2477587f
19 changed files with 976 additions and 61 deletions

View File

@@ -39,6 +39,7 @@ const LOCATION_REQUIRED_EXPENSE_TYPES = new Set([
])
const SYSTEM_GENERATED_EXPENSE_TYPES = new Set(['travel_allowance'])
const STANDARD_ADJUSTMENT_RISK_SOURCE = 'reimbursement_standard_adjustment'
const LONG_DISTANCE_TRAVEL_EXPENSE_TYPES = new Set(['train_ticket', 'flight_ticket'])
const ROUTE_DESCRIPTION_EXPENSE_TYPES = new Set(['train_ticket', 'flight_ticket', 'ship_ticket', 'ferry_ticket', 'ride_ticket'])
const HOTEL_DESCRIPTION_EXPENSE_TYPES = new Set(['hotel_ticket'])
@@ -83,6 +84,45 @@ function parseNumber(value) {
return Number.isFinite(nextValue) ? nextValue : 0
}
function parseOptionalAmount(value) {
if (value === null || value === undefined || String(value).trim() === '') {
return null
}
const amount = Number(value)
return Number.isFinite(amount) && amount >= 0 ? amount : null
}
function buildStandardAdjustmentMapFromClaim(claim = {}) {
const flags = Array.isArray(claim?.risk_flags_json)
? claim.risk_flags_json
: Array.isArray(claim?.riskFlags)
? claim.riskFlags
: []
const adjustmentMap = new Map()
flags.forEach((flag) => {
if (!flag || typeof flag !== 'object') {
return
}
if (String(flag.source || '').trim() !== STANDARD_ADJUSTMENT_RISK_SOURCE) {
return
}
const itemId = String(flag.item_id || flag.itemId || '').trim()
const reimbursableAmount = parseOptionalAmount(flag.reimbursable_amount ?? flag.reimbursableAmount)
if (!itemId || reimbursableAmount === null) {
return
}
adjustmentMap.set(itemId, {
originalAmount: parseOptionalAmount(flag.original_amount ?? flag.originalAmount),
reimbursableAmount,
employeeAbsorbedAmount: parseOptionalAmount(flag.employee_absorbed_amount ?? flag.employeeAbsorbedAmount) || 0,
message: String(flag.message || flag.summary || '').trim()
})
})
return adjustmentMap
}
function toDate(value) {
if (!value) {
return null
@@ -1272,6 +1312,7 @@ function buildExpenseItems(claim, riskMeta) {
return Number(SYSTEM_GENERATED_EXPENSE_TYPES.has(leftType)) - Number(SYSTEM_GENERATED_EXPENSE_TYPES.has(rightType))
})
const travelTimeLabelMap = buildTravelTimeLabelMap(sortedItems, claim)
const standardAdjustmentMap = buildStandardAdjustmentMapFromClaim(claim)
return sortedItems.map((item, index) => {
const invoiceId = String(item?.invoice_id || '').trim()
@@ -1286,6 +1327,10 @@ function buildExpenseItems(claim, riskMeta) {
const itemNote = String(item?.item_note || item?.itemNote || '').trim()
const itemAmount = parseNumber(item?.item_amount)
const itemAmountDisplay = itemAmount > 0 ? formatAmount(itemAmount) : '待补充'
const standardAdjustment = standardAdjustmentMap.get(id) || null
const originalItemAmount = standardAdjustment?.originalAmount ?? itemAmount
const reimbursableAmount = standardAdjustment?.reimbursableAmount ?? itemAmount
const employeeAbsorbedAmount = standardAdjustment?.employeeAbsorbedAmount || Math.max(originalItemAmount - reimbursableAmount, 0)
return {
id,
@@ -1297,6 +1342,15 @@ function buildExpenseItems(claim, riskMeta) {
itemLocation,
itemNote,
itemAmount,
originalItemAmount,
originalAmountDisplay: originalItemAmount > 0 ? formatAmount(originalItemAmount) : itemAmountDisplay,
reimbursableAmount,
reimbursableAmountDisplay: reimbursableAmount > 0 ? formatAmount(reimbursableAmount) : '待补充',
employeeAbsorbedAmount,
employeeAbsorbedAmountDisplay: employeeAbsorbedAmount > 0 ? formatAmount(employeeAbsorbedAmount) : '',
hasStandardAdjustment: reimbursableAmount >= 0 && reimbursableAmount < originalItemAmount,
standardAdjustmentAccepted: Boolean(standardAdjustment),
standardAdjustmentMessage: standardAdjustment?.message || '',
invoiceId,
isSystemGenerated,
dayLabel: resolveExpenseTimeLabel({
@@ -1336,7 +1390,10 @@ export function mapExpenseClaimToRequest(claim) {
const riskSummary = riskMeta.summary
const relatedApplication = isApplicationDocument ? null : resolveRelatedApplicationInfo(claim, typeLabel)
const expenseItems = buildExpenseItems(claim, riskMeta)
const visibleExpenseAmount = expenseItems.reduce((sum, item) => sum + parseNumber(item.itemAmount), 0)
const visibleExpenseAmount = expenseItems.reduce((sum, item) => {
const amount = parseOptionalAmount(item.reimbursableAmount) ?? parseNumber(item.itemAmount)
return sum + amount
}, 0)
const amountValue = relatedApplication
? expenseItems.length
? visibleExpenseAmount