Refatoracao de qualidade de codigo
- Mover logica de routes.py para RankingMapper na camada de aplicacao - Consolidar funcoes mesclar_periodos e anos_completos_periodos em periodo.py - Extrair RankingCache para modulo separado em infrastructure/cache - Substituir todos os print() por logging adequado - Corrigir exception handlers genericos para tipos especificos - Remover classe Atuacao e atributo atuacoes_raw nao utilizados - Documentar status dos scripts utilitarios
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from itertools import islice
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from ...infrastructure.oracle.client import OracleClient
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PopularComponenteBJob:
|
||||
"""
|
||||
@@ -89,15 +92,15 @@ class PopularComponenteBJob:
|
||||
Este método é síncrono; use asyncio.to_thread quando chamá-lo em corrotina.
|
||||
"""
|
||||
if not self.oracle_local.is_connected:
|
||||
print("PopularComponenteB: Oracle LOCAL não conectado, abortando.")
|
||||
logger.warning("PopularComponenteB: Oracle LOCAL não conectado, abortando.")
|
||||
return
|
||||
if not self.oracle_remote.is_connected:
|
||||
print("PopularComponenteB: Oracle REMOTO não conectado, abortando.")
|
||||
logger.warning("PopularComponenteB: Oracle REMOTO não conectado, abortando.")
|
||||
return
|
||||
|
||||
ids_pessoas = self._buscar_ids_pendentes()
|
||||
total_ids = len(ids_pessoas)
|
||||
print(f"PopularComponenteB: {total_ids} consultores pendentes para COMPONENTE_B")
|
||||
logger.info(f"PopularComponenteB: {total_ids} consultores pendentes para COMPONENTE_B")
|
||||
|
||||
processados = 0
|
||||
com_ppg = 0
|
||||
@@ -107,7 +110,7 @@ class PopularComponenteBJob:
|
||||
try:
|
||||
registros = self._buscar_ppg_lote(lote)
|
||||
except Exception as e:
|
||||
print(f"PopularComponenteB: erro ao buscar lote {lote[:3]}... -> {e}")
|
||||
logger.warning(f"PopularComponenteB: erro ao buscar lote {lote[:3]}... -> {e}")
|
||||
continue
|
||||
|
||||
por_pessoa: Dict[int, List[Dict]] = {}
|
||||
@@ -127,14 +130,14 @@ class PopularComponenteBJob:
|
||||
|
||||
if len(batch) >= batch_updates:
|
||||
self._aplicar_batch(batch)
|
||||
print(f"PopularComponenteB: Processados {processados}/{total_ids} | Com PPG: {com_ppg}")
|
||||
logger.info(f"PopularComponenteB: Processados {processados}/{total_ids} | Com PPG: {com_ppg}")
|
||||
batch = []
|
||||
|
||||
if batch:
|
||||
self._aplicar_batch(batch)
|
||||
|
||||
self._atualizar_posicoes()
|
||||
print(f"PopularComponenteB: Finalizado. Processados={processados} Com PPG={com_ppg}")
|
||||
logger.info(f"PopularComponenteB: Finalizado. Processados={processados} Com PPG={com_ppg}")
|
||||
|
||||
def _aplicar_batch(self, batch: List[Dict[str, int]]) -> None:
|
||||
if not batch:
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
from ...infrastructure.elasticsearch.client import ElasticsearchClient
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
from ...infrastructure.oracle.client import OracleClient
|
||||
from ...infrastructure.oracle.ranking_repository import RankingOracleRepository
|
||||
from ...infrastructure.repositories.consultor_repository_impl import ConsultorRepositoryImpl
|
||||
@@ -87,8 +90,8 @@ class ProcessarRankingJob:
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
print(f"AVISO: Erro ao processar consultor {doc.get('id')}: {e}")
|
||||
print(f"Traceback: {traceback.format_exc()}")
|
||||
logger.warning(f"Erro ao processar consultor {doc.get('id')}: {e}")
|
||||
logger.debug(f"Traceback: {traceback.format_exc()}")
|
||||
continue
|
||||
|
||||
if consultores_para_inserir:
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from datetime import datetime, time, timedelta
|
||||
from typing import Optional
|
||||
|
||||
from .processar_ranking import ProcessarRankingJob
|
||||
from .popular_componente_b_job import PopularComponenteBJob
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RankingScheduler:
|
||||
def __init__(self, job: ProcessarRankingJob, job_componente_b: PopularComponenteBJob | None = None):
|
||||
@@ -24,7 +27,7 @@ class RankingScheduler:
|
||||
proxima_execucao += timedelta(days=1)
|
||||
|
||||
segundos_ate_proxima = (proxima_execucao - agora).total_seconds()
|
||||
print(f"Próxima execução do ranking: {proxima_execucao.strftime('%d/%m/%Y %H:%M:%S')}")
|
||||
logger.info(f"Próxima execução do ranking: {proxima_execucao.strftime('%d/%m/%Y %H:%M:%S')}")
|
||||
|
||||
await asyncio.sleep(segundos_ate_proxima)
|
||||
|
||||
@@ -39,18 +42,18 @@ class RankingScheduler:
|
||||
if not self.running:
|
||||
break
|
||||
|
||||
print(f"[{datetime.now().strftime('%d/%m/%Y %H:%M:%S')}] Executando job de ranking automático")
|
||||
logger.info("Executando job de ranking automático")
|
||||
await self.job.executar(limpar_antes=True)
|
||||
|
||||
if self.job_componente_b:
|
||||
print(f"[{datetime.now().strftime('%d/%m/%Y %H:%M:%S')}] Executando popular_componente_b após ranking")
|
||||
logger.info("Executando popular_componente_b após ranking")
|
||||
await asyncio.to_thread(self.job_componente_b.executar)
|
||||
|
||||
except asyncio.CancelledError:
|
||||
print("Scheduler cancelado")
|
||||
logger.info("Scheduler cancelado")
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"Erro no scheduler: {e}")
|
||||
logger.error(f"Erro no scheduler: {e}")
|
||||
await asyncio.sleep(3600)
|
||||
|
||||
async def iniciar(self, hora_alvo: int = 3) -> None:
|
||||
@@ -64,7 +67,7 @@ class RankingScheduler:
|
||||
self.running = True
|
||||
self.task = asyncio.create_task(self._loop_diario(hora_alvo))
|
||||
await asyncio.sleep(0.1)
|
||||
print(f"Scheduler do ranking iniciado: job rodará diariamente às {hora_alvo}h")
|
||||
logger.info(f"Scheduler do ranking iniciado: job rodará diariamente às {hora_alvo}h")
|
||||
|
||||
def parar(self) -> None:
|
||||
"""
|
||||
|
||||
3
backend/src/application/mappers/__init__.py
Normal file
3
backend/src/application/mappers/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .ranking_mapper import RankingMapper
|
||||
|
||||
__all__ = ["RankingMapper"]
|
||||
104
backend/src/application/mappers/ranking_mapper.py
Normal file
104
backend/src/application/mappers/ranking_mapper.py
Normal file
@@ -0,0 +1,104 @@
|
||||
import json
|
||||
import logging
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from ...domain.entities.consultor_ranking import ConsultorRanking
|
||||
from ...interface.schemas.ranking_schema import ConsultorRankingResumoSchema
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RankingMapper:
|
||||
@staticmethod
|
||||
def consultor_ranking_to_schema(c: ConsultorRanking) -> ConsultorRankingResumoSchema:
|
||||
consultoria = None
|
||||
coordenacoes_capes = None
|
||||
inscricoes = None
|
||||
avaliacoes_comissao = None
|
||||
premiacoes = None
|
||||
bolsas_cnpq = None
|
||||
participacoes = None
|
||||
orientacoes = None
|
||||
membros_banca = None
|
||||
pontuacao = None
|
||||
|
||||
try:
|
||||
jd = json.loads(c.json_detalhes) if c.json_detalhes else {}
|
||||
if isinstance(jd, dict):
|
||||
consultoria = jd.get("consultoria")
|
||||
coordenacoes_capes = jd.get("coordenacoes_capes")
|
||||
inscricoes = jd.get("inscricoes")
|
||||
avaliacoes_comissao = jd.get("avaliacoes_comissao")
|
||||
premiacoes = jd.get("premiacoes")
|
||||
bolsas_cnpq = jd.get("bolsas_cnpq")
|
||||
participacoes = jd.get("participacoes")
|
||||
orientacoes = jd.get("orientacoes")
|
||||
membros_banca = jd.get("membros_banca")
|
||||
pontuacao = jd.get("pontuacao")
|
||||
except (json.JSONDecodeError, TypeError) as e:
|
||||
logger.warning(f"Erro ao parsear json_detalhes do consultor {c.id_pessoa}: {e}")
|
||||
|
||||
pontuacao_total = float(c.pontuacao_total or 0)
|
||||
bloco_a = float(c.componente_a or 0)
|
||||
bloco_b = float(c.componente_b or 0)
|
||||
bloco_c = float(c.componente_c or 0)
|
||||
bloco_d = float(c.componente_d or 0)
|
||||
|
||||
pontuacao_ajustada = RankingMapper._ajustar_pontuacao(
|
||||
pontuacao, bloco_a, bloco_b, bloco_c, bloco_d, pontuacao_total
|
||||
)
|
||||
|
||||
return ConsultorRankingResumoSchema(
|
||||
id_pessoa=c.id_pessoa,
|
||||
nome=c.nome,
|
||||
posicao=c.posicao,
|
||||
pontuacao_total=pontuacao_total,
|
||||
bloco_a=bloco_a,
|
||||
bloco_b=bloco_b,
|
||||
bloco_c=bloco_c,
|
||||
bloco_d=bloco_d,
|
||||
ativo=c.ativo,
|
||||
anos_atuacao=c.anos_atuacao,
|
||||
consultoria=consultoria,
|
||||
coordenacoes_capes=coordenacoes_capes,
|
||||
inscricoes=inscricoes,
|
||||
avaliacoes_comissao=avaliacoes_comissao,
|
||||
premiacoes=premiacoes,
|
||||
bolsas_cnpq=bolsas_cnpq,
|
||||
participacoes=participacoes,
|
||||
orientacoes=orientacoes,
|
||||
membros_banca=membros_banca,
|
||||
pontuacao=pontuacao_ajustada if pontuacao_ajustada else None,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _ajustar_pontuacao(
|
||||
pontuacao: Optional[Dict],
|
||||
bloco_a: float,
|
||||
bloco_b: float,
|
||||
bloco_c: float,
|
||||
bloco_d: float,
|
||||
pontuacao_total: float,
|
||||
) -> Dict[str, Any]:
|
||||
if isinstance(pontuacao, dict):
|
||||
pontuacao_ajustada = dict(pontuacao)
|
||||
else:
|
||||
pontuacao_ajustada = {}
|
||||
|
||||
def ajustar_bloco(chave: str, total: float, letra: str):
|
||||
b = pontuacao_ajustada.get(chave)
|
||||
if isinstance(b, dict):
|
||||
b2 = dict(b)
|
||||
b2["bloco"] = letra
|
||||
b2["total"] = total
|
||||
pontuacao_ajustada[chave] = b2
|
||||
else:
|
||||
pontuacao_ajustada[chave] = {"bloco": letra, "total": total, "atuacoes": []}
|
||||
|
||||
ajustar_bloco("bloco_a", bloco_a, "A")
|
||||
ajustar_bloco("bloco_b", bloco_b, "B")
|
||||
ajustar_bloco("bloco_c", bloco_c, "C")
|
||||
ajustar_bloco("bloco_d", bloco_d, "D")
|
||||
pontuacao_ajustada["pontuacao_total"] = pontuacao_total
|
||||
|
||||
return pontuacao_ajustada
|
||||
Reference in New Issue
Block a user