diff --git a/app.py b/app.py index c38880f..319ada0 100644 --- a/app.py +++ b/app.py @@ -26,7 +26,6 @@ from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker, joinedload from datetime import datetime, timedelta 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 @@ -91,9 +90,6 @@ def generate_qr_code(user): return qr_code -# Registrar blueprints -app.register_blueprint(cota_bp) - # Configuração da sessão do SQLAlchemy db_session = get_db_connection() @@ -182,24 +178,19 @@ def index(): def login(): """Rota de login""" if request.method == "POST": - username = request.form.get("username") + email = request.form.get("email") password = request.form.get("password") - otp_code = request.form.get("otp_code") - if not all([username, password, otp_code]): + if not all([email, password]): flash("Todos os campos são obrigatórios.", "error") return redirect(url_for("login")) db = get_db_connection() try: - user = db.query(Usuario).filter_by(username=username).first() + user = db.query(Usuario).filter_by(email=email).first() if not user or not user.check_password(password): - flash("Usuário ou senha incorretos.", "error") - return redirect(url_for("login")) - - if not user.verify_otp(otp_code): - flash("Código OTP inválido.", "error") + flash("Email ou senha incorretos.", "error") return redirect(url_for("login")) # Atualizar último login @@ -244,76 +235,23 @@ def home(): nome_usuario = usuario.username if usuario else "Usuário" # Formatar data atual em português - meses = { - 1: 'Janeiro', 2: 'Fevereiro', 3: 'Março', 4: 'Abril', - 5: 'Maio', 6: 'Junho', 7: 'Julho', 8: 'Agosto', - 9: 'Setembro', 10: 'Outubro', 11: 'Novembro', 12: 'Dezembro' - } - data_atual = datetime.now() - data_formatada = f"{data_atual.day} de {meses[data_atual.month]} de {data_atual.year}" + data_atual = datetime.now().strftime("%d de %B de %Y") - # Buscar totais - total_militantes = db.query(Militante).count() - total_cotas = db.query(func.sum(CotaMensal.valor_novo)).scalar() or 0 - total_materiais = db.query(MaterialVendido).count() - total_assinaturas = db.query(AssinaturaAnual).filter( - AssinaturaAnual.data_fim >= datetime.now() - ).count() + # Buscar dados para o dashboard + total_militantes = db.query(func.count(Militante.id)).scalar() + total_cotas = db.query(func.sum(CotaMensal.valor)).scalar() or 0 + total_materiais = db.query(func.sum(MaterialVendido.valor)).scalar() or 0 + total_assinaturas = db.query(func.sum(AssinaturaAnual.valor)).scalar() or 0 - # Buscar últimos militantes cadastrados com tratamento de erro - try: - ultimos_militantes = db.query(Militante)\ - .order_by(Militante.id.desc())\ - .limit(5)\ - .all() - except Exception as e: - print(f"Erro ao buscar últimos militantes: {e}") - ultimos_militantes = [] - - # Buscar últimos pagamentos com tratamento de erro - try: - ultimos_pagamentos = db.query(Pagamento)\ - .join(Militante)\ - .order_by(Pagamento.data_pagamento.desc())\ - .limit(5)\ - .all() - except Exception as e: - print(f"Erro ao buscar últimos pagamentos: {e}") - ultimos_pagamentos = [] - - return render_template('home.html', - nome_usuario=nome_usuario, - data_atual=data_formatada, - total_militantes=total_militantes, - total_cotas="{:.2f}".format(total_cotas), - total_materiais=total_materiais, - total_assinaturas=total_assinaturas, - ultimos_militantes=ultimos_militantes, - ultimos_pagamentos=ultimos_pagamentos) - 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', 'danger') - - # Mesmo com erro, tentar formatar a data e buscar o nome do usuário - try: - data_atual = datetime.now() - data_formatada = f"{data_atual.day} de {meses[data_atual.month]} de {data_atual.year}" - nome_usuario = db.query(Usuario).get(session.get('user_id')).username - except: - data_formatada = datetime.now().strftime("%d/%m/%Y") - nome_usuario = "Usuário" - - return render_template('home.html', - nome_usuario=nome_usuario, - data_atual=data_formatada, - total_militantes=db.query(Militante).count(), - total_cotas="0.00", - total_materiais=0, - total_assinaturas=0, - ultimos_militantes=[], - ultimos_pagamentos=[]) + return render_template( + "home.html", + nome_usuario=nome_usuario, + data_atual=data_atual, + total_militantes=total_militantes, + total_cotas=total_cotas, + total_materiais=total_materiais, + total_assinaturas=total_assinaturas + ) finally: db.close() @@ -459,11 +397,25 @@ def nova_cota(): ) db.add(cotas_mensais) db.commit() + + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return jsonify({ + 'status': 'success', + 'message': 'Cota cadastrada com sucesso!' + }) + flash('Cota cadastrada com sucesso!', 'success') return redirect(url_for('listar_cotas')) except Exception as e: db.rollback() print(f"Erro ao cadastrar cota: {e}") + + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return jsonify({ + 'status': 'error', + 'message': 'Erro ao cadastrar cota. Verifique os dados e tente novamente.' + }), 400 + flash('Erro ao cadastrar cota', 'danger') return render_template("nova_cota.html") finally: @@ -502,45 +454,68 @@ def listar_cotas(): cota.status = "pendente" print(f"Cota {cota.id}: Militante={cota.militante.nome}, Valor={cota.valor_novo}, Status={cota.status}") - return render_template("listar_cotas.html", cotas=cotas) + # Buscar militantes para o modal de nova cota + militantes = db.query(Militante).order_by(Militante.nome).all() + + return render_template("listar_cotas.html", cotas=cotas, militantes=militantes) except Exception as e: print(f"Erro ao listar cotas: {e}") flash('Erro ao listar cotas', 'danger') - return render_template("listar_cotas.html", cotas=[]) + return render_template("listar_cotas.html", cotas=[], militantes=[]) finally: db.close() # Rota para editar cota -@app.route("/cotas/editar/", methods=["GET", "POST"]) +@app.route('/cotas/editar/', methods=['GET', 'POST']) @login_required @session_timeout def editar_cota(id): db = get_db_connection() try: - cota = db.query(CotaMensal).filter_by(id=id).first() - if not cota: - flash('Cota não encontrada', 'danger') - return redirect(url_for('listar_cotas')) + cota = db.query(CotaMensal).get_or_404(id) - if request.method == "POST": - valor_novo = float(request.form.get("valor_novo")) - data_vencimento = datetime.strptime(request.form.get("data_vencimento"), "%Y-%m-%d").date() - pago = request.form.get("pago") == "true" - - cota.valor_novo = valor_novo - cota.data_vencimento = data_vencimento - cota.pago = pago - cota.data_alteracao = datetime.now().date() - - db.commit() - flash('Cota atualizada com sucesso!', 'success') - return redirect(url_for('listar_cotas')) + if request.method == 'POST': + try: + cota.militante_id = int(request.form['militante_id']) + cota.valor_antigo = float(request.form['valor_antigo']) + cota.valor_novo = float(request.form['valor_novo']) + cota.data_alteracao = datetime.strptime(request.form['data_alteracao'], '%Y-%m-%d').date() + cota.data_vencimento = datetime.strptime(request.form['data_vencimento'], '%Y-%m-%d').date() + + db.commit() + + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return jsonify({ + 'status': 'success', + 'message': 'Cota atualizada com sucesso!' + }) + + flash('Cota atualizada com sucesso!', 'success') + return redirect(url_for('listar_cotas')) + + except Exception as e: + db.rollback() + print(f"Erro ao atualizar cota: {e}") + + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return jsonify({ + 'status': 'error', + 'message': 'Erro ao atualizar cota. Verifique os dados e tente novamente.' + }), 400 + + flash('Erro ao atualizar cota. Verifique os dados e tente novamente.', 'danger') + return redirect(url_for('editar_cota', id=id)) + + return render_template('editar_cota.html', cota=cota) - return render_template("editar_cota.html", cota=cota) except Exception as e: - db.rollback() - print(f"Erro ao editar cota: {e}") - flash('Erro ao editar cota', 'danger') + print(f"Erro ao carregar cota: {e}") + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return jsonify({ + 'status': 'error', + 'message': 'Erro ao carregar cota.' + }), 404 + flash('Erro ao carregar cota', 'danger') return redirect(url_for('listar_cotas')) finally: db.close() @@ -605,39 +580,44 @@ def listar_pagamentos(): @require_login @require_permission(Permission.VIEW_CELL_REPORTS) def novo_material(): - if request.method == "POST": - militante_id = request.form.get("militante_id") - tipo_material_id = request.form.get("tipo_material_id") - descricao = request.form.get("descricao") - valor = float(request.form.get("valor")) - data_venda = datetime.strptime(request.form.get("data_venda"), "%Y-%m-%d").date() - - db = get_db_connection() - try: - materiais_vendidos = MaterialVendido( - militante_id=militante_id, - tipo_material_id=tipo_material_id, - descricao=descricao, - valor=valor, - data_venda=data_venda - ) - db.add(materiais_vendidos) - db.commit() - flash('Material vendido cadastrado com sucesso!', 'success') - return redirect(url_for('listar_materiais')) - except Exception as e: - db.rollback() - print(f"Erro ao cadastrar material vendido: {e}") - flash('Erro ao cadastrar material vendido', 'danger') - return render_template("novo_material.html") - finally: - db.close() - db = get_db_connection() try: - militantes = db.query(Militante).order_by(Militante.nome).all() - tipos_material = db.query(TipoMaterial).order_by(TipoMaterial.descricao).all() - return render_template("novo_material.html", militantes=militantes, tipos_material=tipos_material) + militante_id = request.form.get('militante_id') + tipo_material_id = request.form.get('tipo_material_id') + descricao = request.form.get('descricao') + valor = float(request.form.get('valor')) + data_venda = datetime.strptime(request.form.get('data_venda'), '%Y-%m-%d') + + material = MaterialVendido( + militante_id=militante_id, + tipo_material_id=tipo_material_id, + descricao=descricao, + valor=valor, + data_venda=data_venda + ) + + db.add(material) + db.commit() + + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return jsonify({ + 'status': 'success', + 'message': 'Material cadastrado com sucesso!' + }) + + flash('Material cadastrado com sucesso!', 'success') + return redirect(url_for('listar_materiais')) + + except Exception as e: + db.rollback() + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return jsonify({ + 'status': 'error', + 'message': 'Erro ao cadastrar material. Por favor, tente novamente.' + }), 400 + + flash('Erro ao cadastrar material. Por favor, tente novamente.', 'error') + return redirect(url_for('listar_materiais')) finally: db.close() @@ -646,14 +626,15 @@ def novo_material(): @require_login @require_permission(Permission.VIEW_CELL_REPORTS) def listar_materiais(): + db = get_db_connection() try: - db = get_db_connection() - materiais = db.query(MaterialVendido).order_by(MaterialVendido.data_venda.desc()).all() - return render_template("listar_materiais.html", materiais=materiais) - except Exception as e: - print(f"Erro ao listar materiais: {e}") - flash('Erro ao listar materiais', 'danger') - return render_template("listar_materiais.html", materiais=[]) + materiais = db.query(MaterialVendido).join(Militante).join(TipoMaterial).all() + militantes = db.query(Militante).all() + tipos_material = db.query(TipoMaterial).all() + return render_template('listar_materiais.html', + materiais=materiais, + militantes=militantes, + tipos_material=tipos_material) finally: db.close() @@ -662,36 +643,42 @@ def listar_materiais(): @require_login @require_permission(Permission.VIEW_CELL_REPORTS) def nova_venda_jornal(): - if request.method == "POST": - militante_id = request.form.get("militante_id") - quantidade = int(request.form.get("quantidade")) - valor_total = float(request.form.get("valor_total")) - data_venda = datetime.strptime(request.form.get("data_venda"), "%Y-%m-%d").date() - - db = get_db_connection() - try: - vendas_jornais_avulsos = VendaJornalAvulso( - militante_id=militante_id, - quantidade=quantidade, - valor_total=valor_total, - data_venda=data_venda - ) - db.add(vendas_jornais_avulsos) - db.commit() - flash('Venda de jornal cadastrada com sucesso!', 'success') - return redirect(url_for('listar_vendas_jornal')) - except Exception as e: - db.rollback() - print(f"Erro ao cadastrar venda de jornal: {e}") - flash('Erro ao cadastrar venda de jornal', 'danger') - return render_template("nova_venda_jornal.html") - finally: - db.close() - db = get_db_connection() try: - militantes = db.query(Militante).order_by(Militante.nome).all() - return render_template("nova_venda_jornal.html", militantes=militantes) + militante_id = request.form.get('militante_id') + quantidade = int(request.form.get('quantidade')) + valor_total = float(request.form.get('valor_total')) + data_venda = datetime.strptime(request.form.get('data_venda'), '%Y-%m-%d') + + venda = VendaJornalAvulso( + militante_id=militante_id, + quantidade=quantidade, + valor_total=valor_total, + data_venda=data_venda + ) + + db.add(venda) + db.commit() + + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return jsonify({ + 'status': 'success', + 'message': 'Venda cadastrada com sucesso!' + }) + + flash('Venda cadastrada com sucesso!', 'success') + return redirect(url_for('listar_vendas_jornal')) + + except Exception as e: + db.rollback() + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return jsonify({ + 'status': 'error', + 'message': 'Erro ao cadastrar venda. Por favor, tente novamente.' + }), 400 + + flash('Erro ao cadastrar venda. Por favor, tente novamente.', 'error') + return redirect(url_for('listar_vendas_jornal')) finally: db.close() @@ -700,73 +687,13 @@ def nova_venda_jornal(): @require_login @require_permission(Permission.VIEW_CELL_REPORTS) def listar_vendas_jornal(): - try: - db = get_db_connection() - vendas = db.query(VendaJornalAvulso).order_by(VendaJornalAvulso.data_venda.desc()).all() - return render_template("listar_vendas_jornal.html", vendas=vendas) - except Exception as e: - print(f"Erro ao listar vendas de jornal: {e}") - flash('Erro ao listar vendas de jornal', 'danger') - return render_template("listar_vendas_jornal.html", vendas=[]) - finally: - db.close() - -# Rota para criar uma nova assinatura -@app.route("/assinaturas/novo", methods=["GET", "POST"]) -@require_login -@require_permission(Permission.VIEW_CELL_REPORTS) -def nova_assinatura(): - if request.method == "POST": - militante_id = request.form.get("militante_id") - tipo_material_id = request.form.get("tipo_material_id") - quantidade = int(request.form.get("quantidade")) - valor_total = float(request.form.get("valor_total")) - data_inicio = datetime.strptime(request.form.get("data_inicio"), "%Y-%m-%d").date() - data_fim = datetime.strptime(request.form.get("data_fim"), "%Y-%m-%d").date() - - db = get_db_connection() - try: - assinaturas_anuais = AssinaturaAnual( - militante_id=militante_id, - tipo_material_id=tipo_material_id, - quantidade=quantidade, - valor_total=valor_total, - data_inicio=data_inicio, - data_fim=data_fim - ) - db.add(assinaturas_anuais) - db.commit() - flash('Assinatura cadastrada com sucesso!', 'success') - return redirect(url_for('listar_assinaturas')) - except Exception as e: - db.rollback() - print(f"Erro ao cadastrar assinatura: {e}") - flash('Erro ao cadastrar assinatura', 'danger') - return render_template("nova_assinatura.html") - finally: - db.close() - db = get_db_connection() try: - militantes = db.query(Militante).order_by(Militante.nome).all() - tipos_material = db.query(TipoMaterial).order_by(TipoMaterial.descricao).all() - return render_template("nova_assinatura.html", militantes=militantes, tipos_material=tipos_material) - finally: - db.close() - -# Rota para listar assinaturas -@app.route("/assinaturas") -@require_login -@require_permission(Permission.VIEW_CELL_REPORTS) -def listar_assinaturas(): - try: - db = get_db_connection() - assinaturas = db.query(AssinaturaAnual).order_by(AssinaturaAnual.data_inicio.desc()).all() - return render_template("listar_assinaturas.html", assinaturas=assinaturas) - except Exception as e: - print(f"Erro ao listar assinaturas: {e}") - flash('Erro ao listar assinaturas', 'danger') - return render_template("listar_assinaturas.html", assinaturas=[]) + vendas = db.query(VendaJornalAvulso).join(Militante).all() + militantes = db.query(Militante).all() + return render_template('listar_vendas_jornal.html', + vendas=vendas, + militantes=militantes) finally: db.close() @@ -889,32 +816,80 @@ def editar_militante(id): try: militante = db.query(Militante).get(id) if not militante: + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return jsonify({'status': 'error', 'message': 'Militante não encontrado'}), 404 flash('Militante não encontrado', 'danger') return redirect(url_for('listar_militantes')) if request.method == "POST": - militante.nome = request.form.get("nome") - militante.cpf = request.form.get("cpf") - militante.email = request.form.get("email") - militante.telefone = request.form.get("telefone") - militante.endereco = request.form.get("endereco") - militante.filiado = request.form.get("filiado") == "on" + nome = request.form.get("nome") + cpf = request.form.get("cpf") + email = request.form.get("email") + telefone = request.form.get("telefone") + endereco = request.form.get("endereco") + filiado = request.form.get("filiado") == "on" - if not validar_cpf(militante.cpf): + # Validar CPF + if not validar_cpf(cpf): + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return jsonify({'status': 'error', 'message': 'CPF inválido'}), 400 flash('CPF inválido', 'danger') - return render_template("editar_militante.html", militante=militante) + return render_template('editar_militante.html', militante=militante) + + # Verificar se já existe outro militante com este CPF + militante_existente = db.query(Militante).filter( + Militante.cpf == cpf, + Militante.id != id + ).first() + if militante_existente: + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return jsonify({'status': 'error', 'message': 'CPF já cadastrado para outro militante'}), 400 + flash('CPF já cadastrado para outro militante', 'danger') + return render_template('editar_militante.html', militante=militante) try: + militante.nome = nome + militante.cpf = cpf + militante.email = email + militante.telefone = telefone + militante.endereco = endereco + militante.filiado = filiado db.commit() + + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return jsonify({ + 'status': 'success', + 'message': 'Militante atualizado com sucesso', + 'militante': { + 'id': militante.id, + 'nome': militante.nome, + 'cpf': militante.cpf, + 'email': militante.email, + 'telefone': militante.telefone, + 'endereco': militante.endereco, + 'filiado': militante.filiado + } + }) + flash('Militante atualizado com sucesso!', 'success') return redirect(url_for('listar_militantes')) + except Exception as e: db.rollback() print(f"Erro ao atualizar militante: {e}") + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return jsonify({'status': 'error', 'message': 'Erro ao atualizar militante'}), 500 flash('Erro ao atualizar militante', 'danger') - return render_template("editar_militante.html", militante=militante) + return render_template('editar_militante.html', militante=militante) - return render_template("editar_militante.html", militante=militante) + return render_template('editar_militante.html', militante=militante) + + except Exception as e: + print(f"Erro ao editar militante: {e}") + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return jsonify({'status': 'error', 'message': 'Erro ao carregar militante'}), 500 + flash('Erro ao carregar militante', 'danger') + return redirect(url_for('listar_militantes')) finally: db.close() @@ -1410,69 +1385,6 @@ def has_permission(value, permission): """Verifica se o valor contém a permissão especificada.""" return bool(value & permission) -def create_app(): - app = Flask(__name__) - # ... existing code ... - - # ... existing code ... - return app - -def init_system(): - """Inicializa o sistema com todos os usuários necessários""" - print("Inicializando sistema...") - - # Inicializar banco de dados - print("Inicializando banco de dados...") - init_database() - - # Criar admin - create_admin() - - # Criar usuários de teste - create_test_users() - - # Verificar configuração - db = get_db_connection() - try: - # Verificar admin - admin = db.query(Usuario).filter_by(username='admin').first() - if admin: - print("\nAdmin configurado:") - print(f"Username: admin") - print(f"Senha: admin123") - if os.path.exists('admin_qr.png'): - print("OTP: Usando configuração existente do arquivo admin_qr.png") - else: - print("OTP: Nova configuração gerada") - - # Verificar usuários de teste - test_users = ['aligner', 'tester', 'deployer'] - for username in test_users: - user = db.query(Usuario).filter_by(username=username).first() - if user: - print(f"\nUsuário {username} configurado:") - print(f"Username: {username}") - print(f"Senha: Test123!@#") - if user.otp_secret: - print("OTP: Configurado") - else: - print("OTP: Não configurado") - finally: - db.close() - - print("\nInstruções:") - print("1. Configure o OTP usando o QR code gerado") - print("2. Faça login com as credenciais fornecidas") - print("3. Altere a senha no primeiro login") - - print("\nCredenciais:") - print("Admin:") - print("Username: admin") - print("Senha: admin123") - print("\nUsuários de teste:") - print("Username: aligner, tester, deployer") - print("Senha: Test123!@#") - @app.route('/militante/desligar/', methods=['POST']) @login_required def desligar_militante(id): @@ -1566,6 +1478,69 @@ def session_timeout(): except Exception as e: print(f"Erro ao atualizar última atividade: {e}") +def create_app(): + app = Flask(__name__) + # ... existing code ... + + # ... existing code ... + return app + +def init_system(): + """Inicializa o sistema com todos os usuários necessários""" + print("Inicializando sistema...") + + # Inicializar banco de dados + print("Inicializando banco de dados...") + init_database() + + # Criar admin + create_admin() + + # Criar usuários de teste + create_test_users() + + # Verificar configuração + db = get_db_connection() + try: + # Verificar admin + admin = db.query(Usuario).filter_by(username='admin').first() + if admin: + print("\nAdmin configurado:") + print(f"Username: admin") + print(f"Senha: admin123") + if os.path.exists('admin_qr.png'): + print("OTP: Usando configuração existente do arquivo admin_qr.png") + else: + print("OTP: Nova configuração gerada") + + # Verificar usuários de teste + test_users = ['aligner', 'tester', 'deployer'] + for username in test_users: + user = db.query(Usuario).filter_by(username=username).first() + if user: + print(f"\nUsuário {username} configurado:") + print(f"Username: {username}") + print(f"Senha: Test123!@#") + if user.otp_secret: + print("OTP: Configurado") + else: + print("OTP: Não configurado") + finally: + db.close() + + print("\nInstruções:") + print("1. Configure o OTP usando o QR code gerado") + print("2. Faça login com as credenciais fornecidas") + print("3. Altere a senha no primeiro login") + + print("\nCredenciais:") + print("Admin:") + print("Username: admin") + print("Senha: admin123") + print("\nUsuários de teste:") + print("Username: aligner, tester, deployer") + print("Senha: Test123!@#") + if __name__ == '__main__': init_system() app.run(debug=True) diff --git a/functions/__pycache__/database.cpython-312.pyc b/functions/__pycache__/database.cpython-312.pyc index 72b5042..3a339b7 100644 Binary files a/functions/__pycache__/database.cpython-312.pyc and b/functions/__pycache__/database.cpython-312.pyc differ diff --git a/functions/database.py b/functions/database.py index 3ba2a1e..b08399e 100644 --- a/functions/database.py +++ b/functions/database.py @@ -39,10 +39,14 @@ def get_db_connection(): session.commit() raise Exception("Sessão expirada. Por favor, faça login novamente.") + # Testa a conexão usando text() + session.execute(text("SELECT 1")) return session except Exception as e: - session.close() - raise e + print(f"Erro ao conectar ao banco de dados: {str(e)}") + if session: + session.close() + raise def execute_query(query, params=None): """ diff --git a/requirements.txt b/requirements.txt index 21c5927..898da9c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,3 +14,4 @@ cryptography==42.0.2 bcrypt==4.1.2 Bootstrap-Flask==2.3.3 flask-bootstrap5==0.1.dev1 +PyJWT==2.8.0 diff --git a/routes/cota.py b/routes/cota.py deleted file mode 100644 index 478a6cb..0000000 --- a/routes/cota.py +++ /dev/null @@ -1,30 +0,0 @@ -from flask import Blueprint, request, jsonify -from models.integracao import calcular_cota - -cota_bp = Blueprint('cota', __name__) - -@cota_bp.route('/calculate_cota', methods=['POST']) -def calculate_cota(): - try: - data = request.get_json() - - # Extrair dados do request - salary = float(data.get('salary', 0)) - num_children = int(data.get('num_children', 0)) - pays_school = bool(data.get('pays_school', False)) - pays_rent = bool(data.get('pays_rent', False)) - num_parents = int(data.get('num_parents', 0)) - - # Calcular a cota (implemente sua lógica de cálculo aqui) - cota = calcular_cota( - salary=salary, - num_children=num_children, - pays_school=pays_school, - pays_rent=pays_rent, - num_parents=num_parents - ) - - return jsonify({'cota': cota}) - - except Exception as e: - return jsonify({'error': str(e)}), 400 \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index e1197aa..c4eed0a 100644 --- a/templates/base.html +++ b/templates/base.html @@ -4,161 +4,504 @@ {% block title %}{% endblock %} - Controles OCI - {{ bootstrap.load_css() }} - - - - - + + + + + + + {% block extra_css %}{% endblock %} - {% if current_user is defined and current_user.is_authenticated %} + - {% endif %} - + +
{% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} - {% if not (category == 'success' and message == 'Login realizado com sucesso!') %} - - {{ bootstrap.load_js() }} - - - {% block extra_js %}{% endblock %} - + + + {% block scripts %}{% endblock %} \ No newline at end of file diff --git a/templates/editar_pagamento.html b/templates/editar_pagamento.html new file mode 100644 index 0000000..9dfd363 --- /dev/null +++ b/templates/editar_pagamento.html @@ -0,0 +1,60 @@ +{% extends "base.html" %} + +{% block title %}Editar Pagamento{% endblock %} + +{% block content %} +
+
+
+
+
+
+ Editar Pagamento +
+
+
+
+
+
+ +
+ R$ + +
+
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+ + Cancelar + + +
+
+
+
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/templates/home.html b/templates/home.html index 893d7cc..b00e27f 100644 --- a/templates/home.html +++ b/templates/home.html @@ -13,159 +13,126 @@
- {% if current_user.has_permission('view_cell_data') %} - +
-
-
-
-
-
Total de Militantes
-

