feat: 增强员工管理与报销单全流程功能
- 新增员工Excel导入服务(employee_spreadsheet)及导入/导出API端点 - 员工服务增加批量创建、邮箱唯一校验、组织架构关联等能力 - 报销单提交补充身份回填、部门信息透传及预审结果展示优化 - 认证流程增加部门信息(departmentName)并在schema中同步扩展 - 用户Agent服务增加部门关联与报销单回填逻辑 - 前端员工管理页面全面重构,新增导入导出、搜索过滤、分页等功能 - 前端审批中心、审计、差旅报销等视图交互与样式优化 - 新增TableLoadingState共享组件及员工导入测试用例
This commit is contained in:
@@ -54,7 +54,7 @@ EXPENSE_TYPE_LABELS = {
|
||||
"welfare": "福利",
|
||||
}
|
||||
|
||||
PRIVILEGED_CLAIM_ROLE_CODES = {"finance"}
|
||||
PRIVILEGED_CLAIM_ROLE_CODES = {"finance", "executive"}
|
||||
APPROVAL_VISIBLE_CLAIM_ROLE_CODES = {"manager", "approver"}
|
||||
MAX_DRAFT_CLAIMS_PER_USER = 3
|
||||
LOCATION_REQUIRED_EXPENSE_TYPES = {
|
||||
@@ -814,17 +814,19 @@ class ExpenseClaimService:
|
||||
"invoice_count": int(claim.invoice_count or 0),
|
||||
}
|
||||
|
||||
def delete_claim(self, claim_id: str, 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)
|
||||
resource_id = claim.id
|
||||
|
||||
self._delete_claim_attachment_root(claim.id)
|
||||
self.db.delete(claim)
|
||||
def delete_claim(self, claim_id: str, current_user: CurrentUserContext) -> ExpenseClaim | None:
|
||||
claim = self.get_claim(claim_id, current_user)
|
||||
if claim is None:
|
||||
return None
|
||||
|
||||
if not self._has_privileged_claim_access(current_user):
|
||||
self._ensure_draft_claim(claim)
|
||||
|
||||
before_json = self._serialize_claim(claim)
|
||||
resource_id = claim.id
|
||||
|
||||
self._delete_claim_attachment_root(claim.id)
|
||||
self.db.delete(claim)
|
||||
self.db.commit()
|
||||
|
||||
self.audit_service.log_action(
|
||||
@@ -835,10 +837,60 @@ class ExpenseClaimService:
|
||||
before_json=before_json,
|
||||
after_json=None,
|
||||
)
|
||||
|
||||
return claim
|
||||
|
||||
def upsert_draft_from_ontology(
|
||||
|
||||
return claim
|
||||
|
||||
def return_claim(
|
||||
self,
|
||||
claim_id: str,
|
||||
current_user: CurrentUserContext,
|
||||
*,
|
||||
reason: str | None = None,
|
||||
) -> ExpenseClaim | None:
|
||||
claim = self.get_claim(claim_id, current_user)
|
||||
if claim is None:
|
||||
return None
|
||||
|
||||
if not self._has_privileged_claim_access(current_user):
|
||||
raise ValueError("只有财务人员或高级管理人员可以退回报销单。")
|
||||
|
||||
normalized_status = str(claim.status or "").strip().lower()
|
||||
if normalized_status == "draft":
|
||||
raise ValueError("草稿状态无需退回。")
|
||||
if normalized_status in {"approved", "completed", "paid"}:
|
||||
raise ValueError("已完成单据不允许退回。")
|
||||
|
||||
before_json = self._serialize_claim(claim)
|
||||
operator = current_user.name or current_user.username
|
||||
return_reason = str(reason or "").strip()
|
||||
return_flag = {
|
||||
"source": "manual_return",
|
||||
"severity": "medium",
|
||||
"label": "人工退回",
|
||||
"message": return_reason or f"{operator} 已退回该报销单,请申请人补充后重新提交。",
|
||||
"operator": operator,
|
||||
"created_at": datetime.now(UTC).isoformat(),
|
||||
}
|
||||
|
||||
claim.status = "returned"
|
||||
claim.approval_stage = "待补充"
|
||||
claim.risk_flags_json = [*list(claim.risk_flags_json or []), return_flag]
|
||||
|
||||
self.db.commit()
|
||||
self.db.refresh(claim)
|
||||
|
||||
self.audit_service.log_action(
|
||||
actor=operator,
|
||||
action="expense_claim.return",
|
||||
resource_type="expense_claim",
|
||||
resource_id=claim.id,
|
||||
before_json=before_json,
|
||||
after_json=self._serialize_claim(claim),
|
||||
)
|
||||
|
||||
return claim
|
||||
|
||||
def upsert_draft_from_ontology(
|
||||
self,
|
||||
*,
|
||||
run_id: str,
|
||||
|
||||
Reference in New Issue
Block a user