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:
Frederico Castro
2025-12-13 16:41:55 -03:00
parent 97cd328415
commit 2d4e93f82a
15 changed files with 1517 additions and 1001 deletions

View File

@@ -22,19 +22,10 @@ class ProcessarRankingJob:
self.oracle_remote_client = oracle_remote_client
self.oracle_local_client = oracle_local_client
self.ranking_repo = ranking_repo
# Para acelerar a carga principal, não buscamos PPG aqui (Componente B vem depois)
self.consultor_repo = ConsultorRepositoryImpl(es_client, oracle_client=None)
self.calculador = CalculadorPontuacao()
async def executar(self, limpar_antes: bool = True) -> Dict[str, Any]:
"""
Executa o processamento completo do ranking:
1. Limpa tabela (se solicitado)
2. Scroll por todos os documentos ES
3. Para cada batch: calcula pontuação e insere no Oracle
4. Atualiza posições
5. Retorna estatísticas
"""
if job_status.is_running:
raise RuntimeError("Job já está em execução")
@@ -73,13 +64,6 @@ class ProcessarRankingJob:
raise RuntimeError(f"Erro ao processar ranking: {e}")
async def _processar_batch(self, docs: list, progress: dict) -> None:
"""
Processa um batch de documentos:
1. Constrói consultores
2. Calcula pontuação
3. Insere no Oracle
4. Atualiza status
"""
consultores_para_inserir = []
for doc in docs:
@@ -90,10 +74,10 @@ class ProcessarRankingJob:
"id_pessoa": consultor.id_pessoa,
"nome": consultor.nome,
"pontuacao_total": consultor.pontuacao_total,
"componente_a": consultor.pontuacao.componente_a.total,
"componente_b": consultor.pontuacao.componente_b.total,
"componente_c": consultor.pontuacao.componente_c.total,
"componente_d": consultor.pontuacao.componente_d.total,
"componente_a": consultor.pontuacao_bloco_a,
"componente_b": 0,
"componente_c": consultor.pontuacao_bloco_c,
"componente_d": consultor.pontuacao_bloco_d,
"ativo": consultor.ativo,
"anos_atuacao": consultor.anos_atuacao,
"detalhes": self._gerar_json_detalhes(consultor)
@@ -117,15 +101,13 @@ class ProcessarRankingJob:
)
def _gerar_json_detalhes(self, consultor) -> dict:
"""
Gera JSON com detalhes completos do consultor para armazenar no CLOB.
"""
return {
"id_pessoa": consultor.id_pessoa,
"nome": consultor.nome,
"cpf": consultor.cpf,
"coordenacoes_capes": [
{
"codigo": c.codigo,
"tipo": c.tipo,
"area_avaliacao": c.area_avaliacao,
"inicio": c.periodo.inicio.isoformat() if c.periodo.inicio else None,
@@ -134,37 +116,78 @@ class ProcessarRankingJob:
}
for c in consultor.coordenacoes_capes
],
"coordenacoes_programas": [
{
"id_programa": c.id_programa,
"nome_programa": c.nome_programa,
"codigo_programa": c.codigo_programa,
"nota_ppg": c.nota_ppg,
"modalidade": c.modalidade,
"area_avaliacao": c.area_avaliacao,
"inicio": c.periodo.inicio.isoformat() if c.periodo.inicio else None,
"fim": c.periodo.fim.isoformat() if c.periodo.fim else None
}
for c in consultor.coordenacoes_programas
],
"consultoria": {
"total_eventos": consultor.consultoria.total_eventos,
"eventos_recentes": consultor.consultoria.eventos_recentes,
"continuidade": consultor.consultoria.continuidade,
"anos_consecutivos": consultor.consultoria.anos_consecutivos,
"codigo": consultor.consultoria.codigo,
"situacao": consultor.consultoria.situacao,
"anos_completos": consultor.consultoria.anos_completos,
"inicio": consultor.consultoria.periodo.inicio.isoformat() if consultor.consultoria.periodo.inicio else None,
"fim": consultor.consultoria.periodo.fim.isoformat() if consultor.consultoria.periodo.fim else None,
"areas": consultor.consultoria.areas,
"vezes_responsavel": consultor.consultoria.vezes_responsavel
"anos_consecutivos": consultor.consultoria.anos_consecutivos,
"retornos": consultor.consultoria.retornos
} if consultor.consultoria else None,
"inscricoes": [
{
"codigo": i.codigo,
"tipo": i.tipo,
"premio": i.premio,
"ano": i.ano,
"situacao": i.situacao
}
for i in consultor.inscricoes
],
"avaliacoes_comissao": [
{
"codigo": a.codigo,
"tipo": a.tipo,
"premio": a.premio,
"ano": a.ano,
"comissao_tipo": a.comissao_tipo
}
for a in consultor.avaliacoes_comissao
],
"premiacoes": [
{
"codigo": p.codigo,
"tipo": p.tipo,
"nome_premio": p.nome_premio,
"ano": p.ano,
"pontos": p.pontos
"ano": p.ano
}
for p in consultor.premiacoes
],
"pontuacao": consultor.pontuacao.detalhamento
"bolsas_cnpq": [
{
"codigo": b.codigo,
"nivel": b.nivel,
"area": b.area
}
for b in consultor.bolsas_cnpq
],
"participacoes": [
{
"codigo": p.codigo,
"tipo": p.tipo,
"descricao": p.descricao,
"ano": p.ano
}
for p in consultor.participacoes
],
"orientacoes": [
{
"codigo": o.codigo,
"tipo": o.tipo,
"nivel": o.nivel,
"ano": o.ano
}
for o in consultor.orientacoes
],
"membros_banca": [
{
"codigo": m.codigo,
"tipo": m.tipo,
"nivel": m.nivel,
"ano": m.ano
}
for m in consultor.membros_banca
],
"pontuacao": consultor.pontuacao.to_dict() if consultor.pontuacao else None
}