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