feat: 优化差旅报销预审流程与个人工作台 UI 体系
- 完善 user_agent_application 申请差旅报销预审槽位与消息组装 - 增强预算助理报告与风险建议卡片交互 - 重构登录页视觉样式与移动端响应式适配 - 优化个人工作台、文档中心、政策中心、员工管理等页面布局 - 拆分 travelRequestDetailPreReviewModel 为 advice/submit 模型 - 补充报销草稿、风险复核、Item Sync 与模板执行器测试覆盖
This commit is contained in:
@@ -23,6 +23,7 @@ from app.services.expense_claim_constants import (
|
||||
AI_REVIEW_REPEAT_RISK_WARNING_COUNT,
|
||||
DOCUMENT_FACT_ITEM_TYPES,
|
||||
LOCATION_REQUIRED_EXPENSE_TYPES,
|
||||
OPTIONAL_ATTACHMENT_ITEM_TYPES,
|
||||
SYSTEM_GENERATED_ITEM_TYPES,
|
||||
TRAVEL_ALLOWANCE_TRIGGER_ITEM_TYPES,
|
||||
TRAVEL_POLICY_HOTEL_NIGHT_PATTERN,
|
||||
@@ -399,6 +400,20 @@ class ExpenseClaimItemSyncMixin:
|
||||
return 1
|
||||
return max(0, int(policy.min_attachment_count or 0))
|
||||
|
||||
@staticmethod
|
||||
def _is_attachment_required_item_type(item_type: str | None) -> bool:
|
||||
normalized = str(item_type or "").strip().lower()
|
||||
return normalized not in SYSTEM_GENERATED_ITEM_TYPES and normalized not in OPTIONAL_ATTACHMENT_ITEM_TYPES
|
||||
|
||||
def _resolve_claim_required_attachment_count(self, claim: ExpenseClaim) -> int:
|
||||
required_items = [
|
||||
item for item in list(claim.items or [])
|
||||
if self._is_attachment_required_item_type(item.item_type)
|
||||
]
|
||||
if not required_items:
|
||||
return 0
|
||||
return min(self._resolve_min_attachment_count(claim.expense_type), len(required_items))
|
||||
|
||||
def _build_scene_reason_corpus(self, claim: ExpenseClaim) -> str:
|
||||
parts = [str(claim.reason or "").strip(), str(claim.location or "").strip()]
|
||||
for item in claim.items:
|
||||
@@ -454,16 +469,16 @@ class ExpenseClaimItemSyncMixin:
|
||||
def _format_submission_blocked_message(issues: list[str]) -> str:
|
||||
normalized_issues = [str(issue or "").strip() for issue in issues if str(issue or "").strip()]
|
||||
if not normalized_issues:
|
||||
return "AI预审未通过,但没有返回明确原因,请刷新草稿后重试。"
|
||||
return "自动检测未通过,但没有返回明确原因,请刷新草稿后重试。"
|
||||
|
||||
return "AI预审暂未通过,原因如下:\n" + "\n".join(
|
||||
return "自动检测暂未通过,原因如下:\n" + "\n".join(
|
||||
f"{index}. {issue}" for index, issue in enumerate(normalized_issues, start=1)
|
||||
)
|
||||
|
||||
def _validate_claim_for_submission(self, claim: ExpenseClaim) -> list[str]:
|
||||
issues: list[str] = []
|
||||
claim_location_required = self._is_location_required_expense_type(claim.expense_type)
|
||||
claim_min_attachment_count = self._resolve_min_attachment_count(claim.expense_type)
|
||||
claim_min_attachment_count = self._resolve_claim_required_attachment_count(claim)
|
||||
|
||||
if self._is_missing_value(claim.employee_name):
|
||||
issues.append("申请人未完善")
|
||||
@@ -498,7 +513,7 @@ class ExpenseClaimItemSyncMixin:
|
||||
issues.append(f"{prefix}缺少地点")
|
||||
if item.item_amount is None or item.item_amount <= Decimal("0.00"):
|
||||
issues.append(f"{prefix}缺少金额")
|
||||
if not is_system_generated and self._is_missing_value(item.invoice_id):
|
||||
if self._is_attachment_required_item_type(item.item_type) and self._is_missing_value(item.invoice_id):
|
||||
issues.append(f"{prefix}缺少票据标识")
|
||||
|
||||
return issues
|
||||
|
||||
Reference in New Issue
Block a user