refactor: Implementa arquitetura MVC limpa
- Separa modelos em entidades individuais - Cria camada de serviços para acesso a dados - Implementa controladores para lógica de negócio - Organiza rotas em blueprints por funcionalidade - Adiciona documentação de arquitetura no README - Cria script para preparação da estrutura 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
153
models/entities/militante.py
Normal file
153
models/entities/militante.py
Normal file
@@ -0,0 +1,153 @@
|
||||
from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey, Date, Text, Enum
|
||||
from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
import enum
|
||||
import secrets
|
||||
|
||||
from models.entities.base import Base
|
||||
|
||||
class EstadoMilitante(enum.Enum):
|
||||
ATIVO = 'ativo'
|
||||
DESLIGADO = 'desligado'
|
||||
SUSPENSO = 'suspenso'
|
||||
AFASTADO = 'afastado'
|
||||
|
||||
class Militante(Base):
|
||||
__tablename__ = 'militantes'
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
nome = Column(String(100), nullable=False)
|
||||
cpf = Column(String(14), unique=True)
|
||||
# Novos campos básicos
|
||||
titulo_eleitoral = Column(String(20))
|
||||
data_nascimento = Column(Date)
|
||||
data_entrada_oci = Column(Date)
|
||||
data_efetivacao_oci = Column(Date)
|
||||
# Campos de contato
|
||||
telefone1 = Column(String(15))
|
||||
telefone2 = Column(String(15))
|
||||
# Relacionamento para múltiplos emails
|
||||
emails = relationship("EmailMilitante", back_populates="militante")
|
||||
# Endereço
|
||||
endereco_id = Column(Integer, ForeignKey('enderecos.id', use_alter=True, name='fk_militante_endereco'))
|
||||
endereco = relationship("Endereco", back_populates="militantes")
|
||||
# Redes sociais
|
||||
redes_sociais = relationship("RedeSocial", back_populates="militante")
|
||||
# Campos profissionais
|
||||
profissao = Column(String(100))
|
||||
regime_trabalho = Column(String(50)) # CLT, Estatutário, etc.
|
||||
empresa = Column(String(100))
|
||||
contratante = Column(String(100)) # Para terceirizados
|
||||
# Campos acadêmicos
|
||||
instituicao_ensino = Column(String(100))
|
||||
tipo_instituicao = Column(String(20)) # Federal, Estadual, etc.
|
||||
# Campos sindicais
|
||||
sindicato = Column(String(100))
|
||||
cargo_sindical = Column(String(50))
|
||||
dirigente_sindical = Column(Boolean)
|
||||
central_sindical = Column(String(100))
|
||||
# Responsável pelo cadastro
|
||||
registrado_por = Column(Integer, ForeignKey('militantes.id', use_alter=True, name='fk_militante_registrado_por'))
|
||||
# Campos existentes
|
||||
celula_id = Column(Integer, ForeignKey('celulas.id', use_alter=True, name='fk_militante_celula'))
|
||||
responsabilidades = Column(Integer, default=0)
|
||||
otp_secret = Column(String(32))
|
||||
temp_token = Column(String(64))
|
||||
temp_token_expiry = Column(DateTime)
|
||||
# Novo campo para Quadro-Orientador
|
||||
quadro_orientador = Column(Boolean, default=False)
|
||||
# Campos para Aspirante
|
||||
aspirante = Column(Boolean, default=True) # Por padrão, todo novo militante é aspirante
|
||||
data_inicio_aspirante = Column(DateTime, default=datetime.utcnow)
|
||||
avaliacao_aspirante = Column(Text)
|
||||
data_avaliacao_aspirante = Column(DateTime)
|
||||
|
||||
# Campos para estado do militante
|
||||
estado = Column(Enum(EstadoMilitante), default=EstadoMilitante.ATIVO)
|
||||
data_desligamento = Column(DateTime)
|
||||
motivo_desligamento = Column(Text)
|
||||
|
||||
# Relacionamentos existentes
|
||||
cotas_mensais = relationship("CotaMensal", back_populates="militante")
|
||||
pagamentos = relationship("Pagamento", back_populates="militante")
|
||||
materiais_vendidos = relationship("MaterialVendido", back_populates="militante")
|
||||
vendas_jornais = relationship("VendaJornalAvulso", back_populates="militante")
|
||||
assinaturas = relationship("AssinaturaAnual", back_populates="militante")
|
||||
celula = relationship("Celula", back_populates="militantes", foreign_keys=[celula_id])
|
||||
|
||||
# Constantes para responsabilidades
|
||||
SECRETARIO = 1
|
||||
TESOUREIRO = 2
|
||||
IMPRENSA = 4
|
||||
MNS = 8
|
||||
MPS = 16
|
||||
JUVENTUDE = 32
|
||||
QUADRO_ORIENTADOR = 64
|
||||
ASPIRANTE = 128
|
||||
RESPONSAVEL_FINANCAS = 256
|
||||
RESPONSAVEL_IMPRENSA = 512
|
||||
|
||||
@staticmethod
|
||||
def get_responsabilidades_list():
|
||||
return [
|
||||
(Militante.SECRETARIO, "Secretário"),
|
||||
(Militante.TESOUREIRO, "Tesoureiro"),
|
||||
(Militante.IMPRENSA, "Imprensa"),
|
||||
(Militante.MNS, "MNS"),
|
||||
(Militante.MPS, "MPS"),
|
||||
(Militante.JUVENTUDE, "Juventude"),
|
||||
(Militante.QUADRO_ORIENTADOR, "Quadro-Orientador"),
|
||||
(Militante.ASPIRANTE, "Aspirante"),
|
||||
(Militante.RESPONSAVEL_FINANCAS, "Responsável de Finanças"),
|
||||
(Militante.RESPONSAVEL_IMPRENSA, "Responsável de Imprensa")
|
||||
]
|
||||
|
||||
def set_responsabilidades(self, resp_list):
|
||||
"""
|
||||
Define as responsabilidades do militante
|
||||
resp_list: lista de inteiros representando as responsabilidades
|
||||
"""
|
||||
self.responsabilidades = sum(resp_list)
|
||||
|
||||
def get_responsabilidades(self):
|
||||
"""
|
||||
Retorna lista de responsabilidades ativas
|
||||
"""
|
||||
resp = []
|
||||
for valor, nome in self.get_responsabilidades_list():
|
||||
if self.responsabilidades & valor:
|
||||
resp.append(nome)
|
||||
return resp
|
||||
|
||||
def generate_temp_token(self):
|
||||
"""
|
||||
Gera um token temporário para acesso ao QR code
|
||||
"""
|
||||
self.temp_token = secrets.token_urlsafe(32)
|
||||
self.temp_token_expiry = datetime.now() + timedelta(hours=48)
|
||||
return self.temp_token
|
||||
|
||||
def generate_username(self):
|
||||
"""Gera um nome de usuário único baseado no primeiro nome e um código"""
|
||||
from sqlalchemy import func
|
||||
from services.database_service import DatabaseService
|
||||
|
||||
db = DatabaseService.get_db_connection()
|
||||
try:
|
||||
# Pega o primeiro nome
|
||||
primeiro_nome = self.nome.split()[0].lower()
|
||||
|
||||
# Importação local para evitar dependência circular
|
||||
from models.entities.usuario import Usuario
|
||||
|
||||
# Conta quantos usuários já existem com esse prefixo
|
||||
count = db.query(func.count(Usuario.id)).filter(
|
||||
Usuario.username.like(f"{primeiro_nome}%")
|
||||
).scalar()
|
||||
|
||||
# Gera o código (número sequencial)
|
||||
codigo = str(count + 1).zfill(3)
|
||||
|
||||
return f"{primeiro_nome}{codigo}"
|
||||
finally:
|
||||
db.close()
|
||||
Reference in New Issue
Block a user