From 57ef5a763adc5c9d64557b34746991b8713f3623 Mon Sep 17 00:00:00 2001 From: Frederico Castro Date: Wed, 10 Dec 2025 04:24:24 -0300 Subject: [PATCH] =?UTF-8?q?fix:=20Corrige=20c=C3=A1lculo=20de=20pontua?= =?UTF-8?q?=C3=A7=C3=A3o=20da=20nota=20do=20PPG=20no=20Componente=20B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mudanças: - Implementa escala correta de nota: 7=20, 6=15, 5=10, 4=5, 3=0 - Usa MAIOR nota entre os programas coordenados - Adiciona documentação detalhada no método - Corrige extras para programas adicionais (só conta se > 1) Conforme especificação técnica oficial CAPES --- .../domain/services/calculador_pontuacao.py | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/backend/src/domain/services/calculador_pontuacao.py b/backend/src/domain/services/calculador_pontuacao.py index ef82bfd..158959b 100644 --- a/backend/src/domain/services/calculador_pontuacao.py +++ b/backend/src/domain/services/calculador_pontuacao.py @@ -103,27 +103,54 @@ class CalculadorPontuacao: @staticmethod def calcular_componente_b(coordenacoes: List[CoordenacaoPrograma]) -> ComponentePontuacao: + """ + Calcula pontuação do Componente B (Coordenação de Programa PPG). + + Regras (máximo 180 pts): + - Base: 70 pts por ser coordenador + - Tempo: 5 pts/ano (máx 50) + - Programas adicionais: 20 pts/programa (máx 40) + - Nota do PPG: usar MAIOR nota (7=20, 6=15, 5=10, 4=5, 3=0) + """ if not coordenacoes: return ComponentePontuacao(base=0, tempo=0, extras=0, bonus=0) + # Base: 70 pts por ser coordenador base = 70 + + # Tempo: 5 pts/ano (máx 50) anos_totais = sum(c.periodo.anos_completos(datetime.now()) for c in coordenacoes) tempo = min(int(anos_totais * 5), 50) + # Programas adicionais: 20 pts/programa extra (máx 40) programas_distintos = len({c.id_programa for c in coordenacoes}) - extras = min((programas_distintos - 1) * 20, 40) + extras = min((programas_distintos - 1) * 20, 40) if programas_distintos > 1 else 0 - nota_bonus = 0 + # Nota do PPG: usar MAIOR nota entre os programas + # Escala: 7=20, 6=15, 5=10, 4=5, 3=0 + maior_nota = 0 for c in coordenacoes: try: - nota_num = float(c.nota_ppg) - if nota_num >= 0: - nota_bonus = 20 - break + nota_str = str(c.nota_ppg).strip() + # Trata notas válidas (3-7 ou A para programas novos) + if nota_str in ['7']: + maior_nota = max(maior_nota, 7) + elif nota_str in ['6']: + maior_nota = max(maior_nota, 6) + elif nota_str in ['5']: + maior_nota = max(maior_nota, 5) + elif nota_str in ['4']: + maior_nota = max(maior_nota, 4) + elif nota_str in ['3']: + maior_nota = max(maior_nota, 3) except Exception: continue - return ComponentePontuacao(base=base, tempo=tempo, extras=extras, bonus=nota_bonus) + # Mapeia nota para pontos + mapa_nota = {7: 20, 6: 15, 5: 10, 4: 5, 3: 0} + bonus = mapa_nota.get(maior_nota, 0) + + return ComponentePontuacao(base=base, tempo=tempo, extras=extras, bonus=bonus) @staticmethod def calcular_componente_c(consultoria: Consultoria) -> ComponentePontuacao: