Files
controles/models/militante_model.py
Mateus Tavares 2b1668206d - inits centralizados, READMEs atualizados
- padronizando o nome de get_db_connection e session para get_db_session, para não confundir com session do Flask ou sessoes web

- corrigindo potenciais erros

-- has_permission nao consegue com lazy load carregar permission depois de load_user fechar a conexao, entao joinedLoad com Permission antes de fechar

-- db.rollback não existe caso db = get_db_session() apareça muito depois dentro do try, padronizando antes de try

--- comparar role por nivel (Role.SECRETARIO_GERAL) e nao por nome ("Secretario Geral")

- unificacao de get_otp_qr_code

- mudança de nowutc() para now(UTC) conforme novo padrão
2026-02-20 17:19:15 -03:00

328 lines
14 KiB
Python

from functions.database import get_db_session, Militante, EmailMilitante, Endereco
from sqlalchemy.orm import joinedload
from datetime import datetime
from typing import List, Dict, Optional
from services.cache_service import cache_service, cached, CacheKeys, invalidate_cache_pattern
import logging
logger = logging.getLogger(__name__)
class MilitanteModel:
"""Model para operações com militantes"""
@staticmethod
@invalidate_cache_pattern("militantes:*")
def criar_militante(data: Dict) -> Dict:
"""Cria um novo militante"""
db = get_db_session()
try:
# Criar endereço se fornecido
endereco_id = None
if data.get('endereco'):
endereco = Endereco(**data['endereco'])
db.add(endereco)
db.flush()
endereco_id = endereco.id
# Criar militante
militante = Militante(
nome=data['nome'],
cpf=data['cpf'],
titulo_eleitoral=data.get('titulo_eleitoral'),
data_nascimento=data.get('data_nascimento'),
data_entrada_oci=data.get('data_entrada_oci'),
data_efetivacao_oci=data.get('data_efetivacao_oci'),
telefone1=data.get('telefone1'),
telefone2=data.get('telefone2'),
profissao=data.get('profissao'),
regime_trabalho=data.get('regime_trabalho'),
empresa=data.get('empresa'),
contratante=data.get('contratante'),
instituicao_ensino=data.get('instituicao_ensino'),
tipo_instituicao=data.get('tipo_instituicao'),
sindicato=data.get('sindicato'),
cargo_sindical=data.get('cargo_sindical'),
dirigente_sindical=data.get('dirigente_sindical', False),
central_sindical=data.get('central_sindical'),
endereco_id=endereco_id,
celula_id=data.get('celula_id'),
registrado_por=data.get('registrado_por')
)
db.add(militante)
db.flush()
# Criar email se fornecido
if data.get('email'):
email = EmailMilitante(
militante_id=militante.id,
endereco_email=data['email']
)
db.add(email)
db.commit()
# Cache the new militante
cache_key = CacheKeys.militante_detail(militante.id)
militante_data = MilitanteModel.formatar_dados_militante(militante)
cache_service.set(cache_key, militante_data, 1800) # 30 minutes
logger.info(f"Militante {militante.id} criado e cacheado")
return {
'status': 'success',
'message': 'Militante criado com sucesso',
'militante_id': militante.id
}
except Exception as e:
db.rollback()
logger.error(f"Erro ao criar militante: {e}")
return {
'status': 'error',
'message': f'Erro ao criar militante: {str(e)}'
}
finally:
db.close()
@staticmethod
@cached(expire=1800, key_prefix="militantes") # Cache for 30 minutes
def listar_militantes() -> List[Militante]:
"""Lista todos os militantes"""
db = get_db_session()
try:
militantes = db.query(Militante).options(
joinedload(Militante.emails),
joinedload(Militante.endereco),
joinedload(Militante.celula)
).order_by(Militante.nome).all()
# Cache individual militantes
for militante in militantes:
cache_key = CacheKeys.militante_detail(militante.id)
militante_data = MilitanteModel.formatar_dados_militante(militante)
cache_service.set(cache_key, militante_data, 1800)
logger.debug(f"Listados {len(militantes)} militantes e cacheados")
return militantes
except Exception as e:
logger.error(f"Erro ao listar militantes: {e}")
return []
finally:
db.close()
@staticmethod
def buscar_por_id(militante_id: int) -> Optional[Militante]:
"""Busca um militante por ID"""
# Try cache first
cache_key = CacheKeys.militante_detail(militante_id)
cached_militante = cache_service.get(cache_key)
if cached_militante:
logger.debug(f"Cache hit para militante {militante_id}")
# Convert cached data back to Militante object if needed
return cached_militante
# Cache miss, get from database
db = get_db_session()
try:
militante = db.query(Militante).options(
joinedload(Militante.emails),
joinedload(Militante.endereco)
).get(militante_id)
if militante:
# Cache the militante
militante_data = MilitanteModel.formatar_dados_militante(militante)
cache_service.set(cache_key, militante_data, 1800)
logger.debug(f"Cache miss para militante {militante_id}, cacheado")
return militante
except Exception as e:
logger.error(f"Erro ao buscar militante {militante_id}: {e}")
return None
finally:
db.close()
@staticmethod
@invalidate_cache_pattern("militantes:*")
def atualizar_militante(militante_id: int, data: Dict) -> Dict:
"""Atualiza um militante existente"""
db = get_db_session()
try:
militante = db.query(Militante).get(militante_id)
if not militante:
return {
'status': 'error',
'message': 'Militante não encontrado'
}
# Atualizar dados básicos
militante.nome = data.get('nome', militante.nome)
militante.cpf = data.get('cpf', militante.cpf)
militante.titulo_eleitoral = data.get('titulo_eleitoral', militante.titulo_eleitoral)
militante.telefone1 = data.get('telefone1', militante.telefone1)
militante.telefone2 = data.get('telefone2', militante.telefone2)
militante.profissao = data.get('profissao', militante.profissao)
militante.regime_trabalho = data.get('regime_trabalho', militante.regime_trabalho)
militante.empresa = data.get('empresa', militante.empresa)
militante.contratante = data.get('contratante', militante.contratante)
militante.instituicao_ensino = data.get('instituicao_ensino', militante.instituicao_ensino)
militante.tipo_instituicao = data.get('tipo_instituicao', militante.tipo_instituicao)
militante.sindicato = data.get('sindicato', militante.sindicato)
militante.cargo_sindical = data.get('cargo_sindical', militante.cargo_sindical)
militante.dirigente_sindical = data.get('dirigente_sindical', militante.dirigente_sindical)
militante.central_sindical = data.get('central_sindical', militante.central_sindical)
# Atualizar datas
if data.get('data_nascimento'):
militante.data_nascimento = data['data_nascimento']
if data.get('data_entrada_oci'):
militante.data_entrada_oci = data['data_entrada_oci']
if data.get('data_efetivacao_oci'):
militante.data_efetivacao_oci = data['data_efetivacao_oci']
# Atualizar endereço
if data.get('endereco') and militante.endereco:
endereco = militante.endereco
endereco.cep = data['endereco'].get('cep', endereco.cep)
endereco.estado = data['endereco'].get('estado', endereco.estado)
endereco.cidade = data['endereco'].get('cidade', endereco.cidade)
endereco.bairro = data['endereco'].get('bairro', endereco.bairro)
endereco.rua = data['endereco'].get('rua', endereco.rua)
endereco.numero = data['endereco'].get('numero', endereco.numero)
endereco.complemento = data['endereco'].get('complemento', endereco.complemento)
# Atualizar email
if data.get('email') and militante.emails:
militante.emails[0].endereco_email = data['email']
db.commit()
# Update cache
cache_key = CacheKeys.militante_detail(militante_id)
militante_data = MilitanteModel.formatar_dados_militante(militante)
cache_service.set(cache_key, militante_data, 1800)
logger.info(f"Militante {militante_id} atualizado e cache atualizado")
return {
'status': 'success',
'message': 'Militante atualizado com sucesso'
}
except Exception as e:
db.rollback()
logger.error(f"Erro ao atualizar militante {militante_id}: {e}")
return {
'status': 'error',
'message': f'Erro ao atualizar militante: {str(e)}'
}
finally:
db.close()
@staticmethod
@invalidate_cache_pattern("militantes:*")
def excluir_militante(militante_id: int) -> Dict:
"""Exclui um militante"""
db = get_db_session()
try:
militante = db.query(Militante).get(militante_id)
if not militante:
return {
'status': 'error',
'message': 'Militante não encontrado'
}
db.delete(militante)
db.commit()
# Remove from cache
cache_key = CacheKeys.militante_detail(militante_id)
cache_service.delete(cache_key)
logger.info(f"Militante {militante_id} excluído e removido do cache")
return {
'status': 'success',
'message': 'Militante excluído com sucesso'
}
except Exception as e:
db.rollback()
logger.error(f"Erro ao excluir militante {militante_id}: {e}")
return {
'status': 'error',
'message': f'Erro ao excluir militante: {str(e)}'
}
finally:
db.close()
@staticmethod
@cached(expire=1800, key_prefix="militantes")
def buscar_por_cpf(cpf: str) -> Optional[Militante]:
"""Busca um militante por CPF"""
db = get_db_session()
try:
militante = db.query(Militante).filter_by(cpf=cpf).first()
if militante:
# Cache the militante
cache_key = CacheKeys.militante_detail(militante.id)
militante_data = MilitanteModel.formatar_dados_militante(militante)
cache_service.set(cache_key, militante_data, 1800)
return militante
except Exception as e:
logger.error(f"Erro ao buscar militante por CPF {cpf}: {e}")
return None
finally:
db.close()
@staticmethod
def formatar_dados_militante(militante: Militante) -> Dict:
"""Formata os dados de um militante para retorno JSON"""
def formatar_data_segura(data):
try:
if not data:
return None
return data.strftime('%Y-%m-%d')
except Exception as e:
logger.error(f"Erro ao formatar data: {str(e)}, valor: {data}")
return None
return {
'id': militante.id,
'nome': militante.nome,
'cpf': militante.cpf,
'titulo_eleitoral': militante.titulo_eleitoral,
'data_nascimento': formatar_data_segura(militante.data_nascimento),
'data_entrada_oci': formatar_data_segura(militante.data_entrada_oci),
'data_efetivacao_oci': formatar_data_segura(militante.data_efetivacao_oci),
'telefone1': militante.telefone1,
'telefone2': militante.telefone2,
'profissao': militante.profissao,
'regime_trabalho': militante.regime_trabalho,
'empresa': militante.empresa,
'contratante': militante.contratante,
'instituicao_ensino': militante.instituicao_ensino,
'tipo_instituicao': militante.tipo_instituicao,
'sindicato': militante.sindicato,
'cargo_sindical': militante.cargo_sindical,
'dirigente_sindical': militante.dirigente_sindical,
'central_sindical': militante.central_sindical,
'responsabilidades': militante.responsabilidades,
'estado': militante.estado.value if militante.estado else None,
'celula_id': militante.celula_id,
'email': militante.emails[0].endereco_email if militante.emails else None,
'endereco': {
'cep': militante.endereco.cep if militante.endereco else None,
'estado': militante.endereco.estado if militante.endereco else None,
'cidade': militante.endereco.cidade if militante.endereco else None,
'bairro': militante.endereco.bairro if militante.endereco else None,
'rua': militante.endereco.rua if militante.endereco else None,
'numero': militante.endereco.numero if militante.endereco else None,
'complemento': militante.endereco.complemento if militante.endereco else None
} if militante.endereco else None
}