feat(selos): implementar sistema completo de selos para consultores
- Adicionar coluna SELOS na tabela TB_RANKING_CONSULTOR (migration v1.2) - Criar script popular_selos.py para popular/atualizar selos em batch - Simplificar para 22 selos com dados reais (remover selos sem dados) - Adicionar selo IDIOMA_MULTILINGUE para consultores com 3+ idiomas - Corrigir filtro de selos com query LIKE exata (evitar matches parciais) - Alinhar ícones entre FiltroSelos e ConsultorCard - Reorganizar filtro em 7 categorias: Coordenação, Consultoria, Avaliações, Premiações, Orientações, Participações, Características Selos disponíveis: CA, CAJ, CAJ_MP, CAM, PRESID_CAMARA, CONS_ATIVO, AVAL_COMIS, COORD_COMIS, AUTOR_GP, AUTOR_PREMIO, AUTOR_MENCAO, ORIENT_GP, ORIENT_PREMIO, ORIENT_MENCAO, COORIENT_GP, COORIENT_PREMIO, COORIENT_MENCAO, ORIENT_TESE, ORIENT_DISS, EVENTO, PROJ, IDIOMA_MULTILINGUE
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
from typing import List, Optional, Dict, Any
|
||||
from typing import List, Optional, Dict, Any, Set
|
||||
from datetime import datetime
|
||||
import json
|
||||
|
||||
from ...domain.entities.consultor_ranking import ConsultorRanking
|
||||
from .client import OracleClient
|
||||
from ..ranking_store import extrair_selos_entry
|
||||
|
||||
|
||||
class RankingOracleRepository:
|
||||
@@ -24,17 +25,19 @@ class RankingOracleRepository:
|
||||
INSERT INTO TB_RANKING_CONSULTOR (
|
||||
ID_PESSOA, NOME, PONTUACAO_TOTAL,
|
||||
COMPONENTE_A, COMPONENTE_B, COMPONENTE_C, COMPONENTE_D, COMPONENTE_E,
|
||||
ATIVO, ANOS_ATUACAO, JSON_DETALHES, DT_CALCULO
|
||||
ATIVO, ANOS_ATUACAO, JSON_DETALHES, SELOS, DT_CALCULO
|
||||
) VALUES (
|
||||
:id_pessoa, :nome, :pontuacao_total,
|
||||
:componente_a, :componente_b, :componente_c, :componente_d, :componente_e,
|
||||
:ativo, :anos_atuacao, :json_detalhes, CURRENT_TIMESTAMP
|
||||
:ativo, :anos_atuacao, :json_detalhes, :selos, CURRENT_TIMESTAMP
|
||||
)
|
||||
"""
|
||||
|
||||
batch_data = []
|
||||
for consultor in consultores:
|
||||
json_str = json.dumps(consultor, ensure_ascii=False)
|
||||
selos_set = extrair_selos_entry(consultor)
|
||||
selos_str = ",".join(sorted(selos_set)) if selos_set else None
|
||||
batch_data.append({
|
||||
"id_pessoa": int(consultor["id_pessoa"]),
|
||||
"nome": str(consultor.get("nome", ""))[:500],
|
||||
@@ -46,7 +49,8 @@ class RankingOracleRepository:
|
||||
"componente_e": int(consultor.get("bloco_e") or consultor.get("componente_e") or 0),
|
||||
"ativo": "S" if consultor.get("ativo") else "N",
|
||||
"anos_atuacao": float(consultor.get("anos_atuacao") or 0),
|
||||
"json_detalhes": json_str
|
||||
"json_detalhes": json_str,
|
||||
"selos": selos_str
|
||||
})
|
||||
|
||||
with self.client.get_connection() as conn:
|
||||
@@ -66,7 +70,8 @@ class RankingOracleRepository:
|
||||
self,
|
||||
page: int = 1,
|
||||
size: int = 50,
|
||||
filtro_ativo: Optional[bool] = None
|
||||
filtro_ativo: Optional[bool] = None,
|
||||
filtro_selos: Optional[List[str]] = None
|
||||
) -> List[ConsultorRanking]:
|
||||
"""
|
||||
Busca ranking paginado ordenado por posição.
|
||||
@@ -79,16 +84,26 @@ class RankingOracleRepository:
|
||||
offset = (page - 1) * size
|
||||
limit_end = offset + size
|
||||
|
||||
where_clause = ""
|
||||
where_clauses = []
|
||||
params = {
|
||||
"offset": offset,
|
||||
"limit_end": limit_end,
|
||||
}
|
||||
|
||||
if filtro_ativo is not None:
|
||||
where_clause = "AND ATIVO = :ativo"
|
||||
where_clauses.append("ATIVO = :ativo")
|
||||
params["ativo"] = "S" if filtro_ativo else "N"
|
||||
|
||||
if filtro_selos:
|
||||
for i, selo in enumerate(filtro_selos):
|
||||
param_name = f"selo_{i}"
|
||||
where_clauses.append(f"((',' || SELOS || ',') LIKE '%,' || :{param_name} || ',%')")
|
||||
params[param_name] = selo
|
||||
|
||||
where_clause = ""
|
||||
if where_clauses:
|
||||
where_clause = "AND " + " AND ".join(where_clauses)
|
||||
|
||||
query = f"""
|
||||
SELECT * FROM (
|
||||
SELECT
|
||||
@@ -142,17 +157,31 @@ class RankingOracleRepository:
|
||||
|
||||
return consultores
|
||||
|
||||
def contar_total(self, filtro_ativo: Optional[bool] = None) -> int:
|
||||
def contar_total(
|
||||
self,
|
||||
filtro_ativo: Optional[bool] = None,
|
||||
filtro_selos: Optional[List[str]] = None
|
||||
) -> int:
|
||||
"""
|
||||
Conta total de consultores no ranking.
|
||||
"""
|
||||
where_clause = ""
|
||||
where_clauses = []
|
||||
params = {}
|
||||
|
||||
if filtro_ativo is not None:
|
||||
where_clause = "WHERE ATIVO = :ativo"
|
||||
where_clauses.append("ATIVO = :ativo")
|
||||
params["ativo"] = "S" if filtro_ativo else "N"
|
||||
|
||||
if filtro_selos:
|
||||
for i, selo in enumerate(filtro_selos):
|
||||
param_name = f"selo_{i}"
|
||||
where_clauses.append(f"((',' || SELOS || ',') LIKE '%,' || :{param_name} || ',%')")
|
||||
params[param_name] = selo
|
||||
|
||||
where_clause = ""
|
||||
if where_clauses:
|
||||
where_clause = "WHERE " + " AND ".join(where_clauses)
|
||||
|
||||
query = f"SELECT COUNT(*) AS TOTAL FROM TB_RANKING_CONSULTOR {where_clause}"
|
||||
results = self.client.executar_query(query, params)
|
||||
|
||||
|
||||
@@ -7,9 +7,14 @@ from typing import Any, Dict, List, Optional, Set, Tuple
|
||||
|
||||
|
||||
SELOS_DISPONIVEIS = [
|
||||
"CA",
|
||||
"CAJ",
|
||||
"CAJ_MP",
|
||||
"CAM",
|
||||
"PRESID_CAMARA",
|
||||
"COORD_PPG",
|
||||
"BPQ",
|
||||
"CONS_ATIVO",
|
||||
"AVAL_COMIS",
|
||||
"COORD_COMIS",
|
||||
"AUTOR_GP",
|
||||
"AUTOR_PREMIO",
|
||||
"AUTOR_MENCAO",
|
||||
@@ -19,12 +24,11 @@ SELOS_DISPONIVEIS = [
|
||||
"COORIENT_GP",
|
||||
"COORIENT_PREMIO",
|
||||
"COORIENT_MENCAO",
|
||||
"ORIENT_POS_DOC",
|
||||
"ORIENT_TESE",
|
||||
"ORIENT_DISS",
|
||||
"CO_ORIENT_POS_DOC",
|
||||
"CO_ORIENT_TESE",
|
||||
"CO_ORIENT_DISS",
|
||||
"EVENTO",
|
||||
"PROJ",
|
||||
"IDIOMA_MULTILINGUE",
|
||||
]
|
||||
|
||||
|
||||
@@ -32,46 +36,75 @@ def extrair_selos_entry(detalhes: Dict[str, Any]) -> Set[str]:
|
||||
selos = set()
|
||||
|
||||
for c in detalhes.get("coordenacoes_capes", []):
|
||||
codigo = c.get("codigo", "")
|
||||
if codigo == "CA":
|
||||
selos.add("CA")
|
||||
elif codigo == "CAJ":
|
||||
selos.add("CAJ")
|
||||
elif codigo == "CAJ_MP":
|
||||
selos.add("CAJ_MP")
|
||||
elif codigo == "CAM":
|
||||
selos.add("CAM")
|
||||
if c.get("presidente"):
|
||||
selos.add("PRESID_CAMARA")
|
||||
|
||||
if detalhes.get("coordenador_ppg"):
|
||||
selos.add("COORD_PPG")
|
||||
consultoria = detalhes.get("consultoria")
|
||||
if consultoria and consultoria.get("codigo") == "CONS_ATIVO":
|
||||
selos.add("CONS_ATIVO")
|
||||
|
||||
if detalhes.get("bolsas_cnpq"):
|
||||
selos.add("BPQ")
|
||||
for aval in detalhes.get("avaliacoes_comissao", []):
|
||||
codigo = aval.get("codigo", "")
|
||||
if "COORD" in codigo:
|
||||
selos.add("COORD_COMIS")
|
||||
elif "AVAL" in codigo:
|
||||
selos.add("AVAL_COMIS")
|
||||
|
||||
for part in detalhes.get("participacoes", []):
|
||||
codigo = part.get("codigo", "")
|
||||
if codigo == "EVENTO":
|
||||
selos.add("EVENTO")
|
||||
elif codigo == "PROJ":
|
||||
selos.add("PROJ")
|
||||
|
||||
for prem in detalhes.get("premiacoes", []):
|
||||
codigo = prem.get("codigo", "")
|
||||
papel = prem.get("papel", "").lower() if prem.get("papel") else ""
|
||||
|
||||
is_orientador = "orientador" in papel
|
||||
is_coorientador = "coorientador" in papel or "co-orientador" in papel
|
||||
|
||||
if codigo == "PREMIACAO_GP_AUTOR":
|
||||
selos.add("AUTOR_GP")
|
||||
if is_coorientador:
|
||||
selos.add("COORIENT_GP")
|
||||
elif is_orientador:
|
||||
selos.add("ORIENT_GP")
|
||||
else:
|
||||
selos.add("AUTOR_GP")
|
||||
elif codigo == "PREMIACAO_AUTOR":
|
||||
selos.add("AUTOR_PREMIO")
|
||||
if is_coorientador:
|
||||
selos.add("COORIENT_PREMIO")
|
||||
elif is_orientador:
|
||||
selos.add("ORIENT_PREMIO")
|
||||
else:
|
||||
selos.add("AUTOR_PREMIO")
|
||||
elif codigo == "MENCAO_AUTOR":
|
||||
selos.add("AUTOR_MENCAO")
|
||||
if is_coorientador:
|
||||
selos.add("COORIENT_MENCAO")
|
||||
elif is_orientador:
|
||||
selos.add("ORIENT_MENCAO")
|
||||
else:
|
||||
selos.add("AUTOR_MENCAO")
|
||||
|
||||
for orient in detalhes.get("orientacoes", []):
|
||||
codigo = orient.get("codigo", "")
|
||||
is_coorient = orient.get("coorientacao", False)
|
||||
|
||||
if is_coorient:
|
||||
if codigo in ("CO_ORIENT_POS_DOC", "CO_ORIENT_POS_DOC_PREM"):
|
||||
selos.add("CO_ORIENT_POS_DOC")
|
||||
elif codigo in ("CO_ORIENT_TESE", "CO_ORIENT_TESE_PREM"):
|
||||
selos.add("CO_ORIENT_TESE")
|
||||
elif codigo in ("CO_ORIENT_DISS", "CO_ORIENT_DISS_PREM"):
|
||||
selos.add("CO_ORIENT_DISS")
|
||||
else:
|
||||
if codigo in ("ORIENT_POS_DOC", "ORIENT_POS_DOC_PREM"):
|
||||
selos.add("ORIENT_POS_DOC")
|
||||
elif codigo in ("ORIENT_TESE", "ORIENT_TESE_PREM"):
|
||||
selos.add("ORIENT_TESE")
|
||||
elif codigo in ("ORIENT_DISS", "ORIENT_DISS_PREM"):
|
||||
selos.add("ORIENT_DISS")
|
||||
if codigo in ("ORIENT_TESE", "ORIENT_TESE_PREM"):
|
||||
selos.add("ORIENT_TESE")
|
||||
elif codigo in ("ORIENT_DISS", "ORIENT_DISS_PREM"):
|
||||
selos.add("ORIENT_DISS")
|
||||
|
||||
if orient.get("premiada") or "_PREM" in codigo:
|
||||
prem_tipo = orient.get("premiacao_tipo", "")
|
||||
is_coorient = orient.get("coorientacao", False)
|
||||
if is_coorient:
|
||||
if prem_tipo == "GP":
|
||||
selos.add("COORIENT_GP")
|
||||
@@ -87,6 +120,10 @@ def extrair_selos_entry(detalhes: Dict[str, Any]) -> Set[str]:
|
||||
elif prem_tipo == "MENCAO":
|
||||
selos.add("ORIENT_MENCAO")
|
||||
|
||||
idiomas = detalhes.get("idiomas", [])
|
||||
if len(idiomas) >= 3:
|
||||
selos.add("IDIOMA_MULTILINGUE")
|
||||
|
||||
return selos
|
||||
|
||||
|
||||
|
||||
@@ -214,14 +214,20 @@ async def ranking_paginado(
|
||||
if not oracle_repo:
|
||||
raise HTTPException(status_code=503, detail="Oracle não configurado")
|
||||
|
||||
total = oracle_repo.contar_total(filtro_ativo=ativo)
|
||||
selos_lista = [s.strip() for s in selos.split(",") if s.strip()] if selos else None
|
||||
|
||||
total = oracle_repo.contar_total(filtro_ativo=ativo, filtro_selos=selos_lista)
|
||||
if total == 0:
|
||||
if selos_lista:
|
||||
return RankingPaginadoResponseSchema(
|
||||
total=0, page=page, size=size, total_pages=0, consultores=[]
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=503,
|
||||
detail="Ranking ainda não foi processado. Execute POST /api/v1/ranking/processar.",
|
||||
)
|
||||
|
||||
consultores = oracle_repo.buscar_paginado(page=page, size=size, filtro_ativo=ativo)
|
||||
consultores = oracle_repo.buscar_paginado(page=page, size=size, filtro_ativo=ativo, filtro_selos=selos_lista)
|
||||
total_pages = (total + size - 1) // size
|
||||
|
||||
consultores_schema = []
|
||||
|
||||
Reference in New Issue
Block a user