from __future__ import annotations from sqlalchemy import func, or_, select from sqlalchemy.orm import Session, selectinload from app.models.employee import Employee from app.models.organization import OrganizationUnit from app.models.role import Role from app.services.pagination import PageResult, paginate_select from app.services.tenant_registry import required_tenant_id class EmployeeRepository: def __init__(self, db: Session, *, tenant_id: str) -> None: self.db = db self.tenant_id = required_tenant_id(tenant_id) def _list_stmt(self, status: str | None = None, keyword: str | None = None): stmt = ( select(Employee) .options( selectinload(Employee.organization_unit), selectinload(Employee.manager), selectinload(Employee.roles), selectinload(Employee.change_logs), ) .where(Employee.tenant_id == self.tenant_id) .order_by(Employee.updated_at.desc(), Employee.name.asc()) ) if status and status != "全部员工": stmt = stmt.where(Employee.employment_status == status) if keyword: pattern = f"%{keyword.strip()}%" stmt = stmt.where( or_( Employee.name.ilike(pattern), Employee.employee_no.ilike(pattern), Employee.email.ilike(pattern), Employee.position.ilike(pattern), ) ) return stmt def list(self, status: str | None = None, keyword: str | None = None) -> list[Employee]: stmt = self._list_stmt(status=status, keyword=keyword) return list(self.db.execute(stmt).scalars().unique().all()) def list_page( self, *, status: str | None = None, keyword: str | None = None, page: int | None, page_size: int | None, ) -> PageResult[Employee]: stmt = self._list_stmt(status=status, keyword=keyword) return paginate_select(self.db, stmt, page=page, page_size=page_size, unique=True) def get(self, employee_id: str) -> Employee | None: stmt = ( select(Employee) .options( selectinload(Employee.organization_unit), selectinload(Employee.manager), selectinload(Employee.roles), selectinload(Employee.change_logs), ) .where( Employee.tenant_id == self.tenant_id, Employee.id == employee_id, ) ) return self.db.execute(stmt).scalars().unique().first() def get_by_employee_no(self, employee_no: str) -> Employee | None: stmt = select(Employee).where( Employee.tenant_id == self.tenant_id, Employee.employee_no == employee_no, ) return self.db.execute(stmt).scalars().first() def get_by_email(self, email: str) -> Employee | None: stmt = select(Employee).where( Employee.tenant_id == self.tenant_id, Employee.email == email, ) return self.db.execute(stmt).scalars().first() def list_roles(self) -> list[Role]: stmt = select(Role) return list(self.db.execute(stmt).scalars().all()) def get_role_by_code(self, role_code: str) -> Role | None: stmt = select(Role).where(Role.role_code == role_code) return self.db.execute(stmt).scalars().first() def list_organization_units(self) -> list[OrganizationUnit]: stmt = select(OrganizationUnit).where( OrganizationUnit.tenant_id == self.tenant_id ) return list(self.db.execute(stmt).scalars().all()) def get_organization_by_code(self, unit_code: str) -> OrganizationUnit | None: stmt = select(OrganizationUnit).where( OrganizationUnit.tenant_id == self.tenant_id, OrganizationUnit.unit_code == unit_code, ) return self.db.execute(stmt).scalars().first() def count_employees(self) -> int: stmt = ( select(func.count()) .select_from(Employee) .where(Employee.tenant_id == self.tenant_id) ) return int(self.db.execute(stmt).scalar_one()) def count_roles(self) -> int: stmt = select(func.count()).select_from(Role) return int(self.db.execute(stmt).scalar_one()) def count_organization_units(self) -> int: stmt = ( select(func.count()) .select_from(OrganizationUnit) .where(OrganizationUnit.tenant_id == self.tenant_id) ) return int(self.db.execute(stmt).scalar_one()) def create(self, employee: Employee) -> Employee: self._require_employee_tenant(employee) self.db.add(employee) self.db.commit() self.db.refresh(employee) return employee def save(self, employee: Employee) -> Employee: self._require_employee_tenant(employee) self.db.add(employee) self.db.commit() self.db.refresh(employee) return employee def _require_employee_tenant(self, employee: Employee) -> None: if required_tenant_id(employee.tenant_id) != self.tenant_id: raise ValueError("员工记录不属于当前可信租户。")