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_avulsos = relationship("VendaJornalAvulso", back_populates="militante") vendas_jornais = relationship("VendaJornal", back_populates="militante", foreign_keys="[VendaJornal.militante_id]") assinaturas = relationship("AssinaturaJornal", back_populates="militante", foreign_keys="[AssinaturaJornal.militante_id]") celula = relationship("Celula", back_populates="militantes", foreign_keys=[celula_id]) comprovantes = relationship("Comprovante", back_populates="militante") # 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()