Files
X-Financial/server/src/app/services/employee_serialization.py

130 lines
4.1 KiB
Python
Raw Normal View History

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,
bankName=employee.bank_name,
bankAccountNo=employee.bank_account_no,
bankAccountName=employee.bank_account_name,
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