refactor: enforce 800 line source limits
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
import { isApplicationDocumentNo } from '../../utils/documentClassification.js'
|
||||
import {
|
||||
applicationDateRangesOverlap,
|
||||
normalizeApplicationPreview,
|
||||
resolveApplicationDateRange
|
||||
} from '../../utils/expenseApplicationPreview.js'
|
||||
import { APPLICATION_DUPLICATE_IGNORED_STATUSES } from './travelReimbursementSubmitConstants.js'
|
||||
|
||||
function normalizeClaimListPayload(payload) {
|
||||
if (Array.isArray(payload)) {
|
||||
return payload
|
||||
}
|
||||
return Array.isArray(payload?.items) ? payload.items : []
|
||||
}
|
||||
|
||||
function normalizeClaimRiskFlags(claim) {
|
||||
const flags = claim?.risk_flags_json || claim?.riskFlagsJson || claim?.riskFlags || []
|
||||
if (Array.isArray(flags)) {
|
||||
return flags
|
||||
}
|
||||
return flags && typeof flags === 'object' ? [flags] : []
|
||||
}
|
||||
|
||||
function extractApplicationDetailFromClaim(claim) {
|
||||
return normalizeClaimRiskFlags(claim).reduce((found, item) => {
|
||||
if (found || !item || typeof item !== 'object') {
|
||||
return found
|
||||
}
|
||||
const detail = item.application_detail || item.applicationDetail
|
||||
return detail && typeof detail === 'object' ? detail : null
|
||||
}, null)
|
||||
}
|
||||
|
||||
function isApplicationClaimRecord(claim) {
|
||||
const expenseType = String(claim?.expense_type || claim?.expenseType || '').trim().toLowerCase()
|
||||
const claimNo = String(claim?.claim_no || claim?.claimNo || '').trim().toUpperCase()
|
||||
return (
|
||||
expenseType === 'application' ||
|
||||
expenseType === 'expense_application' ||
|
||||
expenseType.endsWith('_application') ||
|
||||
isApplicationDocumentNo(claimNo) ||
|
||||
Boolean(extractApplicationDetailFromClaim(claim))
|
||||
)
|
||||
}
|
||||
|
||||
function normalizeApplicationExpenseType(value) {
|
||||
const text = String(value || '').trim().toLowerCase()
|
||||
if (!text) {
|
||||
return ''
|
||||
}
|
||||
if (text === 'travel_application' || /差旅|出差/.test(text)) {
|
||||
return 'travel_application'
|
||||
}
|
||||
if (text === 'purchase_application' || /采购/.test(text)) {
|
||||
return 'purchase_application'
|
||||
}
|
||||
if (text === 'meeting_application' || /会务|会议/.test(text)) {
|
||||
return 'meeting_application'
|
||||
}
|
||||
if (text === 'expense_application' || text === 'application' || text.endsWith('_application')) {
|
||||
return text === 'application' ? 'expense_application' : text
|
||||
}
|
||||
return 'expense_application'
|
||||
}
|
||||
|
||||
function resolveClaimApplicationExpenseType(claim) {
|
||||
const detail = extractApplicationDetailFromClaim(claim) || {}
|
||||
return normalizeApplicationExpenseType(
|
||||
claim?.expense_type ||
|
||||
claim?.expenseType ||
|
||||
detail.application_type ||
|
||||
detail.applicationType ||
|
||||
''
|
||||
)
|
||||
}
|
||||
|
||||
function isIgnoredApplicationDuplicateStatus(status) {
|
||||
return APPLICATION_DUPLICATE_IGNORED_STATUSES.has(String(status || '').trim().toLowerCase())
|
||||
}
|
||||
|
||||
function resolveClaimApplicationDateRange(claim) {
|
||||
const detail = extractApplicationDetailFromClaim(claim) || {}
|
||||
return (
|
||||
resolveApplicationDateRange(
|
||||
detail.time ||
|
||||
detail.time_range ||
|
||||
detail.timeRange ||
|
||||
detail.application_time ||
|
||||
detail.applicationTime ||
|
||||
detail.application_business_time ||
|
||||
detail.applicationBusinessTime ||
|
||||
detail.application_date ||
|
||||
detail.applicationDate,
|
||||
detail.days || detail.application_days || detail.applicationDays
|
||||
) ||
|
||||
resolveApplicationDateRange(claim?.occurred_at || claim?.occurredAt || '')
|
||||
)
|
||||
}
|
||||
|
||||
function formatApplicationDateRangeLabel(range) {
|
||||
if (!range?.startDate) {
|
||||
return '待确认'
|
||||
}
|
||||
return range.startDate === range.endDate ? range.startDate : `${range.startDate} 至 ${range.endDate}`
|
||||
}
|
||||
|
||||
function findOverlappingApplicationClaim(applicationPreview, claimsPayload) {
|
||||
const preview = normalizeApplicationPreview(applicationPreview)
|
||||
const fields = preview.fields || {}
|
||||
const currentRange = resolveApplicationDateRange(fields.time, fields.days)
|
||||
if (!currentRange) {
|
||||
return null
|
||||
}
|
||||
const currentExpenseType = normalizeApplicationExpenseType(fields.applicationType)
|
||||
const claims = normalizeClaimListPayload(claimsPayload)
|
||||
for (const claim of claims) {
|
||||
if (!isApplicationClaimRecord(claim) || isIgnoredApplicationDuplicateStatus(claim?.status)) {
|
||||
continue
|
||||
}
|
||||
const existingExpenseType = resolveClaimApplicationExpenseType(claim)
|
||||
if (currentExpenseType && existingExpenseType && currentExpenseType !== existingExpenseType) {
|
||||
continue
|
||||
}
|
||||
const existingRange = resolveClaimApplicationDateRange(claim)
|
||||
if (!existingRange || !applicationDateRangesOverlap(currentRange, existingRange)) {
|
||||
continue
|
||||
}
|
||||
return {
|
||||
claim,
|
||||
currentRange,
|
||||
existingRange,
|
||||
claimId: String(claim?.id || claim?.claim_id || claim?.claimId || '').trim(),
|
||||
claimNo: String(claim?.claim_no || claim?.claimNo || claim?.id || '').trim(),
|
||||
status: String(claim?.approval_stage || claim?.approvalStage || claim?.status || '').trim(),
|
||||
reason: String(claim?.reason || '').trim(),
|
||||
location: String(claim?.location || '').trim()
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function buildApplicationDateConflictMessage(conflict) {
|
||||
const claimNo = conflict?.claimNo || '已有申请'
|
||||
return [
|
||||
'我先检查了你的申请时间,发现同一天或重叠日期已经存在差旅申请,不能重复创建。',
|
||||
'',
|
||||
'已有申请:',
|
||||
`- **单号**:${claimNo}`,
|
||||
`- **申请时间**:${formatApplicationDateRangeLabel(conflict?.existingRange)}`,
|
||||
conflict?.location ? `- **地点**:${conflict.location}` : '',
|
||||
conflict?.reason ? `- **事由**:${conflict.reason}` : '',
|
||||
`- **当前节点**:${conflict?.status || '处理中'}`,
|
||||
'',
|
||||
`本次识别时间:${formatApplicationDateRangeLabel(conflict?.currentRange)}`,
|
||||
'',
|
||||
'请先查看已有申请,或修改本次出差时间后再继续。'
|
||||
].filter(Boolean).join('\n')
|
||||
}
|
||||
|
||||
function buildApplicationDateConflictActions(conflict) {
|
||||
const actions = []
|
||||
if (conflict?.claimId) {
|
||||
actions.push({
|
||||
action_type: 'open_application_detail',
|
||||
label: '查看已有申请',
|
||||
description: conflict.claimNo ? `进入 ${conflict.claimNo} 单据详情。` : '进入已有申请单据详情。',
|
||||
icon: 'mdi mdi-file-search-outline',
|
||||
payload: {
|
||||
claim_id: conflict.claimId,
|
||||
claim_no: conflict.claimNo
|
||||
}
|
||||
})
|
||||
}
|
||||
actions.push({
|
||||
action_type: 'prefill_composer',
|
||||
label: '修改出差时间',
|
||||
description: '在输入框中补充新的出差日期后继续。',
|
||||
icon: 'mdi mdi-calendar-edit-outline',
|
||||
payload: {
|
||||
prompt_prefill: '修改出差时间为:'
|
||||
}
|
||||
})
|
||||
return actions
|
||||
}
|
||||
|
||||
export {
|
||||
buildApplicationDateConflictActions,
|
||||
buildApplicationDateConflictMessage,
|
||||
findOverlappingApplicationClaim
|
||||
}
|
||||
Reference in New Issue
Block a user