fix: preserve reviewer risk notice after standard adjustment

This commit is contained in:
caoxiaozhu
2026-06-03 19:10:29 +08:00
parent cb36d78fa2
commit 0f8bc4071a
3 changed files with 80 additions and 16 deletions

View File

@@ -93,7 +93,7 @@ import {
import {
buildCurrentStandardAdjustmentMap,
buildStandardAdjustmentPayload as buildStandardAdjustmentPayloadModel,
filterSubmitterStandardAdjustedRiskCards as filterSubmitterStandardAdjustedRiskCardsModel,
filterSubmitterResolvedRiskCards as filterSubmitterResolvedRiskCardsModel,
isRiskCardMissingExpenseNote as isRiskCardMissingExpenseNoteModel,
resolveExpenseItemForRiskCard as resolveExpenseItemForRiskCardModel
} from './travelRequestDetailStandardAdjustment.js'
@@ -1179,8 +1179,8 @@ export default {
return resolveExpenseItemForRiskCardModel(card, expenseItems.value)
}
function filterSubmitterStandardAdjustedRiskCards(cards, businessStage) {
return filterSubmitterStandardAdjustedRiskCardsModel({
function filterSubmitterResolvedRiskCards(cards, businessStage) {
return filterSubmitterResolvedRiskCardsModel({
cards,
businessStage,
isCurrentApplicant: isCurrentApplicant.value,
@@ -1597,7 +1597,7 @@ export default {
: []
const scopedRiskCards = [
...(hasActionableRiskCards ? [] : summaryRiskCards),
...filterSubmitterStandardAdjustedRiskCards(directRiskCards, currentBusinessStage)
...filterSubmitterResolvedRiskCards(directRiskCards, currentBusinessStage)
]
const riskCards = filterRiskCardsForVisibility(scopedRiskCards, riskViewerContext.value)

View File

@@ -31,14 +31,6 @@ export function resolveExpenseItemForRiskCard(card, expenseItems = []) {
|| null
}
export function hasStandardAdjustmentForItem(item, standardAdjustmentMap = new Map()) {
const itemId = normalizeText(item?.id)
if (!itemId) {
return false
}
return Boolean(item?.standardAdjustmentAccepted || standardAdjustmentMap.has(itemId))
}
export function isRiskCardMissingExpenseNote(card, expenseItems = []) {
const item = resolveExpenseItemForRiskCard(card, expenseItems)
if (!item) {
@@ -47,7 +39,15 @@ export function isRiskCardMissingExpenseNote(card, expenseItems = []) {
return !normalizeText(item.itemNote)
}
function isRiskCardCoveredByStandardAdjustment(card, expenseItems, standardAdjustmentMap) {
export function hasStandardAdjustmentForItem(item, standardAdjustmentMap = new Map()) {
const itemId = normalizeText(item?.id)
if (!itemId) {
return false
}
return Boolean(item?.standardAdjustmentAccepted || standardAdjustmentMap.has(itemId))
}
function isRiskCardResolvedForSubmitter(card, expenseItems, standardAdjustmentMap) {
if (normalizeText(card?.source) === STANDARD_ADJUSTMENT_RISK_SOURCE) {
return true
}
@@ -57,7 +57,7 @@ function isRiskCardCoveredByStandardAdjustment(card, expenseItems, standardAdjus
)
}
export function filterSubmitterStandardAdjustedRiskCards({
export function filterSubmitterResolvedRiskCards({
cards = [],
businessStage = 'reimbursement',
isCurrentApplicant = false,
@@ -67,7 +67,7 @@ export function filterSubmitterStandardAdjustedRiskCards({
if (businessStage !== 'reimbursement' || !isCurrentApplicant) {
return cards
}
return cards.filter((card) => !isRiskCardCoveredByStandardAdjustment(card, expenseItems, standardAdjustmentMap))
return cards.filter((card) => !isRiskCardResolvedForSubmitter(card, expenseItems, standardAdjustmentMap))
}
function extractRiskCardMoneyValues(card) {

View File

@@ -24,6 +24,9 @@ import {
buildEmployeeProfileAdviceItems,
buildTravelReceiptMaterialPrompts
} from '../src/views/scripts/travelRequestDetailAdviceModel.js'
import {
filterSubmitterResolvedRiskCards
} from '../src/views/scripts/travelRequestDetailStandardAdjustment.js'
const detailViewTemplate = readFileSync(
fileURLToPath(new URL('../src/views/TravelRequestDetailView.vue', import.meta.url)),
@@ -708,7 +711,8 @@ test('expense detail shows standard-adjusted reimbursable amount separately from
assert.match(detailViewTemplate, /submitConfirmAmountDisplay/)
assert.match(detailViewStyle, /\.expense-original-amount[\s\S]*text-decoration-line: line-through/)
assert.match(detailViewScript, /const expenseTotal = computed\(\(\) => \{[\s\S]*item\.reimbursableAmount/)
assert.match(detailViewScript, /filterSubmitterStandardAdjustedRiskCards/)
assert.match(detailViewScript, /filterSubmitterResolvedRiskCards/)
assert.doesNotMatch(detailViewScript, /filterSubmitterStandardAdjustedRiskCards/)
assert.match(detailViewScript, /acceptExpenseClaimStandardAdjustment/)
assert.match(detailExpenseModelScript, /STANDARD_ADJUSTMENT_RISK_SOURCE = 'reimbursement_standard_adjustment'/)
assert.match(requestsComposableScript, /STANDARD_ADJUSTMENT_RISK_SOURCE = 'reimbursement_standard_adjustment'/)
@@ -744,6 +748,66 @@ test('expense detail shows standard-adjusted reimbursable amount separately from
assert.equal(item.hasStandardAdjustment, true)
})
test('standard adjustment resolves submitter risk prompt only after accepted while reviewer still sees notice', () => {
const originalRiskCard = {
id: 'risk-hotel-1',
source: 'attachment_analysis',
itemId: 'expense-item-1',
tone: 'high',
risk: '住宿票据金额超过职级标准。'
}
const reviewerNoticeCard = {
id: 'standard-adjustment-1',
source: 'reimbursement_standard_adjustment',
itemId: 'expense-item-1',
tone: 'medium',
risk: '提交人已选择按职级标准报销,超出部分由员工自担。'
}
const expenseItems = [{ id: 'expense-item-1' }]
const standardAdjustmentMap = buildStandardAdjustmentMap({
riskFlags: [
{
source: 'reimbursement_standard_adjustment',
item_id: 'expense-item-1',
original_amount: '880.00',
reimbursable_amount: '600.00',
employee_absorbed_amount: '280.00'
}
]
})
assert.deepEqual(
filterSubmitterResolvedRiskCards({
cards: [originalRiskCard],
businessStage: 'reimbursement',
isCurrentApplicant: true,
expenseItems,
standardAdjustmentMap: new Map()
}),
[originalRiskCard]
)
assert.deepEqual(
filterSubmitterResolvedRiskCards({
cards: [originalRiskCard],
businessStage: 'reimbursement',
isCurrentApplicant: true,
expenseItems,
standardAdjustmentMap
}),
[]
)
assert.deepEqual(
filterSubmitterResolvedRiskCards({
cards: [originalRiskCard, reviewerNoticeCard],
businessStage: 'reimbursement',
isCurrentApplicant: false,
expenseItems,
standardAdjustmentMap
}),
[originalRiskCard, reviewerNoticeCard]
)
})
test('expense item upload remains limited to one receipt per detail row', () => {
assert.match(detailViewTemplate, /ref="expenseUploadInput"[\s\S]*type="file"/)
assert.doesNotMatch(