Atualiza criterios de pontuacao para V2

Backend:
- CAJ retorno 20->15, CAJ_MP retorno 20->10, CAM atualidade 10->20, retorno 20->10
- CONS_ATIVO/HIST/FALECIDO continuidade 8a+ = 20 (simplificado)
- CONS_FALECIDO agora pontua tempo (5 pts/ano, teto 50)
- AVAL_COMIS_PREMIO e AVAL_COMIS_GP mudaram tipo para PAPEL
- AVAL_COMIS_GP teto 100->80
- Novo bonus de recorrencia anual para comissoes (2-6 pts/ano)
- PREMIACAO base 150->100, PREMIACAO_GP base 30->50, MENCAO base 10->30
- BOL_BPQ_INTERMEDIARIO base 50->30 (consolidado)
- Orientacoes/Co-orientacoes/Bancas: tetos zerados (sem limite)
- TipoAtuacao.RESULTADO renomeado para COMPETENCIA_RECONHECIMENTO

Frontend:
- Atualiza PONTOS_BASE e TETOS com novos valores V2
- Atualiza descricoes das formulas nos tooltips
- Melhora exibicao de teto=0 como "sem limite"
- Adiciona info de bonus de recorrencia nos tooltips
This commit is contained in:
Frederico Castro
2025-12-14 20:37:55 -03:00
parent 7000268261
commit 120593831c
3 changed files with 95 additions and 74 deletions

View File

