diff --git a/app.py b/app.py index 4a6aabb..e97959a 100644 --- a/app.py +++ b/app.py @@ -1,5 +1,4 @@ -from flask import Flask, request, render_template, redirect, url_for -from functions.database import execute_query +from flask import Flask, request, render_template, redirect, url_for, flash from functions.database import ( Base, Militante, @@ -19,11 +18,14 @@ from sqlalchemy import create_engine, and_ 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 Session = sessionmaker(bind=engine) session = Session() app = Flask(__name__) +app.secret_key = 'sua_chave_secreta_aqui' bootstrap = Bootstrap5(app) @@ -40,17 +42,24 @@ def session_run(model): @app.route("/militantes/novo", methods=["GET", "POST"]) 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=request.form["cpf"], + cpf=cpf, email=request.form["email"], telefone=request.form["telefone"], endereco=request.form["endereco"], - filiado=request.form.get("filiado", False), + filiado=bool(request.form.get("filiado", False)) ) session_run(novo_militante) - # execute_query(query, (nome, cpf, email, telefone, endereco, filiado)) + flash('Militante cadastrado com sucesso!', 'success') return redirect(url_for("listar_militantes")) return render_template("novo_militante.html") @@ -147,7 +156,7 @@ def nova_venda_jornal(): data_venda=datetime.strptime(request.form["data_venda"], "%Y-%m-%d"), ) - session_run(VendaJornalAvulso) + session_run(vendas_jornais_avulsos) return redirect(url_for("listar_vendas_jornal")) return render_template("nova_venda_jornal.html") @@ -236,11 +245,14 @@ def listar_relatorios_vendas(): @app.route("/") def home(): + """Página inicial do sistema""" links = [] for rule in app.url_map.iter_rules(): if "GET" in rule.methods and has_no_empty_params(rule): url = url_for(rule.endpoint, **(rule.defaults or {})) - links.append((url, rule.endpoint)) + # Substituindo 'home' por 'início' no menu + endpoint_name = 'Início' if rule.endpoint == 'home' else rule.endpoint + links.append((url, endpoint_name)) return render_template('home.html', links=links) @@ -251,6 +263,48 @@ def has_no_empty_params(rule): return len(defaults) >= len(arguments) +@app.route("/militantes/editar/", methods=["GET", "POST"]) +def editar_militante(id): + militante = 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)) + + session.commit() + flash('Militante atualizado com sucesso!', 'success') + return redirect(url_for('listar_militantes')) + except Exception as e: + 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) + + +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) diff --git a/functions/database.py b/functions/database.py index 9011125..50bf650 100644 --- a/functions/database.py +++ b/functions/database.py @@ -1,39 +1,31 @@ -import mysql.connector -from mysql.connector import Error -# from config.db_config import db_config from sqlalchemy import create_engine, Column, Integer, String, Boolean, Numeric, Date, ForeignKey -from sqlalchemy.orm import relationship +from sqlalchemy.orm import relationship, sessionmaker from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() - engine = create_engine('sqlite:///database.db', echo=True) -Base = declarative_base() +SessionLocal = sessionmaker(bind=engine) -def get_db_connection(db_config): - try: - connection = mysql.connector.connect(**db_config) - return connection - except Error as e: - print(f"Error connecting to database: {e}") - return None +def get_db_connection(): + """ + Retorna uma nova sessão do banco de dados + """ + return SessionLocal() def execute_query(query, params=None): - connection = get_db_connection('') - if connection is None: - return None + """ + Executa uma query usando SQLAlchemy + """ + session = get_db_connection() try: - cursor = connection.cursor(dictionary=True) - cursor.execute(query, params) - connection.commit() - return cursor - except Error as e: - print(f"Error executing query: {e}") - return None + result = session.execute(query, params) + session.commit() + return result + except Exception as e: + session.rollback() + raise e finally: - if connection.is_connected(): - cursor.close() - connection.close() + session.close() class Militante(Base): __tablename__ = 'militantes' diff --git a/functions/validations.py b/functions/validations.py new file mode 100644 index 0000000..acd74ca --- /dev/null +++ b/functions/validations.py @@ -0,0 +1,34 @@ +def validar_cpf(cpf): + """ + Valida um CPF seguindo as regras do governo brasileiro. + Retorna True se o CPF é válido, False caso contrário. + """ + # Remove caracteres não numéricos + cpf = ''.join(filter(str.isdigit, cpf)) + + # Verifica se tem 11 dígitos + if len(cpf) != 11: + return False + + # Verifica se todos os dígitos são iguais + if len(set(cpf)) == 1: + return False + + # Calcula primeiro dígito verificador + soma = 0 + for i in range(9): + soma += int(cpf[i]) * (10 - i) + resto = soma % 11 + digito1 = 0 if resto < 2 else 11 - resto + + if int(cpf[9]) != digito1: + return False + + # Calcula segundo dígito verificador + soma = 0 + for i in range(10): + soma += int(cpf[i]) * (11 - i) + resto = soma % 11 + digito2 = 0 if resto < 2 else 11 - resto + + return int(cpf[10]) == digito2 \ No newline at end of file diff --git a/models/integracao.py b/models/integracao.py new file mode 100644 index 0000000..523ec8f --- /dev/null +++ b/models/integracao.py @@ -0,0 +1,24 @@ +def calcular_cota(salary, num_children, pays_school, pays_rent, num_parents): + """ + Calcula o valor da cota baseado nos parâmetros fornecidos + """ + # Base da cota é 1% do salário + cota_base = salary * 0.01 + + # Adiciona 0.5% por filho + cota_filhos = (salary * 0.005) * num_children + + # Adiciona 0.3% por pai/mãe dependente + cota_pais = (salary * 0.003) * num_parents + + # Reduz 0.2% se paga escola + reducao_escola = (salary * 0.002) if pays_school else 0 + + # Reduz 0.2% se paga aluguel + reducao_aluguel = (salary * 0.002) if pays_rent else 0 + + # Calcula cota final + cota_final = cota_base + cota_filhos + cota_pais - reducao_escola - reducao_aluguel + + # Garante que a cota não seja menor que 0.5% do salário + return max(cota_final, salary * 0.005) \ No newline at end of file diff --git a/routes/cota.py b/routes/cota.py new file mode 100644 index 0000000..478a6cb --- /dev/null +++ b/routes/cota.py @@ -0,0 +1,30 @@ +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 f46b591..d2f91cc 100644 --- a/templates/base.html +++ b/templates/base.html @@ -38,4 +38,4 @@ {{ bootstrap.load_js() }} - \ No newline at end of file + \ No newline at end of file diff --git a/templates/editar_militante.html b/templates/editar_militante.html new file mode 100644 index 0000000..d12776a --- /dev/null +++ b/templates/editar_militante.html @@ -0,0 +1,34 @@ +{% extends 'base.html' %} + +{% block title %}Editar Militante{% endblock %} + +{% block content %} +

