Files
controles/app.py
2025-03-24 14:50:42 -03:00

505 lines
18 KiB
Python

from flask import Flask, request, render_template, redirect, url_for, flash, session
from functions.database import (
Base,
Militante,
CotaMensal,
TipoPagamento,
Pagamento,
MaterialVendido,
TipoMaterial,
VendaJornalAvulso,
engine,
AssinaturaAnual,
RelatorioCotasMensais,
RelatorioVendasMateriais,
Usuario,
get_db_connection,
)
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from datetime import datetime
from flask_bootstrap import Bootstrap5
from routes.cota import cota_bp
from functions.validations import validar_cpf
from functools import wraps
from pathlib import Path
app = Flask(__name__)
app.secret_key = 'sua_chave_secreta_aqui' # Necessário para sessões do Flask
bootstrap = Bootstrap5(app)
# Configuração da sessão do SQLAlchemy
db_session = get_db_connection()
# Decorator para verificar se o usuário está logado
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if 'user_id' not in session:
flash('Por favor, faça login para acessar esta página.', 'warning')
return redirect(url_for('login'))
return f(*args, **kwargs)
return decorated_function
# Rota raiz - redireciona para login se não estiver autenticado
@app.route("/")
def index():
if 'user_id' not in session:
return redirect(url_for('login'))
return redirect(url_for('home'))
# Rota de login
@app.route("/login", methods=["GET", "POST"])
def login():
if 'user_id' in session:
return redirect(url_for('home'))
if request.method == "POST":
username = request.form.get("username")
password = request.form.get("password")
otp = request.form.get("otp")
# Log dos dados recebidos (sem a senha)
print(f"Tentativa de login - Username: {username}, OTP fornecido: {'Sim' if otp else 'Não'}")
user = db_session.query(Usuario).filter_by(username=username).first()
if not user:
print(f"Erro: Usuário '{username}' não encontrado")
flash('Usuário não encontrado', 'danger')
return render_template('login.html')
if not user.check_password(password):
print(f"Erro: Senha incorreta para o usuário '{username}'")
flash('Senha incorreta', 'danger')
return render_template('login.html')
if not user.verify_otp(otp):
print(f"Erro: Código OTP inválido para o usuário '{username}'")
print(f"OTP fornecido: {otp}")
print(f"OTP secret do usuário: {user.otp_secret}")
flash('Código OTP inválido', 'danger')
return render_template('login.html')
# Se chegou aqui, login bem sucedido
print(f"Login bem sucedido para o usuário '{username}'")
session['user_id'] = user.id
session['is_admin'] = user.is_admin
next_page = request.args.get('next')
flash('Login realizado com sucesso!', 'success')
return redirect(next_page or url_for('home'))
return render_template('login.html')
# Rota de logout
@app.route("/logout")
def logout():
session.clear() # Limpa a sessão do Flask
flash('Você foi desconectado com sucesso.', 'info')
return redirect(url_for('login'))
# Rota home (protegida)
@app.route("/home")
@login_required
def home():
"""Página inicial do sistema"""
try:
links = []
# Filtrar apenas as rotas que queremos mostrar
allowed_endpoints = {
'listar_militantes': 'Militantes',
'listar_cotas': 'Cotas',
'listar_pagamentos': 'Pagamentos',
'listar_materiais': 'Materiais',
'listar_vendas_jornal': 'Vendas de Jornal',
'listar_assinaturas': 'Assinaturas'
}
for rule in app.url_map.iter_rules():
if (rule.endpoint in allowed_endpoints and
"GET" in rule.methods and
len(rule.arguments) == 0): # Apenas rotas sem parâmetros
url = url_for(rule.endpoint)
nome = allowed_endpoints[rule.endpoint]
links.append((url, nome))
# Ordenar links pelo nome
links.sort(key=lambda x: x[1])
return render_template('home.html', links=links)
except Exception as e:
print(f"Erro na página inicial: {e}")
import traceback
traceback.print_exc()
flash('Erro ao carregar a página inicial', 'error')
return render_template('home.html', links=[])
# Rota para criar um novo militante
@app.route("/militantes/novo", methods=["GET", "POST"])
@login_required
def novo_militante():
if request.method == "POST":
cpf = request.form["cpf"]
if not validar_cpf(cpf):
flash('CPF inválido. Por favor, verifique o número informado.', 'error')
return render_template("novo_militante.html",
dados_anteriores=request.form)
novo_militante = Militante(
nome=request.form["nome"],
cpf=cpf,
email=request.form["email"],
telefone=request.form["telefone"],
endereco=request.form["endereco"],
filiado=bool(request.form.get("filiado", False))
)
db_session.add(novo_militante)
try:
db_session.commit()
flash('Militante cadastrado com sucesso!', 'success')
return redirect(url_for("listar_militantes"))
except Exception as e:
print(e)
db_session.rollback()
flash('Erro ao cadastrar militante. Verifique se o CPF ou email já não estão cadastrados.', 'error')
return render_template("novo_militante.html",
dados_anteriores=request.form)
return render_template("novo_militante.html")
# Rota para listar militantes
@app.route("/militantes")
@login_required
def listar_militantes():
militantes = db_session.query(Militante).all()
return render_template("listar_militantes.html", militantes=militantes)
# Rota para criar uma nova cota mensal
@app.route("/cotas/novo", methods=["GET", "POST"])
@login_required
def nova_cota():
if request.method == "POST":
cotas_mensais = CotaMensal(
militante_id=request.form["militante_id"],
valor_antigo=request.form["valor_antigo"],
valor_novo=request.form["valor_novo"],
data_alteracao=datetime.strptime(request.form["data_alteracao"], "%Y-%m-%d")
)
db_session.add(cotas_mensais)
try:
db_session.commit()
return redirect(url_for("listar_cotas"))
except Exception as e:
print(e)
db_session.rollback()
flash('Erro ao cadastrar cota mensal. Verifique se os dados fornecidos são válidos.', 'error')
return render_template("nova_cota.html")
return render_template("nova_cota.html")
# Rota para listar cotas mensais
@app.route("/cotas")
@login_required
def listar_cotas():
cotas = db_session.query(CotaMensal).all()
return render_template("listar_cotas.html", cotas=cotas)
# Rota para criar um novo pagamento
@app.route("/pagamentos/novo", methods=["GET", "POST"])
@login_required
def novo_pagamento():
if request.method == "POST":
pagamentos = Pagamento(
militante_id=request.form["militante_id"],
tipo_pagamento_id=request.form["tipo_pagamento_id"],
valor=request.form["valor"],
data_pagamento=datetime.strptime(request.form["data_pagamento"], "%Y-%m-%d")
)
db_session.add(pagamentos)
try:
db_session.commit()
return redirect(url_for("listar_pagamentos"))
except Exception as e:
print(e)
db_session.rollback()
flash('Erro ao cadastrar pagamento. Verifique se os dados fornecidos são válidos.', 'error')
return render_template("novo_pagamento.html")
return render_template("novo_pagamento.html")
# Rota para listar pagamentos
@app.route("/pagamentos")
@login_required
def listar_pagamentos():
pagamentos = db_session.query(Pagamento).all()
return render_template("listar_pagamentos.html", pagamentos=pagamentos)
# Rota para criar um novo material vendido
@app.route("/materiais/novo", methods=["GET", "POST"])
@login_required
def novo_material():
if request.method == "POST":
materiais_vendidos = MaterialVendido(
militante_id=request.form["militante_id"],
tipo_material_id=request.form["tipo_material_id"],
descricao=request.form["descricao"],
valor=request.form["valor"],
data_venda=datetime.strptime(request.form["data_venda"], "%Y-%m-%d"),
)
db_session.add(materiais_vendidos)
try:
db_session.commit()
return redirect(url_for("listar_materiais"))
except Exception as e:
print(e)
db_session.rollback()
flash('Erro ao cadastrar material vendido. Verifique se os dados fornecidos são válidos.', 'error')
return render_template("novo_material.html")
return render_template("novo_material.html")
# Rota para listar materiais vendidos
@app.route("/materiais")
@login_required
def listar_materiais():
materiais = db_session.query(MaterialVendido).all()
return render_template("listar_materiais.html", materiais=materiais)
# Rota para criar uma nova venda de jornais avulsos
@app.route("/jornais/novo", methods=["GET", "POST"])
@login_required
def nova_venda_jornal():
if request.method == "POST":
vendas_jornais_avulsos = VendaJornalAvulso(
militante_id=request.form["militante_id"],
quantidade=request.form["quantidade"],
valor_total=request.form["valor_total"],
data_venda=datetime.strptime(request.form["data_venda"], "%Y-%m-%d"),
)
db_session.add(vendas_jornais_avulsos)
try:
db_session.commit()
return redirect(url_for("listar_vendas_jornal"))
except Exception as e:
print(e)
db_session.rollback()
flash('Erro ao cadastrar venda de jornal avulso. Verifique se os dados fornecidos são válidos.', 'error')
return render_template("nova_venda_jornal.html")
return render_template("nova_venda_jornal.html")
# Rota para listar vendas de jornais avulsos
@app.route("/jornais")
@login_required
def listar_vendas_jornal():
vendas = db_session.query(VendaJornalAvulso).all()
return render_template("listar_vendas_jornal.html", vendas=vendas)
# Rota para criar uma nova assinatura anual
@app.route("/assinaturas/novo", methods=["GET", "POST"])
@login_required
def nova_assinatura():
if request.method == "POST":
assinaturas_anuais = AssinaturaAnual(
militante_id=request.form["militante_id"],
tipo_material_id=request.form["tipo_material_id"],
quantidade=request.form["quantidade"],
valor_total=request.form["valor_total"],
data_inicio=datetime.strptime(request.form["data_inicio"], "%Y-%m-%d"),
data_fim=datetime.strptime(request.form["data_fim"], "%Y-%m-%d")
)
db_session.add(assinaturas_anuais)
try:
db_session.commit()
return redirect(url_for("listar_assinaturas"))
except Exception as e:
print(e)
db_session.rollback()
flash('Erro ao cadastrar assinatura anual. Verifique se os dados fornecidos são válidos.', 'error')
return render_template("nova_assinatura.html")
return render_template("nova_assinatura.html")
# Rota para listar assinaturas anuais
@app.route("/assinaturas")
@login_required
def listar_assinaturas():
assinaturas = db_session.query(AssinaturaAnual).all()
return render_template("listar_assinaturas.html", assinaturas=assinaturas)
# Rota para criar um novo relatório de cotas mensais
@app.route("/relatorios/cotas/novo", methods=["GET", "POST"])
@login_required
def novo_relatorio_cotas():
if request.method == "POST":
relatorio_cotas_mensais = RelatorioCotasMensais(
setor_id=request.form["setor_id"],
comite_id=request.form["comite_id"],
total_cotas=request.form["total_cotas"],
data_relatorio=datetime.strptime(request.form["data_relatorio"], "%Y-%m-%d")
)
db_session.add(relatorio_cotas_mensais)
try:
db_session.commit()
return redirect(url_for("listar_relatorios_cotas"))
except Exception as e:
print(e)
db_session.rollback()
flash('Erro ao cadastrar relatório de cotas mensais. Verifique se os dados fornecidos são válidos.', 'error')
return render_template("novo_relatorio_cotas.html")
return render_template("novo_relatorio_cotas.html")
# Rota para listar relatórios de cotas mensais
@app.route("/relatorios/cotas")
@login_required
def listar_relatorios_cotas():
relatorios = db_session.query(RelatorioCotasMensais).all()
return render_template("listar_relatorios_cotas.html", relatorios=relatorios)
# Rota para criar um novo relatório de vendas de materiais
@app.route("/relatorios/vendas/novo", methods=["GET", "POST"])
@login_required
def novo_relatorio_vendas():
if request.method == "POST":
relatorio_vendas_materiais = RelatorioVendasMateriais(
setor_id=request.form["setor_id"],
comite_id=request.form["comite_id"],
total_vendas=request.form["total_vendas"],
data_relatorio=datetime.strptime(request.form["data_relatorio"], "%Y-%m-%d")
)
db_session.add(relatorio_vendas_materiais)
try:
db_session.commit()
return redirect(url_for("listar_relatorios_vendas"))
except Exception as e:
print(e)
db_session.rollback()
flash('Erro ao cadastrar relatório de vendas de materiais. Verifique se os dados fornecidos são válidos.', 'error')
return render_template("novo_relatorio_vendas.html")
return render_template("novo_relatorio_vendas.html")
# Rota para listar relatórios de vendas de materiais
@app.route("/relatorios/vendas")
@login_required
def listar_relatorios_vendas():
relatorios = db_session.query(RelatorioVendasMateriais).all()
return render_template("listar_relatorios_vendas.html", relatorios=relatorios)
@app.route("/militantes/editar/<int:id>", methods=["GET", "POST"])
@login_required
def editar_militante(id):
militante = db_session.query(Militante).get(id)
if not militante:
flash('Militante não encontrado.', 'error')
return redirect(url_for('listar_militantes'))
if request.method == "POST":
cpf = request.form["cpf"]
if cpf != militante.cpf and not validar_cpf(cpf): # Só valida se o CPF foi alterado
flash('CPF inválido. Por favor, verifique o número informado.', 'error')
return render_template("editar_militante.html", militante=militante)
try:
militante.nome = request.form["nome"]
militante.cpf = cpf
militante.email = request.form["email"]
militante.telefone = request.form["telefone"]
militante.endereco = request.form["endereco"]
militante.filiado = bool(request.form.get("filiado", False))
db_session.commit()
flash('Militante atualizado com sucesso!', 'success')
return redirect(url_for('listar_militantes'))
except Exception as e:
db_session.rollback()
flash('Erro ao atualizar militante. Verifique se o CPF ou email já não estão cadastrados.', 'error')
return render_template("editar_militante.html", militante=militante)
return render_template("editar_militante.html", militante=militante)
# Rota para criar novo usuário
@app.route("/usuarios/novo", methods=["GET", "POST"])
@login_required
def novo_usuario():
if not session.get('is_admin'):
flash('Acesso negado. Apenas administradores podem criar novos usuários.', 'danger')
return redirect(url_for('home'))
if request.method == "POST":
username = request.form.get("username")
email = request.form.get("email")
password = request.form.get("password")
confirm_password = request.form.get("confirm_password")
is_admin = bool(request.form.get("is_admin"))
# Validações
if password != confirm_password:
flash('As senhas não conferem.', 'danger')
return render_template('novo_usuario.html')
# Verificar se usuário já existe
if db_session.query(Usuario).filter_by(username=username).first():
flash('Nome de usuário já existe.', 'danger')
return render_template('novo_usuario.html')
if db_session.query(Usuario).filter_by(email=email).first():
flash('E-mail já cadastrado.', 'danger')
return render_template('novo_usuario.html')
# Criar novo usuário
try:
novo_usuario = Usuario(
username=username,
password=password,
is_admin=is_admin
)
novo_usuario.email = email
db_session.add(novo_usuario)
db_session.commit()
# Gerar QR code para configuração do OTP
qr_uri = novo_usuario.get_otp_uri()
flash('Usuário criado com sucesso!', 'success')
# Modificação alternativa para salvar no diretório atual
qr_path = Path('admin_qr.png')
img = qrcode.QRCode(version=1, box_size=10, border=5)
img.add_data(qr_uri)
img.make(fit=True)
img.save(str(qr_path))
return render_template('mostrar_qr_code.html', qr_uri=qr_uri)
except Exception as e:
db_session.rollback()
flash('Erro ao criar usuário. Por favor, tente novamente.', 'danger')
print(f"Erro: {e}")
return render_template('novo_usuario.html')
return render_template('novo_usuario.html')
def create_app():
app = Flask(__name__)
# ... existing code ...
app.register_blueprint(cota_bp)
# ... existing code ...
return app
# Iniciar o servidor Flask
if __name__ == "__main__":
app.run(debug=True)