@@ -114,18 +114,13 @@ class CalculadorPontuacao:
tempo = min(anos_total * criterio.multiplicador_tempo, criterio.teto_tempo)
bonus = 0
if codigo == "CONS_ATIVO":
if consultoria.anos_consecutivos >= 8:
bonus += criterio.bonus_continuidade_8anos
elif consultoria.anos_consecutivos >= 5:
bonus += criterio.bonus_continuidade_5anos
elif consultoria.anos_consecutivos >= 3:
bonus += criterio.bonus_continuidade_3anos
if consultoria.retornos > 0:
bonus += criterio.bonus_retorno
if consultoria.anos_consecutivos >= 8 and criterio.bonus_continuidade_8anos:
bonus += criterio.bonus_continuidade_8anos
if codigo == "CONS_ATIVO" and consultoria.retornos > 0 and criterio.bonus_retorno:
bonus += criterio.bonus_retorno
total_bruto = base + tempo + bonus
total = min(total_bruto, criterio.teto)
total = min(total_bruto, criterio.teto) if criterio.teto > 0 else total_bruto
atuacoes = [PontuacaoAtuacao(
codigo=codigo,
@@ -149,7 +144,7 @@ class CalculadorPontuacao:
membros_banca: List[MembroBanca],
) -> PontuacaoBloco:
atuacoes = []
totais_por_codigo: Dict[str, Dict] = defaultdict(lambda: {"base": 0, "qtd": 0})
totais_por_codigo: Dict[str, Dict] = defaultdict(lambda: {"base": 0, "qtd": 0, "anos": set()})
for insc in inscricoes:
criterio = get_criterio(insc.codigo)
@@ -162,6 +157,8 @@ class CalculadorPontuacao:
if criterio:
totais_por_codigo[aval.codigo]["base"] += criterio.base
totais_por_codigo[aval.codigo]["qtd"] += 1
if hasattr(aval, 'ano') and aval.ano:
totais_por_codigo[aval.codigo]["anos"].add(aval.ano)
for prem in premiacoes:
criterio = get_criterio(prem.codigo)
@@ -198,12 +195,24 @@ class CalculadorPontuacao:
if not criterio:
continue
total = min(dados["base"], criterio.teto)
base_total = dados["base"]
bonus = 0
if criterio.bonus_recorrencia_anual > 0:
anos_distintos = len(dados["anos"])
bonus_recorrencia = anos_distintos * criterio.bonus_recorrencia_anual
bonus = min(bonus_recorrencia, criterio.teto_recorrencia)
total_bruto = base_total + bonus
if criterio.teto > 0:
total = min(total_bruto, criterio.teto)
else:
total = total_bruto
atuacoes.append(PontuacaoAtuacao(
codigo=codigo,
base=dados["base"],
base=base_total,
tempo=0,
bonus=0,
bonus=bonus,
total=total,
quantidade=dados["qtd"],
))

View File

@@ -11,7 +11,7 @@ class Bloco(Enum):
class TipoAtuacao(Enum):
FUNCAO = "Função"
RESULTADO = "Resultado"
COMPETENCIA_RECONHECIMENTO = "Competência e Reconhecimento"
PAPEL = "Papel"
PARTICIPACAO = "Participação"
@@ -28,9 +28,9 @@ class CriterioPontuacao:
teto_tempo: int = 0
bonus_atualidade: int = 0
bonus_retorno: int = 0
bonus_continuidade_3anos: int = 0
bonus_continuidade_5anos: int = 0
bonus_continuidade_8anos: int = 0
bonus_recorrencia_anual: int = 0
teto_recorrencia: int = 0
CRITERIOS: Dict[str, CriterioPontuacao] = {
@@ -56,7 +56,7 @@ CRITERIOS: Dict[str, CriterioPontuacao] = {
multiplicador_tempo=8,
teto_tempo=80,
bonus_atualidade=20,
bonus_retorno=20,
bonus_retorno=15,
),
"CAJ_MP": CriterioPontuacao(
codigo="CAJ_MP",
@@ -68,7 +68,7 @@ CRITERIOS: Dict[str, CriterioPontuacao] = {
multiplicador_tempo=6,
teto_tempo=60,
bonus_atualidade=15,
bonus_retorno=20,
bonus_retorno=10,
),
"CAM": CriterioPontuacao(
codigo="CAM",
@@ -79,8 +79,8 @@ CRITERIOS: Dict[str, CriterioPontuacao] = {
pontua_tempo=True,
multiplicador_tempo=5,
teto_tempo=50,
bonus_atualidade=10,
bonus_retorno=20,
bonus_atualidade=20,
bonus_retorno=10,
),
"PPG_COORD": CriterioPontuacao(
codigo="PPG_COORD",
@@ -101,9 +101,7 @@ CRITERIOS: Dict[str, CriterioPontuacao] = {
pontua_tempo=True,
multiplicador_tempo=5,
teto_tempo=50,
bonus_continuidade_3anos=5,
bonus_continuidade_5anos=10,
bonus_continuidade_8anos=15,
bonus_continuidade_8anos=20,
bonus_retorno=15,
),
"CONS_HIST": CriterioPontuacao(
@@ -115,6 +113,7 @@ CRITERIOS: Dict[str, CriterioPontuacao] = {
pontua_tempo=True,
multiplicador_tempo=5,
teto_tempo=50,
bonus_continuidade_8anos=20,
),
"CONS_FALECIDO": CriterioPontuacao(
codigo="CONS_FALECIDO",
@@ -122,35 +121,42 @@ CRITERIOS: Dict[str, CriterioPontuacao] = {
tipo=TipoAtuacao.FUNCAO,
base=100,
teto=230,
pontua_tempo=False,
pontua_tempo=True,
multiplicador_tempo=5,
teto_tempo=50,
bonus_continuidade_8anos=20,
),
"INSC_AUTOR": CriterioPontuacao(
codigo="INSC_AUTOR",
bloco=Bloco.D,
tipo=TipoAtuacao.PAPEL,
tipo=TipoAtuacao.FUNCAO,
base=10,
teto=20,
),
"INSC_INST": CriterioPontuacao(
codigo="INSC_INST",
bloco=Bloco.D,
tipo=TipoAtuacao.PAPEL,
tipo=TipoAtuacao.FUNCAO,
base=30,
teto=60,
),
"AVAL_COMIS_PREMIO": CriterioPontuacao(
codigo="AVAL_COMIS_PREMIO",
bloco=Bloco.D,
tipo=TipoAtuacao.FUNCAO,
tipo=TipoAtuacao.PAPEL,
base=30,
teto=60,
bonus_recorrencia_anual=2,
teto_recorrencia=15,
),
"AVAL_COMIS_GP": CriterioPontuacao(
codigo="AVAL_COMIS_GP",
bloco=Bloco.D,
tipo=TipoAtuacao.FUNCAO,
tipo=TipoAtuacao.PAPEL,
base=50,
teto=100,
teto=80,
bonus_recorrencia_anual=3,
teto_recorrencia=20,
),
"COORD_COMIS_PREMIO": CriterioPontuacao(
codigo="COORD_COMIS_PREMIO",
@@ -158,6 +164,8 @@ CRITERIOS: Dict[str, CriterioPontuacao] = {
tipo=TipoAtuacao.FUNCAO,
base=50,
teto=100,
bonus_recorrencia_anual=4,
teto_recorrencia=20,
),
"COORD_COMIS_GP": CriterioPontuacao(
codigo="COORD_COMIS_GP",
@@ -165,40 +173,42 @@ CRITERIOS: Dict[str, CriterioPontuacao] = {
tipo=TipoAtuacao.FUNCAO,
base=60,
teto=120,
bonus_recorrencia_anual=6,
teto_recorrencia=20,
),
"BOL_BPQ_SUPERIOR": CriterioPontuacao(
codigo="BOL_BPQ_SUPERIOR",
bloco=Bloco.D,
tipo=TipoAtuacao.RESULTADO,
tipo=TipoAtuacao.COMPETENCIA_RECONHECIMENTO,
base=30,
teto=60,
),
"BOL_BPQ_INTERMEDIARIO": CriterioPontuacao(
codigo="BOL_BPQ_INTERMEDIARIO",
bloco=Bloco.D,
tipo=TipoAtuacao.RESULTADO,
base=50,
teto=100,
tipo=TipoAtuacao.COMPETENCIA_RECONHECIMENTO,
base=30,
teto=60,
),
"PREMIACAO": CriterioPontuacao(
codigo="PREMIACAO",
bloco=Bloco.D,
tipo=TipoAtuacao.RESULTADO,
base=150,
tipo=TipoAtuacao.COMPETENCIA_RECONHECIMENTO,
base=100,
teto=180,
),
"PREMIACAO_GP": CriterioPontuacao(
codigo="PREMIACAO_GP",
bloco=Bloco.D,
tipo=TipoAtuacao.RESULTADO,
base=30,
tipo=TipoAtuacao.COMPETENCIA_RECONHECIMENTO,
base=50,
teto=60,
),
"MENCAO": CriterioPontuacao(
codigo="MENCAO",
bloco=Bloco.D,
tipo=TipoAtuacao.RESULTADO,
base=10,
tipo=TipoAtuacao.COMPETENCIA_RECONHECIMENTO,
base=30,
teto=20,
),
"EVENTO": CriterioPontuacao(
@@ -220,63 +230,63 @@ CRITERIOS: Dict[str, CriterioPontuacao] = {
bloco=Bloco.D,
tipo=TipoAtuacao.PARTICIPACAO,
base=15,
teto=100,
teto=0,
),
"ORIENT_TESE": CriterioPontuacao(
codigo="ORIENT_TESE",
bloco=Bloco.D,
tipo=TipoAtuacao.PARTICIPACAO,
base=10,
teto=50,
teto=0,
),
"ORIENT_DISS": CriterioPontuacao(
codigo="ORIENT_DISS",
bloco=Bloco.D,
tipo=TipoAtuacao.PARTICIPACAO,
base=5,
teto=25,
teto=0,
),
"CO_ORIENT_POS_DOC": CriterioPontuacao(
codigo="CO_ORIENT_POS_DOC",
bloco=Bloco.D,
tipo=TipoAtuacao.PARTICIPACAO,
base=7,
teto=35,
teto=0,
),
"CO_ORIENT_TESE": CriterioPontuacao(
codigo="CO_ORIENT_TESE",
bloco=Bloco.D,
tipo=TipoAtuacao.PARTICIPACAO,
base=5,
teto=25,
teto=0,
),
"CO_ORIENT_DISS": CriterioPontuacao(
codigo="CO_ORIENT_DISS",
bloco=Bloco.D,
tipo=TipoAtuacao.PARTICIPACAO,
base=3,
teto=15,
teto=0,
),
"MB_BANCA_POS_DOC": CriterioPontuacao(
codigo="MB_BANCA_POS_DOC",
bloco=Bloco.D,
tipo=TipoAtuacao.PARTICIPACAO,
base=3,
teto=15,
teto=0,
),
"MB_BANCA_TESE": CriterioPontuacao(
codigo="MB_BANCA_TESE",
bloco=Bloco.D,
tipo=TipoAtuacao.PARTICIPACAO,
base=3,
teto=15,
teto=0,
),
"MB_BANCA_DISS": CriterioPontuacao(
codigo="MB_BANCA_DISS",
bloco=Bloco.D,
tipo=TipoAtuacao.PARTICIPACAO,
base=2,
teto=10,
teto=0,
),
}

View File

@@ -4,7 +4,7 @@ import './ConsultorCard.css';
const FORMULAS = {
bloco_a: {
titulo: 'Coordenacao CAPES',
descricao: 'CA=200 | CAJ=150 | CAJ_MP=120 | CAM=100\nTempo: multiplicador por ano\nBonus atualidade + Retorno',
descricao: 'CA=200 | CAJ=150 | CAJ_MP=120 | CAM=100\nTempo: multiplicador por ano\nBonus atualidade + Retorno (V2)',
},
bloco_b: {
titulo: 'Coordenacao PPG',
@@ -12,11 +12,11 @@ const FORMULAS = {
},
bloco_c: {
titulo: 'Consultoria',
descricao: 'CONS_ATIVO=150 | CONS_HIST=100 | CONS_FALECIDO=100\nTempo: 5 pts/ano (max 50)\nContinuidade 8a+=15 | Retorno=15',
descricao: 'CONS_ATIVO=150 | CONS_HIST=100 | CONS_FALECIDO=100\nTempo: 5 pts/ano (max 50)\nContinuidade 8a+=20 | Retorno=15 (V2)',
},
bloco_d: {
titulo: 'Premiacoes/Avaliacoes',
descricao: 'PREMIACAO=150 | PREMIACAO_GP=30 | MENCAO=10\nAVAL_COMIS=30-50 | COORD_COMIS=50-60\nINSC_AUTOR=10 | INSC_INST=30',
descricao: 'GP=100 | Premio=50 | Mencao=30\nAVAL_COMIS=30-50 | COORD_COMIS=50-60\nINSC_AUTOR=10 | INSC_INST=30 (V2)',
},
};
@@ -26,34 +26,37 @@ const PONTOS_BASE = {
INSC_AUTOR: 10, INSC_INST: 30,
AVAL_COMIS_PREMIO: 30, AVAL_COMIS_GP: 50,
COORD_COMIS_PREMIO: 50, COORD_COMIS_GP: 60,
PREMIACAO: 150, PREMIACAO_GP: 30, MENCAO: 10,
BOL_BPQ_SUPERIOR: 30, BOL_BPQ_INTERMEDIARIO: 50,
PREMIACAO: 100, PREMIACAO_GP: 50, MENCAO: 30,
BOL_BPQ_SUPERIOR: 30, BOL_BPQ_INTERMEDIARIO: 30,
EVENTO: 1, PROJ: 10,
ORIENT_POS_DOC: 15, ORIENT_TESE: 10, ORIENT_DISS: 5,
CO_ORIENT_POS_DOC: 7, CO_ORIENT_TESE: 5, CO_ORIENT_DISS: 3,
MB_BANCA_POS_DOC: 3, MB_BANCA_TESE: 3, MB_BANCA_DISS: 2,
};
// Teto oficial por código, conforme documento de critérios (seção 3.x)
const TETOS = {
// 3.3 Inscrições
INSC_AUTOR: { teto: 20, doc: '3.3 Inscrições' },
INSC_INST: { teto: 60, doc: '3.3 Inscrições' },
// 3.4 Avaliação / Coordenação de Comissão
AVAL_COMIS_PREMIO: { teto: 60, doc: '3.4 Avaliação/Comissão' },
AVAL_COMIS_GP: { teto: 100, doc: '3.4 Avaliação/Comissão' },
COORD_COMIS_PREMIO: { teto: 100, doc: '3.4 Avaliação/Comissão' },
COORD_COMIS_GP: { teto: 120, doc: '3.4 Avaliação/Comissão' },
// 3.6 Premiações
PREMIACAO: { teto: 180, doc: '3.6 Premiações' },
PREMIACAO_GP: { teto: 60, doc: '3.6 Premiações' },
MENCAO: { teto: 20, doc: '3.6 Premiações' },
// 3.7 Participações
AVAL_COMIS_PREMIO: { teto: 60, doc: '3.4 Avaliação/Comissão', bonus: '+2/ano (max 15)' },
AVAL_COMIS_GP: { teto: 80, doc: '3.4 Avaliação/Comissão', bonus: '+3/ano (max 20)' },
COORD_COMIS_PREMIO: { teto: 100, doc: '3.4 Avaliação/Comissão', bonus: '+4/ano (max 20)' },
COORD_COMIS_GP: { teto: 120, doc: '3.4 Avaliação/Comissão', bonus: '+6/ano (max 20)' },
PREMIACAO: { teto: 180, doc: '3.6 Grande Prêmio' },
PREMIACAO_GP: { teto: 60, doc: '3.6 Prêmio' },
MENCAO: { teto: 20, doc: '3.6 Menção Honrosa' },
EVENTO: { teto: 5, doc: '3.7 Participações' },
PROJ: { teto: 40, doc: '3.7 Participações' },
// 3.5 Bolsas CNPQ (nomes resumidos)
BOL_BPQ_SUPERIOR: { teto: 60, doc: '3.5 Bolsas CNPQ' },
BOL_BPQ_INTERMEDIARIO: { teto: 100, doc: '3.5 Bolsas CNPQ' },
BOL_BPQ_INTERMEDIARIO: { teto: 60, doc: '3.5 Bolsas CNPQ' },
ORIENT_POS_DOC: { teto: 0, doc: '3.8 Orientação (sem limite)' },
ORIENT_TESE: { teto: 0, doc: '3.8 Orientação (sem limite)' },
ORIENT_DISS: { teto: 0, doc: '3.8 Orientação (sem limite)' },
CO_ORIENT_POS_DOC: { teto: 0, doc: '3.9 Co-Orientação (sem limite)' },
CO_ORIENT_TESE: { teto: 0, doc: '3.9 Co-Orientação (sem limite)' },
CO_ORIENT_DISS: { teto: 0, doc: '3.9 Co-Orientação (sem limite)' },
MB_BANCA_POS_DOC: { teto: 0, doc: '3.10 Banca (sem limite)' },
MB_BANCA_TESE: { teto: 0, doc: '3.10 Banca (sem limite)' },
MB_BANCA_DISS: { teto: 0, doc: '3.10 Banca (sem limite)' },
};
const ScoreItemWithTooltip = ({ value, label, formula, style }) => (
@@ -313,7 +316,8 @@ const BlocoDetalhes = ({ titulo, bloco, cor }) => (
const bonus = at.bonus || 0;
const bruto = base + tempo + bonus;
const meta = TETOS[at.codigo];
const capped = bruto !== at.total;
const hasTeto = meta && meta.teto > 0;
const capped = hasTeto && bruto > meta.teto;
const unidade = at.quantidade > 1 ? Math.round(base / at.quantidade) : null;
const partes = [];
@@ -322,13 +326,11 @@ const BlocoDetalhes = ({ titulo, bloco, cor }) => (
? `Base ${unidade} x ${at.quantidade} = ${base}`
: `Base ${base}`
);
if (capped) {
partes.push(`Bruto ${bruto}`);
}
if (tempo) partes.push(`Tempo ${tempo}`);
if (bonus) partes.push(`Bônus ${bonus}`);
if (meta) partes.push(`Teto ${meta.teto}`);
partes.push(capped && meta ? `Total ${at.total} (teto)` : `Total ${at.total}`);
if (hasTeto) partes.push(`Teto ${meta.teto}`);
if (meta && meta.bonus) partes.push(meta.bonus);
partes.push(capped ? `Total ${at.total} (teto)` : `Total ${at.total}`);
return partes.join(" | ");
})()}
</div>