feat: 重构报销单服务并完善前端提交与审核交互
重构 expense_claims 服务模块结构并优化差旅票据审核逻辑, 增强用户代理服务的票据类型识别,前端报销创建页面拆分为 附件模型和会话模型模块,重构提交编排器和草稿关联确认流 程,更新知识库索引,补充单元测试。
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -3354,23 +3354,23 @@ class UserAgentService:
|
||||
location = slots.get("location")
|
||||
customer = slots.get("customer_name")
|
||||
|
||||
summary = "我先根据您当前提供的信息整理出一笔报销。"
|
||||
summary = "我先根据您当前提供的信息整理出一笔报销:"
|
||||
if expense_type and expense_type.value:
|
||||
summary = f"识别到您希望报销一笔“{expense_type.value}”费用。"
|
||||
summary = f"识别到您希望报销一笔“{expense_type.value}”费用:"
|
||||
details: list[str] = []
|
||||
if customer and customer.value:
|
||||
details.append(f"客户为 {customer.value}")
|
||||
details.append(f"客户:{customer.value}")
|
||||
if time_range and time_range.value:
|
||||
details.append(f"时间为 {time_range.value}")
|
||||
details.append(f"时间:{time_range.value}")
|
||||
if location and location.value:
|
||||
details.append(f"地点为 {location.value}")
|
||||
details.append(f"地点:{location.value}")
|
||||
if amount and amount.value:
|
||||
details.append(f"金额为 {amount.value}")
|
||||
details.append(f"金额:{amount.value}")
|
||||
reason = slots.get("reason")
|
||||
if reason and reason.value:
|
||||
details.append(f"事由是 {reason.value}")
|
||||
details.append(f"事由:{reason.value}")
|
||||
if details:
|
||||
return f"{summary} {','.join(details)}。"
|
||||
return "\n\n".join([summary, "基础信息识别结果:", "\n".join(details)])
|
||||
return summary
|
||||
|
||||
def _build_review_body_answer(
|
||||
@@ -3399,6 +3399,11 @@ class UserAgentService:
|
||||
slot_cards=review_payload.slot_cards,
|
||||
claim_groups=review_payload.claim_groups,
|
||||
)
|
||||
if payload.tool_payload.get("duplicate_attachment_blocked") or payload.tool_payload.get("duplicate_invoice_blocked"):
|
||||
return (
|
||||
str(payload.tool_payload.get("message") or "").strip()
|
||||
or "检测到本次上传票据与当前单据已有票据重复,请重新上传不同的票据后再归集。"
|
||||
)
|
||||
if review_action == "save_draft":
|
||||
if draft_payload is not None and draft_payload.claim_no:
|
||||
return (
|
||||
@@ -3441,7 +3446,7 @@ class UserAgentService:
|
||||
)
|
||||
return str(payload.tool_payload.get("message") or "").strip() or "当前报销单暂时还不能提交审批。"
|
||||
return (
|
||||
f"{self._build_review_intent_summary(payload, slot_cards=review_payload.slot_cards, claim_groups=review_payload.claim_groups)} "
|
||||
f"{self._build_review_intent_summary(payload, slot_cards=review_payload.slot_cards, claim_groups=review_payload.claim_groups)}\n\n"
|
||||
"当前关键信息已基本齐全,您确认无误后可以继续下一步。"
|
||||
)
|
||||
return review_payload.body_message or None
|
||||
@@ -3497,7 +3502,7 @@ class UserAgentService:
|
||||
expense_type_slot = next((item for item in slot_cards if item.key == "expense_type"), None)
|
||||
if expense_type_slot is not None and not str(expense_type_slot.value or "").strip():
|
||||
return (
|
||||
f"{self._build_review_intent_summary(payload, slot_cards=slot_cards, claim_groups=[])} "
|
||||
f"{self._build_review_intent_summary(payload, slot_cards=slot_cards, claim_groups=[])}\n\n"
|
||||
"我已经先保留了当前识别出的时间、地点和事由,但还不能确定这张单据应该走哪类报销流程。"
|
||||
"请先点击“选择报销类型”,在差旅费、交通费、住宿费等选项中选定;"
|
||||
"选定后,后续上传的票据都会作为这张单据的补充继续核对,不会重新改判报销类型。"
|
||||
@@ -3616,17 +3621,17 @@ class UserAgentService:
|
||||
[
|
||||
"报销测算参考:",
|
||||
"",
|
||||
(
|
||||
f"职级 {calculation.grade},目的地 {destination},匹配城市 {calculation.matched_city};"
|
||||
"补齐交通、酒店等票据后,我会按真实票据金额和规则中心标准重新复核。"
|
||||
),
|
||||
"",
|
||||
"| 项目 | 测算口径 | 金额 |",
|
||||
"| --- | --- | ---: |",
|
||||
f"| 交通票据 | {ticket_basis} | {self._format_decimal_money(ticket_amount)} 元 |",
|
||||
f"| 住宿标准 | {self._format_decimal_money(calculation.hotel_rate)} 元/天 × {calculation.days} 天 | {self._format_decimal_money(calculation.hotel_amount)} 元 |",
|
||||
f"| 出差补贴 | {self._format_decimal_money(calculation.total_allowance_rate)} 元/天 × {calculation.days} 天 | {self._format_decimal_money(calculation.allowance_amount)} 元 |",
|
||||
f"| 参考合计 | 交通票据 + 住宿标准 + 出差补贴 | {self._format_decimal_money(total_amount)} 元 |",
|
||||
"",
|
||||
(
|
||||
f"测算依据:职级 {calculation.grade},目的地 {destination},匹配城市 {calculation.matched_city};"
|
||||
"补齐交通、酒店等票据后,我会按真实票据金额和规则中心标准重新复核。"
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
@@ -3850,7 +3855,6 @@ class UserAgentService:
|
||||
*,
|
||||
mention_save_draft: bool,
|
||||
) -> str:
|
||||
missing_count = len(review_payload.missing_slots)
|
||||
reminder_count = len(review_payload.risk_briefs)
|
||||
|
||||
if review_payload.can_proceed:
|
||||
@@ -3861,18 +3865,7 @@ class UserAgentService:
|
||||
)
|
||||
return "当前关键信息已基本齐全,您确认无误后可以继续下一步。"
|
||||
|
||||
issue_parts: list[str] = []
|
||||
if missing_count:
|
||||
issue_parts.append(f"{missing_count} 项信息待补充")
|
||||
if reminder_count:
|
||||
issue_parts.append(f"{reminder_count} 条提醒")
|
||||
issue_summary = "、".join(issue_parts) if issue_parts else "一些细节还需要进一步确认"
|
||||
|
||||
suffix = ";如果想先暂存,也可以点击对话文字中的“草稿”。" if mention_save_draft else "。"
|
||||
return (
|
||||
f"当前还有 {issue_summary}。"
|
||||
f"请核查对话中的文字说明{suffix}"
|
||||
)
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def _can_proceed_review(
|
||||
|
||||
Reference in New Issue
Block a user