{{ total_militantes }}

-
-
- -
-
- - Ver detalhes - -
-
-
- {% endif %} - - {% if current_user.has_permission('view_cell_reports') %} - -
-
-
-
Total de Cotas
-
-
-

R$ {{ total_cotas }}

-
-
- -
-
- - Ver detalhes - +
+
Total de Militantes
+
{{ total_militantes }}
+ + Ver detalhes + +
+
-
-
-
-
-
-
Materiais Vendidos
-

{{ total_materiais }}

-
-
- -
-
- - Ver detalhes - +
+
Total de Cotas
+
R$ {{ total_cotas }}
+ + Ver detalhes + +
+
-
-
-
-
-
-
Assinaturas Ativas
-

{{ total_assinaturas }}

-
-
- -
-
- - Ver detalhes - +
+
Materiais Vendidos
+
{{ total_materiais }}
+ + Ver detalhes + +
+ +
+
+
+ +
+
+
Assinaturas Ativas
+
{{ total_assinaturas }}
+ + Ver detalhes + +
+
- {% endif %}
- {% if current_user.has_permission('view_cell_data') %}
-
- Últimos Militantes Cadastrados +
+ Últimos Militantes Cadastrados
-
+
{% if ultimos_militantes %}
{% for militante in ultimos_militantes %} - -
+ - {% else %} -

