fix: Correções no cálculo de pontuação e extração de dados
- Refatora calculador para agrupar coordenações por tipo com hierarquia - Corrige contagem de eventos separando SAE de consultorias - Melhora extração de área de avaliação usando dadosConsultoria - Ajusta pontuação de premiações conforme regras documentadas - Usa alias ES em vez de índice específico
This commit is contained in:
@@ -17,21 +17,40 @@ class CalculadorPontuacao:
|
|||||||
if not coordenacoes:
|
if not coordenacoes:
|
||||||
return ComponentePontuacao(base=0, tempo=0, extras=0, bonus=0, retorno=0)
|
return ComponentePontuacao(base=0, tempo=0, extras=0, bonus=0, retorno=0)
|
||||||
|
|
||||||
coord_atual = next((c for c in coordenacoes if c.periodo.ativo), None)
|
|
||||||
if not coord_atual:
|
|
||||||
return ComponentePontuacao(base=0, tempo=0, extras=0, bonus=0, retorno=0)
|
|
||||||
|
|
||||||
base_map = {"CA": 200, "CAJ": 150, "CAJ-MP": 120, "CAM": 100}
|
base_map = {"CA": 200, "CAJ": 150, "CAJ-MP": 120, "CAM": 100}
|
||||||
tempo_max_map = {"CA": 100, "CAJ": 80, "CAJ-MP": 60, "CAM": 50}
|
tempo_max_map = {"CA": 100, "CAJ": 80, "CAJ-MP": 60, "CAM": 50}
|
||||||
bonus_atual_map = {"CA": 30, "CAJ": 20, "CAJ-MP": 15, "CAM": 10}
|
bonus_atual_map = {"CA": 30, "CAJ": 20, "CAJ-MP": 15, "CAM": 10}
|
||||||
|
mult_tempo_map = {"CA": 10, "CAJ": 8, "CAJ-MP": 6, "CAM": 5}
|
||||||
|
|
||||||
base = base_map.get(coord_atual.tipo, 0)
|
# Agrupa por tipo de coordenação e considera o melhor tipo (hierarquia)
|
||||||
anos = coord_atual.periodo.anos_decorridos
|
tipos_ordenados = ["CA", "CAJ", "CAJ-MP", "CAM"]
|
||||||
tempo = min(int(anos * 10), tempo_max_map.get(coord_atual.tipo, 0))
|
coord_por_tipo = {t: [] for t in tipos_ordenados}
|
||||||
|
for c in coordenacoes:
|
||||||
|
coord_por_tipo.setdefault(c.tipo, []).append(c)
|
||||||
|
|
||||||
extras = min(len(coord_atual.areas_adicionais) * 20, 100)
|
coord_escolhida_tipo = None
|
||||||
bonus = bonus_atual_map.get(coord_atual.tipo, 0) if coord_atual.periodo.ativo else 0
|
for t in tipos_ordenados:
|
||||||
retorno = 20 if coord_atual.ja_coordenou_antes else 0
|
if coord_por_tipo.get(t):
|
||||||
|
coord_escolhida_tipo = t
|
||||||
|
break
|
||||||
|
|
||||||
|
if not coord_escolhida_tipo:
|
||||||
|
return ComponentePontuacao(base=0, tempo=0, extras=0, bonus=0, retorno=0)
|
||||||
|
|
||||||
|
coord_do_tipo = coord_por_tipo.get(coord_escolhida_tipo, [])
|
||||||
|
anos_total = sum(c.periodo.anos_decorridos for c in coord_do_tipo)
|
||||||
|
ativo = any(c.periodo.ativo for c in coord_do_tipo)
|
||||||
|
|
||||||
|
base = base_map.get(coord_escolhida_tipo, 0)
|
||||||
|
tempo = min(int(anos_total * mult_tempo_map.get(coord_escolhida_tipo, 0)), tempo_max_map.get(coord_escolhida_tipo, 0))
|
||||||
|
|
||||||
|
extras = 0
|
||||||
|
areas_adicionais = [a for c in coord_do_tipo for a in c.areas_adicionais]
|
||||||
|
if areas_adicionais:
|
||||||
|
extras = min(len(set(areas_adicionais)) * 20, 100)
|
||||||
|
|
||||||
|
bonus = bonus_atual_map.get(coord_escolhida_tipo, 0) if ativo else 0
|
||||||
|
retorno = 20 if len(coord_do_tipo) > 1 else 0
|
||||||
|
|
||||||
return ComponentePontuacao(base=base, tempo=tempo, extras=extras, bonus=bonus, retorno=retorno)
|
return ComponentePontuacao(base=base, tempo=tempo, extras=extras, bonus=bonus, retorno=retorno)
|
||||||
|
|
||||||
|
|||||||
@@ -63,33 +63,51 @@ class ConsultorRepositoryImpl(ConsultorRepository):
|
|||||||
if not consultorias:
|
if not consultorias:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
datas_inicio = [
|
datas_inicio_consultoria = [
|
||||||
self._parse_date(c.get("inicio"))
|
self._parse_date(c.get("inicio"))
|
||||||
for c in consultorias
|
for c in consultorias
|
||||||
]
|
]
|
||||||
datas_inicio = [d for d in datas_inicio if d]
|
datas_inicio_consultoria = [d for d in datas_inicio_consultoria if d]
|
||||||
|
|
||||||
datas_fim = [
|
if not datas_inicio_consultoria:
|
||||||
self._parse_date(c.get("fim"))
|
|
||||||
for c in consultorias
|
|
||||||
]
|
|
||||||
datas_fim = [d for d in datas_fim if d]
|
|
||||||
|
|
||||||
if not datas_inicio:
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
limite_recente = datetime.now() - timedelta(days=730)
|
eventos_sae = [
|
||||||
eventos_recentes = sum(1 for d in datas_fim if d >= limite_recente)
|
a for a in atuacoes if a.get("tipo") == "Evento"
|
||||||
|
]
|
||||||
|
|
||||||
areas = list({c.get("areaAvaliacao", "N/A") for c in consultorias if c.get("areaAvaliacao")})
|
total_eventos = len(eventos_sae)
|
||||||
|
|
||||||
|
# considerar últimos 24 meses como janela de atividade
|
||||||
|
limite_recente = datetime.now() - timedelta(days=730)
|
||||||
|
eventos_recentes = 0
|
||||||
|
for ev in eventos_sae:
|
||||||
|
data_fim = self._parse_date(ev.get("fim")) or self._parse_date(ev.get("inicio"))
|
||||||
|
if data_fim and data_fim >= limite_recente:
|
||||||
|
eventos_recentes += 1
|
||||||
|
|
||||||
|
dados_consultoria = consultorias[0].get("dadosConsultoria", {}) or {}
|
||||||
|
areas = []
|
||||||
|
for c in consultorias:
|
||||||
|
dc = c.get("dadosConsultoria", {}) or {}
|
||||||
|
area = dc.get("areaAvaliacao") or c.get("areaAvaliacao")
|
||||||
|
if area:
|
||||||
|
areas.append(area)
|
||||||
|
areas = list(set(areas)) if areas else ["N/A"]
|
||||||
|
|
||||||
vezes_responsavel = sum(1 for c in consultorias if c.get("responsavel", False))
|
vezes_responsavel = sum(1 for c in consultorias if c.get("responsavel", False))
|
||||||
|
|
||||||
|
datas_fim_consultoria = [
|
||||||
|
self._parse_date(c.get("fim"))
|
||||||
|
for c in consultorias
|
||||||
|
]
|
||||||
|
datas_fim_consultoria = [d for d in datas_fim_consultoria if d]
|
||||||
|
|
||||||
return Consultoria(
|
return Consultoria(
|
||||||
total_eventos=len(consultorias),
|
total_eventos=total_eventos,
|
||||||
eventos_recentes=eventos_recentes,
|
eventos_recentes=eventos_recentes,
|
||||||
primeiro_evento=min(datas_inicio),
|
primeiro_evento=min(datas_inicio_consultoria),
|
||||||
ultimo_evento=max(datas_fim) if datas_fim else datetime.now(),
|
ultimo_evento=max(datas_fim_consultoria) if datas_fim_consultoria else datetime.now(),
|
||||||
vezes_responsavel=vezes_responsavel,
|
vezes_responsavel=vezes_responsavel,
|
||||||
areas=areas,
|
areas=areas,
|
||||||
)
|
)
|
||||||
@@ -116,25 +134,46 @@ class ConsultorRepositoryImpl(ConsultorRepository):
|
|||||||
tipo = self._inferir_tipo_coordenacao(coord)
|
tipo = self._inferir_tipo_coordenacao(coord)
|
||||||
fim = self._parse_date(coord.get("fim"))
|
fim = self._parse_date(coord.get("fim"))
|
||||||
|
|
||||||
|
dados_coord = coord.get("dadosCoordenacaoArea", {}) or {}
|
||||||
|
area_avaliacao_obj = dados_coord.get("areaAvaliacao", {}) or {}
|
||||||
|
area_avaliacao = area_avaliacao_obj.get("nome") if isinstance(area_avaliacao_obj, dict) else coord.get("areaAvaliacao", "N/A")
|
||||||
|
if not area_avaliacao:
|
||||||
|
area_avaliacao = coord.get("descricao", "N/A").split(" - ")[0] if coord.get("descricao") else "N/A"
|
||||||
|
|
||||||
resultado.append(
|
resultado.append(
|
||||||
CoordenacaoCapes(
|
CoordenacaoCapes(
|
||||||
tipo=tipo,
|
tipo=tipo,
|
||||||
area_avaliacao=coord.get("areaAvaliacao", "N/A"),
|
area_avaliacao=area_avaliacao,
|
||||||
periodo=Periodo(inicio=inicio, fim=fim),
|
periodo=Periodo(inicio=inicio, fim=fim),
|
||||||
areas_adicionais=[],
|
areas_adicionais=[],
|
||||||
ja_coordenou_antes=False,
|
ja_coordenou_antes=len(resultado) > 0,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return resultado
|
return resultado
|
||||||
|
|
||||||
def _inferir_tipo_coordenacao(self, coord: Dict[str, Any]) -> str:
|
def _inferir_tipo_coordenacao(self, coord: Dict[str, Any]) -> str:
|
||||||
nome = coord.get("nome", "").lower()
|
dados_coord = coord.get("dadosCoordenacaoArea", {}) or {}
|
||||||
if "câmara" in nome or "camara" in nome:
|
tipo_coord = dados_coord.get("tipo", "").lower()
|
||||||
|
|
||||||
|
if "câmara" in tipo_coord or "camara" in tipo_coord:
|
||||||
return "CAM"
|
return "CAM"
|
||||||
elif "mestrado profissional" in nome:
|
elif "adjunt" in tipo_coord:
|
||||||
|
if "profissional" in tipo_coord or "mestrado" in tipo_coord:
|
||||||
|
return "CAJ-MP"
|
||||||
|
return "CAJ"
|
||||||
|
elif "coordenador de área" in tipo_coord:
|
||||||
|
return "CA"
|
||||||
|
|
||||||
|
descricao = coord.get("descricao", "").lower()
|
||||||
|
nome = coord.get("nome", "").lower()
|
||||||
|
texto = f"{descricao} {nome}"
|
||||||
|
|
||||||
|
if "câmara" in texto or "camara" in texto:
|
||||||
|
return "CAM"
|
||||||
|
elif "mestrado profissional" in texto:
|
||||||
return "CAJ-MP"
|
return "CAJ-MP"
|
||||||
elif "adjunta" in nome:
|
elif "adjunt" in texto:
|
||||||
return "CAJ"
|
return "CAJ"
|
||||||
else:
|
else:
|
||||||
return "CA"
|
return "CA"
|
||||||
@@ -148,6 +187,7 @@ class ConsultorRepositoryImpl(ConsultorRepository):
|
|||||||
"Premiação Prêmio",
|
"Premiação Prêmio",
|
||||||
"Avaliação Prêmio",
|
"Avaliação Prêmio",
|
||||||
"Inscrição Prêmio",
|
"Inscrição Prêmio",
|
||||||
|
"Premiação",
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -169,10 +209,12 @@ class ConsultorRepositoryImpl(ConsultorRepository):
|
|||||||
return premiacoes
|
return premiacoes
|
||||||
|
|
||||||
def _calcular_pontos_premiacao(self, tipo: str) -> int:
|
def _calcular_pontos_premiacao(self, tipo: str) -> int:
|
||||||
|
# Aproximação das regras (D) seguindo .claude/rules/ranking-consultores-capes.md
|
||||||
mapa = {
|
mapa = {
|
||||||
"Premiação Prêmio": 60,
|
"Premiação Prêmio": 150,
|
||||||
|
"Premiação": 150,
|
||||||
"Avaliação Prêmio": 40,
|
"Avaliação Prêmio": 40,
|
||||||
"Inscrição Prêmio": 20,
|
"Inscrição Prêmio": 10,
|
||||||
}
|
}
|
||||||
return mapa.get(tipo, 0)
|
return mapa.get(tipo, 0)
|
||||||
|
|
||||||
@@ -186,9 +228,9 @@ class ConsultorRepositoryImpl(ConsultorRepository):
|
|||||||
premiacoes = self._extrair_premiacoes(atuacoes)
|
premiacoes = self._extrair_premiacoes(atuacoes)
|
||||||
|
|
||||||
coordenacoes_programas_raw = []
|
coordenacoes_programas_raw = []
|
||||||
if self.oracle_client.is_connected:
|
if self.oracle_client and self.oracle_client.is_connected:
|
||||||
try:
|
try:
|
||||||
coordenacoes_programas_raw = self.oracle_client.buscar_coordenacoes_programa(id_pessoa)
|
coordenacoes_programas_raw = self.oracle_client.buscar_coordenacoes_programa(int(id_pessoa))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"AVISO Oracle: erro ao buscar coordenacoes do programa para {id_pessoa}: {e}")
|
print(f"AVISO Oracle: erro ao buscar coordenacoes do programa para {id_pessoa}: {e}")
|
||||||
coordenacoes_programas = [
|
coordenacoes_programas = [
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ from typing import List
|
|||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")
|
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")
|
||||||
|
|
||||||
|
# Preferir o alias apontado para o índice vigente do Atuacapes
|
||||||
ES_URL: str = "http://localhost:9200"
|
ES_URL: str = "http://localhost:9200"
|
||||||
ES_INDEX: str = "atuacapes__1763197236"
|
ES_INDEX: str = "atuacapes"
|
||||||
ES_USER: str = ""
|
ES_USER: str = ""
|
||||||
ES_PASSWORD: str = ""
|
ES_PASSWORD: str = ""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user