Editar Militante

+ + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} +
{{ message }}
+ {% endfor %} + {% endif %} + {% endwith %} + +
+ Nome:
+ CPF:
+ Email:
+ Telefone:
+ Endereço:
+ Filiado:
+ + Cancelar +
+{% endblock %} \ No newline at end of file diff --git a/templates/listar_militantes.html b/templates/listar_militantes.html index 385168f..1a71ca3 100644 --- a/templates/listar_militantes.html +++ b/templates/listar_militantes.html @@ -8,7 +8,7 @@

Lista de Militantes

Novo Militante - +
@@ -21,7 +21,7 @@ {% for militante in militantes %} - + @@ -34,4 +34,24 @@
Nome
{{ militante.nome }} {{ militante.cpf }} {{ militante.email }}
+ + + + {% endblock %} \ No newline at end of file diff --git a/templates/nova_assinatura.html b/templates/nova_assinatura.html index 9bb99fe..c83813a 100644 --- a/templates/nova_assinatura.html +++ b/templates/nova_assinatura.html @@ -29,9 +29,11 @@ - +
+ + Voltar + Início +
- Voltar para Lista - Home {% endblock %} diff --git a/templates/nova_cota.html b/templates/nova_cota.html index 0fa224f..1de22b4 100644 --- a/templates/nova_cota.html +++ b/templates/nova_cota.html @@ -21,9 +21,11 @@ - +
+ + Voltar + Início +
- Voltar para Lista - Home {% endblock %} diff --git a/templates/nova_venda_jornal.html b/templates/nova_venda_jornal.html index c72070c..05b296f 100644 --- a/templates/nova_venda_jornal.html +++ b/templates/nova_venda_jornal.html @@ -21,9 +21,11 @@ - +
+ + Voltar + Início +
- Voltar para Lista - Home {% endblock %} diff --git a/templates/novo_material.html b/templates/novo_material.html index b58b188..d48b738 100644 --- a/templates/novo_material.html +++ b/templates/novo_material.html @@ -25,9 +25,11 @@ - +
+ + Voltar + Início +
- Voltar para Lista - Home {% endblock %} diff --git a/templates/novo_militante.html b/templates/novo_militante.html index 14495b2..a9d5919 100644 --- a/templates/novo_militante.html +++ b/templates/novo_militante.html @@ -1,19 +1,68 @@ {% extends 'base.html' %} -{% block title %}Listar Militantes{% endblock %} +{% block title %}Novo Militante{% endblock %} {% block content %} -

Criar Novo Militante

-
- Nome:
- CPF:
- Email:
- Telefone:
- Endereço:
- Filiado:
- -
- Home - +
+
+
+

Criar Novo Militante

+ + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} +
{{ message }}
+ {% endfor %} + {% endif %} + {% endwith %} + +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + Voltar + Início +
+
+
+
+
{% endblock %} diff --git a/templates/novo_pagamento.html b/templates/novo_pagamento.html index 27bd77a..cf76169 100644 --- a/templates/novo_pagamento.html +++ b/templates/novo_pagamento.html @@ -1,29 +1,41 @@ {% extends 'base.html' %} -{% block title %}Listar Militantes{% endblock %} +{% block title %}Novo Pagamento{% endblock %} {% block content %} -

Registrar Novo Pagamento

-
-
- - +
+
+
+

Registrar Novo Pagamento

+ + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + Voltar + Início +
+
-
- - -
-
- - -
-
- - -
- - - Voltar para Lista - Home - +
+
{% endblock %}