refactor(server): split oversized backend services
This commit is contained in:
126
server/src/app/services/employee_serialization.py
Normal file
126
server/src/app/services/employee_serialization.py
Normal file
@@ -0,0 +1,126 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from datetime import date, datetime
|
||||
|
||||
from app.models.employee import Employee
|
||||
from app.models.employee_change_log import EmployeeChangeLog
|
||||
from app.models.role import Role
|
||||
from app.schemas.employee import (
|
||||
EmployeeHistoryRead,
|
||||
EmployeeOrganizationRead,
|
||||
EmployeeRead,
|
||||
)
|
||||
|
||||
|
||||
def serialize_employee(
|
||||
employee: Employee,
|
||||
*,
|
||||
sorted_roles: list[Role],
|
||||
sorted_change_logs: list[EmployeeChangeLog],
|
||||
format_date: Callable[[date | None], str | None],
|
||||
format_datetime: Callable[[datetime | None], str | None],
|
||||
format_history_datetime: Callable[[datetime | None], str],
|
||||
role_permission_map: dict[str, list[str]],
|
||||
status_tone_map: dict[str, str],
|
||||
max_change_logs: int,
|
||||
) -> EmployeeRead:
|
||||
organization = employee.organization_unit
|
||||
role_labels = [role.name for role in sorted_roles]
|
||||
role_codes = [role.role_code for role in sorted_roles]
|
||||
|
||||
history = [
|
||||
EmployeeHistoryRead(
|
||||
action=item.action,
|
||||
owner=item.owner,
|
||||
time=format_history_datetime(item.occurred_at),
|
||||
occurredAt=format_history_datetime(item.occurred_at),
|
||||
)
|
||||
for item in sorted_change_logs[:max_change_logs]
|
||||
]
|
||||
|
||||
return EmployeeRead(
|
||||
id=employee.id,
|
||||
avatar=(employee.name or "?")[:1],
|
||||
name=employee.name,
|
||||
employeeNo=employee.employee_no,
|
||||
department=organization.name if organization else "",
|
||||
position=employee.position,
|
||||
grade=employee.grade,
|
||||
manager=employee.manager.name if employee.manager else "CEO",
|
||||
managerEmployeeNo=employee.manager.employee_no if employee.manager else None,
|
||||
financeOwner=employee.finance_owner_name or "",
|
||||
roles=role_labels,
|
||||
roleCodes=role_codes,
|
||||
status=employee.employment_status,
|
||||
statusTone=status_tone_map.get(employee.employment_status, "neutral"),
|
||||
gender=employee.gender,
|
||||
age=calculate_age(employee.birth_date),
|
||||
birthDate=format_date(employee.birth_date),
|
||||
email=employee.email,
|
||||
phone=employee.phone,
|
||||
joinDate=format_date(employee.join_date),
|
||||
location=employee.location,
|
||||
costCenter=employee.cost_center,
|
||||
updatedAt=format_datetime(employee.updated_at or employee.created_at),
|
||||
lastSync=format_datetime(employee.last_sync_at),
|
||||
syncState=employee.sync_state,
|
||||
spotlight=employee.spotlight,
|
||||
permissions=collect_permissions(role_codes, role_permission_map),
|
||||
history=history,
|
||||
organization=(
|
||||
EmployeeOrganizationRead(
|
||||
id=organization.id,
|
||||
code=organization.unit_code,
|
||||
name=organization.name,
|
||||
unitType=organization.unit_type,
|
||||
costCenter=organization.cost_center,
|
||||
location=organization.location,
|
||||
managerName=organization.manager_name,
|
||||
)
|
||||
if organization
|
||||
else None
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def collect_permissions(
|
||||
role_codes: list[str],
|
||||
role_permission_map: dict[str, list[str]],
|
||||
) -> list[str]:
|
||||
permissions: list[str] = []
|
||||
seen: set[str] = set()
|
||||
|
||||
for role_code in role_codes:
|
||||
for permission in role_permission_map.get(role_code, []):
|
||||
if permission in seen:
|
||||
continue
|
||||
permissions.append(permission)
|
||||
seen.add(permission)
|
||||
|
||||
return permissions
|
||||
|
||||
|
||||
def format_history_datetime(
|
||||
value: datetime | None,
|
||||
*,
|
||||
to_display_datetime: Callable[[datetime], datetime],
|
||||
) -> str:
|
||||
if value is None:
|
||||
return ""
|
||||
local = to_display_datetime(value)
|
||||
return (
|
||||
f"{local.year}年{local.month}月{local.day}日"
|
||||
f"{local.hour}时{local.minute}分"
|
||||
)
|
||||
|
||||
|
||||
def calculate_age(birth_date: date | None) -> int | None:
|
||||
if birth_date is None:
|
||||
return None
|
||||
|
||||
today = date.today()
|
||||
age = today.year - birth_date.year
|
||||
if (today.month, today.day) < (birth_date.month, birth_date.day):
|
||||
age -= 1
|
||||
return age
|
||||
Reference in New Issue
Block a user