From b183b0bd5ed03ef7412a5fc2300965e32d0570e6 Mon Sep 17 00:00:00 2001 From: caoxiaozhu Date: Thu, 21 May 2026 10:57:06 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BB=86=E5=8C=96=E5=B7=AE=E6=97=85?= =?UTF-8?q?=E7=A5=A8=E6=8D=AE=E8=B4=B9=E7=94=A8=E6=98=8E=E7=BB=86=E5=88=86?= =?UTF-8?q?=E7=B1=BB=E5=B9=B6=E8=87=AA=E5=8A=A8=E8=AE=A1=E7=AE=97=E5=87=BA?= =?UTF-8?q?=E5=B7=AE=E8=A1=A5=E8=B4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将差旅费用明细拆分为火车票、机票、住宿票、乘车等细分类 型,根据票据字段自动生成行程/事由描述,结合规则引擎自 动计算出差补贴金额,前端适配费用明细编辑和差旅票据审 核交互,补充单元测试覆盖。 --- .../app/api/v1/endpoints/reimbursements.py | 38 + server/src/app/schemas/reimbursement.py | 4 + server/src/app/services/expense_claims.py | 777 +++++++++++++++--- server/src/app/services/user_agent.py | 466 ++++++++++- .../发票_3_京S98876.pdf | Bin 61170 -> 0 bytes .../发票_3_京S98876.pdf.meta.json | 88 -- .../发票_3_京S98876.preview.png | Bin 146315 -> 0 bytes .../2月20_武汉-上海.pdf | Bin .../2月20_武汉-上海.pdf.meta.json | 23 +- .../2月20_武汉-上海.preview.png | Bin .../2月23_上海-武汉.pdf | Bin .../2月23_上海-武汉.pdf.meta.json | 23 +- .../2月23_上海-武汉.preview.png | Bin server/tests/test_expense_claim_service.py | 195 ++++- server/tests/test_user_agent_service.py | 224 +++++ .../views/travel-request-detail-view.css | 281 ++++++- web/src/composables/useRequests.js | 95 ++- web/src/services/reimbursements.js | 7 + web/src/utils/requestViewModel.js | 30 + .../views/TravelReimbursementCreateView.vue | 1 + web/src/views/TravelRequestDetailView.vue | 134 ++- .../scripts/TravelReimbursementCreateView.js | 97 ++- .../views/scripts/TravelRequestDetailView.js | 233 +++++- .../scripts/travelRequestDetailInsights.js | 40 +- web/tests/requestProgressSteps.test.mjs | 65 ++ ...travel-request-detail-risk-advice.test.mjs | 129 ++- 26 files changed, 2588 insertions(+), 362 deletions(-) delete mode 100644 server/storage/expense_claims/193e6c44-29f7-4ac9-9d64-c57ddfd186c0/f8e2b572-9f9f-472f-957c-cb49c5e1e283/发票_3_京S98876.pdf delete mode 100644 server/storage/expense_claims/193e6c44-29f7-4ac9-9d64-c57ddfd186c0/f8e2b572-9f9f-472f-957c-cb49c5e1e283/发票_3_京S98876.pdf.meta.json delete mode 100644 server/storage/expense_claims/193e6c44-29f7-4ac9-9d64-c57ddfd186c0/f8e2b572-9f9f-472f-957c-cb49c5e1e283/发票_3_京S98876.preview.png rename server/storage/expense_claims/{08f51e80-512e-498e-bcd6-50ca5d0becfc/62fe16f9-ad9f-4f96-948f-0b31a427a81d => 3754b9c8-e0f0-4d88-a24c-d52c7620be2c/3d643ccb-cfb5-48c5-8037-39dbe1fa87e4}/2月20_武汉-上海.pdf (100%) rename server/storage/expense_claims/{08f51e80-512e-498e-bcd6-50ca5d0becfc/62fe16f9-ad9f-4f96-948f-0b31a427a81d => 3754b9c8-e0f0-4d88-a24c-d52c7620be2c/3d643ccb-cfb5-48c5-8037-39dbe1fa87e4}/2月20_武汉-上海.pdf.meta.json (76%) rename server/storage/expense_claims/{08f51e80-512e-498e-bcd6-50ca5d0becfc/62fe16f9-ad9f-4f96-948f-0b31a427a81d => 3754b9c8-e0f0-4d88-a24c-d52c7620be2c/3d643ccb-cfb5-48c5-8037-39dbe1fa87e4}/2月20_武汉-上海.preview.png (100%) rename server/storage/expense_claims/{08f51e80-512e-498e-bcd6-50ca5d0becfc/1170b632-ad59-46c0-9876-7230d9d97e30 => 3754b9c8-e0f0-4d88-a24c-d52c7620be2c/a8d8e56b-8e0c-4feb-9371-1e3cd71ce25b}/2月23_上海-武汉.pdf (100%) rename server/storage/expense_claims/{08f51e80-512e-498e-bcd6-50ca5d0becfc/1170b632-ad59-46c0-9876-7230d9d97e30 => 3754b9c8-e0f0-4d88-a24c-d52c7620be2c/a8d8e56b-8e0c-4feb-9371-1e3cd71ce25b}/2月23_上海-武汉.pdf.meta.json (76%) rename server/storage/expense_claims/{08f51e80-512e-498e-bcd6-50ca5d0becfc/1170b632-ad59-46c0-9876-7230d9d97e30 => 3754b9c8-e0f0-4d88-a24c-d52c7620be2c/a8d8e56b-8e0c-4feb-9371-1e3cd71ce25b}/2月23_上海-武汉.preview.png (100%) diff --git a/server/src/app/api/v1/endpoints/reimbursements.py b/server/src/app/api/v1/endpoints/reimbursements.py index 727f5d2..bb616ae 100644 --- a/server/src/app/api/v1/endpoints/reimbursements.py +++ b/server/src/app/api/v1/endpoints/reimbursements.py @@ -18,6 +18,7 @@ from app.schemas.reimbursement import ( ExpenseClaimItemUpdate, ExpenseClaimRead, ExpenseClaimReturnPayload, + ExpenseClaimUpdate, ReimbursementCreate, ReimbursementRead, TravelReimbursementCalculatorRequest, @@ -115,6 +116,43 @@ def get_expense_claim(claim_id: str, db: DbSession, current_user: CurrentUser) - return claim +@router.patch( + "/claims/{claim_id}", + response_model=ExpenseClaimRead, + summary="更新草稿报销单", + description="更新草稿待提交报销单的主说明等草稿字段。", + responses={ + status.HTTP_404_NOT_FOUND: { + "model": ErrorResponse, + "description": "报销单不存在。", + }, + status.HTTP_400_BAD_REQUEST: { + "model": ErrorResponse, + "description": "报销单状态不允许更新。", + }, + }, +) +def update_expense_claim( + claim_id: str, + payload: ExpenseClaimUpdate, + db: DbSession, + current_user: CurrentUser, +) -> ExpenseClaimRead: + service = ExpenseClaimService(db) + try: + claim = service.update_claim( + claim_id=claim_id, + payload=payload, + current_user=current_user, + ) + except ValueError as error: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(error)) from error + + if claim is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Claim not found") + return claim + + @router.patch( "/claims/{claim_id}/items/{item_id}", response_model=ExpenseClaimRead, diff --git a/server/src/app/schemas/reimbursement.py b/server/src/app/schemas/reimbursement.py index 97e206c..5d4ae22 100644 --- a/server/src/app/schemas/reimbursement.py +++ b/server/src/app/schemas/reimbursement.py @@ -113,6 +113,10 @@ class ExpenseClaimItemCreate(BaseModel): invoice_id: str | None = None +class ExpenseClaimUpdate(BaseModel): + reason: str | None = Field(default=None, max_length=500) + + class ExpenseClaimRead(BaseModel): model_config = ConfigDict(from_attributes=True) diff --git a/server/src/app/services/expense_claims.py b/server/src/app/services/expense_claims.py index 9e66b7a..94dce02 100644 --- a/server/src/app/services/expense_claims.py +++ b/server/src/app/services/expense_claims.py @@ -27,7 +27,12 @@ from app.models.employee import Employee from app.models.financial_record import ExpenseClaim, ExpenseClaimItem from app.models.organization import OrganizationUnit from app.schemas.ontology import OntologyEntity, OntologyParseResult -from app.schemas.reimbursement import ExpenseClaimItemCreate, ExpenseClaimItemUpdate +from app.schemas.reimbursement import ( + ExpenseClaimItemCreate, + ExpenseClaimItemUpdate, + ExpenseClaimUpdate, + TravelReimbursementCalculatorRequest, +) from app.services.agent_asset_rule_library import AgentAssetRuleLibraryManager from app.services.agent_asset_spreadsheet import RISK_RULES_LIBRARY from app.services.agent_foundation import AgentFoundationService @@ -42,10 +47,15 @@ from app.services.expense_rule_runtime import ( ) from app.services.ocr import OcrService -EXPENSE_TYPE_LABELS = { - "travel": "差旅", - "hotel": "住宿", - "transport": "交通", +EXPENSE_TYPE_LABELS = { + "travel": "差旅", + "train_ticket": "火车票", + "flight_ticket": "机票", + "hotel_ticket": "住宿票", + "ride_ticket": "乘车", + "travel_allowance": "出差补贴", + "hotel": "住宿", + "transport": "交通", "meal": "餐费", "meeting": "会务", "entertainment": "招待", @@ -60,8 +70,45 @@ APPROVAL_VISIBLE_CLAIM_ROLE_CODES = {"manager", "approver"} CLAIM_DELETE_ROLE_CODES = {"executive"} MAX_DRAFT_CLAIMS_PER_USER = 3 EDITABLE_CLAIM_STATUSES = ("draft", "supplement", "returned") +SYSTEM_GENERATED_ITEM_TYPES = {"travel_allowance"} +TRAVEL_DETAIL_ITEM_TYPES = { + "train_ticket", + "flight_ticket", + "hotel_ticket", + "ride_ticket", + "travel_allowance", +} +DOCUMENT_TYPE_ITEM_TYPE_MAP = { + "train_ticket": "train_ticket", + "flight_itinerary": "flight_ticket", + "hotel_invoice": "hotel_ticket", + "taxi_receipt": "ride_ticket", + "transport_receipt": "ride_ticket", +} +DOCUMENT_FACT_ITEM_TYPES = {"train_ticket", "flight_ticket", "hotel_ticket", "ride_ticket"} +DOCUMENT_ROUTE_TEXT_PATTERN = re.compile( + r"([A-Za-z0-9\u4e00-\u9fa5()()·]{2,40})\s*(?:至|到|→|->|—|–|-)\s*" + r"([A-Za-z0-9\u4e00-\u9fa5()()·]{2,40})" +) +DOCUMENT_ROUTE_ORIGIN_LABELS = {"起点", "上车", "上车地点", "上车地址", "出发", "出发地", "出发站", "始发站", "乘车起点"} +DOCUMENT_ROUTE_DESTINATION_LABELS = { + "终点", + "下车", + "下车地点", + "下车地址", + "到达", + "到达地", + "到达站", + "目的地", + "乘车终点", +} +GENERIC_ATTACHMENT_BACKFILL_ITEM_TYPES = {"", "other", "travel", "transport", "hotel"} LOCATION_REQUIRED_EXPENSE_TYPES = { "travel", + "train_ticket", + "flight_ticket", + "hotel_ticket", + "ride_ticket", "meeting", "entertainment", } @@ -109,9 +156,14 @@ EXPENSE_SCENE_KEYWORDS = { "training": ("培训", "课程", "讲师", "教材", "学费", "认证"), } -EXPENSE_TYPE_ALLOWED_DOCUMENT_SCENES = { - "travel": {"travel", "hotel", "transport", "meal"}, - "hotel": {"hotel"}, +EXPENSE_TYPE_ALLOWED_DOCUMENT_SCENES = { + "travel": {"travel", "hotel", "transport", "meal"}, + "train_ticket": {"travel"}, + "flight_ticket": {"travel"}, + "hotel_ticket": {"hotel"}, + "ride_ticket": {"transport"}, + "travel_allowance": set(), + "hotel": {"hotel"}, "transport": {"transport", "travel"}, "meal": {"meal", "entertainment"}, "entertainment": {"entertainment", "meal"}, @@ -343,23 +395,55 @@ class ExpenseClaimService: ) stmt = self._apply_claim_scope(stmt, current_user, include_approval_scope=True) return self.db.scalar(stmt) - - def update_claim_item( - self, - *, + + def update_claim( + self, + *, + claim_id: str, + payload: ExpenseClaimUpdate, + current_user: CurrentUserContext, + ) -> ExpenseClaim | None: + claim = self.get_claim(claim_id, current_user) + if claim is None: + return None + + self._ensure_draft_pending_claim(claim) + before_json = self._serialize_claim(claim) + + if payload.reason is not None: + claim.reason = self._normalize_optional_text(payload.reason, allow_empty=True) or "待补充" + + self.db.commit() + self.db.refresh(claim) + + self.audit_service.log_action( + actor=current_user.name or current_user.username, + action="expense_claim.update", + resource_type="expense_claim", + resource_id=claim.id, + before_json=before_json, + after_json=self._serialize_claim(claim), + ) + + return claim + + def update_claim_item( + self, + *, claim_id: str, item_id: str, payload: ExpenseClaimItemUpdate, current_user: CurrentUserContext, ) -> ExpenseClaim | None: claim = self.get_claim(claim_id, current_user) - if claim is None: - return None - - self._ensure_draft_claim(claim) - item = next((entry for entry in claim.items if entry.id == item_id), None) - if item is None: - raise LookupError("Item not found") + if claim is None: + return None + + self._ensure_draft_claim(claim) + item = next((entry for entry in claim.items if entry.id == item_id), None) + if item is None: + raise LookupError("Item not found") + self._ensure_mutable_claim_item(item) before_json = self._serialize_claim(claim) @@ -407,12 +491,12 @@ class ExpenseClaimService: current_user: CurrentUserContext, ) -> ExpenseClaim | None: claim = self.get_claim(claim_id, current_user) - if claim is None: - return None - - self._ensure_draft_claim(claim) - before_json = self._serialize_claim(claim) - payload = payload or ExpenseClaimItemCreate() + if claim is None: + return None + + self._ensure_draft_claim(claim) + before_json = self._serialize_claim(claim) + payload = payload or ExpenseClaimItemCreate() occurred_at = claim.occurred_at if claim.occurred_at is not None else datetime.now(UTC) item_amount = Decimal("0.00") @@ -509,11 +593,12 @@ class ExpenseClaimService: item_id=item_id, current_user=current_user, ) - if claim is None: - return None - - self._ensure_draft_claim(claim) - normalized_name = self._normalize_attachment_filename(filename) + if claim is None: + return None + + self._ensure_draft_claim(claim) + self._ensure_mutable_claim_item(item) + normalized_name = self._normalize_attachment_filename(filename) if not content: raise ValueError("上传文件不能为空。") @@ -547,11 +632,20 @@ class ExpenseClaimService: ocr_document = documents[0] ocr_status = "recognized" document_info = self._build_attachment_document_info(ocr_document) + self._backfill_item_type_from_attachment( + item=item, + document_info=document_info, + ) self._backfill_item_amount_from_attachment( item=item, document=ocr_document, document_info=document_info, ) + self._backfill_item_reason_from_attachment( + item=item, + document=ocr_document, + document_info=document_info, + ) requirement_check = self._build_attachment_requirement_check( item=item, document_info=document_info, @@ -694,11 +788,12 @@ class ExpenseClaimService: item_id=item_id, current_user=current_user, ) - if claim is None: - return None - - self._ensure_draft_claim(claim) - before_json = self._serialize_claim(claim) + if claim is None: + return None + + self._ensure_draft_claim(claim) + self._ensure_mutable_claim_item(item) + before_json = self._serialize_claim(claim) previous_name = self._resolve_attachment_display_name(item.invoice_id) self._delete_item_attachment_files(item) item.invoice_id = None @@ -1234,15 +1329,18 @@ class ExpenseClaimService: self.db.flush() if context_documents or attachment_names: - document_specs = self._build_context_item_specs( - context_documents=context_documents, - attachment_names=attachment_names, - occurred_at=final_occurred_at, - expense_type=final_expense_type, - amount=final_amount, - reason=final_reason, - location=final_location, - ) + document_specs = self._build_context_item_specs( + context_documents=context_documents, + attachment_names=attachment_names, + occurred_at=final_occurred_at, + expense_type=final_expense_type, + amount=final_amount, + reason=final_reason, + location=final_location, + context_json=context_json, + employee_grade=str(employee.grade or "").strip() if employee is not None else "", + user_id=user_id, + ) else: document_specs = [] @@ -1486,28 +1584,31 @@ class ExpenseClaimService: ) return normalized - def _build_context_item_specs( - self, - *, - context_documents: list[dict[str, Any]], - attachment_names: list[str], - occurred_at: datetime, - expense_type: str, - amount: Decimal, - reason: str, - location: str, - ) -> list[dict[str, Any]]: - specs: list[dict[str, Any]] = [] - if context_documents: - for document in context_documents: + def _build_context_item_specs( + self, + *, + context_documents: list[dict[str, Any]], + attachment_names: list[str], + occurred_at: datetime, + expense_type: str, + amount: Decimal, + reason: str, + location: str, + context_json: dict[str, Any], + employee_grade: str | None = None, + user_id: str = "", + ) -> list[dict[str, Any]]: + specs: list[dict[str, Any]] = [] + if context_documents: + for document in context_documents: specs.append( { - "item_date": self._resolve_document_item_date(document, fallback=occurred_at.date()), - "item_type": self._resolve_document_item_type(document, fallback=expense_type), - "item_reason": reason, - "item_location": location, - "item_amount": self._resolve_document_item_amount(document), - "invoice_id": str(document.get("filename") or "").strip() or None, + "item_date": self._resolve_document_item_date(document, fallback=occurred_at.date()), + "item_type": self._resolve_document_item_type(document, fallback=expense_type), + "item_reason": self._resolve_document_item_reason(document, fallback=reason), + "item_location": location, + "item_amount": self._resolve_document_item_amount(document), + "invoice_id": str(document.get("filename") or "").strip() or None, } ) elif attachment_names: @@ -1535,13 +1636,191 @@ class ExpenseClaimService: if remaining > Decimal("0.00"): missing_specs[0]["item_amount"] = remaining - for spec in specs: - if spec.get("item_amount") is None: - spec["item_amount"] = Decimal("0.00") - - return specs - - def _replace_claim_items( + for spec in specs: + if spec.get("item_amount") is None: + spec["item_amount"] = Decimal("0.00") + + allowance_spec = self._build_travel_allowance_item_spec( + context_documents=context_documents, + specs=specs, + occurred_at=occurred_at, + expense_type=expense_type, + location=location, + context_json=context_json, + employee_grade=employee_grade, + user_id=user_id, + ) + if allowance_spec is not None: + specs = [spec for spec in specs if str(spec.get("item_type") or "").strip() != "travel_allowance"] + specs.append(allowance_spec) + + return specs + + def _build_travel_allowance_item_spec( + self, + *, + context_documents: list[dict[str, Any]], + specs: list[dict[str, Any]], + occurred_at: datetime, + expense_type: str, + location: str, + context_json: dict[str, Any], + employee_grade: str | None, + user_id: str, + ) -> dict[str, Any] | None: + if not self._should_add_travel_allowance_item( + expense_type=expense_type, + context_documents=context_documents, + context_json=context_json, + ): + return None + + grade = str(employee_grade or context_json.get("grade") or "").strip() + if not grade: + return None + + days, _, end_date = self._resolve_travel_allowance_days( + context_json=context_json, + occurred_at=occurred_at, + ) + allowance_location = self._resolve_travel_allowance_location( + location=location, + context_documents=context_documents, + ) + if days < 1 or not allowance_location: + return None + + try: + from app.services.travel_reimbursement_calculator import TravelReimbursementCalculatorService + + result = TravelReimbursementCalculatorService(self.db).calculate( + TravelReimbursementCalculatorRequest( + days=days, + location=allowance_location, + grade=grade, + ), + CurrentUserContext( + username=user_id, + name="", + role_codes=[], + is_admin=False, + ), + ) + except ValueError: + return None + + allowance_amount = Decimal(result.allowance_amount or Decimal("0.00")).quantize(Decimal("0.01")) + allowance_rate = Decimal(result.total_allowance_rate or Decimal("0.00")).quantize(Decimal("0.01")) + if allowance_amount <= Decimal("0.00") or allowance_rate <= Decimal("0.00"): + return None + + return { + "item_date": end_date, + "item_type": "travel_allowance", + "item_reason": ( + f"系统自动计算出差补贴:{result.matched_city},{days}天," + f"{allowance_rate:.2f}元/天" + ), + "item_location": str(result.allowance_region or allowance_location).strip(), + "item_amount": allowance_amount, + "invoice_id": None, + } + + @staticmethod + def _should_add_travel_allowance_item( + *, + expense_type: str, + context_documents: list[dict[str, Any]], + context_json: dict[str, Any], + ) -> bool: + normalized_expense_type = str(expense_type or "").strip().lower() + if normalized_expense_type == "travel": + return True + + review_form_values = context_json.get("review_form_values") + if isinstance(review_form_values, dict): + review_type = str( + review_form_values.get("expense_type") + or review_form_values.get("scene_label") + or review_form_values.get("reason_value") + or "" + ) + if any(keyword in review_type for keyword in ("差旅", "出差")): + return True + + for document in context_documents: + document_type = str(document.get("document_type") or "").strip() + scene_code = str(document.get("scene_code") or "").strip() + if document_type in {"train_ticket", "flight_itinerary", "hotel_invoice"} or scene_code == "travel": + return True + return False + + def _resolve_travel_allowance_days( + self, + *, + context_json: dict[str, Any], + occurred_at: datetime, + ) -> tuple[int, date, date]: + start_date = occurred_at.date() + end_date = start_date + + business_time_context = context_json.get("business_time_context") + if isinstance(business_time_context, dict): + start_date = self._parse_iso_date_or_default(business_time_context.get("start_date"), start_date) + end_date = self._parse_iso_date_or_default(business_time_context.get("end_date"), start_date) + else: + review_form_values = context_json.get("review_form_values") + if isinstance(review_form_values, dict): + time_text = str( + review_form_values.get("time_range") + or review_form_values.get("business_time") + or review_form_values.get("occurred_date") + or "" + ).strip() + matched_dates = re.findall(r"\d{4}-\d{2}-\d{2}", time_text) + if matched_dates: + start_date = self._parse_iso_date_or_default(matched_dates[0], start_date) + end_date = self._parse_iso_date_or_default(matched_dates[-1], start_date) + + if end_date < start_date: + end_date = start_date + days = (end_date - start_date).days + 1 + return max(1, days), start_date, end_date + + @staticmethod + def _parse_iso_date_or_default(value: Any, fallback: date) -> date: + try: + return date.fromisoformat(str(value or "").strip()) + except ValueError: + return fallback + + @staticmethod + def _resolve_travel_allowance_location( + *, + location: str, + context_documents: list[dict[str, Any]], + ) -> str: + normalized_location = str(location or "").strip() + if normalized_location and normalized_location not in {"待补充", "未知", "暂无"}: + return normalized_location + + for document in context_documents: + for field in list(document.get("document_fields") or []): + if not isinstance(field, dict): + continue + key = str(field.get("key") or "").strip().lower() + label = str(field.get("label") or "").strip() + value = str(field.get("value") or "").strip() + if key == "route" or "行程" in label: + separators = ("-", "至", "→", "->") + for separator in separators: + if separator in value: + return value.split(separator)[-1].strip() + if key in {"destination", "arrival_city"} or label in {"目的地", "到达城市"}: + return value + return "" + + def _replace_claim_items( self, *, claim: ExpenseClaim, @@ -1565,18 +1844,28 @@ class ExpenseClaimService: item.item_reason = spec["item_reason"] item.item_location = spec["item_location"] item.item_amount = spec["item_amount"] - item.invoice_id = self._merge_attachment_reference(item.invoice_id, spec["invoice_id"]) + item.invoice_id = ( + None + if str(spec.get("item_type") or "").strip() in SYSTEM_GENERATED_ITEM_TYPES + else self._merge_attachment_reference(item.invoice_id, spec["invoice_id"]) + ) for stale_item in existing_items[len(item_specs) :]: claim.items.remove(stale_item) self.db.delete(stale_item) - def _append_document_items( - self, - *, - claim: ExpenseClaim, - item_specs: list[dict[str, Any]], - ) -> None: + def _append_document_items( + self, + *, + claim: ExpenseClaim, + item_specs: list[dict[str, Any]], + ) -> None: + system_specs = [ + spec for spec in item_specs if str(spec.get("item_type") or "").strip() in SYSTEM_GENERATED_ITEM_TYPES + ] + normal_specs = [ + spec for spec in item_specs if str(spec.get("item_type") or "").strip() not in SYSTEM_GENERATED_ITEM_TYPES + ] existing_invoice_ids = { str(item.invoice_id or "").strip() for item in claim.items @@ -1587,7 +1876,7 @@ class ExpenseClaimService: for item in claim.items if str(item.invoice_id or "").strip() } - for spec in item_specs: + for spec in normal_specs: invoice_id = str(spec.get("invoice_id") or "").strip() invoice_name = self._resolve_attachment_display_name(invoice_id) if invoice_id and (invoice_id in existing_invoice_ids or invoice_name in existing_invoice_names): @@ -1607,15 +1896,40 @@ class ExpenseClaimService: if invoice_id: existing_invoice_ids.add(invoice_id) existing_invoice_names.add(invoice_name) + + if system_specs: + existing_system_items = [ + item for item in list(claim.items) if str(item.item_type or "").strip() in SYSTEM_GENERATED_ITEM_TYPES + ] + for stale_item in existing_system_items: + claim.items.remove(stale_item) + self.db.delete(stale_item) + for spec in system_specs: + claim.items.append( + ExpenseClaimItem( + claim_id=claim.id, + item_date=spec["item_date"], + item_type=spec["item_type"], + item_reason=spec["item_reason"], + item_location=spec["item_location"], + item_amount=spec["item_amount"], + invoice_id=spec["invoice_id"], + ) + ) + self.db.add(claim.items[-1]) - def _resolve_document_item_type(self, document: dict[str, Any], *, fallback: str) -> str: - scene_code = str(document.get("scene_code") or "").strip() - if scene_code in {"travel", "hotel", "transport", "meal", "office", "meeting", "training"}: - return scene_code - - document_type = str(document.get("document_type") or "").strip() - if document_type in {"flight_itinerary", "train_ticket"}: - return "travel" + def _resolve_document_item_type(self, document: dict[str, Any], *, fallback: str) -> str: + document_type = str(document.get("document_type") or "").strip() + mapped_type = DOCUMENT_TYPE_ITEM_TYPE_MAP.get(document_type) + if mapped_type: + return mapped_type + + scene_code = str(document.get("scene_code") or "").strip() + if scene_code in {"travel", "hotel", "transport", "meal", "office", "meeting", "training"}: + return scene_code + + if document_type in {"flight_itinerary", "train_ticket"}: + return "travel" if document_type in {"taxi_receipt", "parking_toll_receipt", "transport_receipt"}: return "transport" if document_type == "hotel_invoice": @@ -1639,12 +1953,212 @@ class ExpenseClaimService: if "会务" in scene_label or "会议" in scene_label: return "meeting" if "培训" in scene_label: - return "training" - return fallback or "other" - - def _resolve_document_item_amount(self, document: dict[str, Any]) -> Decimal | None: - for field in list(document.get("document_fields") or []): - if not isinstance(field, dict): + return "training" + return fallback or "other" + + def _resolve_document_item_reason(self, document: dict[str, Any], *, fallback: str) -> str: + document_type = str(document.get("document_type") or "").strip().lower() + item_type = self._resolve_document_item_type(document, fallback="") + + if document_type in {"train_ticket", "flight_itinerary"} or item_type in {"train_ticket", "flight_ticket"}: + route = self._resolve_document_route_value(document) + trip_no = self._resolve_document_fact_field( + document, + keys={"trip_no", "flight_no", "train_no"}, + labels={"车次", "航班"}, + ) + if route and trip_no: + return f"{self._format_document_route(route)}({trip_no})" + if route: + return self._format_document_route(route) + + if document_type in {"taxi_receipt", "transport_receipt"} or item_type == "ride_ticket": + route = self._resolve_document_route_value(document) + if route: + return self._format_document_route(route) + + if document_type == "hotel_invoice" or item_type == "hotel_ticket": + merchant = self._resolve_document_fact_field( + document, + keys={"merchant_name", "merchant", "seller_name", "vendor_name", "hotel_name"}, + labels={"商户", "酒店", "宾馆", "销售方", "开票方"}, + ) + stay_range = self._resolve_document_stay_range(document) + if merchant and stay_range: + return f"{merchant},{stay_range}" + if merchant: + return merchant + if stay_range: + return stay_range + + merchant = self._resolve_document_fact_field( + document, + keys={"merchant_name", "merchant", "seller_name", "vendor_name"}, + labels={"商户", "销售方", "开票方", "收款方"}, + ) + if merchant: + return merchant + + summary = str(document.get("summary") or "").strip() + return summary or fallback or "" + + def _resolve_document_route_value(self, document: dict[str, Any]) -> str: + route = self._resolve_document_fact_field( + document, + keys={"route", "trip_route"}, + labels={"行程", "路线"}, + ) + if route: + return route + + origin = self._resolve_document_fact_field( + document, + keys={ + "origin", + "from", + "from_city", + "departure", + "departure_city", + "start", + "start_location", + "start_address", + "pickup_location", + "pickup_address", + "boarding_station", + }, + labels=DOCUMENT_ROUTE_ORIGIN_LABELS, + ) + destination = self._resolve_document_fact_field( + document, + keys={ + "destination", + "to", + "to_city", + "arrival", + "arrival_city", + "end", + "end_location", + "end_address", + "dropoff_location", + "dropoff_address", + "alighting_station", + }, + labels=DOCUMENT_ROUTE_DESTINATION_LABELS, + ) + if origin and destination: + return f"{origin}-{destination}" + + text = " ".join( + [ + str(document.get("summary") or "").strip(), + str(document.get("text") or "").strip(), + ] + ).strip() + text_route = self._extract_document_route_from_text(text) + if text_route: + return text_route + + text_origin = self._extract_document_labeled_text_value(text, DOCUMENT_ROUTE_ORIGIN_LABELS) + text_destination = self._extract_document_labeled_text_value(text, DOCUMENT_ROUTE_DESTINATION_LABELS) + if text_origin and text_destination: + return f"{text_origin}-{text_destination}" + return "" + + @staticmethod + def _resolve_document_fact_field( + document: dict[str, Any], + *, + keys: set[str], + labels: set[str], + ) -> str: + raw_fields = document.get("document_fields") + if not isinstance(raw_fields, list): + raw_fields = document.get("fields") + if not isinstance(raw_fields, list): + return "" + + normalized_keys = {str(key or "").strip().lower().replace("_", "") for key in keys} + for field in raw_fields: + if not isinstance(field, dict): + continue + field_key = str(field.get("key") or "").strip().lower().replace("_", "") + label = str(field.get("label") or "").replace(" ", "") + value = str(field.get("value") or "").strip() + if not value: + continue + if field_key in normalized_keys or any(token in label for token in labels): + return value + return "" + + @staticmethod + def _format_document_route(route: str) -> str: + normalized = ( + str(route or "") + .strip() + .replace("->", "-") + .replace("→", "-") + .replace("—", "-") + .replace("–", "-") + .replace("至", "-") + .replace("到", "-") + ) + if "-" not in normalized: + return str(route or "").strip() + origin, destination = [part.strip() for part in normalized.split("-", 1)] + origin = origin.removeprefix("从").strip() + destination = destination.removeprefix("至").removeprefix("到").strip() + if not origin or not destination or origin == destination: + return str(route or "").strip() + return f"从{origin}到{destination}" + + @staticmethod + def _extract_document_route_from_text(text: str) -> str: + match = DOCUMENT_ROUTE_TEXT_PATTERN.search(str(text or "")) + if not match: + return "" + origin = str(match.group(1) or "").strip() + destination = str(match.group(2) or "").strip() + if not origin or not destination or origin == destination: + return "" + return f"{origin}-{destination}" + + @staticmethod + def _extract_document_labeled_text_value(text: str, labels: set[str]) -> str: + for label in sorted(labels, key=len, reverse=True): + pattern = re.compile( + rf"{re.escape(label)}[::\s]*" + r"([A-Za-z0-9\u4e00-\u9fa5()()·\-路街道号弄区县市省园桥站机场中心]{2,50})" + ) + match = pattern.search(str(text or "")) + if match: + return str(match.group(1) or "").strip() + return "" + + def _resolve_document_stay_range(self, document: dict[str, Any]) -> str: + check_in = self._resolve_document_fact_field( + document, + keys={"check_in", "checkin", "arrival_date", "start_date"}, + labels={"入住", "入住日期", "到店", "开始日期"}, + ) + check_out = self._resolve_document_fact_field( + document, + keys={"check_out", "checkout", "departure_date", "end_date"}, + labels={"离店", "退房", "离店日期", "结束日期"}, + ) + if check_in and check_out: + return f"{check_in}至{check_out}" + nights = self._resolve_document_fact_field( + document, + keys={"nights", "night_count", "room_nights"}, + labels={"间夜", "晚数", "入住天数"}, + ) + if nights: + return f"{nights}晚" + return "" + + def _resolve_document_item_amount(self, document: dict[str, Any]) -> Decimal | None: + for field in list(document.get("document_fields") or []): + if not isinstance(field, dict): continue key = str(field.get("key") or "").strip().lower().replace("_", "") label = str(field.get("label") or "").replace(" ", "") @@ -2575,6 +3089,21 @@ class ExpenseClaimService: "fields": normalized_fields, } + def _backfill_item_type_from_attachment( + self, + *, + item: ExpenseClaimItem, + document_info: dict[str, Any], + ) -> None: + current_type = str(item.item_type or "").strip().lower() + if current_type not in GENERIC_ATTACHMENT_BACKFILL_ITEM_TYPES: + return + + document_type = str(document_info.get("document_type") or "").strip() + mapped_type = DOCUMENT_TYPE_ITEM_TYPE_MAP.get(document_type) + if mapped_type: + item.item_type = mapped_type + def _backfill_item_amount_from_attachment( self, *, @@ -2596,6 +3125,27 @@ class ExpenseClaimService: if amount is not None and amount > Decimal("0.00"): item.item_amount = amount + def _backfill_item_reason_from_attachment( + self, + *, + item: ExpenseClaimItem, + document: Any, + document_info: dict[str, Any], + ) -> None: + reason = self._resolve_document_item_reason( + { + "document_type": str(document_info.get("document_type") or "").strip(), + "scene_code": str(document_info.get("scene_code") or "").strip(), + "scene_label": str(document_info.get("scene_label") or "").strip(), + "document_fields": document_info.get("fields") or [], + "summary": str(getattr(document, "summary", "") or ""), + "text": str(getattr(document, "text", "") or ""), + }, + fallback=str(item.item_reason or "").strip(), + ) + if reason: + item.item_reason = reason + def _build_attachment_requirement_check( self, *, @@ -3063,6 +3613,17 @@ class ExpenseClaimService: if not self._is_editable_claim_status(claim.status): raise ValueError("只有草稿、待补充或退回待提交状态的报销单才允许执行该操作。") + @staticmethod + def _ensure_draft_pending_claim(claim: ExpenseClaim) -> None: + status = str(claim.status or "").strip().lower() + if status != "draft": + raise ValueError("只有草稿待提交状态的报销单才允许编辑附加说明。") + + @staticmethod + def _ensure_mutable_claim_item(item: ExpenseClaimItem) -> None: + if str(item.item_type or "").strip().lower() in SYSTEM_GENERATED_ITEM_TYPES: + raise ValueError("系统自动计算的费用明细不可手动修改。") + def _delete_submitted_claim_assistant_sessions(self, claim_id: str | None) -> None: from app.services.agent_conversations import AgentConversationService @@ -4531,10 +5092,16 @@ class ExpenseClaimService: primary_item.item_date.day, tzinfo=UTC, ) - claim.expense_type = str(primary_item.item_type or claim.expense_type or "other").strip() or "other" - claim.reason = ( - self._normalize_optional_text(primary_item.item_reason, fallback=claim.reason or "待补充") or "待补充" - ) + claim.expense_type = self._resolve_claim_expense_type_from_items( + ordered_items, + fallback=str(primary_item.item_type or claim.expense_type or "other").strip() or "other", + ) + primary_item_type = str(primary_item.item_type or "").strip() + if primary_item_type not in DOCUMENT_FACT_ITEM_TYPES: + claim.reason = ( + self._normalize_optional_text(primary_item.item_reason, fallback=claim.reason or "待补充") + or "待补充" + ) claim.location = ( self._normalize_optional_text(primary_item.item_location, fallback=claim.location or "待补充") or "待补充" @@ -4543,8 +5110,20 @@ class ExpenseClaimService: claim, self._build_claim_attachment_risk_flags(ordered_items), ) - if str(claim.status or "").strip().lower() == "draft": - claim.approval_stage = "待提交" + if str(claim.status or "").strip().lower() == "draft": + claim.approval_stage = "待提交" + + @staticmethod + def _resolve_claim_expense_type_from_items( + items: list[ExpenseClaimItem], + *, + fallback: str, + ) -> str: + fallback_type = str(fallback or "").strip() or "other" + item_types = {str(item.item_type or "").strip().lower() for item in items} + if item_types & TRAVEL_DETAIL_ITEM_TYPES: + return "travel" + return fallback_type def _refresh_item_attachment_analysis(self, item: ExpenseClaimItem) -> None: file_path = self._resolve_attachment_path(item.invoice_id) diff --git a/server/src/app/services/user_agent.py b/server/src/app/services/user_agent.py index ff7fe8a..5d6a822 100644 --- a/server/src/app/services/user_agent.py +++ b/server/src/app/services/user_agent.py @@ -9,10 +9,12 @@ from typing import Any from sqlalchemy import or_, select from sqlalchemy.orm import Session, selectinload +from app.api.deps import CurrentUserContext from app.core.agent_enums import AgentAssetStatus, AgentAssetType from app.models.employee import Employee from app.models.financial_record import ExpenseClaim from app.schemas.agent_asset import AgentAssetListItem +from app.schemas.reimbursement import TravelReimbursementCalculatorRequest from app.schemas.user_agent import ( UserAgentCitation, UserAgentDraftPayload, @@ -37,6 +39,7 @@ from app.services.expense_claims import ExpenseClaimService from app.services.expense_rule_runtime import ExpenseRuleRuntimeService, RuntimeTravelPolicy, resolve_document_type_label from app.services.risk_ontology_bridge import resolve_rule_codes_for_risk_check from app.services.runtime_chat import RuntimeChatService +from app.services.travel_reimbursement_calculator import TravelReimbursementCalculatorService SCENARIO_LABELS = { "expense": "报销", @@ -187,6 +190,7 @@ DOCUMENT_AMOUNT_PATTERN = re.compile( ) DOCUMENT_CURRENCY_AMOUNT_PATTERN = re.compile(r"[¥¥]\s*([0-9]+(?:[.,][0-9]{1,2})?)") TRAVEL_REVIEW_HOTEL_NIGHT_PATTERN = re.compile(r"(\d+)\s*(?:晚|间夜)") +TRAVEL_ROUTE_PATTERN = re.compile(r"([\u4e00-\u9fa5]{2,12})\s*(?:至|→|->|-|—)\s*([\u4e00-\u9fa5]{2,12})") SOURCE_LABELS = { "user_text": "用户描述", @@ -1900,6 +1904,11 @@ class UserAgentService: ocr_documents=ocr_documents, claim_groups=claim_groups, ) + travel_receipt_state = self._build_travel_receipt_state( + payload, + document_cards=document_cards, + claim_groups=claim_groups, + ) missing_slot_keys = self._resolve_review_missing_slot_keys( payload, slot_cards=slot_cards, @@ -1911,10 +1920,11 @@ class UserAgentService: document_cards=document_cards, claim_groups=claim_groups, ) + risk_briefs.extend(self._build_travel_receipt_briefs(travel_receipt_state)) association_choice_pending = self._is_review_association_choice_pending(payload) can_proceed = ( False - if association_choice_pending or submission_blocked + if association_choice_pending or submission_blocked or travel_receipt_state.get("blocks_next_step") else self._can_proceed_review( payload, missing_slot_keys=missing_slot_keys, @@ -1943,7 +1953,15 @@ class UserAgentService: risk_briefs=risk_briefs, can_proceed=can_proceed, document_cards=document_cards, + travel_receipt_state=travel_receipt_state, ) + missing_slot_labels = [SLOT_LABELS.get(key, key) for key in missing_slot_keys] + missing_slot_labels.extend( + str(item) + for item in travel_receipt_state.get("required_missing_labels", []) + if str(item).strip() + ) + missing_slot_labels = list(dict.fromkeys(missing_slot_labels)) return UserAgentReviewPayload( intent_summary=intent_summary, @@ -1951,7 +1969,7 @@ class UserAgentService: scenario=payload.ontology.scenario, intent=payload.ontology.intent, can_proceed=can_proceed, - missing_slots=[SLOT_LABELS.get(key, key) for key in missing_slot_keys], + missing_slots=missing_slot_labels, risk_briefs=risk_briefs, slot_cards=slot_cards, document_cards=document_cards, @@ -2649,6 +2667,230 @@ class UserAgentService: return True return any(keyword in message_context for keyword in ("差旅", "出差", "机票", "火车", "高铁", "酒店", "住宿")) + def _build_travel_receipt_state( + self, + payload: UserAgentRequest, + *, + document_cards: list[UserAgentReviewDocumentCard], + claim_groups: list[UserAgentReviewClaimGroup], + ) -> dict[str, Any]: + empty_state: dict[str, Any] = { + "is_travel_context": False, + "has_long_distance_ticket": False, + "ticket_type_label": "", + "ticket_amount": Decimal("0.00"), + "destination": "", + "days": 1, + "has_hotel_invoice": False, + "has_local_transport": False, + "required_missing_labels": [], + "optional_missing_labels": [], + "blocks_next_step": False, + } + if not document_cards or not self._is_travel_review_context(payload, document_cards, claim_groups): + return empty_state + + long_distance_cards = [card for card in document_cards if self._is_long_distance_travel_card(card)] + if not long_distance_cards: + return { + **empty_state, + "is_travel_context": True, + } + + has_hotel_invoice = any(self._is_review_hotel_card(card) for card in document_cards) + has_local_transport = any(self._is_local_transport_receipt_card(card) for card in document_cards) + required_missing_labels = [] if has_hotel_invoice else ["酒店的报销票据待上传(必须)"] + optional_missing_labels = [] if has_local_transport else ["市内交通/乘车票据可继续上传(非必须)"] + ticket_amount = sum( + (self._extract_amount_decimal_from_card(card) or Decimal("0.00")) + for card in long_distance_cards + ).quantize(Decimal("0.01")) + + return { + **empty_state, + "is_travel_context": True, + "has_long_distance_ticket": True, + "ticket_type_label": self._resolve_travel_ticket_type_label(long_distance_cards), + "ticket_amount": ticket_amount, + "destination": self._resolve_travel_receipt_destination(payload, long_distance_cards), + "days": self._resolve_travel_receipt_days(payload, long_distance_cards), + "has_hotel_invoice": has_hotel_invoice, + "has_local_transport": has_local_transport, + "required_missing_labels": required_missing_labels, + "optional_missing_labels": optional_missing_labels, + "blocks_next_step": bool(required_missing_labels), + } + + @staticmethod + def _is_long_distance_travel_card(card: UserAgentReviewDocumentCard) -> bool: + document_type = str(card.document_type or "").strip().lower() + return document_type in {"train_ticket", "flight_itinerary"} + + @staticmethod + def _is_local_transport_receipt_card(card: UserAgentReviewDocumentCard) -> bool: + document_type = str(card.document_type or "").strip().lower() + suggested_type = str(card.suggested_expense_type or "").strip().lower() + return document_type in {"taxi_receipt", "parking_toll_receipt", "transport_receipt"} or ( + suggested_type == "transport" and document_type not in {"train_ticket", "flight_itinerary"} + ) + + @staticmethod + def _resolve_travel_ticket_type_label(cards: list[UserAgentReviewDocumentCard]) -> str: + labels: list[str] = [] + for card in cards: + document_type = str(card.document_type or "").strip().lower() + if document_type == "train_ticket" and "火车" not in labels: + labels.append("火车") + if document_type == "flight_itinerary" and "飞机" not in labels: + labels.append("飞机") + return "/".join(labels) if labels else "交通" + + def _resolve_travel_receipt_destination( + self, + payload: UserAgentRequest, + long_distance_cards: list[UserAgentReviewDocumentCard], + ) -> str: + for card in long_distance_cards: + for field in card.fields: + if str(field.label or "").strip() not in {"行程", "路线"}: + continue + destination = self._extract_travel_destination_from_route(field.value) + if destination: + return self._normalize_travel_destination(destination) + + card_text = self._build_review_document_card_text(card) + route_match = TRAVEL_ROUTE_PATTERN.search(card_text) + if route_match: + return self._normalize_travel_destination(route_match.group(2)) + + location = self._resolve_location_value(payload) + if location: + return self._normalize_travel_destination(location) + return "" + + @staticmethod + def _extract_travel_destination_from_route(value: str) -> str: + route_text = str(value or "").strip() + if not route_text: + return "" + route_match = TRAVEL_ROUTE_PATTERN.search(route_text) + if route_match: + return route_match.group(2).strip() + parts = [ + item.strip() + for item in re.split(r"\s*(?:至|到|→|->|-|—|~|~)\s*", route_text) + if item.strip() + ] + return parts[-1] if len(parts) >= 2 else "" + + def _normalize_travel_destination(self, value: str) -> str: + candidate = re.sub( + r"(?:火车站|高铁站|动车站|车站|站|机场|航站楼)$", + "", + str(value or "").strip(), + ) + if not candidate: + return "" + try: + policy = ExpenseRuleRuntimeService(self.db).load_catalog().travel_policy + except Exception: + policy = None + if policy is not None: + policy_city = self._extract_policy_city_from_text(candidate, policy) + if policy_city: + return policy_city + return candidate + + def _resolve_travel_receipt_days( + self, + payload: UserAgentRequest, + long_distance_cards: list[UserAgentReviewDocumentCard], + ) -> int: + dates: list[datetime] = [] + for card in long_distance_cards: + card_text = self._build_review_document_card_text(card) + dates.extend(self._extract_dates_from_text(card_text)) + + if dates: + return max(1, (max(dates).date() - min(dates).date()).days + 1) + + start_date = self._parse_date_text(payload.ontology.time_range.start_date or "") + end_date = self._parse_date_text(payload.ontology.time_range.end_date or "") + if start_date and end_date: + return max(1, (end_date.date() - start_date.date()).days + 1) + return 1 + + @staticmethod + def _extract_dates_from_text(text: str) -> list[datetime]: + dates: list[datetime] = [] + for match in DATE_TEXT_PATTERN.finditer(str(text or "")): + parsed = UserAgentService._parse_date_text(match.group(1)) + if parsed is not None: + dates.append(parsed) + return dates + + @staticmethod + def _parse_date_text(value: str) -> datetime | None: + raw_value = str(value or "").strip() + if not raw_value: + return None + normalized = ( + raw_value.replace("年", "-") + .replace("月", "-") + .replace("/", "-") + .replace("日", "") + .strip() + ) + parts = [part for part in normalized.split("-") if part] + if len(parts) != 3: + return None + try: + year, month, day = (int(part) for part in parts) + return datetime(year, month, day) + except ValueError: + return None + + def _build_travel_receipt_briefs( + self, + travel_receipt_state: dict[str, Any], + ) -> list[UserAgentReviewRiskBrief]: + if not travel_receipt_state.get("has_long_distance_ticket"): + return [] + + required_labels = [ + str(item).strip() + for item in travel_receipt_state.get("required_missing_labels", []) + if str(item).strip() + ] + optional_labels = [ + str(item).strip() + for item in travel_receipt_state.get("optional_missing_labels", []) + if str(item).strip() + ] + if not required_labels and not optional_labels: + return [] + + content_parts = [*required_labels, *optional_labels] + required_text = ";".join(required_labels) + optional_text = ";".join(optional_labels) + return [ + UserAgentReviewRiskBrief( + title="差旅票据待补充", + level="warning" if required_labels else "info", + content=";".join(content_parts), + detail=( + "系统已识别到长途交通票据,会按差旅报销口径核对住宿、交通等票据完整性。" + + (f"当前必须补充:{required_text}。" if required_text else "") + + (f"当前还可以补充:{optional_text}。" if optional_text else "") + ), + suggestion=( + "请先补充酒店住宿发票或住宿清单;在补齐前只能保存为草稿。" + if required_labels + else "如还有市内交通、打车、地铁或停车等乘车票据,可以继续上传;没有也可以进入下一步或保存草稿。" + ), + ) + ] + def _resolve_review_travel_allowance_standard( self, policy: RuntimeTravelPolicy, @@ -3008,7 +3250,7 @@ class UserAgentService: if draft_payload is not None and draft_payload.claim_no and not can_proceed: primary_action.description = f"保存后会生成草稿 {draft_payload.claim_no},后续仍可继续补充。" - return [ + actions = [ UserAgentReviewAction( label="取消", action_type="cancel_review", @@ -3021,8 +3263,18 @@ class UserAgentService: description="打开结构化模板,按已识别字段逐项修改。", emphasis="secondary", ), - primary_action, ] + if can_proceed: + actions.append( + UserAgentReviewAction( + label="保存为草稿", + action_type="save_draft", + description="先暂存当前已识别信息,稍后仍可从个人报销继续补充或提交。", + emphasis="secondary", + ) + ) + actions.append(primary_action) + return actions def _build_review_intent_summary( self, @@ -3086,20 +3338,22 @@ class UserAgentService: return "已按您当前确认的信息保存为草稿。后续您可以继续补充缺失项,或修改识别结果后再继续提交。" if review_action == "link_to_existing_draft": document_count = self._resolve_review_document_count(payload) + followup_copy = self._build_review_action_followup_copy(review_payload) if draft_payload is not None and draft_payload.claim_no: return ( f"已将本次上传的 {document_count} 张票据关联到草稿 {draft_payload.claim_no}。" - "您可以继续补充识别字段,确认无误后再提交审批。" + f"{followup_copy or '您可以继续补充识别字段,确认无误后再提交审批。'}" ) - return "已将本次上传的票据关联到现有草稿。您可以继续补充识别字段,确认无误后再提交审批。" + return f"已将本次上传的票据关联到现有草稿。{followup_copy or '您可以继续补充识别字段,确认无误后再提交审批。'}" if review_action == "create_new_claim_from_documents": document_count = self._resolve_review_document_count(payload) + followup_copy = self._build_review_action_followup_copy(review_payload) if draft_payload is not None and draft_payload.claim_no: return ( f"已按当前上传的 {document_count} 张票据新建报销草稿 {draft_payload.claim_no}。" - "您可以继续补充识别字段,确认无误后再提交审批。" + f"{followup_copy or '您可以继续补充识别字段,确认无误后再提交审批。'}" ) - return "已按当前上传票据新建报销草稿。您可以继续补充识别字段,确认无误后再提交审批。" + return f"已按当前上传票据新建报销草稿。{followup_copy or '您可以继续补充识别字段,确认无误后再提交审批。'}" if review_action == "next_step": if draft_payload is not None and draft_payload.status == "submitted": stage_text = draft_payload.approval_stage or "审批中" @@ -3135,6 +3389,7 @@ class UserAgentService: risk_briefs: list[UserAgentReviewRiskBrief], can_proceed: bool, document_cards: list[UserAgentReviewDocumentCard], + travel_receipt_state: dict[str, Any] | None = None, ) -> str: if self._is_review_association_choice_pending(payload): claim_no = str(payload.tool_payload.get("association_candidate_claim_no") or "").strip() @@ -3157,13 +3412,30 @@ class UserAgentService: "请先根据风险提示补充原因、调整金额或更换附件,整改后再继续提交。" ) + travel_message = self._build_travel_receipt_guidance_message( + payload, + travel_receipt_state=travel_receipt_state or {}, + can_proceed=can_proceed, + ) + if travel_message: + return travel_message + + missing_labels = self._resolve_review_missing_slot_labels(slot_cards) + if travel_receipt_state: + missing_labels.extend( + str(item) + for item in travel_receipt_state.get("required_missing_labels", []) + if str(item).strip() + ) + missing_labels = list(dict.fromkeys(missing_labels)) + review_payload = UserAgentReviewPayload( intent_summary="", body_message="", scenario=payload.ontology.scenario, intent=payload.ontology.intent, can_proceed=can_proceed, - missing_slots=self._resolve_review_missing_slot_labels(slot_cards), + missing_slots=missing_labels, risk_briefs=risk_briefs, slot_cards=slot_cards, document_cards=[], @@ -3176,6 +3448,155 @@ class UserAgentService: f"{self._build_review_guidance_copy(review_payload, mention_save_draft=not can_proceed)}" ) + @staticmethod + def _build_review_action_followup_copy(review_payload: UserAgentReviewPayload) -> str: + missing_slots = [str(item).strip() for item in review_payload.missing_slots if str(item).strip()] + receipt_briefs = [ + item + for item in review_payload.risk_briefs + if "差旅票据待补充" in str(item.title or "") + ] + if missing_slots: + return f"当前仍有 {'、'.join(missing_slots)},暂时只能保存为草稿,补齐后再继续下一步。" + if receipt_briefs: + return "当前必需票据已具备;如还有市内交通、打车、地铁或停车等乘车票据,可以继续上传,也可以继续下一步或保存草稿。" + if review_payload.can_proceed: + return "当前信息已较完整,您可以继续下一步,也可以先保存为草稿。" + return "" + + def _build_travel_receipt_guidance_message( + self, + payload: UserAgentRequest, + *, + travel_receipt_state: dict[str, Any], + can_proceed: bool, + ) -> str: + review_action = str(payload.context_json.get("review_action") or "").strip() + if review_action or not travel_receipt_state.get("has_long_distance_ticket"): + return "" + + employee = self._resolve_employee_profile(payload) + user_name = ( + str(employee.name).strip() + if employee is not None and employee.name + else str(payload.context_json.get("name") or payload.user_id or "同事").strip() + ) + destination = str(travel_receipt_state.get("destination") or "待确认").strip() + days = max(1, int(travel_receipt_state.get("days") or 1)) + ticket_type_label = str(travel_receipt_state.get("ticket_type_label") or "交通").strip() + ticket_amount = self._coerce_decimal_money(travel_receipt_state.get("ticket_amount")) + + required_labels = [ + str(item).strip() + for item in travel_receipt_state.get("required_missing_labels", []) + if str(item).strip() + ] + optional_labels = [ + str(item).strip() + for item in travel_receipt_state.get("optional_missing_labels", []) + if str(item).strip() + ] + + lines = [ + f"您好:{user_name},根据您提交的票据信息,您可能出差的地点为 {destination},天数为:{days} 天。", + f"根据票据,您现在提交的是{ticket_type_label}票,一共金额为:{self._format_decimal_money(ticket_amount)} 元。", + ] + + provide_items: list[str] = [] + if required_labels: + provide_items.append("1. 酒店住宿发票/住宿清单(必须,当前待上传)") + if optional_labels: + provide_items.append(f"{len(provide_items) + 1}. 市内交通/乘车票据(非必须,如打车、地铁、停车等)") + if provide_items: + lines.append("根据公司相关报销制度,您还可以继续提供:\n" + "\n".join(provide_items)) + else: + lines.append("根据公司相关报销制度,当前核心票据已较完整,无需继续上传票据。") + + if required_labels: + lines.append("酒店票据仍缺失,所以暂时不能继续下一步;您可以先保存为草稿,补齐后再提交。") + elif can_proceed and optional_labels: + lines.append("当前必需票据已具备;如暂时没有乘车票据,也可以继续下一步,或先保存为草稿。") + elif can_proceed: + lines.append("当前信息已较完整,确认无误后可以继续下一步,也可以先保存为草稿。") + + estimate_copy = self._build_travel_receipt_estimate_copy( + payload, + travel_receipt_state=travel_receipt_state, + ) + if estimate_copy: + lines.append(estimate_copy) + return "\n".join(line for line in lines if line) + + def _build_travel_receipt_estimate_copy( + self, + payload: UserAgentRequest, + *, + travel_receipt_state: dict[str, Any], + ) -> str: + destination = str(travel_receipt_state.get("destination") or "").strip() + days = max(1, int(travel_receipt_state.get("days") or 1)) + ticket_type_label = str(travel_receipt_state.get("ticket_type_label") or "交通").strip() + ticket_amount = self._coerce_decimal_money(travel_receipt_state.get("ticket_amount")) + employee = self._resolve_employee_profile(payload) + grade = self._resolve_review_employee_grade(payload, employee=employee) + + if not destination or not grade: + return ( + "根据公司差旅费报销依据," + f"您的职级为:{grade or '待确认'},去{destination or '出差地点待确认'}," + f"当前可确认的{ticket_type_label}票据金额为:{self._format_decimal_money(ticket_amount)} 元;" + "住宿和补贴金额需补齐职级或地点后再核算。" + ) + + current_user = CurrentUserContext( + username=str(payload.user_id or payload.context_json.get("name") or "anonymous").strip() or "anonymous", + name=str(payload.context_json.get("name") or payload.user_id or "anonymous").strip() or "anonymous", + role_codes=[ + str(item).strip() + for item in list(payload.context_json.get("role_codes") or []) + if str(item).strip() + ], + is_admin=bool(payload.context_json.get("is_admin")), + department_name=str(payload.context_json.get("department_name") or payload.context_json.get("department") or "").strip(), + ) + try: + calculation = TravelReimbursementCalculatorService(self.db).calculate( + TravelReimbursementCalculatorRequest(days=days, location=destination, grade=grade), + current_user, + ) + except Exception: + return ( + "根据公司差旅费报销依据," + f"您的职级为:{grade},去{destination},当前可确认的{ticket_type_label}票据金额为:" + f"{self._format_decimal_money(ticket_amount)} 元;住宿和补贴标准暂时无法自动测算,请以规则中心最新差旅标准为准。" + ) + + total_amount = ( + ticket_amount + + self._coerce_decimal_money(calculation.hotel_amount) + + self._coerce_decimal_money(calculation.allowance_amount) + ).quantize(Decimal("0.01")) + return ( + "根据公司差旅费报销依据," + f"您的职级为:{calculation.grade},去{calculation.matched_city or destination}," + "报销费用核算约为:" + f"已提交{ticket_type_label} {self._format_decimal_money(ticket_amount)} 元 + " + f"住宿标准 {self._format_decimal_money(calculation.hotel_rate)} 元/天 × {calculation.days} 天 + " + f"出差补贴 {self._format_decimal_money(calculation.total_allowance_rate)} 元/天 × {calculation.days} 天 = " + f"{self._format_decimal_money(total_amount)} 元。" + ) + + @staticmethod + def _coerce_decimal_money(value: Any) -> Decimal: + try: + return Decimal(str(value or "0")).quantize(Decimal("0.01")) + except (InvalidOperation, ValueError): + return Decimal("0.00") + + @staticmethod + def _format_decimal_money(value: Any) -> str: + return f"{UserAgentService._coerce_decimal_money(value):.2f}" + @staticmethod def _resolve_review_missing_slot_labels( slot_cards: list[UserAgentReviewSlotCard], @@ -4076,16 +4497,11 @@ class UserAgentService: merchant_value = "" for document in ocr_documents: - if str(document.get("document_type") or "").strip().lower() != "hotel_invoice": + if not self._is_hotel_document_item(document): continue merchant_value = self._extract_document_merchant_name(document) if merchant_value: break - if not merchant_value: - for document in ocr_documents: - merchant_value = self._extract_document_merchant_name(document) - if merchant_value: - break if merchant_value: return self._build_slot_value( value=merchant_value, @@ -4407,6 +4823,8 @@ class UserAgentService: label=display_label, value=value, ) + if display_label == "商户/酒店" and not self._is_hotel_document_item(item): + continue if display_label and normalized_value: normalized_fields.setdefault(display_label, normalized_value) @@ -4418,7 +4836,7 @@ class UserAgentService: if date_match and "时间" not in normalized_fields: normalized_fields["时间"] = date_match.group(1) - merchant = self._extract_document_merchant_name_from_text(text) + merchant = self._extract_document_merchant_name_from_text(text) if self._is_hotel_document_item(item) else "" if merchant and "商户/酒店" not in normalized_fields: normalized_fields["商户/酒店"] = merchant return normalized_fields @@ -4484,9 +4902,25 @@ class UserAgentService: merchant = str(fields.get("商户/酒店") or "").strip() if merchant: return merchant + if not self._is_hotel_document_item(item): + return "" text = " ".join([str(item.get("summary") or ""), str(item.get("text") or "")]).strip() return self._extract_document_merchant_name_from_text(text) + @staticmethod + def _is_hotel_document_item(item: dict[str, object]) -> bool: + document_type = str(item.get("document_type") or "").strip().lower() + scene_code = str(item.get("scene_code") or "").strip().lower() + scene_label = str(item.get("scene_label") or "").strip() + suggested_expense_type = str(item.get("suggested_expense_type") or "").strip().lower() + return ( + document_type == "hotel_invoice" + or scene_code == "hotel" + or suggested_expense_type == "hotel" + or "住宿" in scene_label + or "酒店" in scene_label + ) + @staticmethod def _extract_document_merchant_name_from_text(text: str) -> str: for keyword in ("酒店", "宾馆", "饭店", "酒楼", "餐厅", "航空", "铁路", "滴滴"): diff --git a/server/storage/expense_claims/193e6c44-29f7-4ac9-9d64-c57ddfd186c0/f8e2b572-9f9f-472f-957c-cb49c5e1e283/发票_3_京S98876.pdf b/server/storage/expense_claims/193e6c44-29f7-4ac9-9d64-c57ddfd186c0/f8e2b572-9f9f-472f-957c-cb49c5e1e283/发票_3_京S98876.pdf deleted file mode 100644 index d2aad1702db5e6ce30305743a435e166117d6165..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61170 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 diff --git a/server/storage/expense_claims/193e6c44-29f7-4ac9-9d64-c57ddfd186c0/f8e2b572-9f9f-472f-957c-cb49c5e1e283/发票_3_京S98876.pdf.meta.json b/server/storage/expense_claims/193e6c44-29f7-4ac9-9d64-c57ddfd186c0/f8e2b572-9f9f-472f-957c-cb49c5e1e283/发票_3_京S98876.pdf.meta.json deleted file mode 100644 index e44c696..0000000 --- a/server/storage/expense_claims/193e6c44-29f7-4ac9-9d64-c57ddfd186c0/f8e2b572-9f9f-472f-957c-cb49c5e1e283/发票_3_京S98876.pdf.meta.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "file_name": "发票_3_京S98876.pdf", - "storage_key": "193e6c44-29f7-4ac9-9d64-c57ddfd186c0/f8e2b572-9f9f-472f-957c-cb49c5e1e283/发票_3_京S98876.pdf", - "media_type": "application/pdf", - "size_bytes": 61170, - "uploaded_at": "2026-05-20T12:25:49.243144+00:00", - "previewable": true, - "preview_kind": "image", - "preview_storage_key": "193e6c44-29f7-4ac9-9d64-c57ddfd186c0/f8e2b572-9f9f-472f-957c-cb49c5e1e283/发票_3_京S98876.preview.png", - "preview_media_type": "image/png", - "preview_file_name": "发票_3_京S98876.preview.png", - "analysis": { - "severity": "pass", - "label": "AI提示符合条件", - "headline": "AI提示:附件符合基础校验条件", - "summary": "已识别到票据类型和关键字段,且符合当前费用场景的附件要求。", - "points": [ - "票据类型:已识别为增值税发票。", - "附件类型要求:当前费用项目为交通费,已识别为增值税发票,符合当前交通费场景的附件要求。", - "金额字段:已识别到与当前明细接近的金额 121.54 元。" - ], - "suggestion": "建议继续核对报销分类、费用说明和业务场景是否一致。" - }, - "document_info": { - "document_type": "vat_invoice", - "document_type_label": "增值税发票", - "scene_code": "other", - "scene_label": "通用发票", - "fields": [ - { - "key": "amount", - "label": "金额", - "value": "121.54元" - }, - { - "key": "date", - "label": "日期", - "value": "2026-03-04" - }, - { - "key": "merchant_name", - "label": "商户", - "value": "信息" - }, - { - "key": "invoice_number", - "label": "票据号码", - "value": "26427004426998871533" - } - ] - }, - "requirement_check": { - "matches": true, - "current_expense_type": "transport", - "current_expense_type_label": "交通费", - "allowed_scene_labels": [ - "交通" - ], - "allowed_document_type_labels": [ - "停车/通行费票据", - "一般收据/凭证", - "出租车/网约车票据", - "增值税发票" - ], - "recognized_scene_code": "other", - "recognized_scene_label": "通用发票", - "recognized_document_type": "vat_invoice", - "recognized_document_type_label": "增值税发票", - "mismatch_severity": "high", - "rule_code": "rule.expense.scene_submission_standard", - "rule_name": "报销场景提交与附件标准", - "message": "当前费用项目为交通费,已识别为增值税发票,符合当前交通费场景的附件要求。" - }, - "ocr_status": "recognized", - "ocr_error": "", - "ocr_text": "发票号码:26427004426998871533\n旅普发票)\n电子发票\n开票日期:2026年03月04日\n购买方信息\n名称:北京京能电力股份有限公司\n销售方信息\n名称:北京小桔科技有限公司\n统一社会信用代码/纳税人识别1:110000717734559Y\n统一社会信用代码/纳税人识别1:110108MA00293G5X\n项目名称\n单价\n数量\n金额\n税率/征收率\n税额\n*运输服务*客运服务费\n118.00\n1\n118.00\n3%\n3.54\n合\n计\n¥118.00\n¥3.54\n出行人\n有效身份证件号\n出行日期\n出发地\n到达地\n等级\n交通工具\n类\n2026-03-04\n小汤山酒店\n林萃花园南门\n网约车\n价税合计(大写)\n壹佰贰拾壹圆伍角肆分\n(小写)¥121.54\n购方开户银行:-;\n银行账号:-;\n备注\n销方开户银行:中国建设银行北京中关村支行;\n银行账号:11001006500059041897;\n开票人:系统自动开票", - "ocr_summary": "发票号码:26427004426998871533;旅普发票);电子发票", - "ocr_avg_score": 0.9825071743194093, - "ocr_line_count": 47, - "ocr_classification_source": "rule", - "ocr_classification_confidence": 0.74, - "ocr_classification_evidence": [ - "发票号码", - "价税合计", - "电子发票" - ], - "ocr_warnings": [] -} \ No newline at end of file diff --git a/server/storage/expense_claims/193e6c44-29f7-4ac9-9d64-c57ddfd186c0/f8e2b572-9f9f-472f-957c-cb49c5e1e283/发票_3_京S98876.preview.png b/server/storage/expense_claims/193e6c44-29f7-4ac9-9d64-c57ddfd186c0/f8e2b572-9f9f-472f-957c-cb49c5e1e283/发票_3_京S98876.preview.png deleted file mode 100644 index 1b02f70ba1c79eaeb19a8c546ab02dc5fea7afb1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 146315 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 GUjGL~s?NLs diff --git a/server/storage/expense_claims/08f51e80-512e-498e-bcd6-50ca5d0becfc/62fe16f9-ad9f-4f96-948f-0b31a427a81d/2月20_武汉-上海.pdf b/server/storage/expense_claims/3754b9c8-e0f0-4d88-a24c-d52c7620be2c/3d643ccb-cfb5-48c5-8037-39dbe1fa87e4/2月20_武汉-上海.pdf similarity index 100% rename from server/storage/expense_claims/08f51e80-512e-498e-bcd6-50ca5d0becfc/62fe16f9-ad9f-4f96-948f-0b31a427a81d/2月20_武汉-上海.pdf rename to server/storage/expense_claims/3754b9c8-e0f0-4d88-a24c-d52c7620be2c/3d643ccb-cfb5-48c5-8037-39dbe1fa87e4/2月20_武汉-上海.pdf diff --git a/server/storage/expense_claims/08f51e80-512e-498e-bcd6-50ca5d0becfc/62fe16f9-ad9f-4f96-948f-0b31a427a81d/2月20_武汉-上海.pdf.meta.json b/server/storage/expense_claims/3754b9c8-e0f0-4d88-a24c-d52c7620be2c/3d643ccb-cfb5-48c5-8037-39dbe1fa87e4/2月20_武汉-上海.pdf.meta.json similarity index 76% rename from server/storage/expense_claims/08f51e80-512e-498e-bcd6-50ca5d0becfc/62fe16f9-ad9f-4f96-948f-0b31a427a81d/2月20_武汉-上海.pdf.meta.json rename to server/storage/expense_claims/3754b9c8-e0f0-4d88-a24c-d52c7620be2c/3d643ccb-cfb5-48c5-8037-39dbe1fa87e4/2月20_武汉-上海.pdf.meta.json index 496127b..d25173f 100644 --- a/server/storage/expense_claims/08f51e80-512e-498e-bcd6-50ca5d0becfc/62fe16f9-ad9f-4f96-948f-0b31a427a81d/2月20_武汉-上海.pdf.meta.json +++ b/server/storage/expense_claims/3754b9c8-e0f0-4d88-a24c-d52c7620be2c/3d643ccb-cfb5-48c5-8037-39dbe1fa87e4/2月20_武汉-上海.pdf.meta.json @@ -1,12 +1,12 @@ { "file_name": "2月20_武汉-上海.pdf", - "storage_key": "08f51e80-512e-498e-bcd6-50ca5d0becfc/62fe16f9-ad9f-4f96-948f-0b31a427a81d/2月20_武汉-上海.pdf", + "storage_key": "3754b9c8-e0f0-4d88-a24c-d52c7620be2c/3d643ccb-cfb5-48c5-8037-39dbe1fa87e4/2月20_武汉-上海.pdf", "media_type": "application/pdf", "size_bytes": 24995, - "uploaded_at": "2026-05-20T13:48:21.652497+00:00", + "uploaded_at": "2026-05-21T01:54:55.627221+00:00", "previewable": true, "preview_kind": "image", - "preview_storage_key": "08f51e80-512e-498e-bcd6-50ca5d0becfc/62fe16f9-ad9f-4f96-948f-0b31a427a81d/2月20_武汉-上海.preview.png", + "preview_storage_key": "3754b9c8-e0f0-4d88-a24c-d52c7620be2c/3d643ccb-cfb5-48c5-8037-39dbe1fa87e4/2月20_武汉-上海.preview.png", "preview_media_type": "image/png", "preview_file_name": "2月20_武汉-上海.preview.png", "analysis": { @@ -15,7 +15,7 @@ "headline": "AI提示:附件存在明显待整改项", "summary": "当前附件可见部分内容,但金额、用途、日期或附件类型仍有缺失或不一致。", "points": [ - "用途字段:用户填写用途“业务发生时间:2026-02-20 至 2026”与票据内容不一致,当前附件更像交通相关材料。" + "用途字段:用户填写用途“至 2026-02-23,支撑上海电力项目部署,”与票据内容不一致,当前附件更像交通相关材料。" ], "suggestion": "建议根据风险点补齐清晰票据,或修正金额、日期、费用说明后再提交。" }, @@ -54,15 +54,10 @@ }, "requirement_check": { "matches": true, - "current_expense_type": "travel", - "current_expense_type_label": "差旅费", - "allowed_scene_labels": [ - "差旅" - ], - "allowed_document_type_labels": [ - "机票/航班行程单", - "火车/高铁票" - ], + "current_expense_type": "train_ticket", + "current_expense_type_label": "火车票", + "allowed_scene_labels": [], + "allowed_document_type_labels": [], "recognized_scene_code": "travel", "recognized_scene_label": "差旅票据", "recognized_document_type": "train_ticket", @@ -70,7 +65,7 @@ "mismatch_severity": "high", "rule_code": "rule.expense.scene_submission_standard", "rule_name": "报销场景提交与附件标准", - "message": "当前费用项目为差旅费,已识别为火车/高铁票,符合当前差旅费场景的附件要求。" + "message": "当前费用项目为火车票,已识别为火车/高铁票。" }, "ocr_status": "recognized", "ocr_error": "", diff --git a/server/storage/expense_claims/08f51e80-512e-498e-bcd6-50ca5d0becfc/62fe16f9-ad9f-4f96-948f-0b31a427a81d/2月20_武汉-上海.preview.png b/server/storage/expense_claims/3754b9c8-e0f0-4d88-a24c-d52c7620be2c/3d643ccb-cfb5-48c5-8037-39dbe1fa87e4/2月20_武汉-上海.preview.png similarity index 100% rename from server/storage/expense_claims/08f51e80-512e-498e-bcd6-50ca5d0becfc/62fe16f9-ad9f-4f96-948f-0b31a427a81d/2月20_武汉-上海.preview.png rename to server/storage/expense_claims/3754b9c8-e0f0-4d88-a24c-d52c7620be2c/3d643ccb-cfb5-48c5-8037-39dbe1fa87e4/2月20_武汉-上海.preview.png diff --git a/server/storage/expense_claims/08f51e80-512e-498e-bcd6-50ca5d0becfc/1170b632-ad59-46c0-9876-7230d9d97e30/2月23_上海-武汉.pdf b/server/storage/expense_claims/3754b9c8-e0f0-4d88-a24c-d52c7620be2c/a8d8e56b-8e0c-4feb-9371-1e3cd71ce25b/2月23_上海-武汉.pdf similarity index 100% rename from server/storage/expense_claims/08f51e80-512e-498e-bcd6-50ca5d0becfc/1170b632-ad59-46c0-9876-7230d9d97e30/2月23_上海-武汉.pdf rename to server/storage/expense_claims/3754b9c8-e0f0-4d88-a24c-d52c7620be2c/a8d8e56b-8e0c-4feb-9371-1e3cd71ce25b/2月23_上海-武汉.pdf diff --git a/server/storage/expense_claims/08f51e80-512e-498e-bcd6-50ca5d0becfc/1170b632-ad59-46c0-9876-7230d9d97e30/2月23_上海-武汉.pdf.meta.json b/server/storage/expense_claims/3754b9c8-e0f0-4d88-a24c-d52c7620be2c/a8d8e56b-8e0c-4feb-9371-1e3cd71ce25b/2月23_上海-武汉.pdf.meta.json similarity index 76% rename from server/storage/expense_claims/08f51e80-512e-498e-bcd6-50ca5d0becfc/1170b632-ad59-46c0-9876-7230d9d97e30/2月23_上海-武汉.pdf.meta.json rename to server/storage/expense_claims/3754b9c8-e0f0-4d88-a24c-d52c7620be2c/a8d8e56b-8e0c-4feb-9371-1e3cd71ce25b/2月23_上海-武汉.pdf.meta.json index b2e8892..8eff481 100644 --- a/server/storage/expense_claims/08f51e80-512e-498e-bcd6-50ca5d0becfc/1170b632-ad59-46c0-9876-7230d9d97e30/2月23_上海-武汉.pdf.meta.json +++ b/server/storage/expense_claims/3754b9c8-e0f0-4d88-a24c-d52c7620be2c/a8d8e56b-8e0c-4feb-9371-1e3cd71ce25b/2月23_上海-武汉.pdf.meta.json @@ -1,12 +1,12 @@ { "file_name": "2月23_上海-武汉.pdf", - "storage_key": "08f51e80-512e-498e-bcd6-50ca5d0becfc/1170b632-ad59-46c0-9876-7230d9d97e30/2月23_上海-武汉.pdf", + "storage_key": "3754b9c8-e0f0-4d88-a24c-d52c7620be2c/a8d8e56b-8e0c-4feb-9371-1e3cd71ce25b/2月23_上海-武汉.pdf", "media_type": "application/pdf", "size_bytes": 24940, - "uploaded_at": "2026-05-20T13:48:38.616319+00:00", + "uploaded_at": "2026-05-21T01:55:11.468967+00:00", "previewable": true, "preview_kind": "image", - "preview_storage_key": "08f51e80-512e-498e-bcd6-50ca5d0becfc/1170b632-ad59-46c0-9876-7230d9d97e30/2月23_上海-武汉.preview.png", + "preview_storage_key": "3754b9c8-e0f0-4d88-a24c-d52c7620be2c/a8d8e56b-8e0c-4feb-9371-1e3cd71ce25b/2月23_上海-武汉.preview.png", "preview_media_type": "image/png", "preview_file_name": "2月23_上海-武汉.preview.png", "analysis": { @@ -15,7 +15,7 @@ "headline": "AI提示:附件存在明显待整改项", "summary": "当前附件可见部分内容,但金额、用途、日期或附件类型仍有缺失或不一致。", "points": [ - "用途字段:用户填写用途“业务发生时间:2026-02-20 至 2026”与票据内容不一致,当前附件更像交通相关材料。" + "用途字段:用户填写用途“至 2026-02-23,支撑上海电力项目部署,”与票据内容不一致,当前附件更像交通相关材料。" ], "suggestion": "建议根据风险点补齐清晰票据,或修正金额、日期、费用说明后再提交。" }, @@ -54,15 +54,10 @@ }, "requirement_check": { "matches": true, - "current_expense_type": "travel", - "current_expense_type_label": "差旅费", - "allowed_scene_labels": [ - "差旅" - ], - "allowed_document_type_labels": [ - "机票/航班行程单", - "火车/高铁票" - ], + "current_expense_type": "train_ticket", + "current_expense_type_label": "火车票", + "allowed_scene_labels": [], + "allowed_document_type_labels": [], "recognized_scene_code": "travel", "recognized_scene_label": "差旅票据", "recognized_document_type": "train_ticket", @@ -70,7 +65,7 @@ "mismatch_severity": "high", "rule_code": "rule.expense.scene_submission_standard", "rule_name": "报销场景提交与附件标准", - "message": "当前费用项目为差旅费,已识别为火车/高铁票,符合当前差旅费场景的附件要求。" + "message": "当前费用项目为火车票,已识别为火车/高铁票。" }, "ocr_status": "recognized", "ocr_error": "", diff --git a/server/storage/expense_claims/08f51e80-512e-498e-bcd6-50ca5d0becfc/1170b632-ad59-46c0-9876-7230d9d97e30/2月23_上海-武汉.preview.png b/server/storage/expense_claims/3754b9c8-e0f0-4d88-a24c-d52c7620be2c/a8d8e56b-8e0c-4feb-9371-1e3cd71ce25b/2月23_上海-武汉.preview.png similarity index 100% rename from server/storage/expense_claims/08f51e80-512e-498e-bcd6-50ca5d0becfc/1170b632-ad59-46c0-9876-7230d9d97e30/2月23_上海-武汉.preview.png rename to server/storage/expense_claims/3754b9c8-e0f0-4d88-a24c-d52c7620be2c/a8d8e56b-8e0c-4feb-9371-1e3cd71ce25b/2月23_上海-武汉.preview.png diff --git a/server/tests/test_expense_claim_service.py b/server/tests/test_expense_claim_service.py index 2f25967..892e9df 100644 --- a/server/tests/test_expense_claim_service.py +++ b/server/tests/test_expense_claim_service.py @@ -15,7 +15,7 @@ from app.models.financial_record import ExpenseClaim, ExpenseClaimItem from app.models.organization import OrganizationUnit from app.schemas.ontology import OntologyParseRequest from app.schemas.ocr import OcrRecognizeBatchRead, OcrRecognizeDocumentRead -from app.schemas.reimbursement import ExpenseClaimItemCreate, ExpenseClaimItemUpdate +from app.schemas.reimbursement import ExpenseClaimItemCreate, ExpenseClaimItemUpdate, ExpenseClaimUpdate from app.services.agent_conversations import AgentConversationService from app.services.expense_claims import ExpenseClaimService from app.services.ontology import SemanticOntologyService @@ -405,6 +405,92 @@ def test_upsert_draft_from_ontology_supports_link_or_create_for_multi_documents( assert float(new_claim.amount) == 50.5 +def test_upsert_travel_draft_uses_ticket_item_types_and_auto_allowance() -> None: + user_id = "travel-allowance@example.com" + + with build_session() as db: + employee = Employee( + employee_no="E5010", + name="差旅员工", + email=user_id, + grade="P4", + ) + db.add(employee) + db.commit() + + ontology = SemanticOntologyService(db).parse( + OntologyParseRequest( + query="我去北京出差 3 天,上传了火车票,帮我生成差旅费报销草稿", + user_id=user_id, + ) + ) + result = ExpenseClaimService(db).upsert_draft_from_ontology( + run_id=ontology.run_id, + user_id=user_id, + message="我去北京出差 3 天,上传了火车票,帮我生成差旅费报销草稿", + ontology=ontology, + context_json={ + "name": "差旅员工", + "grade": "P4", + "attachment_names": ["train-ticket.png"], + "attachment_count": 1, + "review_form_values": { + "expense_type": "差旅费", + "location": "北京", + "time_range": "2026-05-13 至 2026-05-15", + }, + "business_time_context": { + "mode": "range", + "start_date": "2026-05-13", + "end_date": "2026-05-15", + "display_value": "2026-05-13 至 2026-05-15", + }, + "ocr_documents": [ + { + "filename": "train-ticket.png", + "document_type": "train_ticket", + "document_type_label": "火车/高铁票", + "scene_code": "travel", + "scene_label": "差旅费", + "summary": "中国铁路电子客票 广州南-北京南 二等座 票价 354 元", + "text": "中国铁路电子客票 广州南-北京南 二等座 票价:¥354.00", + "document_fields": [ + {"key": "amount", "label": "票价", "value": "¥354.00"}, + {"key": "route", "label": "行程", "value": "广州南-北京南"}, + ], + } + ], + }, + ) + + claim = db.get(ExpenseClaim, result["claim_id"]) + assert claim is not None + assert claim.expense_type == "travel" + assert claim.invoice_count == 1 + assert len(claim.items) == 2 + train_item = next(item for item in claim.items if item.item_type == "train_ticket") + allowance_item = next(item for item in claim.items if item.item_type == "travel_allowance") + assert train_item.item_amount == Decimal("354.00") + assert train_item.item_reason == "从广州南到北京南" + assert allowance_item.item_amount == Decimal("300.00") + assert allowance_item.invoice_id is None + assert allowance_item.is_system_generated is True + assert claim.amount == Decimal("654.00") + + with pytest.raises(ValueError, match="系统自动计算"): + ExpenseClaimService(db).update_claim_item( + claim_id=claim.id, + item_id=allowance_item.id, + payload=ExpenseClaimItemUpdate(item_amount=Decimal("1.00")), + current_user=CurrentUserContext( + username=user_id, + name="差旅员工", + role_codes=[], + is_admin=False, + ), + ) + + def test_upsert_draft_from_ontology_updates_returned_claim_and_preserves_return_events() -> None: user_id = "returned-owner@example.com" return_flag = { @@ -635,6 +721,42 @@ def test_create_claim_item_adds_blank_draft_row_without_forcing_attachment() -> assert new_item.invoice_id is None +def test_update_claim_reason_only_allows_draft_pending_submission() -> None: + current_user = CurrentUserContext( + username="emp-1", + name="张三", + role_codes=[], + is_admin=False, + ) + + with build_session() as db: + claim = build_claim(expense_type="travel", location="北京") + db.add(claim) + db.commit() + + service = ExpenseClaimService(db) + updated = service.update_claim( + claim_id=claim.id, + payload=ExpenseClaimUpdate(reason="去北京客户现场出差,处理项目验收事项"), + current_user=current_user, + ) + + assert updated is not None + assert updated.reason == "去北京客户现场出差,处理项目验收事项" + + claim.status = "submitted" + claim.submitted_at = datetime(2026, 5, 14, tzinfo=UTC) + claim.approval_stage = "直属领导审批" + db.commit() + + with pytest.raises(ValueError, match="草稿待提交"): + service.update_claim( + claim_id=claim.id, + payload=ExpenseClaimUpdate(reason="提交后不能改"), + current_user=current_user, + ) + + def test_update_claim_item_reanalyzes_existing_attachment(monkeypatch, tmp_path) -> None: current_user = CurrentUserContext( username="emp-1", @@ -785,6 +907,8 @@ def test_upload_train_ticket_attachment_backfills_item_amount(monkeypatch, tmp_p assert updated["claim_amount"] == Decimal("354.00") db.refresh(claim) assert claim.items[0].item_amount == Decimal("354.00") + assert claim.items[0].item_type == "train_ticket" + assert claim.items[0].item_reason == "从广州南到北京南" assert claim.amount == Decimal("354.00") uploaded_meta = service.get_claim_item_attachment_meta( claim_id=claim.id, @@ -799,6 +923,75 @@ def test_upload_train_ticket_attachment_backfills_item_amount(monkeypatch, tmp_p ) +def test_upload_ride_receipt_backfills_item_reason_from_addresses(monkeypatch, tmp_path) -> None: + current_user = CurrentUserContext( + username="emp-1", + name="张三", + role_codes=[], + is_admin=False, + ) + + def fake_recognize( + self, + files: list[tuple[str, bytes, str | None]], + ) -> OcrRecognizeBatchRead: + return OcrRecognizeBatchRead( + total_file_count=1, + success_count=1, + documents=[ + OcrRecognizeDocumentRead( + filename="ride-receipt.png", + media_type="image/png", + text="滴滴出行订单 起点:深圳北站 终点:腾讯滨海大厦 实付金额:42.00元", + summary="滴滴出行乘车票据,深圳北站到腾讯滨海大厦,金额 42 元。", + avg_score=0.98, + line_count=1, + page_count=1, + document_type="taxi_receipt", + document_type_label="出租车/网约车票据", + scene_code="transport", + scene_label="交通票据", + document_fields=[ + {"key": "start_location", "label": "起点", "value": "深圳北站"}, + {"key": "end_location", "label": "终点", "value": "腾讯滨海大厦"}, + {"key": "amount", "label": "实付金额", "value": "42.00元"}, + ], + ) + ], + ) + + monkeypatch.setattr(OcrService, "recognize_files", fake_recognize) + monkeypatch.setattr(ExpenseClaimService, "_get_attachment_storage_root", lambda self: tmp_path) + + with build_session() as db: + claim = build_claim(expense_type="transport", location="深圳") + claim.amount = Decimal("0.00") + claim.invoice_count = 0 + claim.items[0].item_type = "transport" + claim.items[0].item_reason = "打车报销" + claim.items[0].item_amount = Decimal("0.00") + claim.items[0].invoice_id = None + db.add(claim) + db.commit() + + service = ExpenseClaimService(db) + updated = service.upload_claim_item_attachment( + claim_id=claim.id, + item_id=claim.items[0].id, + filename="ride-receipt.png", + content=b"fake-image-bytes", + media_type="image/png", + current_user=current_user, + ) + + assert updated is not None + db.refresh(claim) + assert claim.items[0].item_type == "ride_ticket" + assert claim.items[0].item_reason == "从深圳北站到腾讯滨海大厦" + assert claim.items[0].item_amount == Decimal("42.00") + assert claim.amount == Decimal("42.00") + + def test_delete_claim_item_removes_row_and_attachment_files(monkeypatch, tmp_path) -> None: current_user = CurrentUserContext( username="emp-1", diff --git a/server/tests/test_user_agent_service.py b/server/tests/test_user_agent_service.py index d407c9a..6c63ccb 100644 --- a/server/tests/test_user_agent_service.py +++ b/server/tests/test_user_agent_service.py @@ -1315,6 +1315,230 @@ def test_user_agent_review_payload_prefers_hotel_invoice_for_hotel_name() -> Non assert slot_map["merchant_name"].value == "北京中心酒店" +def test_user_agent_review_payload_does_not_fill_hotel_name_from_train_ticket() -> None: + session_factory = build_session_factory() + with session_factory() as db: + query = "我去北京出差,先上传一张火车票,酒店发票还没上传,帮我生成差旅费报销草稿" + context = { + "name": "张三", + "grade": "P4", + "attachment_names": ["北京南站火车票.png"], + "attachment_count": 1, + "ocr_documents": [ + { + "filename": "北京南站火车票.png", + "document_type": "train_ticket", + "scene_code": "travel", + "scene_label": "差旅票据", + "summary": "电子发票(铁路电子客票) 2026-03-04 广州南至北京南 G123 二等座 金额 560 元 中国铁路", + "text": "电子发票(铁路电子客票) 2026-03-04 广州南至北京南 G123 二等座 票价 ¥560.00 中国铁路祝您旅途愉快", + "avg_score": 0.95, + "document_fields": [ + {"key": "amount", "label": "金额", "value": "560"}, + {"key": "route", "label": "行程", "value": "广州南-北京南"}, + {"key": "date", "label": "业务发生时间", "value": "2026-03-04"}, + {"key": "merchant_name", "label": "商户", "value": "中国铁路"}, + ], + "warnings": [], + }, + ], + } + ontology = SemanticOntologyService(db).parse( + OntologyParseRequest( + query=query, + user_id="pytest-train-only-hotel-name@example.com", + context_json=context, + ) + ) + + response = UserAgentService(db).respond( + UserAgentRequest( + run_id=ontology.run_id, + user_id="pytest-train-only-hotel-name@example.com", + message=query, + ontology=ontology, + context_json=context, + tool_payload={"draft_only": True}, + ) + ) + + assert response.review_payload is not None + slot_map = {item.key: item for item in response.review_payload.slot_cards} + assert slot_map["merchant_name"].value == "" + assert "酒店/商户" not in response.review_payload.missing_slots + assert "酒店的报销票据待上传(必须)" in response.review_payload.missing_slots + assert response.review_payload.can_proceed is False + assert [item.action_type for item in response.review_payload.confirmation_actions if item.emphasis == "primary"] == [ + "save_draft" + ] + assert "继续下一步" not in [item.label for item in response.review_payload.confirmation_actions] + assert "酒店住宿发票/住宿清单(必须,当前待上传)" in response.answer + assert "市内交通/乘车票据(非必须" in response.answer + assert "只能保存为草稿" in response.answer or "保存为草稿" in response.answer + assert "您的职级为:P4" in response.answer + assert "去北京" in response.answer + assert "已提交火车 560.00 元" in response.answer + field_labels = [ + field.label + for card in response.review_payload.document_cards + for field in card.fields + ] + assert "商户/酒店" not in field_labels + + +def test_user_agent_review_payload_allows_next_step_when_only_optional_ride_receipt_is_missing() -> None: + session_factory = build_session_factory() + with session_factory() as db: + query = "我去北京出差,上传了火车票和酒店票,帮我生成差旅费报销草稿" + context = { + "name": "张三", + "grade": "P4", + "review_form_values": {"occurred_date": "2026-03-04"}, + "attachment_names": ["北京南站火车票.png", "北京酒店发票.png"], + "attachment_count": 2, + "ocr_documents": [ + { + "filename": "北京南站火车票.png", + "document_type": "train_ticket", + "scene_code": "travel", + "scene_label": "差旅票据", + "summary": "电子发票(铁路电子客票) 2026-03-04 广州南至北京南 G123 二等座 金额 560 元", + "text": "电子发票(铁路电子客票) 2026-03-04 广州南至北京南 G123 二等座 票价 ¥560.00", + "avg_score": 0.95, + "document_fields": [ + {"key": "amount", "label": "金额", "value": "560"}, + {"key": "route", "label": "行程", "value": "广州南-北京南"}, + ], + "warnings": [], + }, + { + "filename": "北京酒店发票.png", + "document_type": "hotel_invoice", + "summary": "北京中心酒店 住宿 1 晚 金额 450 元", + "text": "北京中心酒店 住宿 1 晚 金额 450 元", + "avg_score": 0.96, + "document_fields": [ + {"key": "amount", "label": "金额", "value": "450"}, + {"key": "merchant", "label": "酒店名称", "value": "北京中心酒店"}, + ], + "warnings": [], + }, + ], + } + ontology = SemanticOntologyService(db).parse( + OntologyParseRequest( + query=query, + user_id="pytest-travel-optional-ride@example.com", + context_json=context, + ) + ) + + response = UserAgentService(db).respond( + UserAgentRequest( + run_id=ontology.run_id, + user_id="pytest-travel-optional-ride@example.com", + message=query, + ontology=ontology, + context_json=context, + tool_payload={"draft_only": True}, + ) + ) + + assert response.review_payload is not None + assert response.review_payload.can_proceed is True + assert response.review_payload.missing_slots == [] + receipt_brief = next(item for item in response.review_payload.risk_briefs if item.title == "差旅票据待补充") + assert receipt_brief.level == "info" + assert "市内交通/乘车票据可继续上传(非必须)" in receipt_brief.content + assert "酒店的报销票据待上传(必须)" not in receipt_brief.content + action_types = [item.action_type for item in response.review_payload.confirmation_actions] + assert "save_draft" in action_types + assert "next_step" in action_types + assert "市内交通/乘车票据(非必须" in response.answer + assert "也可以继续下一步" in response.answer + + +def test_user_agent_review_payload_allows_next_step_after_required_travel_receipts_are_complete() -> None: + session_factory = build_session_factory() + with session_factory() as db: + query = "我去北京出差,上传了火车票、酒店票和打车票,帮我生成差旅费报销草稿" + context = { + "name": "张三", + "grade": "P4", + "review_form_values": {"occurred_date": "2026-03-04"}, + "attachment_names": ["北京南站火车票.png", "北京酒店发票.png", "北京打车票.png"], + "attachment_count": 3, + "ocr_documents": [ + { + "filename": "北京南站火车票.png", + "document_type": "train_ticket", + "scene_code": "travel", + "scene_label": "差旅票据", + "summary": "电子发票(铁路电子客票) 2026-03-04 广州南至北京南 G123 二等座 金额 560 元", + "text": "电子发票(铁路电子客票) 2026-03-04 广州南至北京南 G123 二等座 票价 ¥560.00", + "avg_score": 0.95, + "document_fields": [ + {"key": "amount", "label": "金额", "value": "560"}, + {"key": "route", "label": "行程", "value": "广州南-北京南"}, + {"key": "date", "label": "日期", "value": "2026-03-04"}, + ], + "warnings": [], + }, + { + "filename": "北京酒店发票.png", + "document_type": "hotel_invoice", + "summary": "北京中心酒店 住宿 1 晚 金额 450 元", + "text": "北京中心酒店 住宿 1 晚 金额 450 元", + "avg_score": 0.96, + "document_fields": [ + {"key": "amount", "label": "金额", "value": "450"}, + {"key": "merchant", "label": "酒店名称", "value": "北京中心酒店"}, + ], + "warnings": [], + }, + { + "filename": "北京打车票.png", + "document_type": "taxi_receipt", + "summary": "北京网约车 打车票 支付金额 32 元", + "text": "北京网约车 打车票 支付金额 32 元", + "avg_score": 0.94, + "document_fields": [ + {"key": "amount", "label": "支付金额", "value": "32"}, + ], + "warnings": [], + }, + ], + } + ontology = SemanticOntologyService(db).parse( + OntologyParseRequest( + query=query, + user_id="pytest-travel-complete@example.com", + context_json=context, + ) + ) + + response = UserAgentService(db).respond( + UserAgentRequest( + run_id=ontology.run_id, + user_id="pytest-travel-complete@example.com", + message=query, + ontology=ontology, + context_json=context, + tool_payload={"draft_only": True}, + ) + ) + + assert response.review_payload is not None + assert response.review_payload.can_proceed is True + assert response.review_payload.missing_slots == [] + action_types = [item.action_type for item in response.review_payload.confirmation_actions] + assert "save_draft" in action_types + assert "next_step" in action_types + assert not any(item.title == "差旅票据待补充" for item in response.review_payload.risk_briefs) + assert "无需继续上传票据" in response.answer + assert "当前信息已较完整" in response.answer + + def test_user_agent_review_payload_prechecks_taxi_amount_against_rule_standard() -> None: session_factory = build_session_factory() with session_factory() as db: diff --git a/web/src/assets/styles/views/travel-request-detail-view.css b/web/src/assets/styles/views/travel-request-detail-view.css index a83cfde..741c20e 100644 --- a/web/src/assets/styles/views/travel-request-detail-view.css +++ b/web/src/assets/styles/views/travel-request-detail-view.css @@ -561,6 +561,46 @@ white-space: pre-wrap; } +.detail-note.readonly { + background: #f8fafc; + border-color: #e2e8f0; +} + +.detail-note-editor { + display: grid; + gap: 10px; +} + +.detail-note-editor textarea { + min-height: 92px; + border-color: rgba(16, 185, 129, .28); + background: #fff; +} + +.detail-note-editor textarea:focus { + border-color: #10b981; + box-shadow: 0 0 0 3px rgba(16, 185, 129, .12); + outline: none; +} + +.detail-note-editor-meta { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + color: #64748b; + font-size: 12px; + line-height: 1.5; +} + +.detail-note-actions { + display: inline-flex; + align-items: center; + justify-content: flex-end; + flex-shrink: 0; + gap: 8px; +} + .leader-approval-card { border-color: rgba(5, 150, 105, .18); background: linear-gradient(180deg, #ffffff 0%, #f7fdfb 100%); @@ -633,6 +673,15 @@ background: #fbfefd; } +.detail-expense-table tbody tr.system-generated-row td { + background: #f0fdf4; + border-bottom-color: #bbf7d0; +} + +.detail-expense-table tbody tr.system-generated-row:hover td { + background: #ecfdf5; +} + .detail-expense-table .col-time { width: 11%; } .detail-expense-table .col-filled-at { width: 15%; } .detail-expense-table .col-type { width: 13%; } @@ -756,6 +805,36 @@ color: #ea580c; } +.over-tag.system { + background: #dcfce7; + color: #047857; +} + +.expense-total-under-table { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 12px; + margin-top: 12px; + padding: 12px 14px; + border: 1px solid #d1fae5; + border-radius: 8px; + background: #f0fdf4; + color: #0f766e; +} + +.expense-total-under-table span { + color: #475569; + font-size: 12px; + font-weight: 800; +} + +.expense-total-under-table strong { + color: #047857; + font-size: 17px; + font-weight: 900; +} + .attachment-action-group { display: inline-flex; align-items: center; @@ -932,6 +1011,36 @@ min-width: 128px; } +.system-row-lock { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 5px; + min-height: 28px; + padding: 0 9px; + border-radius: 8px; + background: #dcfce7; + color: #047857; + font-size: 11px; + font-weight: 850; + white-space: nowrap; +} + +.system-attachment-note { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 5px; + min-height: 28px; + padding: 0 9px; + border-radius: 8px; + background: #ecfdf5; + color: #047857; + font-size: 11px; + font-weight: 850; + white-space: nowrap; +} + .row-action-group { display: flex; flex-wrap: wrap; @@ -1332,8 +1441,9 @@ } .validation-card { - border: 1px solid #e6f0eb; - background: linear-gradient(180deg, #fcfffd 0%, #f7fbf9 100%); + border: 1px solid #e5e7eb; + background: #ffffff; + box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04); } .validation-head { @@ -1341,11 +1451,14 @@ align-items: flex-start; justify-content: space-between; gap: 12px; - margin-bottom: 8px; + margin-bottom: 10px; } .validation-head h3 { margin-bottom: 4px; + color: #0f172a; + font-size: 15px; + font-weight: 800; } .validation-head p { @@ -1356,28 +1469,32 @@ } .validation-pill { - min-height: 26px; + min-height: 24px; display: inline-flex; align-items: center; padding: 0 10px; border-radius: 999px; - font-size: 12px; + border: 1px solid transparent; + font-size: 11px; font-weight: 800; } .validation-pill.ready { - background: #dcfce7; - color: #047857; + background: #f0fdf4; + border-color: #bbf7d0; + color: #166534; } .validation-pill.pending { background: #fff7ed; + border-color: #fed7aa; color: #c2410c; } .validation-pill.warning { background: #fef2f2; - color: #dc2626; + border-color: #fecaca; + color: #b91c1c; } .validation-summary { @@ -1387,29 +1504,155 @@ line-height: 1.6; } +.validation-sections { + display: grid; + gap: 18px; + margin-top: 16px; +} + +.validation-section { + display: grid; + gap: 10px; + padding-top: 14px; + border-top: 1px solid #e5e7eb; +} + +.validation-section:first-child { + padding-top: 0; + border-top: none; +} + +.validation-section-title { + display: flex; + align-items: center; + gap: 8px; + margin: 0; + color: #0f172a; + font-size: 13px; + font-weight: 800; + line-height: 1.4; +} + +.validation-section-title::before { + content: ''; + width: 6px; + height: 6px; + border-radius: 999px; + background: #10b981; + box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.12); +} + +.validation-section--risk .validation-section-title { + color: #b91c1c; +} + +.validation-section--risk .validation-section-title::before { + background: #ef4444; + box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1); +} + .validation-list { display: grid; gap: 6px; - margin-top: 12px; - padding-left: 18px; - color: #b45309; + margin: 0; + padding: 0 0 0 18px; + color: #0f766e; font-size: 13px; line-height: 1.55; } -.risk-advice-list { - display: grid; - gap: 12px; - margin-top: 14px; +.validation-list li::marker { + color: #14b8a6; } -.risk-advice-card { +.validation-section--risk .risk-advice-list { display: grid; gap: 10px; - padding: 14px; - border: 1px solid #fee2e2; + margin-top: 0; +} + +.validation-section--risk .risk-advice-card { + display: grid; + gap: 8px; + padding: 12px 12px 11px; + border: 1px solid #e5e7eb; + border-radius: 10px; + background: #ffffff; + box-shadow: 0 1px 1px rgba(15, 23, 42, 0.03); +} + +.validation-section--risk .risk-advice-card.medium { + border-color: #f3e8d9; + background: #fffcf7; +} + +.validation-section--risk .risk-advice-card-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; +} + +.validation-section--risk .risk-advice-card-head span { + min-height: 20px; + display: inline-flex; + align-items: center; + padding: 0 8px; + border-radius: 999px; + background: #fef2f2; + color: #b91c1c; + font-size: 10px; + font-weight: 800; + white-space: nowrap; +} + +.validation-section--risk .risk-advice-card.medium .risk-advice-card-head span { + background: #fff7ed; + color: #c2410c; +} + +.validation-section--risk .risk-advice-card-head strong { + min-width: 0; + color: #0f172a; + font-size: 12px; + line-height: 1.4; + text-align: right; +} + +.validation-section--risk .risk-advice-point { + margin: 0; + color: #334155; + font-size: 13px; + line-height: 1.5; +} + +.validation-section--risk .risk-advice-meta { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + gap: 8px; +} + +.validation-section--risk .risk-advice-meta > div { + min-width: 0; + display: grid; + gap: 4px; + padding: 8px 9px; border-radius: 8px; - background: #fffafa; + background: #f8fafc; +} + +.validation-section--risk .risk-advice-meta span { + color: #64748b; + font-size: 10px; + font-weight: 800; +} + +.validation-section--risk .risk-advice-meta ul, +.validation-section--risk .risk-advice-meta p { + margin: 0; + color: #334155; + font-size: 11px; + line-height: 1.5; } .risk-advice-card.medium { diff --git a/web/src/composables/useRequests.js b/web/src/composables/useRequests.js index 841523b..f6e26a0 100644 --- a/web/src/composables/useRequests.js +++ b/web/src/composables/useRequests.js @@ -4,6 +4,11 @@ import { fetchExpenseClaims } from '../services/reimbursements.js' const EXPENSE_TYPE_LABELS = { travel: '差旅费', + train_ticket: '火车票', + flight_ticket: '机票', + hotel_ticket: '住宿票', + ride_ticket: '乘车', + travel_allowance: '出差补贴', entertainment: '业务招待费', office: '办公费', meeting: '会务费', @@ -16,10 +21,17 @@ const EXPENSE_TYPE_LABELS = { const LOCATION_REQUIRED_EXPENSE_TYPES = new Set([ 'travel', + 'train_ticket', + 'flight_ticket', + 'hotel_ticket', + 'ride_ticket', 'meeting', 'entertainment' ]) +const SYSTEM_GENERATED_EXPENSE_TYPES = new Set(['travel_allowance']) +const LONG_DISTANCE_TRAVEL_EXPENSE_TYPES = new Set(['train_ticket', 'flight_ticket']) + const REIMBURSEMENT_PROGRESS_LABELS = [ '创建单据', '待提交', @@ -123,6 +135,57 @@ function resolveLocationDisplay(location, typeCode) { return isLocationRequiredExpenseType(typeCode) ? '待补充' : '非必填' } +function resolveExpenseItemViewId(item, index, claim) { + return String(item?.id || `${claim?.id || 'claim'}-item-${index}`) +} + +function buildTravelTimeLabelMap(items, claim) { + const travelItems = items + .map((item, index) => { + const itemType = normalizeExpenseType(item?.item_type || claim?.expense_type) + return { + id: resolveExpenseItemViewId(item, index, claim), + index, + itemType, + itemDate: formatDate(item?.item_date), + isSystemGenerated: Boolean(item?.is_system_generated || SYSTEM_GENERATED_EXPENSE_TYPES.has(itemType)) + } + }) + .filter((item) => !item.isSystemGenerated && LONG_DISTANCE_TRAVEL_EXPENSE_TYPES.has(item.itemType)) + .sort((left, right) => { + const dateCompare = String(left.itemDate || '').localeCompare(String(right.itemDate || '')) + return dateCompare || left.index - right.index + }) + + const labels = new Map() + travelItems.forEach((item, index) => { + if (index === 0) { + labels.set(item.id, '出发时间') + } else if (index === travelItems.length - 1) { + labels.set(item.id, '返回时间') + } else { + labels.set(item.id, '中转时间') + } + }) + return labels +} + +function resolveExpenseTimeLabel({ id, itemType, isSystemGenerated, claim, travelTimeLabelMap }) { + if (isSystemGenerated) { + return '系统自动计算' + } + if (travelTimeLabelMap?.has(id)) { + return travelTimeLabelMap.get(id) + } + if (itemType === 'ride_ticket') { + return '乘车时间' + } + if (itemType === 'hotel_ticket') { + return '住宿时间' + } + return claim?.expense_type === 'travel' ? '出行时间' : '业务发生时间' +} + function resolveAttachmentDisplayName(value) { const normalized = String(value || '').trim() if (!normalized) { @@ -498,11 +561,20 @@ function buildExpenseItems(claim, riskSummary) { return [] } - return claim.items.map((item, index) => { + const sortedItems = [...claim.items].sort((left, right) => { + const leftType = normalizeExpenseType(left?.item_type) + const rightType = normalizeExpenseType(right?.item_type) + return Number(SYSTEM_GENERATED_EXPENSE_TYPES.has(leftType)) - Number(SYSTEM_GENERATED_EXPENSE_TYPES.has(rightType)) + }) + const travelTimeLabelMap = buildTravelTimeLabelMap(sortedItems, claim) + + return sortedItems.map((item, index) => { const invoiceId = String(item?.invoice_id || '').trim() const attachmentName = resolveAttachmentDisplayName(invoiceId) const attachments = invoiceId ? [attachmentName || invoiceId] : [] const itemType = normalizeExpenseType(item?.item_type || claim?.expense_type) + const isSystemGenerated = Boolean(item?.is_system_generated || SYSTEM_GENERATED_EXPENSE_TYPES.has(itemType)) + const id = resolveExpenseItemViewId(item, index, claim) const itemTypeLabel = resolveTypeLabel(itemType) const itemLocation = String(item?.item_location || '').trim() const itemReason = String(item?.item_reason || '').trim() @@ -510,7 +582,7 @@ function buildExpenseItems(claim, riskSummary) { const itemAmountDisplay = itemAmount > 0 ? formatAmount(itemAmount) : '待补充' return { - id: String(item?.id || `${claim?.id || 'claim'}-item-${index}`), + id, time: formatDate(item?.item_date) || '待补充', itemDate: formatDate(item?.item_date) || '', filledAt: formatDateTime(item?.created_at) || '待同步', @@ -519,17 +591,24 @@ function buildExpenseItems(claim, riskSummary) { itemLocation, itemAmount, invoiceId, - dayLabel: claim?.expense_type === 'travel' ? `第 ${index + 1} 项` : '业务发生项', + isSystemGenerated, + dayLabel: resolveExpenseTimeLabel({ + id, + itemType, + isSystemGenerated, + claim, + travelTimeLabelMap + }), name: itemTypeLabel, category: itemTypeLabel, desc: itemReason || '待补充', detail: resolveLocationDisplay(itemLocation, itemType), amount: itemAmountDisplay, - status: attachments.length ? '已识别' : '待补充', - tone: attachments.length ? 'ok' : 'bad', - attachmentStatus: attachments.length ? '已关联票据' : '未上传', - attachmentHint: attachments.length ? attachments[0] : '仅支持上传 1 张 JPG、PNG、PDF 单据', - attachmentTone: attachments.length ? 'ok' : 'missing', + status: isSystemGenerated ? '系统计算' : attachments.length ? '已识别' : '待补充', + tone: isSystemGenerated ? 'system' : attachments.length ? 'ok' : 'bad', + attachmentStatus: isSystemGenerated ? '无需附件' : attachments.length ? '已关联票据' : '未上传', + attachmentHint: isSystemGenerated ? '根据出差天数与职级自动测算' : attachments.length ? attachments[0] : '仅支持上传 1 张 JPG、PNG、PDF 单据', + attachmentTone: isSystemGenerated ? 'system' : attachments.length ? 'ok' : 'missing', attachments, riskLabel: riskSummary === '无' ? '无' : '待关注', riskText: riskSummary === '无' ? '' : riskSummary, diff --git a/web/src/services/reimbursements.js b/web/src/services/reimbursements.js index a4773d3..5fbfece 100644 --- a/web/src/services/reimbursements.js +++ b/web/src/services/reimbursements.js @@ -12,6 +12,13 @@ export function fetchExpenseClaimDetail(claimId) { return apiRequest(`/reimbursements/claims/${encodeURIComponent(String(claimId || '').trim())}`) } +export function updateExpenseClaim(claimId, payload = {}) { + return apiRequest(`/reimbursements/claims/${encodeURIComponent(String(claimId || '').trim())}`, { + method: 'PATCH', + body: JSON.stringify(payload) + }) +} + export function calculateTravelReimbursement(payload = {}) { return apiRequest('/reimbursements/travel-calculator', { method: 'POST', diff --git a/web/src/utils/requestViewModel.js b/web/src/utils/requestViewModel.js index ebb5199..d689972 100644 --- a/web/src/utils/requestViewModel.js +++ b/web/src/utils/requestViewModel.js @@ -5,6 +5,36 @@ const REQUEST_TYPE_META = { tone: 'travel', secondaryStatusLabel: '行程状态' }, + train_ticket: { + label: '火车票', + detailVariant: 'travel', + tone: 'travel', + secondaryStatusLabel: '行程状态' + }, + flight_ticket: { + label: '机票', + detailVariant: 'travel', + tone: 'travel', + secondaryStatusLabel: '行程状态' + }, + hotel_ticket: { + label: '住宿票', + detailVariant: 'travel', + tone: 'travel', + secondaryStatusLabel: '票据状态' + }, + ride_ticket: { + label: '乘车', + detailVariant: 'travel', + tone: 'travel', + secondaryStatusLabel: '票据状态' + }, + travel_allowance: { + label: '出差补贴', + detailVariant: 'travel', + tone: 'travel', + secondaryStatusLabel: '系统计算' + }, entertainment: { label: '业务招待费', detailVariant: 'general', diff --git a/web/src/views/TravelReimbursementCreateView.vue b/web/src/views/TravelReimbursementCreateView.vue index c2924c3..20dceb1 100644 --- a/web/src/views/TravelReimbursementCreateView.vue +++ b/web/src/views/TravelReimbursementCreateView.vue @@ -352,6 +352,7 @@ + + + + +
{{ detailNote }}
+ +
@@ -129,7 +169,7 @@