diff --git a/app.py b/app.py index 83da760..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, @@ -18,11 +17,16 @@ from functions.database import ( 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) def session_run(model): @@ -38,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") @@ -145,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") @@ -234,21 +245,16 @@ def listar_relatorios_vendas(): @app.route("/") def home(): + """Página inicial do sistema""" links = [] for rule in app.url_map.iter_rules(): - # Filter out rules we can't navigate to in a browser - # and rules that require parameters if "GET" in rule.methods and has_no_empty_params(rule): url = url_for(rule.endpoint, **(rule.defaults or {})) - links.append((url, rule.endpoint)) - l_html = "" - for l in links: - l_html += f'{l[1].replace("_"," ")}
' - home_html = f""" -

Links

- {l_html} - """ - return home_html + # 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) def has_no_empty_params(rule): @@ -257,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/cota_calculator.py b/functions/cota_calculator.py new file mode 100644 index 0000000..3c8799a --- /dev/null +++ b/functions/cota_calculator.py @@ -0,0 +1,33 @@ +def calculate_cota(salary, num_children=0, pays_school=False, pays_rent=False, num_parents=0): + # Calculate discounts + discount = 0 + discount += 0.5 * num_children + discount += 1 if pays_school else 0 + discount += 1 if pays_rent else 0 + discount += 0.5 * num_parents + + # Determine base percentage based on salary + if salary < 1320.00: + base_percentage = 3 + elif salary < 1980.00: + base_percentage = 4 + elif salary < 2640.00: + base_percentage = 5 + elif salary < 3300.00: + base_percentage = 6 + elif salary < 3960.00: + base_percentage = 7 + elif salary < 5280.00: + base_percentage = 8 + elif salary < 6600.00: + base_percentage = 9 + else: + base_percentage = 10 + + # Calculate final percentage after applying discounts + final_percentage = base_percentage - discount + final_percentage = max(final_percentage, 0) # Ensure percentage is not negative + + # Calculate cota + cota = (final_percentage / 100) * salary + return cota \ No newline at end of file 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 new file mode 100644 index 0000000..d2f91cc --- /dev/null +++ b/templates/base.html @@ -0,0 +1,41 @@ + + + + + + {% block title %}{% endblock %} - Sistema de Gestão + {{ bootstrap.load_css() }} + + + + +
+ {% block content %}{% endblock %} +
+ + {{ bootstrap.load_js() }} + + \ 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/home.html b/templates/home.html new file mode 100644 index 0000000..31779b9 --- /dev/null +++ b/templates/home.html @@ -0,0 +1,18 @@ +{% extends 'base.html' %} + +{% block title %}Início{% endblock %} + +{% block content %} +
+
+

Menu do Sistema

+
+ {% for url, endpoint in links %} + + {{ endpoint|replace('_', ' ')|title }} + + {% endfor %} +
+
+
+{% endblock %} \ No newline at end of file diff --git a/templates/listar_assinaturas.html b/templates/listar_assinaturas.html index 64b2168..b2024d0 100644 --- a/templates/listar_assinaturas.html +++ b/templates/listar_assinaturas.html @@ -1,10 +1,8 @@ - - - - - Listar Assinaturas Anuais - - +{% extends 'base.html' %} + +{% block title %}Início{% endblock %} + +{% block content %}

Assinaturas Anuais

Adicionar Nova Assinatura @@ -34,5 +32,4 @@
Home - - +{% endblock %} \ No newline at end of file diff --git a/templates/listar_cotas.html b/templates/listar_cotas.html index 5dd5760..feddf64 100644 --- a/templates/listar_cotas.html +++ b/templates/listar_cotas.html @@ -1,10 +1,8 @@ - - - - - Listar Cotas Mensais - - +{% extends 'base.html' %} + +{% block title %}Listar Militantes{% endblock %} + +{% block content %}

Cotas Mensais

Adicionar Nova Cota @@ -30,5 +28,4 @@
Home - - +{% endblock %} diff --git a/templates/listar_materiais.html b/templates/listar_materiais.html index c392f3e..00ff160 100644 --- a/templates/listar_materiais.html +++ b/templates/listar_materiais.html @@ -1,10 +1,8 @@ - - - - - Listar Materiais - - +{% extends 'base.html' %} + +{% block title %}Listar Militantes{% endblock %} + +{% block content %}

Materiais Vendidos

Adicionar Novo Material @@ -32,5 +30,4 @@
Home - - +{% endblock %} diff --git a/templates/listar_militantes.html b/templates/listar_militantes.html index 77ac145..1a71ca3 100644 --- a/templates/listar_militantes.html +++ b/templates/listar_militantes.html @@ -1,17 +1,57 @@ - - - - - Lista de Militantes - - -

Militantes

- - Adicionar Novo Militante - Home - - \ No newline at end of file +{% extends 'base.html' %} + +{% block title %}Listar Militantes{% endblock %} + +{% block content %} +
+
+

Lista de Militantes

+ Novo Militante + + + + + + + + + + + + + + {% for militante in militantes %} + + + + + + + + + {% endfor %} + +
NomeCPFEmailTelefoneEndereçoFiliado
{{ militante.nome }}{{ militante.cpf }}{{ militante.email }}{{ militante.telefone }}{{ militante.endereco }}{{ 'Sim' if militante.filiado else 'Não' }}
+
+
+ + + + +{% endblock %} \ No newline at end of file diff --git a/templates/listar_pagamentos.html b/templates/listar_pagamentos.html index c5317bc..30dfe5a 100644 --- a/templates/listar_pagamentos.html +++ b/templates/listar_pagamentos.html @@ -1,10 +1,8 @@ - - - - - Listar Pagamentos - - +{% extends 'base.html' %} + +{% block title %}Listar Militantes{% endblock %} + +{% block content %}

Pagamentos

Adicionar Novo Pagamento @@ -30,5 +28,5 @@
Home - - +{% endblock %} + diff --git a/templates/listar_relatorios_cotas.html b/templates/listar_relatorios_cotas.html index 1fac21d..85c3558 100644 --- a/templates/listar_relatorios_cotas.html +++ b/templates/listar_relatorios_cotas.html @@ -1,10 +1,8 @@ - - - - - Listar Relatórios de Cotas - - +{% extends 'base.html' %} + +{% block title %}Listar Militantes{% endblock %} + +{% block content %}

Relatórios de Cotas Mensais

Adicionar Novo Relatório @@ -30,5 +28,5 @@
Home - - +{% endblock %} + diff --git a/templates/listar_relatorios_vendas.html b/templates/listar_relatorios_vendas.html index 63635fa..0694fca 100644 --- a/templates/listar_relatorios_vendas.html +++ b/templates/listar_relatorios_vendas.html @@ -1,10 +1,8 @@ - - - - - Listar Relatórios de Vendas - - +{% extends 'base.html' %} + +{% block title %}Listar Militantes{% endblock %} + +{% block content %}

Relatórios de Vendas de Materiais

Adicionar Novo Relatório @@ -30,5 +28,5 @@
Home - - + +{% endblock %} diff --git a/templates/listar_vendas_jornal.html b/templates/listar_vendas_jornal.html index d54304f..1916aa9 100644 --- a/templates/listar_vendas_jornal.html +++ b/templates/listar_vendas_jornal.html @@ -1,10 +1,8 @@ - - - - - Listar Vendas de Jornais - - +{% extends 'base.html' %} + +{% block title %}Listar Militantes{% endblock %} + +{% block content %}

Vendas de Jornais Avulsos

Adicionar Nova Venda @@ -30,5 +28,5 @@
Home - - + +{% endblock %} diff --git a/templates/nova_assinatura.html b/templates/nova_assinatura.html index 3205ce3..c83813a 100644 --- a/templates/nova_assinatura.html +++ b/templates/nova_assinatura.html @@ -1,10 +1,8 @@ - - - - - Nova Assinatura Anual - - +{% extends 'base.html' %} + +{% block title %}Listar Militantes{% endblock %} + +{% block content %}

Registrar Nova Assinatura Anual

@@ -31,9 +29,11 @@
- +
+ + Voltar + Início +
- Voltar para Lista - Home - - + +{% endblock %} diff --git a/templates/nova_cota.html b/templates/nova_cota.html index ece5bcc..1de22b4 100644 --- a/templates/nova_cota.html +++ b/templates/nova_cota.html @@ -1,10 +1,8 @@ - - - - - Nova Cota Mensal - - +{% extends 'base.html' %} + +{% block title %}Listar Militantes{% endblock %} + +{% block content %}

Registrar Nova Cota Mensal

@@ -23,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 91b6939..05b296f 100644 --- a/templates/nova_venda_jornal.html +++ b/templates/nova_venda_jornal.html @@ -1,10 +1,8 @@ - - - - - Nova Venda de Jornal - - +{% extends 'base.html' %} + +{% block title %}Listar Militantes{% endblock %} + +{% block content %}

Registrar Nova Venda de Jornal

@@ -23,9 +21,11 @@
- +
+ + Voltar + Início +
- Voltar para Lista - Home - - + +{% endblock %} diff --git a/templates/novo_material.html b/templates/novo_material.html index 1a71b8f..d48b738 100644 --- a/templates/novo_material.html +++ b/templates/novo_material.html @@ -1,10 +1,8 @@ - - - - - Novo Material - - +{% extends 'base.html' %} + +{% block title %}Listar Militantes{% endblock %} + +{% block content %}

Registrar Novo Material

@@ -27,9 +25,11 @@
- +
+ + Voltar + Início +
- Voltar para Lista - Home - - + +{% endblock %} diff --git a/templates/novo_militante.html b/templates/novo_militante.html index f34c634..a9d5919 100644 --- a/templates/novo_militante.html +++ b/templates/novo_militante.html @@ -1,20 +1,68 @@ - - - - - Novo Militante - - -

Criar Novo Militante

-
- Nome:
- CPF:
- Email:
- Telefone:
- Endereço:
- Filiado:
- -
- Home - - \ No newline at end of file +{% extends 'base.html' %} + +{% block title %}Novo Militante{% endblock %} + +{% block content %} +
+
+
+

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 6a32bd9..cf76169 100644 --- a/templates/novo_pagamento.html +++ b/templates/novo_pagamento.html @@ -1,31 +1,41 @@ - - - - - Novo Pagamento - - -

Registrar Novo Pagamento

-
-
- - +{% extends 'base.html' %} + +{% block title %}Novo Pagamento{% endblock %} + +{% block content %} +
+
+
+

Registrar Novo Pagamento

+ + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + Voltar + Início +
+
-
- - -
-
- - -
-
- - -
- - - Voltar para Lista - Home - - +
+
+{% endblock %} diff --git a/templates/novo_relatorio_cotas.html b/templates/novo_relatorio_cotas.html index 1b5f3e6..2e17576 100644 --- a/templates/novo_relatorio_cotas.html +++ b/templates/novo_relatorio_cotas.html @@ -1,10 +1,8 @@ - - - - - Novo Relatório de Cotas - - +{% extends 'base.html' %} + +{% block title %}Listar Militantes{% endblock %} + +{% block content %}

Registrar Novo Relatório de Cotas

@@ -27,5 +25,6 @@ Voltar para Lista Home - - + +{% endblock %} + diff --git a/templates/novo_relatorio_vendas.html b/templates/novo_relatorio_vendas.html index 03dc8cb..06a55a6 100644 --- a/templates/novo_relatorio_vendas.html +++ b/templates/novo_relatorio_vendas.html @@ -1,10 +1,8 @@ - - - - - Novo Relatório de Vendas - - +{% extends 'base.html' %} + +{% block title %}Listar Militantes{% endblock %} + +{% block content %}

Registrar Novo Relatório de Vendas

@@ -27,5 +25,6 @@ Voltar para Lista Home - - + + +{% endblock %}