"""Идентичность: acting (X-Acting-Emp-Id) и target (emp_id).""" from __future__ import annotations from typing import Annotated from fastapi import Header, HTTPException from app.emp_schema import EMP_TABLE_CANONICAL from app.main import _column_lookup, _quote_ident, _table_columns, resolve_emp_table def _biz_error(status: int, code: str, message: str) -> HTTPException: return HTTPException(status_code=status, detail={"code": code, "message": message}) def parse_acting_emp_id( x_acting_emp_id: Annotated[str | None, Header(alias="X-Acting-Emp-Id")] = None, ) -> int: if not x_acting_emp_id or not str(x_acting_emp_id).strip(): raise _biz_error(400, "missing_acting_emp", "Требуется заголовок X-Acting-Emp-Id") try: v = int(str(x_acting_emp_id).strip()) except ValueError as e: raise _biz_error( 400, "invalid_acting_emp", "X-Acting-Emp-Id должен быть целым числом" ) from e if v <= 0: raise _biz_error(400, "invalid_acting_emp", "X-Acting-Emp-Id должен быть > 0") return v def resolve_target_emp_id(acting_emp_id: int, emp_id: int | None) -> int: return int(emp_id) if emp_id is not None else acting_emp_id def ensure_emp_exists(cur, db: str, emp_id: int, *, kind: str = "target") -> None: table = resolve_emp_table(cur, db) cols = _table_columns(cur, db, table) lut = _column_lookup(cols) prefix = EMP_TABLE_CANONICAL.lower() id_col = lut.get(f"{prefix}_id") or lut.get("id") removed_col = lut.get(f"{prefix}_removed") or lut.get("removed") if not id_col: raise _biz_error(500, "db_error", "Не найдена колонка id в таблице сотрудников") cond = f"{_quote_ident(id_col)} = %s" params: list = [emp_id] if removed_col: cond += f" AND {_quote_ident(removed_col)} = 0" cur.execute( f"SELECT 1 AS ok FROM {_quote_ident(table)} WHERE {cond} LIMIT 1", params, ) if not cur.fetchone(): code = "acting_emp_not_found" if kind == "acting" else "target_emp_not_found" raise _biz_error(404, code, f"Сотрудник {emp_id} не найден")