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 %}
+
+
+{% 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 %}
+
+{% 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
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
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
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
-
- {% for militante in militantes %}
- {{ militante.nome }} - {{ militante.email }}
- {% endfor %}
-
- 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
+
+
+
+
+ Nome
+ CPF
+ Email
+ Telefone
+ Endereço
+ Filiado
+
+
+
+ {% for militante in militantes %}
+
+ {{ militante.nome }}
+ {{ militante.cpf }}
+ {{ militante.email }}
+ {{ militante.telefone }}
+ {{ militante.endereco }}
+ {{ 'Sim' if militante.filiado else 'Não' }}
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+{% 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
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
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
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
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
- 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
- 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
- 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
- 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
-
- 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 %}
+
+
+
+
+
+{% 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
-