diff --git a/Ranking_ATUACAPES_Criterios_Gerencia.pdf b/Ranking_ATUACAPES_Criterios_Gerencia.pdf new file mode 100644 index 0000000..9b7d32f Binary files /dev/null and b/Ranking_ATUACAPES_Criterios_Gerencia.pdf differ diff --git a/backend/src/infrastructure/elasticsearch/client.py b/backend/src/infrastructure/elasticsearch/client.py index f4782b9..12caf7f 100644 --- a/backend/src/infrastructure/elasticsearch/client.py +++ b/backend/src/infrastructure/elasticsearch/client.py @@ -614,14 +614,20 @@ class ElasticsearchClient: "query": { "bool": { "must": [ - {"term": {"atuacoes.tipo": "Consultor"}} + {"term": {"atuacoes.tipo": "Consultor"}}, + { + "bool": { + "should": [ + {"match_phrase": {"atuacoes.dadosConsultoria.situacaoConsultoria": "Atividade Contínua"}}, + {"term": {"atuacoes.dadosConsultoria.situacaoConsultoria": "Ativo"}} + ], + "minimum_should_match": 1 + } + } ], - "should": [ - {"match": {"atuacoes.dadosConsultoria.situacaoConsultoria": "Atividade Contínua"}}, - {"match": {"atuacoes.dadosConsultoria.situacaoConsultoria": "Ativo"}}, - {"match": {"atuacoes.dadosConsultoria.situacaoConsultoria": "Contínua"}} - ], - "minimum_should_match": 1 + "must_not": [ + {"match_phrase": {"atuacoes.dadosConsultoria.situacaoConsultoria": "Inatividade"}} + ] } } } diff --git a/frontend/public/logo_capes.jpg b/frontend/public/logo_capes.jpg new file mode 100644 index 0000000..bde2711 Binary files /dev/null and b/frontend/public/logo_capes.jpg differ diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 260bc1e..cd8d218 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -46,13 +46,14 @@ function App() { const handleSugestaoSelecionada = async (idPessoa) => { try { - const resultados = await rankingService.searchConsultor(String(idPessoa), 1); - if (resultados && resultados.length > 0) { - const alvo = resultados[0]; - const pos = alvo.posicao || 1; - const pagina = Math.ceil(pos / pageSize); - setHighlightId(alvo.id_pessoa); - setPage(pagina); + const response = await fetch(`/api/v1/ranking/posicao/${idPessoa}`); + if (response.ok) { + const alvo = await response.json(); + if (alvo.encontrado && alvo.posicao) { + const pagina = Math.ceil(alvo.posicao / pageSize); + setHighlightId(alvo.id_pessoa); + setPage(pagina); + } } } catch (err) { console.error('Erro ao navegar para consultor:', err); diff --git a/frontend/src/components/SugerirConsultores.jsx b/frontend/src/components/SugerirConsultores.jsx index 45fbce4..7e3403b 100644 --- a/frontend/src/components/SugerirConsultores.jsx +++ b/frontend/src/components/SugerirConsultores.jsx @@ -96,7 +96,7 @@ const SugerirConsultores = ({ onClose, onSelectConsultor }) => { {areas.map((area) => ( ))} diff --git a/logo_capes.jpg b/logo_capes.jpg new file mode 100644 index 0000000..bde2711 Binary files /dev/null and b/logo_capes.jpg differ diff --git a/ranking_atuacapes_criterios_gerencia.html b/ranking_atuacapes_criterios_gerencia.html new file mode 100644 index 0000000..df02dfc --- /dev/null +++ b/ranking_atuacapes_criterios_gerencia.html @@ -0,0 +1,1604 @@ + + + + + + Ranking ATUACAPES - Criterios de Classificacao + + + + + +
+ Logo CAPES +
Ranking de Consultores
+
Sistema ATUACAPES
Criterios de Classificacao e Pontuacao
+
Versao 1.0
+
Dezembro de 2025
+
+ + +
+

Sumario

+ +
1. Visao Geral
+
1.1 Introducao
+
1.2 Estrutura do Ranking
+
1.3 Formula de Calculo
+ +
2. Mapa de Atuacoes
+
2.1 Coordenacao CAPES (Bloco A)
+
2.2 Consultoria (Bloco B)
+
2.3 Inscricoes, Avaliacoes e Premiacoes (Bloco C)
+
2.4 Participacoes e Competencias (Bloco D)
+ +
3. Pontuacao Base
+
3.1 Tabela de Pontuacao por Atuacao
+
3.2 Tetos de Pontuacao
+ +
4. Regras de Tempo
+
4.1 Atuacoes com Pontuacao por Tempo
+
4.2 Multiplicadores e Tetos
+ +
5. Bonus e Reconhecimentos
+
5.1 Bonus de Atualidade
+
5.2 Bonus de Retorno
+
5.3 Bonus de Continuidade
+
5.4 Selos de Reconhecimento
+ +
6. Indicadores de Perfil
+ +
Anexos
+
A. Resumo Executivo
+
B. Glossario de Codigos
+
+ + + +

1. Visao Geral

+ +

1.1 Introducao

+

O Ranking de Consultores ATUACAPES e um sistema de classificacao institucional que avalia e ordena os consultores da CAPES com base em suas atuacoes, contribuicoes e reconhecimentos ao longo do tempo. Este documento consolida todos os criterios utilizados para o calculo da pontuacao e ordenacao dos consultores.

+ +
+ Objetivo: Estabelecer criterios transparentes, objetivos e auditaveis para a classificacao de consultores, valorizando a experiencia institucional, a atuacao continua e as contribuicoes ao Sistema Nacional de Pos-Graduacao (SNPG). +
+ +

1.2 Estrutura do Ranking

+ +

O sistema de pontuacao esta organizado em 3 Ramos e 5 Blocos:

+ +
+
+
A
+
Funcoes
+
+
+
B
+
Competencias
+
+
+
C
+
Participacoes
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BlocoConteudoDescricao
ACoordenacao CAPESFuncoes de coordenacao no ambito da CAPES (CA, CAJ, CAJ_MP, CAM)
BConsultoriaAtuacao como consultor (ativo, historico, falecido)
CInscricoes e AvaliacoesParticipacao em processos de premiacao e comissoes avaliadoras
DParticipacoes e CompetenciasEventos, projetos, orientacoes, bolsas e titulacoes
ECoordenacao de PPGReservado (dados incompletos no V1)
+ +

1.3 Formula de Calculo

+ +

A pontuacao total de cada consultor e calculada pela soma das pontuacoes individuais de cada atuacao:

+ +
+ Score_Atuacao = min(Pontuacao_Base + Pontos_Tempo + Bonus, Teto_Atuacao) +
+ +

Onde:

+ + +
+ Importante: Apenas anos completos sao contabilizados para pontuacao de tempo. Fracoes de ano nao geram pontos adicionais. +
+ +

2. Mapa de Atuacoes

+ +

2.1 Coordenacao CAPES (Bloco A)

+ +

Funcoes de coordenacao exercidas no ambito da CAPES, com responsabilidade institucional pela conducao de atividades do SNPG.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AtuacaoCodigoTipoAtivo V1Descricao
Coordenador de AreaCAFuncaoSimFuncao maxima de coordenacao no SNPG, com responsabilidade institucional pela conducao da area de avaliacao.
Coordenador AdjuntoCAJFuncaoSimFuncao estrategica de apoio a Coordenacao de Area, atuando na gestao e suporte as atividades institucionais.
Coordenador Adjunto MPCAJ_MPFuncaoSimFuncao de coordenacao adjunta com foco em Mestrado Profissional, em apoio a Coordenacao de Area.
Camara TematicaCAMFuncaoSimFuncao transversal de apoio tecnico e tematico, com atuacao consultiva em temas especificos.
Coordenador de ProgramaPPG_COORDFuncaoNaoLimitacao de cobertura: tratado como papel de inscricao institucional no Ranking V1.
+ +

2.2 Consultoria (Bloco B)

+ +

Atuacao de consultoria vinculada a processos e demandas da CAPES.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AtuacaoCodigoTipoAtivo V1Descricao
Consultor AtivoCONS_ATIVOFuncaoSimAtuacao de consultoria com impacto institucional no periodo vigente.
Consultor HistoricoCONS_HISTFuncaoSimAtuacao de consultoria em periodos anteriores, registrada como legado institucional.
Consultor FalecidoCONS_FALECIDOFuncaoSimAtuacao de consultoria historica registrada como legado institucional (in memoriam).
+ +

2.3 Inscricoes, Avaliacoes e Premiacoes (Bloco C)

+ +

Participacao em processos de premiacao, inscricoes e atuacao em comissoes avaliadoras.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AtuacaoCodigoTipoDescricao
Inscricao AutoinscricaoINSC_AUTORFuncaoAto individual: inscricao realizada pelo proprio autor, sem validacao colegiada institucional.
Inscricao InstitucionalINSC_INSTFuncaoInscricao institucional: submissao decorrente de deliberacao/validacao do PPG.
Avaliador de PremioAVAL_COMIS_PREMIOPapelAvaliacao tecnica especializada restrita a area de conhecimento.
Avaliador Grande PremioAVAL_COMIS_GPPapelAvaliacao transversal e interdisciplinar entre areas distintas.
Coordenador Comissao PremioCOORD_COMIS_PREMIOFuncaoCoordenacao da comissao avaliadora com responsabilidade organizacional.
Coordenador Comissao GPCOORD_COMIS_GPFuncaoCoordenacao em processo avaliativo de maior complexidade institucional.
Grande Premio (Autor)PREMIACAO_GPReconhecimentoReconhecimento institucional maximo concedido ao autor.
Premio (Autor)PREMIACAOReconhecimentoReconhecimento institucional concedido ao autor por merito academico.
Mencao HonrosaMENCAOReconhecimentoReconhecimento honorifico concedido ao autor por destaque academico.
+ +

2.4 Participacoes e Competencias (Bloco D)

+ +

Participacoes em eventos, projetos, orientacoes academicas e competencias transversais.

+ +

2.4.1 Eventos e Projetos

+ + + + + + + + + + + + + + + + + + + + + + + +
AtuacaoCodigoTipoDescricao
Participacao em EventoEVENTOParticipacaoParticipacao institucional pontual em evento do ecossistema CAPES/ATUACAPES.
Participacao em ProjetoPROJParticipacaoAtuacao em projetos institucionais vinculada ao ecossistema CAPES/ATUACAPES.
+ +

2.4.2 Orientacoes Academicas

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AtuacaoCodigoVariante Premiada
Orientacao Pos-DocORIENT_POS_DOCORIENT_POS_DOC_PREM
Orientacao de TeseORIENT_TESEORIENT_TESE_PREM
Orientacao de DissertacaoORIENT_DISSORIENT_DISS_PREM
Co-orientacao Pos-DocCO_ORIENT_POS_DOCCO_ORIENT_POS_DOC_PREM
Co-orientacao de TeseCO_ORIENT_TESECO_ORIENT_TESE_PREM
Co-orientacao de DissertacaoCO_ORIENT_DISSCO_ORIENT_DISS_PREM
Membro de Banca Pos-DocMB_BANCA_POS_DOCMB_BANCA_POS_DOC_PREM
Membro de Banca de TeseMB_BANCA_TESEMB_BANCA_TESE_PREM
Membro de Banca de DissertacaoMB_BANCA_DISSMB_BANCA_DISS_PREM
+ +

2.4.3 Competencias e Reconhecimentos

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AtuacaoCodigoDescricao
Bolsista CNPqBOL_BPQ - NIVELReconhecimento institucional externo de excelencia academica.
Idioma BilingueIDIOMA - BILINGUECompetencia transversal - qualificador de perfil (sem pontuacao base).
Idioma MultilingueIDIOMA - MULTILINGUECompetencia transversal - qualificador de perfil (sem pontuacao base).
Titulacao MestreTITULACAO - MESTRETitulacao registrada para qualificacao de perfil (sem pontuacao base).
Titulacao DoutorTITULACAO - DOUTORTitulacao registrada para qualificacao de perfil (sem pontuacao base).
Titulacao Pos-DoutorTITULACAO - POS-DOUTORTitulacao registrada para qualificacao de perfil (sem pontuacao base).
+ +

3. Pontuacao Base

+ +

3.1 Tabela de Pontuacao por Atuacao

+ +

A tabela abaixo apresenta a pontuacao base e o teto maximo para cada tipo de atuacao pontuavel no Ranking V1:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodigoBaseTetoJustificativa
CA200450Gera pontuacao base integral, associada ao exercicio da funcao de Coordenacao de Area.
CAJ150370Gera pontuacao base, associada ao exercicio da funcao de Coordenacao Adjunta.
CAJ_MP120315Gera pontuacao base, associada a funcao de Coordenacao Adjunta com foco em MP.
CAM100280Gera pontuacao base, associada a atuacao em funcao transversal de apoio tecnico.
PPG_COORD00Nao gera contagem de tempo no Ranking V1.
CONS_ATIVO150230Gera pontuacao base enquanto vigente a atuacao de consultoria.
CONS_HIST100230Gera pontuacao base como registro de consultoria historica.
CONS_FALECIDO100230Consultoria historica com legado institucional (In Memoriam).
INSC_AUTOR1020Registro de participacao individual no processo de premiacao.
INSC_INST2050Inscricao institucional, considerada de maior peso.
AVAL_COMIS_PREMIO3060Atuacao como avaliador tecnico especializado em comissao de premiacao.
AVAL_COMIS_GP4080Atuacao em avaliacao transversal e interdisciplinar em comissao de Grande Premio.
COORD_COMIS_PREMIO40100Coordenacao institucional de comissao avaliadora.
COORD_COMIS_GP50120Coordenacao de processo avaliativo de maior complexidade e alcance.
BOL_BPQ3060Reconhecimento institucional externo de excelencia academica.
PREMIACAO_GP (Autor)100300Reconhecimento institucional maximo concedido ao autor.
PREMIACAO (Autor)50150Reconhecimento institucional relevante por merito academico.
MENCAO (Autor)3090Reconhecimento honorifico por destaque academico.
EVENTO15Participacao institucional pontual em eventos.
PROJ1030Reconhecimento simbolico (cobertura parcial dos dados).
+ +
+ Nota: Orientacoes, co-orientacoes, bancas, titulacoes e idiomas possuem pontuacao base zero no Ranking V1, sendo utilizados apenas para qualificacao de perfil e geracao de selos. +
+ +

4. Regras de Tempo

+ +

4.1 Formula de Calculo

+ +
+ Pontos_Tempo = min(anos_completos x multiplicador, teto_tempo) +
+ +

Apenas atuacoes do tipo Funcao com registro de periodo (inicio/fim) geram pontuacao por tempo.

+ +

4.2 Atuacoes com Pontuacao por Tempo

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodigoPontua?MultiplicadorTeto TempoCampo InicioCampo Fim
CASim10 pts/ano100inicioVinculacaofimVinculacao
CAJSim8 pts/ano80inicioVinculacaofimVinculacao
CAJ_MPSim6 pts/ano60inicioVinculacaofimVinculacao
CAMSim5 pts/ano50inicioVinculacaofimVinculacao
CONS_ATIVOSim5 pts/ano50inicioVinculacaofimVinculacao
CONS_HISTSim5 pts/ano50inicioVinculacaofimVinculacao
CONS_FALECIDOSim5 pts/ano50inicioVinculacaofimVinculacao
+ +
+ Observacoes: + +
+ +

4.3 Atuacoes SEM Pontuacao por Tempo

+ +

As seguintes atuacoes nao geram pontuacao por tempo:

+ + + +

5. Bonus e Reconhecimentos

+ +

5.1 Bonus de Atualidade

+ +

Aplicado quando o consultor esta em exercicio vigente no momento da apuracao:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodigoCondicaoValorTetoAcumulavel
CA_ATUALMandato vigente como Coordenador de Area3030Nao
CAJ_ATUALMandato vigente como Coordenador Adjunto2020Nao
CAJ_MP_ATUALMandato vigente como Coordenador Adjunto MP1515Nao
CAM_ATUALMandato vigente como Presidente Camara Tematica2020Nao
CONS_ATIVO_ATUALVinculo de consultoria ativo2020Nao
+ +

5.2 Bonus de Retorno

+ +

Aplicado quando ha novo mandato apos periodo anterior concluido (hiato):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodigoCondicaoValorTetoAcumulavel
CA_RETORNONovo mandato apos periodo anterior concluido2020Nao
CAJ_RETORNONovo mandato apos periodo anterior concluido1515Nao
CAJ_MP_RETORNONovo mandato apos periodo anterior concluido1010Nao
CAM_RETORNONovo mandato apos periodo anterior concluido1010Nao
CONS_ATIVO_RETORNOReativacao da consultoria1515Sim
CONS_HIST_RETORNOReativacao da consultoria (historico)2020Nao
+ +

5.3 Bonus de Continuidade

+ +

Aplicado quando ha atuacao continua por periodo prolongado (8 anos ou mais):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodigoCondicaoValorTeto
CONS_ATIVO_CONTINAtuacao continua igual ou maior que 8 anos2020
CONS_HIST_CONTINAtuacao continua igual ou maior que 8 anos (historico)2020
CONS_FALECIDO_CONTINAtuacao continua igual ou maior que 8 anos (in memoriam)2020
PPG_COORD_CONTINAtuacao continua igual ou maior que 8 anos como Coord. PPG1515
+ +

5.4 Bonus de Recorrencia

+ +

Aplicado por participacao recorrente em atividades:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodigoCondicaoValorTetoAcumulavel
INSC_AUTOR_REC_PARTInscricao realizada pelo proprio autor210Sim
INSC_INST_REC_PARTInscricao institucional para o autor510Sim
AVAL_COMIS_PREMIO_RECParticipacao em comissao (anual)215Sim
AVAL_COMIS_GP_RECParticipacao em comissao GP (anual)320Sim
COORD_COMIS_PREMIO_RECCoordenacao de comissao (anual)420Sim
COORD_COMIS_GP_RECCoordenacao de comissao GP (anual)620Sim
EVENTO_REC_PARTParticipacao em evento110Sim
PROJ_REC_PARTParticipacao em projeto210Sim
+ +

5.5 Selos de Reconhecimento

+ +

Selos visuais atribuidos ao perfil do consultor como forma de reconhecimento institucional:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodigoSeloCondicaoPrioridadeRepetivel
CAM_BONUSPresidente Camara TematicaMandato vigente10Uma vez
PPG_COORD_BONUSCoordenador de PPGTer o perfil de Coord. PPG20Uma vez
BOL_BPQ_BONUSBPQ NivelTer a bolsa BPQ30Uma vez
PREMIACAO_GP_BONUSAutor - Grande PremioAutor de tese/dissertacao premiada40Por ocorrencia
PREMIACAO_BONUSAutor - PremioAutor de tese/dissertacao premiada41Por ocorrencia
MENCAO_BONUSAutor - Mencao HonrosaAutor de tese/dissertacao premiada42Por ocorrencia
IDIOMA_BILINGUEBilingueQuantidade de idiomas igual ou maior que 250Uma vez
IDIOMA_MULTILINGUEMultilingueQuantidade de idiomas igual ou maior que 351Uma vez
TITULACAO_MESTREMestreMaior titulacao = Mestrado60Uma vez
TITULACAO_DOUTORDoutorMaior titulacao = Doutorado61Uma vez
TITULACAO_POS_DOUTORPos-DoutorMaior titulacao = Pos-Doutorado62Uma vez
+ +
+ Hierarquia de Titulacao: Pos-Doutor > Doutor > Mestre (apenas um selo de titulacao por perfil) +
+ +

6. Indicadores de Perfil

+ +

Indicadores complementares exibidos no perfil do consultor:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndicadorTipoRegra de CalculoExibicao
StatusEstadoDerivado do vinculo de consultoria no periodo correnteBadge "Ativo" ou "Inativo"
VeteranoQualificadorSoma dos periodos validos de atuacao institucionalBadge "Veterano"
Anos de AtuacaoNumericoSoma dos periodos validos, eliminando sobreposicoesTexto (ex.: "14,5 anos")
Anos ConsecutivosNumericoMaior sequencia continua sem interrupcaoDetalhe do perfil
ScoreSinteticoSoma ponderada das pontuacoes conforme regras do modeloDestaque numerico
Selos VisuaisVisualRenderizacao dos selos definidos na Aba 4Icones
+ +

Funcionalidades Analiticas

+ + + + + +
+

Anexo A - Resumo Executivo

+ +

Pontuacao Maxima por Categoria (Ordenada)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CategoriaCodigoBaseTetoBloco
Coordenador de AreaCA200450A
Coordenador AdjuntoCAJ150370A
Coordenador Adjunto MPCAJ_MP120315A
Grande Premio (Autor)PREMIACAO_GP100300C
Camara TematicaCAM100280A
Consultor AtivoCONS_ATIVO150230B
Consultor HistoricoCONS_HIST100230B
Premio (Autor)PREMIACAO50150C
Coordenador Comissao GPCOORD_COMIS_GP50120C
Coordenador Comissao PremioCOORD_COMIS_PREMIO40100C
Mencao Honrosa (Autor)MENCAO3090C
Avaliador Grande PremioAVAL_COMIS_GP4080C
Avaliador de PremioAVAL_COMIS_PREMIO3060C
Bolsista CNPqBOL_BPQ3060D
Inscricao InstitucionalINSC_INST2050C
Participacao em ProjetoPROJ1030D
Inscricao AutorINSC_AUTOR1020C
Participacao em EventoEVENTO15D
+ +
+

Pontuacoes Maximas Teoricas por Bloco

+
+
+
450
+
Bloco A (CA)
+
+
+
230
+
Bloco B (Consultoria)
+
+
+
300
+
Bloco C (Premiacoes)
+
+
+
60
+
Bloco D (Bolsas)
+
+
+
+
+ +
+

Anexo B - Glossario de Codigos

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodigoNome CompletoBloco
CACoordenador de AreaA
CAJCoordenador AdjuntoA
CAJ_MPCoordenador Adjunto de Mestrado ProfissionalA
CAMCamara Tematica (Presidente)A
PPG_COORDCoordenador de Programa de Pos-GraduacaoE
CONS_ATIVOConsultor AtivoB
CONS_HISTConsultor Historico (Inativo)B
CONS_FALECIDOConsultor Falecido (In Memoriam)B
INSC_AUTORInscricao por Autoinscricao (Autor)C
INSC_INSTInscricao Institucional (Coordenador PPG)C
AVAL_COMIS_PREMIOAvaliador de Comissao de PremioC
AVAL_COMIS_GPAvaliador de Comissao de Grande PremioC
COORD_COMIS_PREMIOCoordenador de Comissao de PremioC
COORD_COMIS_GPCoordenador de Comissao de Grande PremioC
PREMIACAO_GPGrande Premio CAPES (Autor)C
PREMIACAOPremio CAPES (Autor)C
MENCAOMencao Honrosa (Autor)C
BOL_BPQBolsista de Produtividade CNPqD
EVENTOParticipacao em EventoD
PROJParticipacao em ProjetoD
ORIENT_*Orientacoes (Pos-Doc, Tese, Dissertacao)C
CO_ORIENT_*Co-orientacoes (Pos-Doc, Tese, Dissertacao)C
MB_BANCA_*Membro de Banca (Pos-Doc, Tese, Dissertacao)C
+ + +
+ + + diff --git a/scripts/estilizar_planilha.py b/scripts/estilizar_planilha.py new file mode 100644 index 0000000..056a9d1 --- /dev/null +++ b/scripts/estilizar_planilha.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from pathlib import Path +from openpyxl import load_workbook +from openpyxl.styles import Font, PatternFill, Alignment, Border, Side + + +INPUT_PATH = Path("/home/fred/Downloads/Definição Ranking_ATUACAPES - Aba1 a Aba4(7).xlsx") +OUTPUT_PATH = Path("/home/fred/projetos/ranking/docs/Definicao_Ranking_ATUACAPES_estilizada.xlsx") + + +def apply_styles() -> None: + wb = load_workbook(INPUT_PATH) + + header_fill = PatternFill("solid", fgColor="E6F0FF") + header_font = Font(bold=True, color="102A43") + alt_fill = PatternFill("solid", fgColor="F7FAFC") + thin = Side(style="thin", color="CBD5E0") + border = Border(left=thin, right=thin, top=thin, bottom=thin) + + for ws in wb.worksheets: + max_col = ws.max_column + max_row = ws.max_row + + # Header styling + for col in range(1, max_col + 1): + cell = ws.cell(row=1, column=col) + cell.fill = header_fill + cell.font = header_font + cell.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True) + cell.border = border + + # Data rows styling + for row in range(2, max_row + 1): + row_fill = alt_fill if row % 2 == 0 else None + for col in range(1, max_col + 1): + cell = ws.cell(row=row, column=col) + cell.border = border + cell.alignment = Alignment(vertical="top", wrap_text=True) + if row_fill: + cell.fill = row_fill + + # Freeze header row + ws.freeze_panes = "A2" + + # Auto-filter across the used range + ws.auto_filter.ref = ws.dimensions + + # Adjust column widths with caps + for col in ws.columns: + col_letter = col[0].column_letter + max_len = 0 + for cell in col[: min(max_row, 200)]: + if cell.value is None: + continue + text = str(cell.value) + if len(text) > max_len: + max_len = len(text) + width = max(12, min(45, int(max_len * 0.9))) + ws.column_dimensions[col_letter].width = width + + # Slightly taller header + ws.row_dimensions[1].height = 28 + + OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True) + wb.save(OUTPUT_PATH) + + +if __name__ == "__main__": + apply_styles() diff --git a/scripts/gerar_documento_criterios.py b/scripts/gerar_documento_criterios.py new file mode 100644 index 0000000..4632051 --- /dev/null +++ b/scripts/gerar_documento_criterios.py @@ -0,0 +1,262 @@ +from __future__ import annotations + +from pathlib import Path +import datetime +from html import escape + +from openpyxl import load_workbook +from weasyprint import HTML, CSS + + +XLSX_PATH = Path("/home/fred/Downloads/Definição Ranking_ATUACAPES - Aba1 a Aba4(7).xlsx") +PDF_PATH = Path("/home/fred/projetos/ranking/docs/Criterios_Ranking_Consultores.pdf") +LOGO_PATH = Path("/home/fred/projetos/ranking/docs/assets/logo-capes.png") + + +def _fmt(cell) -> str: + if cell is None: + return "" + return str(cell).replace("\n", " ").strip() + + +def _table_html(headers, rows, code_cols=None) -> str: + code_cols = set(code_cols or []) + thead = "" + "".join(f"{escape(_fmt(h))}" for h in headers) + "" + body_rows = [] + for row in rows: + cols = [] + for idx, cell in enumerate(row): + text = _fmt(cell) + if idx in code_cols and text: + text = f"{escape(text)}" + else: + text = escape(text) + cols.append(f"{text}") + body_rows.append("" + "".join(cols) + "") + tbody = "\n".join(body_rows) + return f"{thead}{tbody}
" + + +def load_planilha() -> dict: + wb = load_workbook(XLSX_PATH, data_only=True) + + def extract(sheet, header_cols, row_cols, skip_score=False, formula=False): + ws = wb[sheet] + headers = [_fmt(c) for c in ws[1][:header_cols]] + rows = [] + formula_row = "" + for r in ws.iter_rows(min_row=2, values_only=True): + if not any(r): + continue + if formula and r[0] is None and isinstance(r[1], str) and "tempo =" in r[1]: + formula_row = r[1] + continue + if skip_score and _fmt(r[0]).lower() == "score": + continue + rows.append(r[:row_cols]) + return headers, rows, formula_row + + h1, r1, _ = extract("Aba1_Mapa_Atuacoes", 9, 9) + h2, r2, _ = extract("Aba2_Pontuacao_Base", 4, 4) + h3, r3, f3 = extract("Aba3_Regras_Tempo", 7, 7, formula=True) + h4, r4, _ = extract("Aba4_Bonus_Extras", 12, 12) + h5, r5, _ = extract("Aba5_Detalh. Perfil_Indicadores", 6, 6, skip_score=True) + + return { + "aba1": {"headers": h1, "rows": r1}, + "aba2": {"headers": h2, "rows": r2}, + "aba3": {"headers": h3, "rows": r3, "formula": f3}, + "aba4": {"headers": h4, "rows": r4}, + "aba5": {"headers": h5, "rows": r5}, + } + + +def build_html(data: dict) -> str: + hoje = datetime.date.today().isoformat() + logo_html = "" + if LOGO_PATH.exists(): + logo_html = f"\"CAPES\"" + + return f""" + + + + + Critérios de Pontuação e Ordenação (Versão Executiva) + + + +
+ {logo_html} +

Sistema de Ranking de Consultores

+
Critérios de Pontuação e Ordenação (Versão Executiva)
+
+
Versão: 1.0
+
Data: {hoje}
+
Finalidade: Documento executivo para alta gestão
+
Escopo: Critérios oficiais do ranking conforme planilha de definição (Abas 1 a 5)
+
+
+ +
+

Sumário Executivo

+

Este documento consolida, de forma hierárquica e fiel à planilha oficial, todos os critérios utilizados no ranking de consultores. A estrutura está organizada por abas: mapeamento das atuações (Aba 1), pontuação base e tetos (Aba 2), regras de tempo (Aba 3), bônus e selos (Aba 4) e indicadores não pontuáveis (Aba 5).

+
+ +
+

1. Aba 1 — Mapa de Atuações

+ {_table_html(data["aba1"]["headers"], data["aba1"]["rows"], code_cols=[3])} +
+ +
+

2. Aba 2 — Pontuação Base e Teto por Atuação

+ {_table_html(data["aba2"]["headers"], data["aba2"]["rows"], code_cols=[0])} +
+ +
+

3. Aba 3 — Regras de Tempo

+ {_table_html(data["aba3"]["headers"], data["aba3"]["rows"], code_cols=[0])} +

Fórmula da planilha: {escape(_fmt(data["aba3"]["formula"]))}

+
+ +
+

4. Aba 4 — Bônus e Selos

+ {_table_html(data["aba4"]["headers"], data["aba4"]["rows"], code_cols=[0])} +
+ +
+

5. Aba 5 — Indicadores Não Pontuáveis

+

Os itens abaixo constam na Aba 5 e não impactam a pontuação. O indicador Score é pontuável e já está coberto pelas regras das Abas 2 a 4.

+ {_table_html(data["aba5"]["headers"], data["aba5"]["rows"])} +
+ +
+

6. Fonte Oficial

+

Planilha: {escape(str(XLSX_PATH))}

+
+ + +""" + + +def main() -> None: + data = load_planilha() + html = build_html(data) + HTML(string=html, base_url=str(PDF_PATH.parent)).write_pdf( + target=str(PDF_PATH), + stylesheets=[CSS(string="@page { size: A4; }")], + ) + print(f"PDF: {PDF_PATH}") + + +if __name__ == "__main__": + main() diff --git a/tools/generate_ranking_pdf.py b/tools/generate_ranking_pdf.py new file mode 100644 index 0000000..d54b481 --- /dev/null +++ b/tools/generate_ranking_pdf.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import argparse +import datetime as dt +import os +import subprocess +import tempfile +from pathlib import Path +from typing import Iterable + +from openpyxl import load_workbook + + +def _excel_col_letter(index_1_based: int) -> str: + result = "" + n = index_1_based + while n: + n, rem = divmod(n - 1, 26) + result = chr(ord("A") + rem) + result + return result + + +def _stringify_cell(value) -> str: + if value is None: + return "" + if isinstance(value, (dt.datetime, dt.date)): + return value.isoformat() + return str(value) + + +def _troff_escape(text: str) -> str: + text = text.replace("\\", "\\\\") + text = text.replace("\t", " ") + text = text.replace("|", "¦") + return text + + +def _troff_field(text: str) -> str: + text = _troff_escape(text) + if not text: + return "T{\n\\&\nT}" + lines = text.splitlines() or [text] + safe_lines: list[str] = [] + for line in lines: + if line.startswith((".", "'")): + safe_lines.append(r"\&" + line) + else: + safe_lines.append(line) + body = "\n".join(safe_lines) + return f"T{{\n{body}\nT}}" + + +def _used_bounds(ws) -> tuple[int, int]: + last_row = 0 + last_col = 0 + for row_idx, row in enumerate(ws.iter_rows(values_only=True), start=1): + if any(v not in (None, "") for v in row): + last_row = row_idx + for col_idx, v in enumerate(row, start=1): + if v not in (None, ""): + last_col = max(last_col, col_idx) + return last_row, last_col + + +def _iter_rows(ws, max_row: int, max_col: int) -> Iterable[list[str]]: + for row in ws.iter_rows(min_row=1, max_row=max_row, min_col=1, max_col=max_col, values_only=True): + yield [_stringify_cell(v) for v in row] + + +def _emit_table(rows: list[list[str]], *, col_slice: slice, title: str) -> str: + cols = list(range(col_slice.start or 0, col_slice.stop or len(rows[0]))) + ncols = len(cols) + if ncols <= 0: + return "" + + spec = " ".join(["l"] * ncols) + "." + out: list[str] = [] + out.append(".LP") + out.append(rf"\fB{_troff_escape(title)}\fP") + out.append(".TS") + out.append("tab(|) expand;") + out.append(spec) + + header = rows[0] + header_fields = [] + for i in cols: + header_fields.append(_troff_field(header[i])) + out.append("|".join(header_fields)) + + for row in rows[1:]: + fields = [_troff_field(row[i]) for i in cols] + out.append("|".join(fields)) + + out.append(".TE") + out.append(".LP") + return "\n".join(out) + "\n" + + +def build_troff_from_xlsx(xlsx_path: Path, generated_at: dt.datetime) -> str: + wb = load_workbook(xlsx_path, data_only=False) + + lines: list[str] = [] + lines.append('.\" Auto-generated from XLSX') + lines.append(".po 1i") + lines.append(".ll 6.5i") + lines.append(".ps 10") + lines.append(".vs 12") + lines.append("") + + lines.append(".ps 18") + lines.append(".vs 22") + lines.append(".ce") + lines.append(r"\fBDefinição de Ranking — AtuaCAPES\fP") + lines.append(".sp 0.5") + lines.append(".ps 11") + lines.append(".vs 14") + lines.append(".ce") + lines.append("Documento gerado automaticamente") + lines.append(".sp 0.5") + lines.append(".ce") + lines.append(_troff_escape(generated_at.strftime("%Y-%m-%d %H:%M"))) + lines.append(".sp 1") + lines.append(rf"Fonte: \fB{_troff_escape(str(xlsx_path))}\fP") + lines.append(".LP") + lines.append("Conteúdo: todas as abas da planilha, com critérios e regras conforme definidos no arquivo de entrada.") + lines.append(".bp") + + lines.append(".ps 14") + lines.append(".vs 18") + lines.append(r"\fBSumário de Abas\fP") + lines.append(".ps 10") + lines.append(".vs 12") + lines.append(".sp 0.5") + for i, name in enumerate(wb.sheetnames, start=1): + lines.append(rf"{i}. \fB{_troff_escape(name)}\fP") + lines.append(".br") + lines.append(".bp") + + for sheet_name in wb.sheetnames: + ws = wb[sheet_name] + max_row, max_col = _used_bounds(ws) + if max_row == 0 or max_col == 0: + continue + + rows = list(_iter_rows(ws, max_row=max_row, max_col=max_col)) + if not rows: + continue + + lines.append(".ps 14") + lines.append(".vs 18") + lines.append(rf"\fB{_troff_escape(sheet_name)}\fP") + lines.append(".ps 10") + lines.append(".vs 12") + lines.append(".LP") + lines.append(rf"Linhas: \fB{max_row}\fP — Colunas: \fB{max_col}\fP") + + max_cols_per_table = 8 + if max_col <= max_cols_per_table: + start_letter = _excel_col_letter(1) + end_letter = _excel_col_letter(max_col) + lines.append(_emit_table(rows, col_slice=slice(0, max_col), title=f"Colunas {start_letter}–{end_letter}")) + else: + start = 0 + while start < max_col: + end = min(start + max_cols_per_table, max_col) + start_letter = _excel_col_letter(start + 1) + end_letter = _excel_col_letter(end) + lines.append( + _emit_table( + rows, + col_slice=slice(start, end), + title=f"Colunas {start_letter}–{end_letter}", + ) + ) + start = end + + lines.append(".bp") + + return "\n".join(lines) + + +def render_pdf_from_ms(ms_text: str, pdf_path: Path, *, workdir: Path) -> None: + pdf_path.parent.mkdir(parents=True, exist_ok=True) + with tempfile.TemporaryDirectory(dir=workdir) as td: + td_path = Path(td) + ms_path = td_path / "doc.ms" + ps_path = td_path / "doc.ps" + ms_path.write_text(ms_text, encoding="utf-8") + + groff_cmd = ["groff", "-Kutf8", "-Tps", "-t", str(ms_path)] + ps_bytes = subprocess.check_output(groff_cmd) + ps_path.write_bytes(ps_bytes) + + subprocess.check_call(["ps2pdf", str(ps_path), str(pdf_path)]) + + +def main() -> int: + parser = argparse.ArgumentParser(description="Gera PDF (profissional) a partir de planilha XLSX.") + parser.add_argument("xlsx", type=Path, help="Caminho do XLSX de entrada") + parser.add_argument( + "-o", + "--out", + type=Path, + default=Path("out/definicao_ranking_atuacapes.pdf"), + help="Caminho do PDF de saída (default: out/definicao_ranking_atuacapes.pdf)", + ) + args = parser.parse_args() + + xlsx_path: Path = args.xlsx + out_pdf: Path = args.out + + generated_at = dt.datetime.now().astimezone() + ms_text = build_troff_from_xlsx(xlsx_path=xlsx_path, generated_at=generated_at) + render_pdf_from_ms(ms_text=ms_text, pdf_path=out_pdf, workdir=Path(os.getcwd())) + print(out_pdf) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())