Reimplementa sistema de ranking com novos critérios V2
Mudanças principais: - Substitui 4 Componentes (A,B,C,D) por 3 Blocos (A,C,D) - Remove Componente B (Coordenação PPG = 0 pts no V1) - Adiciona novos tipos de atuação do Elasticsearch - Implementa critérios de pontuação com tetos individuais Bloco A - Coordenação CAPES: - CA (max 450), CAJ (max 370), CAJ_MP (max 315), CAM (max 280) - Calcula base + tempo + bônus atualidade + bônus retorno Bloco C - Consultoria: - CONS_ATIVO (base 150), CONS_HIST (base 100), CONS_FALECIDO (base 100) - Bônus continuidade: 3anos=+5, 5anos=+10, 8anos=+15 - Bônus retorno: +15 Bloco D - Premiações/Avaliações: - Inscrições (INSC_AUTOR, INSC_INST) - Avaliações (AVAL_COMIS_PREMIO, AVAL_COMIS_GP) - Coordenações (COORD_COMIS_PREMIO, COORD_COMIS_GP) - Premiações (PREMIACAO, PREMIACAO_GP, MENCAO) - Bolsas CNPQ, Participações, Orientações, Membros de Banca Frontend: - Header, ConsultorCard, CompararModal atualizados para 3 blocos - API service atualizado para nova estrutura de dados
This commit is contained in:
@@ -6,9 +6,14 @@ import asyncio
|
||||
from ...domain.entities.consultor import (
|
||||
Consultor,
|
||||
CoordenacaoCapes,
|
||||
CoordenacaoPrograma,
|
||||
Consultoria,
|
||||
Inscricao,
|
||||
AvaliacaoComissao,
|
||||
Premiacao,
|
||||
BolsaCNPQ,
|
||||
Participacao,
|
||||
Orientacao,
|
||||
MembroBanca,
|
||||
)
|
||||
from ...domain.repositories.consultor_repository import ConsultorRepository
|
||||
from ...domain.services.calculador_pontuacao import CalculadorPontuacao
|
||||
@@ -42,36 +47,12 @@ _ranking_cache = RankingCache(ttl_seconds=300)
|
||||
|
||||
|
||||
class ConsultorRepositoryImpl(ConsultorRepository):
|
||||
def __init__(self, es_client: ElasticsearchClient, oracle_client: OracleClient):
|
||||
def __init__(self, es_client: ElasticsearchClient, oracle_client: OracleClient = None):
|
||||
self.es_client = es_client
|
||||
self.oracle_client = oracle_client
|
||||
self.calculador = CalculadorPontuacao()
|
||||
self.es_disponivel = True
|
||||
|
||||
def _mesclar_periodos(self, periodos: List[Periodo]) -> List[Periodo]:
|
||||
"""
|
||||
Mescla períodos sobrepostos/contíguos para evitar contagem dupla de tempo.
|
||||
"""
|
||||
if not periodos:
|
||||
return []
|
||||
|
||||
periodos = sorted(periodos, key=lambda p: p.inicio)
|
||||
mesclados: List[Periodo] = []
|
||||
for p in periodos:
|
||||
if not mesclados:
|
||||
mesclados.append(p)
|
||||
continue
|
||||
|
||||
ultimo = mesclados[-1]
|
||||
fim_ultimo = ultimo.fim or datetime.now()
|
||||
fim_atual = p.fim or datetime.now()
|
||||
if p.inicio <= fim_ultimo:
|
||||
novo_fim = max(fim_ultimo, fim_atual)
|
||||
mesclados[-1] = Periodo(inicio=ultimo.inicio, fim=novo_fim if not ultimo.ativo else None)
|
||||
else:
|
||||
mesclados.append(p)
|
||||
return mesclados
|
||||
|
||||
def _parse_date(self, date_str: Optional[str]) -> Optional[datetime]:
|
||||
if not date_str:
|
||||
return None
|
||||
@@ -80,10 +61,87 @@ class ConsultorRepositoryImpl(ConsultorRepository):
|
||||
except:
|
||||
return None
|
||||
|
||||
def _extrair_consultoria(self, atuacoes: List[Dict[str, Any]]) -> Optional[Consultoria]:
|
||||
consultorias = [
|
||||
a for a in atuacoes if a.get("tipo") in ["Consultor", "Histórico de Consultoria"]
|
||||
def _mesclar_periodos(self, periodos: List[Periodo]) -> List[Periodo]:
|
||||
if not periodos:
|
||||
return []
|
||||
periodos = sorted(periodos, key=lambda p: p.inicio if p.inicio else datetime.min)
|
||||
mesclados: List[Periodo] = []
|
||||
for p in periodos:
|
||||
if not mesclados:
|
||||
mesclados.append(p)
|
||||
continue
|
||||
ultimo = mesclados[-1]
|
||||
fim_ultimo = ultimo.fim or datetime.now()
|
||||
fim_atual = p.fim or datetime.now()
|
||||
if p.inicio and p.inicio <= fim_ultimo:
|
||||
novo_fim = max(fim_ultimo, fim_atual)
|
||||
mesclados[-1] = Periodo(inicio=ultimo.inicio, fim=novo_fim if not ultimo.ativo else None)
|
||||
else:
|
||||
mesclados.append(p)
|
||||
return mesclados
|
||||
|
||||
def _inferir_tipo_coordenacao(self, coord: Dict[str, Any]) -> str:
|
||||
dados_coord = coord.get("dadosCoordenacaoArea", {}) or {}
|
||||
tipo_coord = dados_coord.get("tipo", "").lower()
|
||||
|
||||
if "câmara" in tipo_coord or "camara" in tipo_coord:
|
||||
return "CAM"
|
||||
elif "adjunt" in tipo_coord:
|
||||
if "profissional" in tipo_coord or "mestrado" in tipo_coord:
|
||||
return "CAJ_MP"
|
||||
return "CAJ"
|
||||
elif "coordenador de área" in tipo_coord:
|
||||
return "CA"
|
||||
|
||||
descricao = coord.get("descricao", "").lower()
|
||||
nome = coord.get("nome", "").lower()
|
||||
texto = f"{descricao} {nome}"
|
||||
|
||||
if "câmara" in texto or "camara" in texto:
|
||||
return "CAM"
|
||||
elif "mestrado profissional" in texto:
|
||||
return "CAJ_MP"
|
||||
elif "adjunt" in texto:
|
||||
return "CAJ"
|
||||
return "CA"
|
||||
|
||||
def _extrair_coordenacoes_capes(self, atuacoes: List[Dict[str, Any]]) -> List[CoordenacaoCapes]:
|
||||
coordenacoes = [
|
||||
a for a in atuacoes
|
||||
if a.get("tipo") in ["Coordenação de Área de Avaliação", "Histórico de Coordenação de Área de Avaliação"]
|
||||
]
|
||||
|
||||
resultado = []
|
||||
for coord in coordenacoes:
|
||||
dados_coord = coord.get("dadosCoordenacaoArea", {}) or {}
|
||||
inicio = self._parse_date(dados_coord.get("inicioVinculacao")) or self._parse_date(coord.get("inicio"))
|
||||
if not inicio:
|
||||
continue
|
||||
|
||||
codigo = self._inferir_tipo_coordenacao(coord)
|
||||
fim = self._parse_date(dados_coord.get("fimVinculacao")) or self._parse_date(coord.get("fim"))
|
||||
|
||||
if inicio and fim and fim < inicio:
|
||||
fim = None
|
||||
|
||||
area_avaliacao_obj = dados_coord.get("areaAvaliacao", {}) or {}
|
||||
area_avaliacao = area_avaliacao_obj.get("nome") if isinstance(area_avaliacao_obj, dict) else coord.get("areaAvaliacao", "N/A")
|
||||
if not area_avaliacao:
|
||||
area_avaliacao = coord.get("descricao", "N/A").split(" - ")[0] if coord.get("descricao") else "N/A"
|
||||
|
||||
resultado.append(CoordenacaoCapes(
|
||||
codigo=codigo,
|
||||
tipo=codigo,
|
||||
area_avaliacao=area_avaliacao,
|
||||
periodo=Periodo(inicio=inicio, fim=fim),
|
||||
areas_adicionais=[],
|
||||
ja_coordenou_antes=len(resultado) > 0,
|
||||
))
|
||||
|
||||
return resultado
|
||||
|
||||
def _extrair_consultoria(self, atuacoes: List[Dict[str, Any]]) -> Optional[Consultoria]:
|
||||
consultorias = [a for a in atuacoes if a.get("tipo") in ["Consultor", "Histórico de Consultoria"]]
|
||||
if not consultorias:
|
||||
return None
|
||||
|
||||
@@ -109,7 +167,7 @@ class ConsultorRepositoryImpl(ConsultorRepository):
|
||||
)
|
||||
|
||||
if inicio and fim and fim < inicio:
|
||||
fim = None # dados inconsistentes: trata como em aberto
|
||||
fim = None
|
||||
if inicio:
|
||||
try:
|
||||
periodos.append(Periodo(inicio=inicio, fim=fim))
|
||||
@@ -125,283 +183,302 @@ class ConsultorRepositoryImpl(ConsultorRepository):
|
||||
return None
|
||||
|
||||
mesclados = self._mesclar_periodos(periodos)
|
||||
anos_total = sum(p.anos_completos(datetime.now()) for p in mesclados)
|
||||
anos_consecutivos = max((p.anos_completos(datetime.now()) for p in mesclados), default=0)
|
||||
retornos = max(0, len(mesclados) - 1)
|
||||
ativo = any(p.ativo for p in periodos)
|
||||
|
||||
eventos_sae = [a for a in atuacoes if a.get("tipo") == "Evento"]
|
||||
total_eventos = len(eventos_sae)
|
||||
limite_recente = datetime.now() - timedelta(days=730)
|
||||
eventos_recentes = 0
|
||||
vezes_responsavel = 0
|
||||
for ev in eventos_sae:
|
||||
data_fim = self._parse_date(ev.get("fim")) or self._parse_date(ev.get("inicio"))
|
||||
if data_fim and data_fim >= limite_recente:
|
||||
eventos_recentes += 1
|
||||
dados_evento = ev.get("dadosEvento", {}) or {}
|
||||
if dados_evento.get("consultorResponsavel") == "Sim":
|
||||
vezes_responsavel += 1
|
||||
situacao_final = situacoes[0] if situacoes else "N/A"
|
||||
is_ativo = ativo or "atividade" in situacao_final.lower() or "ativo" in situacao_final.lower()
|
||||
is_falecido = "falecido" in situacao_final.lower()
|
||||
|
||||
if is_falecido:
|
||||
codigo = "CONS_FALECIDO"
|
||||
elif is_ativo:
|
||||
codigo = "CONS_ATIVO"
|
||||
else:
|
||||
codigo = "CONS_HIST"
|
||||
|
||||
primeiro_evento = min(p.inicio for p in periodos)
|
||||
ultimo_evento = max((p.fim or datetime.now()) for p in periodos) if not ativo else datetime.now()
|
||||
|
||||
areas = list(set(areas)) if areas else ["N/A"]
|
||||
|
||||
situacao_final = situacoes[0] if situacoes else "N/A"
|
||||
|
||||
return Consultoria(
|
||||
total_eventos=total_eventos,
|
||||
eventos_recentes=eventos_recentes,
|
||||
primeiro_evento=primeiro_evento,
|
||||
ultimo_evento=ultimo_evento,
|
||||
areas=areas,
|
||||
codigo=codigo,
|
||||
situacao=situacao_final,
|
||||
anos_completos=anos_total,
|
||||
periodo=Periodo(inicio=primeiro_evento, fim=None if ativo else datetime.now()),
|
||||
areas=areas,
|
||||
anos_consecutivos=anos_consecutivos,
|
||||
retornos=retornos,
|
||||
vezes_responsavel=vezes_responsavel,
|
||||
)
|
||||
|
||||
def _extrair_coordenacoes_capes(
|
||||
self, atuacoes: List[Dict[str, Any]]
|
||||
) -> List[CoordenacaoCapes]:
|
||||
coordenacoes = [
|
||||
a
|
||||
for a in atuacoes
|
||||
if a.get("tipo")
|
||||
in [
|
||||
"Coordenação de Área de Avaliação",
|
||||
"Histórico de Coordenação de Área de Avaliação",
|
||||
]
|
||||
]
|
||||
|
||||
resultado = []
|
||||
for coord in coordenacoes:
|
||||
dados_coord = coord.get("dadosCoordenacaoArea", {}) or {}
|
||||
|
||||
inicio = (
|
||||
self._parse_date(dados_coord.get("inicioVinculacao"))
|
||||
or self._parse_date(coord.get("inicio"))
|
||||
)
|
||||
if not inicio:
|
||||
def _extrair_inscricoes(self, atuacoes: List[Dict[str, Any]]) -> List[Inscricao]:
|
||||
inscricoes = []
|
||||
for a in atuacoes:
|
||||
if a.get("tipo") != "Inscrição Prêmio":
|
||||
continue
|
||||
|
||||
tipo = self._inferir_tipo_coordenacao(coord)
|
||||
fim = (
|
||||
self._parse_date(dados_coord.get("fimVinculacao"))
|
||||
or self._parse_date(coord.get("fim"))
|
||||
)
|
||||
dados = a.get("dadosParticipacaoInscricaoPremio", {}) or {}
|
||||
tipo_part = dados.get("tipo", "")
|
||||
nome_premio = dados.get("nomePremio") or dados.get("premio") or a.get("descricao", "")
|
||||
ano = dados.get("ano")
|
||||
if not ano:
|
||||
inicio = self._parse_date(a.get("inicio"))
|
||||
ano = inicio.year if inicio else datetime.now().year
|
||||
|
||||
if inicio and fim and fim < inicio:
|
||||
fim = None # ignora fins inconsistentes para não quebrar cálculo
|
||||
is_institucional = "coordenador" in tipo_part.lower() or "ppg" in tipo_part.lower()
|
||||
codigo = "INSC_INST" if is_institucional else "INSC_AUTOR"
|
||||
|
||||
area_avaliacao_obj = dados_coord.get("areaAvaliacao", {}) or {}
|
||||
area_avaliacao = area_avaliacao_obj.get("nome") if isinstance(area_avaliacao_obj, dict) else coord.get("areaAvaliacao", "N/A")
|
||||
if not area_avaliacao:
|
||||
area_avaliacao = coord.get("descricao", "N/A").split(" - ")[0] if coord.get("descricao") else "N/A"
|
||||
inscricoes.append(Inscricao(
|
||||
codigo=codigo,
|
||||
tipo=tipo_part,
|
||||
premio=nome_premio,
|
||||
ano=ano,
|
||||
situacao=dados.get("situacao", ""),
|
||||
))
|
||||
|
||||
resultado.append(
|
||||
CoordenacaoCapes(
|
||||
tipo=tipo,
|
||||
area_avaliacao=area_avaliacao,
|
||||
periodo=Periodo(inicio=inicio, fim=fim),
|
||||
areas_adicionais=[],
|
||||
ja_coordenou_antes=len(resultado) > 0,
|
||||
)
|
||||
)
|
||||
return inscricoes
|
||||
|
||||
return resultado
|
||||
def _extrair_avaliacoes_comissao(self, atuacoes: List[Dict[str, Any]]) -> List[AvaliacaoComissao]:
|
||||
avaliacoes = []
|
||||
for a in atuacoes:
|
||||
if a.get("tipo") != "Avaliação Prêmio":
|
||||
continue
|
||||
|
||||
def _inferir_tipo_coordenacao(self, coord: Dict[str, Any]) -> str:
|
||||
dados_coord = coord.get("dadosCoordenacaoArea", {}) or {}
|
||||
tipo_coord = dados_coord.get("tipo", "").lower()
|
||||
dados = a.get("dadosParticipacaoPremio", {}) or {}
|
||||
tipo_part = dados.get("tipo", "")
|
||||
nome_premio = dados.get("nomePremio") or dados.get("premio") or a.get("descricao", "")
|
||||
ano = dados.get("ano")
|
||||
if not ano:
|
||||
inicio = self._parse_date(a.get("inicio"))
|
||||
ano = inicio.year if inicio else datetime.now().year
|
||||
|
||||
if "câmara" in tipo_coord or "camara" in tipo_coord:
|
||||
return "CAM"
|
||||
elif "adjunt" in tipo_coord:
|
||||
if "profissional" in tipo_coord or "mestrado" in tipo_coord:
|
||||
return "CAJ-MP"
|
||||
return "CAJ"
|
||||
elif "coordenador de área" in tipo_coord:
|
||||
return "CA"
|
||||
comissao = dados.get("comissao", {}) or {}
|
||||
comissao_tipo = comissao.get("tipo", "") if isinstance(comissao, dict) else ""
|
||||
|
||||
descricao = coord.get("descricao", "").lower()
|
||||
nome = coord.get("nome", "").lower()
|
||||
texto = f"{descricao} {nome}"
|
||||
is_grande_premio = "grande" in nome_premio.lower()
|
||||
is_coordenador = "coordenador" in tipo_part.lower() or "presidente" in tipo_part.lower()
|
||||
|
||||
if "câmara" in texto or "camara" in texto:
|
||||
return "CAM"
|
||||
elif "mestrado profissional" in texto:
|
||||
return "CAJ-MP"
|
||||
elif "adjunt" in texto:
|
||||
return "CAJ"
|
||||
else:
|
||||
return "CA"
|
||||
|
||||
def _classificar_nivel_premio(self, nome: str) -> str:
|
||||
nome = (nome or "").lower()
|
||||
if "grande prêmio capes de tese" in nome or "grande premio capes de tese" in nome:
|
||||
return "nivel1_grande"
|
||||
if "prêmio capes de tese" in nome or "premio capes de tese" in nome:
|
||||
return "nivel1_pct"
|
||||
if "interfarma" in nome or "vale-capes" in nome or "vale capes" in nome:
|
||||
return "nivel2"
|
||||
if nome:
|
||||
return "nivel3"
|
||||
return "desconhecido"
|
||||
|
||||
def _pontuar_premiacao_recebida(self, nivel: str, tipo_premiacao: str) -> int:
|
||||
tipo = (tipo_premiacao or "").lower()
|
||||
if nivel == "nivel1_grande":
|
||||
base = 150
|
||||
extra = 50 if "grande" in tipo else 0
|
||||
return min(base + extra, 180)
|
||||
if nivel == "nivel1_pct":
|
||||
base = 100
|
||||
if "mencao" in tipo:
|
||||
extra = 15
|
||||
elif "premio" in tipo:
|
||||
extra = 25
|
||||
if is_coordenador:
|
||||
codigo = "COORD_COMIS_GP" if is_grande_premio else "COORD_COMIS_PREMIO"
|
||||
else:
|
||||
extra = 0
|
||||
return min(base + extra, 150)
|
||||
if nivel == "nivel2":
|
||||
base = 30
|
||||
if "premio" in tipo:
|
||||
extra = 20
|
||||
elif "mencao" in tipo:
|
||||
extra = 10
|
||||
else:
|
||||
extra = 0
|
||||
return min(base + extra, 60)
|
||||
# nivel3 e fallback
|
||||
base = 10
|
||||
if "premio" in tipo:
|
||||
extra = 5
|
||||
elif "mencao" in tipo:
|
||||
extra = 3
|
||||
else:
|
||||
extra = 0
|
||||
return min(base + extra, 20)
|
||||
codigo = "AVAL_COMIS_GP" if is_grande_premio else "AVAL_COMIS_PREMIO"
|
||||
|
||||
def _pontuar_participacao_premio(self, nivel: str, tipo_participacao: str) -> int:
|
||||
tipo = (tipo_participacao or "").lower()
|
||||
if "avaliador" in tipo or "banca" in tipo:
|
||||
return 2 # teto final tratado em componente D
|
||||
if "coordenador" in tipo or "comissao" in tipo or "comissão" in tipo:
|
||||
if nivel == "nivel1_grande":
|
||||
return 115 # valor máximo já com peso
|
||||
if nivel == "nivel1_pct":
|
||||
return 115 # aproximação segura para teto
|
||||
if nivel == "nivel2":
|
||||
return 80
|
||||
return 40
|
||||
if "inscricao" in tipo or "inscrição" in tipo:
|
||||
if nivel in ["nivel1_grande", "nivel1_pct"]:
|
||||
return 2
|
||||
if nivel == "nivel2":
|
||||
return 1
|
||||
return 1
|
||||
return 0
|
||||
avaliacoes.append(AvaliacaoComissao(
|
||||
codigo=codigo,
|
||||
tipo=tipo_part,
|
||||
premio=nome_premio,
|
||||
ano=ano,
|
||||
comissao_tipo=comissao_tipo,
|
||||
))
|
||||
|
||||
return avaliacoes
|
||||
|
||||
def _extrair_premiacoes(self, atuacoes: List[Dict[str, Any]]) -> List[Premiacao]:
|
||||
premiacoes = []
|
||||
for a in atuacoes:
|
||||
tipo_atuacao = a.get("tipo", "")
|
||||
dados_premiacao = a.get("dadosPremiacaoPremio") or a.get("dadosPremio") or {}
|
||||
dados_participacao = (
|
||||
a.get("dadosParticipacaoPremio")
|
||||
or a.get("dadosParticipacaoInscricaoPremio")
|
||||
or {}
|
||||
)
|
||||
|
||||
# Premiações recebidas
|
||||
if dados_premiacao:
|
||||
nome_premio = dados_premiacao.get("nomePremio") or a.get("descricao", "N/A")
|
||||
tipo_premiacao = dados_premiacao.get("tipoPremiacao") or dados_premiacao.get("tipo", "")
|
||||
ano = dados_premiacao.get("ano") or a.get("ano")
|
||||
if not ano:
|
||||
inicio = self._parse_date(a.get("inicio"))
|
||||
ano = inicio.year if inicio else datetime.now().year
|
||||
|
||||
nivel = self._classificar_nivel_premio(nome_premio)
|
||||
pontos = self._pontuar_premiacao_recebida(nivel, tipo_premiacao)
|
||||
|
||||
premiacoes.append(
|
||||
Premiacao(
|
||||
tipo=tipo_premiacao or tipo_atuacao or "Premiação",
|
||||
nome_premio=nome_premio,
|
||||
ano=ano or datetime.now().year,
|
||||
pontos=int(pontos),
|
||||
)
|
||||
)
|
||||
if a.get("tipo") != "Premiação Prêmio":
|
||||
continue
|
||||
|
||||
# Participações (inscrição/avaliação/coordenação)
|
||||
if dados_participacao:
|
||||
tipo_part = (
|
||||
dados_participacao.get("tipoParticipacao")
|
||||
or dados_participacao.get("tipo")
|
||||
or tipo_atuacao
|
||||
)
|
||||
nome_premio = dados_participacao.get("nomePremio") or a.get("descricao", "N/A")
|
||||
ano = dados_participacao.get("ano") or a.get("ano")
|
||||
if not ano:
|
||||
inicio = self._parse_date(a.get("inicio"))
|
||||
ano = inicio.year if inicio else datetime.now().year
|
||||
|
||||
nivel = self._classificar_nivel_premio(nome_premio)
|
||||
pontos = self._pontuar_participacao_premio(nivel, tipo_part)
|
||||
|
||||
premiacoes.append(
|
||||
Premiacao(
|
||||
tipo=tipo_part or "Participação Prêmio",
|
||||
nome_premio=nome_premio,
|
||||
ano=ano or datetime.now().year,
|
||||
pontos=int(pontos),
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
# Fallback para tipos antigos
|
||||
if tipo_atuacao in [
|
||||
"Premiação Prêmio",
|
||||
"Premiação",
|
||||
"Avaliação Prêmio",
|
||||
"Inscrição Prêmio",
|
||||
]:
|
||||
pontos = self._pontuar_participacao_premio("nivel3", tipo_atuacao)
|
||||
dados = a.get("dadosPremiacaoPremio", {}) or a.get("dadosPremio", {}) or {}
|
||||
tipo_premiacao = dados.get("tipoPremiacao") or dados.get("premiacao") or ""
|
||||
nome_premio = dados.get("nomePremio") or dados.get("evento") or a.get("descricao", "")
|
||||
ano = dados.get("ano")
|
||||
if not ano:
|
||||
inicio = self._parse_date(a.get("inicio"))
|
||||
ano = inicio.year if inicio else datetime.now().year
|
||||
premiacoes.append(
|
||||
Premiacao(
|
||||
tipo=tipo_atuacao,
|
||||
nome_premio=a.get("descricao", "N/A"),
|
||||
ano=ano,
|
||||
pontos=int(pontos),
|
||||
)
|
||||
)
|
||||
|
||||
tipo_lower = tipo_premiacao.lower()
|
||||
nome_lower = nome_premio.lower()
|
||||
|
||||
if "grande" in nome_lower or "grande" in tipo_lower:
|
||||
codigo = "PREMIACAO"
|
||||
elif "menção" in tipo_lower or "mencao" in tipo_lower or "honrosa" in tipo_lower:
|
||||
codigo = "MENCAO"
|
||||
else:
|
||||
codigo = "PREMIACAO_GP"
|
||||
|
||||
premiacoes.append(Premiacao(
|
||||
codigo=codigo,
|
||||
tipo=tipo_premiacao,
|
||||
nome_premio=nome_premio,
|
||||
ano=ano,
|
||||
))
|
||||
|
||||
return premiacoes
|
||||
|
||||
def _extrair_bolsas_cnpq(self, atuacoes: List[Dict[str, Any]]) -> List[BolsaCNPQ]:
|
||||
bolsas = []
|
||||
for a in atuacoes:
|
||||
if a.get("tipo") != "Bolsa CNPQ" and "bolsa" not in a.get("tipo", "").lower():
|
||||
continue
|
||||
|
||||
dados = a.get("dadosBolsa", {}) or {}
|
||||
nivel = dados.get("nivel", "") or dados.get("categoria", "") or ""
|
||||
area = dados.get("areaConhecimento", "") or ""
|
||||
|
||||
nivel_lower = nivel.lower()
|
||||
if "1a" in nivel_lower or "1b" in nivel_lower or "1c" in nivel_lower or "1d" in nivel_lower:
|
||||
codigo = "BOL_BPQ_SUPERIOR"
|
||||
else:
|
||||
codigo = "BOL_BPQ_INTERMEDIARIO"
|
||||
|
||||
bolsas.append(BolsaCNPQ(
|
||||
codigo=codigo,
|
||||
nivel=nivel,
|
||||
area=area,
|
||||
))
|
||||
|
||||
return bolsas
|
||||
|
||||
def _extrair_participacoes(self, atuacoes: List[Dict[str, Any]]) -> List[Participacao]:
|
||||
participacoes = []
|
||||
|
||||
for a in atuacoes:
|
||||
tipo = a.get("tipo", "")
|
||||
|
||||
if tipo == "Evento":
|
||||
participacoes.append(Participacao(
|
||||
codigo="EVENTO",
|
||||
tipo="Evento",
|
||||
descricao=a.get("descricao", ""),
|
||||
ano=self._parse_date(a.get("inicio")).year if self._parse_date(a.get("inicio")) else None,
|
||||
))
|
||||
elif tipo == "Projeto" or "projeto" in tipo.lower():
|
||||
participacoes.append(Participacao(
|
||||
codigo="PROJ",
|
||||
tipo="Projeto",
|
||||
descricao=a.get("descricao", ""),
|
||||
ano=self._parse_date(a.get("inicio")).year if self._parse_date(a.get("inicio")) else None,
|
||||
))
|
||||
|
||||
return participacoes
|
||||
|
||||
def _extrair_orientacoes(self, atuacoes: List[Dict[str, Any]]) -> List[Orientacao]:
|
||||
orientacoes = []
|
||||
|
||||
for a in atuacoes:
|
||||
tipo = a.get("tipo", "").lower()
|
||||
if "orientação" not in tipo and "orientacao" not in tipo:
|
||||
continue
|
||||
if "co-orientação" in tipo or "coorientação" in tipo or "co_orient" in tipo:
|
||||
continue
|
||||
|
||||
dados = a.get("dadosOrientacao", {}) or {}
|
||||
nivel = dados.get("nivel", "") or dados.get("tipo", "") or ""
|
||||
ano = dados.get("ano")
|
||||
if not ano:
|
||||
inicio = self._parse_date(a.get("inicio"))
|
||||
ano = inicio.year if inicio else None
|
||||
|
||||
nivel_lower = nivel.lower()
|
||||
if "pós-doc" in nivel_lower or "pos-doc" in nivel_lower or "posdoc" in nivel_lower:
|
||||
codigo = "ORIENT_POS_DOC"
|
||||
elif "tese" in nivel_lower or "doutorado" in nivel_lower:
|
||||
codigo = "ORIENT_TESE"
|
||||
else:
|
||||
codigo = "ORIENT_DISS"
|
||||
|
||||
orientacoes.append(Orientacao(
|
||||
codigo=codigo,
|
||||
tipo=tipo,
|
||||
nivel=nivel,
|
||||
ano=ano,
|
||||
))
|
||||
|
||||
return orientacoes
|
||||
|
||||
def _extrair_coorientacoes(self, atuacoes: List[Dict[str, Any]]) -> List[Orientacao]:
|
||||
coorientacoes = []
|
||||
|
||||
for a in atuacoes:
|
||||
tipo = a.get("tipo", "").lower()
|
||||
if "co-orientação" not in tipo and "coorientação" not in tipo and "co_orient" not in tipo:
|
||||
continue
|
||||
|
||||
dados = a.get("dadosOrientacao", {}) or a.get("dadosCoorientacao", {}) or {}
|
||||
nivel = dados.get("nivel", "") or dados.get("tipo", "") or ""
|
||||
ano = dados.get("ano")
|
||||
if not ano:
|
||||
inicio = self._parse_date(a.get("inicio"))
|
||||
ano = inicio.year if inicio else None
|
||||
|
||||
nivel_lower = nivel.lower()
|
||||
if "pós-doc" in nivel_lower or "pos-doc" in nivel_lower or "posdoc" in nivel_lower:
|
||||
codigo = "CO_ORIENT_POS_DOC"
|
||||
elif "tese" in nivel_lower or "doutorado" in nivel_lower:
|
||||
codigo = "CO_ORIENT_TESE"
|
||||
else:
|
||||
codigo = "CO_ORIENT_DISS"
|
||||
|
||||
coorientacoes.append(Orientacao(
|
||||
codigo=codigo,
|
||||
tipo=tipo,
|
||||
nivel=nivel,
|
||||
ano=ano,
|
||||
))
|
||||
|
||||
return coorientacoes
|
||||
|
||||
def _extrair_membros_banca(self, atuacoes: List[Dict[str, Any]]) -> List[MembroBanca]:
|
||||
membros = []
|
||||
|
||||
for a in atuacoes:
|
||||
tipo = a.get("tipo", "").lower()
|
||||
if "banca" not in tipo:
|
||||
continue
|
||||
|
||||
dados = a.get("dadosBanca", {}) or {}
|
||||
nivel = dados.get("nivel", "") or dados.get("tipo", "") or ""
|
||||
ano = dados.get("ano")
|
||||
if not ano:
|
||||
inicio = self._parse_date(a.get("inicio"))
|
||||
ano = inicio.year if inicio else None
|
||||
|
||||
nivel_lower = nivel.lower()
|
||||
if "pós-doc" in nivel_lower or "pos-doc" in nivel_lower or "posdoc" in nivel_lower:
|
||||
codigo = "MB_BANCA_POS_DOC"
|
||||
elif "tese" in nivel_lower or "doutorado" in nivel_lower:
|
||||
codigo = "MB_BANCA_TESE"
|
||||
else:
|
||||
codigo = "MB_BANCA_DISS"
|
||||
|
||||
membros.append(MembroBanca(
|
||||
codigo=codigo,
|
||||
tipo=tipo,
|
||||
nivel=nivel,
|
||||
ano=ano,
|
||||
))
|
||||
|
||||
return membros
|
||||
|
||||
async def _construir_consultor(self, doc: Dict[str, Any]) -> Consultor:
|
||||
id_pessoa = doc["id"]
|
||||
dados_pessoais = doc.get("dadosPessoais", {})
|
||||
atuacoes = doc.get("atuacoes", [])
|
||||
|
||||
consultoria = self._extrair_consultoria(atuacoes)
|
||||
coordenacoes_capes = self._extrair_coordenacoes_capes(atuacoes)
|
||||
consultoria = self._extrair_consultoria(atuacoes)
|
||||
inscricoes = self._extrair_inscricoes(atuacoes)
|
||||
avaliacoes = self._extrair_avaliacoes_comissao(atuacoes)
|
||||
premiacoes = self._extrair_premiacoes(atuacoes)
|
||||
bolsas = self._extrair_bolsas_cnpq(atuacoes)
|
||||
participacoes = self._extrair_participacoes(atuacoes)
|
||||
orientacoes = self._extrair_orientacoes(atuacoes)
|
||||
coorientacoes = self._extrair_coorientacoes(atuacoes)
|
||||
membros_banca = self._extrair_membros_banca(atuacoes)
|
||||
|
||||
consultor = Consultor(
|
||||
id_pessoa=id_pessoa,
|
||||
nome=dados_pessoais.get("nome", "N/A"),
|
||||
cpf=dados_pessoais.get("cpf"),
|
||||
coordenacoes_capes=coordenacoes_capes,
|
||||
coordenacoes_programas=[], # PPG vem do job/ETL de Componente B
|
||||
consultoria=consultoria,
|
||||
inscricoes=inscricoes,
|
||||
avaliacoes_comissao=avaliacoes,
|
||||
premiacoes=premiacoes,
|
||||
bolsas_cnpq=bolsas,
|
||||
participacoes=participacoes,
|
||||
orientacoes=orientacoes + coorientacoes,
|
||||
membros_banca=membros_banca,
|
||||
)
|
||||
|
||||
consultor.pontuacao = self.calculador.calcular_pontuacao_completa(consultor)
|
||||
@@ -457,8 +534,6 @@ class ConsultorRepositoryImpl(ConsultorRepository):
|
||||
consultores = []
|
||||
for doc in docs:
|
||||
consultor = await self._construir_consultor(doc)
|
||||
score_es = doc.get("_score_es", 0)
|
||||
consultor.score_es = score_es
|
||||
consultores.append(consultor)
|
||||
|
||||
consultores_ordenados = sorted(
|
||||
|
||||
Reference in New Issue
Block a user