diff --git a/functions/database.py b/functions/database.py index 1719042..20e9bcb 100644 --- a/functions/database.py +++ b/functions/database.py @@ -1,4 +1,4 @@ -from sqlalchemy import create_engine, Column, Integer, String, Boolean, Numeric, Date, ForeignKey, DateTime +from sqlalchemy import create_engine, Column, Integer, String, Boolean, Numeric, Date, ForeignKey, DateTime, Text from sqlalchemy.orm import relationship, sessionmaker from sqlalchemy.ext.declarative import declarative_base from werkzeug.security import generate_password_hash, check_password_hash @@ -57,42 +57,116 @@ class Celula(Base): nome = Column(String(100), nullable=False) setor_id = Column(Integer, ForeignKey('setores.id')) cr_id = Column(Integer, ForeignKey('comites_regionais.id')) + secretario = Column(Integer, ForeignKey('militantes.id')) + responsavel_financas = Column(Integer, ForeignKey('militantes.id')) + quadro_orientador = Column(String(255)) + # Relacionamentos setor = relationship("Setor", back_populates="celulas") cr = relationship("ComiteRegional", back_populates="celulas") - militantes = relationship("Militante", back_populates="celula") + militantes = relationship("Militante", back_populates="celula", foreign_keys="[Militante.celula_id]") + secretario_rel = relationship("Militante", foreign_keys=[secretario]) + responsavel_financas_rel = relationship("Militante", foreign_keys=[responsavel_financas]) + pagamentos = relationship("PagamentoCelula", back_populates="celula") class ComiteRegional(Base): __tablename__ = 'comites_regionais' id = Column(Integer, primary_key=True, autoincrement=True) nome = Column(String(100), nullable=False) + responsavel_financas = Column(Integer, ForeignKey('militantes.id')) + responsavel_formacao = Column(Integer, ForeignKey('militantes.id')) + secretario_organizacao = Column(Integer, ForeignKey('militantes.id')) + correspondente_jornal = Column(Integer, ForeignKey('militantes.id')) + # Relacionamentos + responsavel_financas_rel = relationship("Militante", foreign_keys=[responsavel_financas]) + responsavel_formacao_rel = relationship("Militante", foreign_keys=[responsavel_formacao]) + secretario_organizacao_rel = relationship("Militante", foreign_keys=[secretario_organizacao]) + correspondente_jornal_rel = relationship("Militante", foreign_keys=[correspondente_jornal]) setores = relationship("Setor", back_populates="cr") celulas = relationship("Celula", back_populates="cr") +class EmailMilitante(Base): + __tablename__ = 'emails_militantes' + + id = Column(Integer, primary_key=True, autoincrement=True) + militante_id = Column(Integer, ForeignKey('militantes.id')) + endereco_email = Column(String(100)) + militante = relationship("Militante", back_populates="emails") + +class Endereco(Base): + __tablename__ = 'enderecos' + + id = Column(Integer, primary_key=True, autoincrement=True) + estado = Column(String(2)) + cidade = Column(String(50)) + bairro = Column(String(50)) + rua = Column(String(100)) + numero = Column(String(10)) + complemento = Column(String(50)) + cep = Column(String(9)) + militantes = relationship("Militante", back_populates="endereco") + +class RedeSocial(Base): + __tablename__ = 'redes_sociais' + + id = Column(Integer, primary_key=True, autoincrement=True) + militante_id = Column(Integer, ForeignKey('militantes.id')) + tipo = Column(String(20)) # Instagram, TikTok, Discord, etc. + identificador = Column(String(100)) + militante = relationship("Militante", back_populates="redes_sociais") + 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) - email = Column(String(100), unique=True) - telefone = Column(String(15)) - endereco = Column(String(255)) - filiado = Column(Boolean, default=False) + # 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')) + 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')) + # Campos existentes celula_id = Column(Integer, ForeignKey('celulas.id')) - responsabilidades = Column(Integer, default=0) # Armazenará as responsabilidades como bits + responsabilidades = Column(Integer, default=0) otp_secret = Column(String(32)) temp_token = Column(String(64)) temp_token_expiry = Column(DateTime) + # 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") + celula = relationship("Celula", back_populates="militantes", foreign_keys=[celula_id]) # Constantes para responsabilidades SECRETARIO = 1 @@ -186,19 +260,22 @@ class TipoPagamento(Base): id = Column(Integer, primary_key=True, autoincrement=True) descricao = Column(String(100), nullable=False) - pagamentos = relationship("Pagamento", back_populates="tipo_pagamento") - class Pagamento(Base): __tablename__ = 'pagamentos' id = Column(Integer, primary_key=True, autoincrement=True) militante_id = Column(Integer, ForeignKey('militantes.id')) - tipo_pagamento_id = Column(Integer, ForeignKey('tipos_pagamento.id')) + tipo_pagamento = Column(String(50)) # Cota, Jornal, Assinatura, etc. + mes_referencia = Column(Date) + numero_jornal = Column(String(20)) + numero_inicial_assinatura = Column(String(20)) + numero_final_assinatura = Column(String(20)) + campanha_financeira = Column(String(50)) valor = Column(Numeric(10, 2), nullable=False) data_pagamento = Column(Date, nullable=False) militante = relationship("Militante", back_populates="pagamentos") - tipo_pagamento = relationship("TipoPagamento", back_populates="pagamentos") + transacoes_pix = relationship("TransacaoPIX", back_populates="pagamento") class TipoMaterial(Base): __tablename__ = 'tipos_materiais' @@ -250,13 +327,20 @@ class AssinaturaAnual(Base): class Setor(Base): __tablename__ = 'setores' - id = Column(Integer, primary_key=True, autoincrement=True) + id = Column(Integer, primary_key=True) nome = Column(String(100), nullable=False) - - relatorios_cotas = relationship("RelatorioCotasMensais", back_populates="setor") - relatorios_vendas = relationship("RelatorioVendasMateriais", back_populates="setor") + cr_id = Column(Integer, ForeignKey('comites_regionais.id')) + responsavel = Column(Integer, ForeignKey('militantes.id')) + responsavel_financas = Column(Integer, ForeignKey('militantes.id')) + + # Relacionamentos + cr = relationship("ComiteRegional", back_populates="setores") + responsavel_rel = relationship("Militante", foreign_keys=[responsavel]) + responsavel_financas_rel = relationship("Militante", foreign_keys=[responsavel_financas]) usuarios = relationship("Usuario", back_populates="setor") celulas = relationship("Celula", back_populates="setor") + relatorios_cotas = relationship("RelatorioCotasMensais", back_populates="setor") + relatorios_vendas = relationship("RelatorioVendasMateriais", back_populates="setor") class ComiteCentral(Base): __tablename__ = 'comites_centrais' @@ -306,9 +390,13 @@ class Usuario(Base): ultimo_login = Column(DateTime) ultimo_logout = Column(DateTime) motivo_logout = Column(String(100)) + cr_id = Column(Integer, ForeignKey('comites_regionais.id')) + celula_id = Column(Integer, ForeignKey('celulas.id')) role = relationship("Role", back_populates="usuarios") setor = relationship("Setor", back_populates="usuarios") + celula = relationship("Celula") + cr = relationship("ComiteRegional") def __init__(self, username, password, is_admin=False): self.username = username @@ -373,6 +461,78 @@ class RolePermissao(Base): role = relationship("Role", back_populates="permissoes") permissao = relationship("Permissao", back_populates="roles") +class PagamentoCelula(Base): + __tablename__ = 'pagamentos_celula' + + id = Column(Integer, primary_key=True, autoincrement=True) + celula_id = Column(Integer, ForeignKey('celulas.id')) + data = Column(Date) + valor = Column(Numeric(10, 2)) + metodo_pagamento = Column(String(20)) # PIX, Dinheiro, etc. + codigo_pix = Column(String(100)) + descricao = Column(String(255)) + registrado_por = Column(Integer, ForeignKey('militantes.id')) + + celula = relationship("Celula", back_populates="pagamentos") + registrado_por_rel = relationship("Militante", foreign_keys=[registrado_por]) + +class Atividade(Base): + __tablename__ = 'atividades' + + id = Column(Integer, primary_key=True, autoincrement=True) + descricao = Column(String(255)) + data = Column(Date) + responsavel1 = Column(Integer, ForeignKey('militantes.id')) + responsavel2 = Column(Integer, ForeignKey('militantes.id')) + + responsavel1_rel = relationship("Militante", foreign_keys=[responsavel1]) + responsavel2_rel = relationship("Militante", foreign_keys=[responsavel2]) + materiais = relationship("MaterialAtividade", back_populates="atividade") + +class MaterialAtividade(Base): + __tablename__ = 'materiais_atividades' + + id = Column(Integer, primary_key=True, autoincrement=True) + atividade_id = Column(Integer, ForeignKey('atividades.id')) + tipo = Column(String(20)) # Jornal, Revista, etc. + quantidade = Column(Integer) + detalhes = Column(String(255)) + + atividade = relationship("Atividade", back_populates="materiais") + +class Relatorio(Base): + __tablename__ = 'relatorios' + + id = Column(Integer, primary_key=True, autoincrement=True) + tipo = Column(String(50)) # Semanal, Quinzenal, Mensal + periodo_inicio = Column(Date) + periodo_fim = Column(Date) + gerado_por = Column(Integer, ForeignKey('militantes.id')) + conteudo = Column(Text) + # Relacionamento hierárquico + celula_id = Column(Integer, ForeignKey('celulas.id')) + setor_id = Column(Integer, ForeignKey('setores.id')) + cr_id = Column(Integer, ForeignKey('comites_regionais.id')) + + gerado_por_rel = relationship("Militante", foreign_keys=[gerado_por]) + celula = relationship("Celula", foreign_keys=[celula_id]) + setor = relationship("Setor", foreign_keys=[setor_id]) + cr = relationship("ComiteRegional", foreign_keys=[cr_id]) + +class TransacaoPIX(Base): + __tablename__ = 'transacoes_pix' + + id = Column(Integer, primary_key=True, autoincrement=True) + chave_pix = Column(String(100)) + valor = Column(Numeric(10, 2)) + data_geracao = Column(DateTime) + data_pagamento = Column(DateTime) + status = Column(String(20)) # Pendente, Pago, Expirado + qr_code = Column(Text) + pagamento_id = Column(Integer, ForeignKey('pagamentos.id')) + + pagamento = relationship("Pagamento", back_populates="transacoes_pix") + # Remover o banco de dados existente (se existir) if os.path.exists(db_path): os.remove(db_path) diff --git a/templates/base.html b/templates/base.html index 35dc81a..9cbafde 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,26 +1,75 @@ - + - {% block title %}{% endblock %} - Sistema de Gestão - {{ bootstrap.load_css() }} + {% block title %}{% endblock %} - Sistema de Controle OCI + + + - {% if 'user_id' in session %} -