232 lines
8.1 KiB
Python
232 lines
8.1 KiB
Python
from datetime import datetime
|
|
from typing import List, Dict
|
|
from collections import defaultdict
|
|
|
|
from ..entities.consultor import (
|
|
Consultor,
|
|
CoordenacaoCapes,
|
|
Consultoria,
|
|
Inscricao,
|
|
AvaliacaoComissao,
|
|
Premiacao,
|
|
BolsaCNPQ,
|
|
Participacao,
|
|
Orientacao,
|
|
MembroBanca,
|
|
)
|
|
from ..value_objects.pontuacao import PontuacaoAtuacao, PontuacaoBloco, PontuacaoCompleta
|
|
from ..value_objects.criterios_pontuacao import CRITERIOS, get_criterio, Bloco
|
|
from ..value_objects.periodo import Periodo
|
|
|
|
|
|
class CalculadorPontuacao:
|
|
|
|
@staticmethod
|
|
def _mesclar_periodos(periodos: List[Periodo]) -> List[Periodo]:
|
|
if not periodos:
|
|
return []
|
|
periodos_ordenados = sorted(periodos, key=lambda p: p.inicio if p.inicio else datetime.min)
|
|
mesclados: List[Periodo] = []
|
|
for p in periodos_ordenados:
|
|
if not mesclados:
|
|
mesclados.append(p)
|
|
continue
|
|
ultimo = mesclados[-1]
|
|
ultimo_fim = ultimo.fim or datetime.now()
|
|
atual_fim = p.fim or datetime.now()
|
|
if p.inicio and p.inicio <= ultimo_fim:
|
|
novo_fim = max(ultimo_fim, atual_fim)
|
|
mesclados[-1] = Periodo(inicio=ultimo.inicio, fim=novo_fim if not ultimo.ativo else None)
|
|
else:
|
|
mesclados.append(p)
|
|
return mesclados
|
|
|
|
@staticmethod
|
|
def _anos_completos_periodos(periodos: List[Periodo]) -> int:
|
|
ref = datetime.now()
|
|
return sum(p.anos_completos(ref) for p in periodos)
|
|
|
|
@staticmethod
|
|
def calcular_bloco_a(coordenacoes: List[CoordenacaoCapes]) -> PontuacaoBloco:
|
|
if not coordenacoes:
|
|
return PontuacaoBloco(bloco="A", atuacoes=[])
|
|
|
|
tipos_ordenados = ["CA", "CAJ", "CAJ_MP", "CAM"]
|
|
coord_por_tipo: Dict[str, List[CoordenacaoCapes]] = defaultdict(list)
|
|
for c in coordenacoes:
|
|
codigo = c.codigo.replace("-", "_")
|
|
coord_por_tipo[codigo].append(c)
|
|
|
|
atuacoes = []
|
|
for tipo in tipos_ordenados:
|
|
if tipo not in coord_por_tipo:
|
|
continue
|
|
|
|
criterio = get_criterio(tipo)
|
|
if not criterio:
|
|
continue
|
|
|
|
coords = coord_por_tipo[tipo]
|
|
periodos = [c.periodo for c in coords]
|
|
mesclados = CalculadorPontuacao._mesclar_periodos(periodos)
|
|
|
|
anos_total = CalculadorPontuacao._anos_completos_periodos(mesclados)
|
|
ativo = any(c.periodo.ativo for c in coords)
|
|
tem_retorno = len(mesclados) > 1
|
|
|
|
base = criterio.base
|
|
tempo = min(anos_total * criterio.multiplicador_tempo, criterio.teto_tempo)
|
|
bonus_atualidade = criterio.bonus_atualidade if ativo else 0
|
|
bonus_retorno = criterio.bonus_retorno if tem_retorno else 0
|
|
bonus = bonus_atualidade + bonus_retorno
|
|
|
|
total_bruto = base + tempo + bonus
|
|
total = min(total_bruto, criterio.teto)
|
|
|
|
atuacoes.append(PontuacaoAtuacao(
|
|
codigo=tipo,
|
|
base=base,
|
|
tempo=tempo,
|
|
bonus=bonus,
|
|
total=total,
|
|
quantidade=len(coords),
|
|
))
|
|
|
|
return PontuacaoBloco(bloco="A", atuacoes=atuacoes)
|
|
|
|
@staticmethod
|
|
def calcular_bloco_c(consultoria: Consultoria) -> PontuacaoBloco:
|
|
if not consultoria:
|
|
return PontuacaoBloco(bloco="C", atuacoes=[])
|
|
|
|
codigo = consultoria.codigo
|
|
criterio = get_criterio(codigo)
|
|
if not criterio:
|
|
return PontuacaoBloco(bloco="C", atuacoes=[])
|
|
|
|
base = criterio.base
|
|
|
|
tempo = 0
|
|
if criterio.pontua_tempo:
|
|
periodos = consultoria.periodos if consultoria.periodos else [consultoria.periodo]
|
|
mesclados = CalculadorPontuacao._mesclar_periodos(periodos)
|
|
anos_total = CalculadorPontuacao._anos_completos_periodos(mesclados)
|
|
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
|
|
|
|
total_bruto = base + tempo + bonus
|
|
total = min(total_bruto, criterio.teto)
|
|
|
|
atuacoes = [PontuacaoAtuacao(
|
|
codigo=codigo,
|
|
base=base,
|
|
tempo=tempo,
|
|
bonus=bonus,
|
|
total=total,
|
|
quantidade=1,
|
|
)]
|
|
|
|
return PontuacaoBloco(bloco="C", atuacoes=atuacoes)
|
|
|
|
@staticmethod
|
|
def calcular_bloco_d(
|
|
inscricoes: List[Inscricao],
|
|
avaliacoes: List[AvaliacaoComissao],
|
|
premiacoes: List[Premiacao],
|
|
bolsas: List[BolsaCNPQ],
|
|
participacoes: List[Participacao],
|
|
orientacoes: List[Orientacao],
|
|
membros_banca: List[MembroBanca],
|
|
) -> PontuacaoBloco:
|
|
atuacoes = []
|
|
totais_por_codigo: Dict[str, Dict] = defaultdict(lambda: {"base": 0, "qtd": 0})
|
|
|
|
for insc in inscricoes:
|
|
criterio = get_criterio(insc.codigo)
|
|
if criterio:
|
|
totais_por_codigo[insc.codigo]["base"] += criterio.base
|
|
totais_por_codigo[insc.codigo]["qtd"] += 1
|
|
|
|
for aval in avaliacoes:
|
|
criterio = get_criterio(aval.codigo)
|
|
if criterio:
|
|
totais_por_codigo[aval.codigo]["base"] += criterio.base
|
|
totais_por_codigo[aval.codigo]["qtd"] += 1
|
|
|
|
for prem in premiacoes:
|
|
criterio = get_criterio(prem.codigo)
|
|
if criterio:
|
|
totais_por_codigo[prem.codigo]["base"] += criterio.base
|
|
totais_por_codigo[prem.codigo]["qtd"] += 1
|
|
|
|
for bolsa in bolsas:
|
|
criterio = get_criterio(bolsa.codigo)
|
|
if criterio:
|
|
totais_por_codigo[bolsa.codigo]["base"] += criterio.base
|
|
totais_por_codigo[bolsa.codigo]["qtd"] += 1
|
|
|
|
for part in participacoes:
|
|
criterio = get_criterio(part.codigo)
|
|
if criterio:
|
|
totais_por_codigo[part.codigo]["base"] += criterio.base
|
|
totais_por_codigo[part.codigo]["qtd"] += 1
|
|
|
|
for orient in orientacoes:
|
|
criterio = get_criterio(orient.codigo)
|
|
if criterio:
|
|
totais_por_codigo[orient.codigo]["base"] += criterio.base
|
|
totais_por_codigo[orient.codigo]["qtd"] += 1
|
|
|
|
for mb in membros_banca:
|
|
criterio = get_criterio(mb.codigo)
|
|
if criterio:
|
|
totais_por_codigo[mb.codigo]["base"] += criterio.base
|
|
totais_por_codigo[mb.codigo]["qtd"] += 1
|
|
|
|
for codigo, dados in totais_por_codigo.items():
|
|
criterio = get_criterio(codigo)
|
|
if not criterio:
|
|
continue
|
|
|
|
total = min(dados["base"], criterio.teto)
|
|
atuacoes.append(PontuacaoAtuacao(
|
|
codigo=codigo,
|
|
base=dados["base"],
|
|
tempo=0,
|
|
bonus=0,
|
|
total=total,
|
|
quantidade=dados["qtd"],
|
|
))
|
|
|
|
return PontuacaoBloco(bloco="D", atuacoes=atuacoes)
|
|
|
|
@classmethod
|
|
def calcular_pontuacao_completa(cls, consultor: Consultor) -> PontuacaoCompleta:
|
|
bloco_a = cls.calcular_bloco_a(consultor.coordenacoes_capes)
|
|
bloco_c = cls.calcular_bloco_c(consultor.consultoria)
|
|
bloco_d = cls.calcular_bloco_d(
|
|
inscricoes=consultor.inscricoes,
|
|
avaliacoes=consultor.avaliacoes_comissao,
|
|
premiacoes=consultor.premiacoes,
|
|
bolsas=consultor.bolsas_cnpq,
|
|
participacoes=consultor.participacoes,
|
|
orientacoes=consultor.orientacoes,
|
|
membros_banca=consultor.membros_banca,
|
|
)
|
|
|
|
return PontuacaoCompleta(
|
|
bloco_a=bloco_a,
|
|
bloco_c=bloco_c,
|
|
bloco_d=bloco_d,
|
|
)
|