feat: 增强风险规则生成引擎与预算中心页面
后端拆分风险规则生成为解释器、语义分析、本体对齐等子模块, 优化模板执行和流程图生成,完善员工种子数据和导入逻辑,增强 报销单权限策略和草稿持久化,前端新增预算中心视图和趋势图 组件,重构审计页面和风险规则测试对话框交互,完善文档中心 和报销创建页面细节,补充单元测试覆盖。
This commit is contained in:
@@ -15,6 +15,8 @@ from app.models.organization import OrganizationUnit
|
||||
from app.models.role import Role
|
||||
from app.schemas.employee import EmployeeUpdate
|
||||
from app.services.employee import EmployeeService
|
||||
from app.services.employee_seed import CANONICAL_DEPARTMENT_CODES
|
||||
from app.services.employee_time import format_history_datetime
|
||||
|
||||
|
||||
def build_session() -> Session:
|
||||
@@ -49,7 +51,7 @@ def test_employee_directory_seeds_rich_employee_data() -> None:
|
||||
history_count = db.scalar(select(func.count()).select_from(EmployeeChangeLog))
|
||||
|
||||
assert role_count == 6
|
||||
assert org_count == 10
|
||||
assert org_count == 7
|
||||
assert employee_count == 30
|
||||
assert history_count and history_count >= 30
|
||||
|
||||
@@ -194,6 +196,42 @@ def test_employee_meta_includes_organization_options() -> None:
|
||||
|
||||
assert meta.organizationOptions
|
||||
assert all(item.code and item.name for item in meta.organizationOptions)
|
||||
assert [item.name for item in meta.organizationOptions] == [
|
||||
"人力资源部",
|
||||
"市场部",
|
||||
"总裁办",
|
||||
"技术部",
|
||||
"生产部",
|
||||
"财务部",
|
||||
]
|
||||
|
||||
|
||||
def test_employee_directory_normalizes_legacy_departments() -> None:
|
||||
with build_session() as db:
|
||||
service = EmployeeService(db)
|
||||
service.list_employees()
|
||||
|
||||
legacy_department = OrganizationUnit(
|
||||
unit_code="RND-CENTER",
|
||||
name="产品研发中心",
|
||||
unit_type="department",
|
||||
)
|
||||
employee = db.execute(
|
||||
select(Employee).where(Employee.employee_no == "E11745")
|
||||
).scalar_one()
|
||||
employee.organization_unit = legacy_department
|
||||
db.add(legacy_department)
|
||||
db.commit()
|
||||
|
||||
refreshed = next(
|
||||
item for item in service.list_employees() if item.employeeNo == "E11745"
|
||||
)
|
||||
meta = service.get_employee_meta()
|
||||
|
||||
assert refreshed.department == "技术部"
|
||||
assert refreshed.organization is not None
|
||||
assert refreshed.organization.code == "TECH-DEPT"
|
||||
assert "RND-CENTER" not in {item.code for item in meta.organizationOptions}
|
||||
|
||||
|
||||
def test_update_employee_changes_organization() -> None:
|
||||
@@ -202,7 +240,11 @@ def test_update_employee_changes_organization() -> None:
|
||||
employee = service.list_employees()[0]
|
||||
organizations = service.repository.list_organization_units()
|
||||
current_code = employee.organization.code if employee.organization else None
|
||||
target = next(unit for unit in organizations if unit.unit_code != current_code)
|
||||
target = next(
|
||||
unit
|
||||
for unit in organizations
|
||||
if unit.unit_code in CANONICAL_DEPARTMENT_CODES and unit.unit_code != current_code
|
||||
)
|
||||
|
||||
updated = service.update_employee(
|
||||
employee.id,
|
||||
@@ -245,7 +287,7 @@ def test_update_employee_changes_manager() -> None:
|
||||
|
||||
def test_format_history_datetime_uses_local_timezone_without_seconds() -> None:
|
||||
value = datetime(2026, 5, 20, 6, 30, 45, tzinfo=UTC)
|
||||
formatted = EmployeeService._format_history_datetime(value)
|
||||
formatted = format_history_datetime(value)
|
||||
|
||||
assert formatted == "2026年5月20日14时30分"
|
||||
assert "秒" not in formatted
|
||||
|
||||
Reference in New Issue
Block a user