Nenhum militante cadastrado recentemente.

- {% endif %} -
-
-
- {% endif %} - - {% if current_user.has_permission('view_cell_reports') %} - -
-
-
-
- Últimos Pagamentos -
-
-
- {% if ultimos_pagamentos %} -
- {% for pagamento in ultimos_pagamentos %} -
-
-
{{ pagamento.militante.nome }}
- R$ {{ "%.2f"|format(pagamento.valor) }} -
- {{ pagamento.data_pagamento.strftime('%d/%m/%Y') }} +
{% endfor %}
{% else %} -

Nenhum pagamento registrado recentemente.

+

Nenhum militante cadastrado recentemente.

+ {% endif %} +
+
+
+ + +
+
+
+
+ Últimos Pagamentos +
+
+
+ {% if ultimos_pagamentos %} +
+ {% for pagamento in ultimos_pagamentos %} +
+
+
{{ pagamento.militante.nome }}
+ {{ pagamento.data_pagamento.strftime('%d/%m/%Y') }} +
+ R$ {{ "%.2f"|format(pagamento.valor) }} +
+ {% endfor %} +
+ {% else %} +

Nenhum pagamento registrado recentemente.

{% endif %}
- {% endif %}
- - - @@ -27,23 +27,10 @@
-
-
-
- - -
- -
+
+
@@ -52,30 +39,36 @@ Militante - Valor - Vencimento - Status + Valor Antigo + Valor Novo + Data de Alteração + Data de Vencimento Ações {% for cota in cotas %} - + {{ cota.militante.nome }} - R$ {{ "%.2f"|format(cota.valor_novo) }} + R$ {{ "%.2f"|format(cota.valor_antigo) }} + R$ {{ "%.2f"|format(cota.valor_novo) }} + {{ cota.data_alteracao.strftime('%d/%m/%Y') }} {{ cota.data_vencimento.strftime('%d/%m/%Y') }} - - - {{ cota.status.title() }} - - +
+
-
-
- Mostrando {{ cotas|length }} cotas + + - + + + +