feat: implementa sistema de comprovantes com centralizações e PIX
This commit is contained in:
@@ -14,6 +14,9 @@ from flask_login import UserMixin
|
||||
from .rbac import Role, Permission, role_permissions, user_roles
|
||||
from .base import Base, engine, Session
|
||||
import logging
|
||||
import qrcode
|
||||
from PIL import Image
|
||||
import re
|
||||
|
||||
# Configurar caminho do banco de dados
|
||||
db_dir = Path.home() / '.local' / 'share' / 'controles'
|
||||
@@ -329,7 +332,6 @@ class Pagamento(Base):
|
||||
data_pagamento = Column(Date, nullable=False)
|
||||
|
||||
militante = relationship("Militante", back_populates="pagamentos")
|
||||
transacoes_pix = relationship("TransacaoPIX", back_populates="pagamento")
|
||||
|
||||
class TipoMaterial(Base):
|
||||
__tablename__ = 'tipos_materiais'
|
||||
@@ -608,6 +610,49 @@ class Relatorio(Base):
|
||||
setor = relationship("Setor", foreign_keys=[setor_id])
|
||||
cr = relationship("ComiteRegional", foreign_keys=[cr_id])
|
||||
|
||||
class CampanhaFinanceira(Base):
|
||||
__tablename__ = 'campanhas_financeiras'
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
nome = Column(String(100), nullable=False)
|
||||
descricao = Column(Text)
|
||||
data_inicio = Column(Date, nullable=False)
|
||||
data_fim = Column(Date, nullable=False)
|
||||
meta = Column(Numeric(10, 2), nullable=False)
|
||||
valor_arrecadado = Column(Numeric(10, 2), default=0)
|
||||
status = Column(String(20), default='Em andamento') # Em andamento, Concluída, Cancelada
|
||||
|
||||
comprovantes = relationship("Comprovante", back_populates="campanha")
|
||||
|
||||
class TipoComprovante(Base):
|
||||
__tablename__ = 'tipos_comprovante'
|
||||
id = Column(Integer, primary_key=True)
|
||||
descricao = Column(String(50), nullable=False)
|
||||
valor = Column(Numeric(10, 2), nullable=False)
|
||||
|
||||
class CentralizacaoComprovante(Base):
|
||||
__tablename__ = 'centralizacoes_comprovante'
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
comprovante_id = Column(Integer, ForeignKey('comprovantes.id'), nullable=False)
|
||||
tipo_comprovante = Column(String(50), nullable=False) # Cota, Jornal, Assinatura, etc.
|
||||
valor = Column(Numeric(10, 2), nullable=False)
|
||||
|
||||
comprovante = relationship("Comprovante", back_populates="centralizacoes")
|
||||
|
||||
class Comprovante(Base):
|
||||
__tablename__ = 'comprovantes'
|
||||
id = Column(Integer, primary_key=True)
|
||||
militante_id = Column(Integer, ForeignKey('militantes.id'), nullable=False)
|
||||
data_comprovante = Column(Date, nullable=False)
|
||||
forma_pagamento = Column(String(20), nullable=False) # PIX, transferência/DOC, depósito, maquininha
|
||||
campanha_id = Column(Integer, ForeignKey('campanhas_financeiras.id'))
|
||||
|
||||
militante = relationship("Militante", back_populates="comprovantes")
|
||||
transacoes_pix = relationship("TransacaoPIX", back_populates="comprovante")
|
||||
campanha = relationship("CampanhaFinanceira", back_populates="comprovantes")
|
||||
centralizacoes = relationship("CentralizacaoComprovante", back_populates="comprovante", cascade="all, delete-orphan")
|
||||
|
||||
class TransacaoPIX(Base):
|
||||
__tablename__ = 'transacoes_pix'
|
||||
|
||||
@@ -618,25 +663,9 @@ class TransacaoPIX(Base):
|
||||
data_pagamento = Column(DateTime)
|
||||
status = Column(String(20)) # Pendente, Pago, Expirado
|
||||
qr_code = Column(Text)
|
||||
pagamento_id = Column(Integer, ForeignKey('pagamentos.id'))
|
||||
comprovante_id = Column(Integer, ForeignKey('comprovantes.id'))
|
||||
|
||||
pagamento = relationship("Pagamento", back_populates="transacoes_pix")
|
||||
|
||||
class TipoComprovante(Base):
|
||||
__tablename__ = 'tipos_comprovante'
|
||||
id = Column(Integer, primary_key=True)
|
||||
descricao = Column(String(50), nullable=False)
|
||||
valor = Column(Float, nullable=False)
|
||||
|
||||
class Comprovante(Base):
|
||||
__tablename__ = 'comprovantes'
|
||||
id = Column(Integer, primary_key=True)
|
||||
militante_id = Column(Integer, ForeignKey('militantes.id'), nullable=False)
|
||||
tipo_comprovante = Column(String(50)) # Cota, Jornal, Assinatura, etc.
|
||||
data_comprovante = Column(Date, nullable=False)
|
||||
|
||||
militante = relationship("Militante", back_populates="comprovantes")
|
||||
transacoes_pix = relationship("TransacaoPIX", back_populates="comprovante")
|
||||
comprovante = relationship("Comprovante", back_populates="transacoes_pix")
|
||||
|
||||
def init_database():
|
||||
"""Inicializa o banco de dados com dados básicos"""
|
||||
@@ -677,9 +706,30 @@ def init_database():
|
||||
session.add(comite)
|
||||
session.commit()
|
||||
|
||||
# Gerar OTP para admin
|
||||
admin_otp_secret = pyotp.random_base32()
|
||||
print(f"Novo OTP gerado: {admin_otp_secret}")
|
||||
# Verificar se existe QR code do admin
|
||||
admin_otp_secret = None
|
||||
qr_path = 'admin_qr.png'
|
||||
|
||||
if os.path.exists(qr_path):
|
||||
try:
|
||||
# Tentar ler o QR code existente
|
||||
from pyzbar.pyzbar import decode
|
||||
qr_data = decode(Image.open(qr_path))
|
||||
if qr_data:
|
||||
# O URI do OTP está no formato: otpauth://totp/Sistema%20de%20Controles:admin?secret=XXXXX&issuer=Sistema%20de%20Controles
|
||||
uri = qr_data[0].data.decode('utf-8')
|
||||
# Extrair o secret do URI
|
||||
match = re.search(r'secret=([A-Z0-9]+)', uri)
|
||||
if match:
|
||||
admin_otp_secret = match.group(1)
|
||||
print("OTP existente encontrado no QR code")
|
||||
except Exception as e:
|
||||
print(f"Erro ao ler QR code existente: {e}")
|
||||
|
||||
if not admin_otp_secret:
|
||||
# Se não conseguiu ler o QR code ou ele não existe, gera um novo
|
||||
admin_otp_secret = pyotp.random_base32()
|
||||
print(f"Novo OTP gerado: {admin_otp_secret}")
|
||||
|
||||
# Criar usuário admin
|
||||
admin_role = session.query(Role).filter_by(nome="Administrador").first()
|
||||
@@ -698,23 +748,23 @@ def init_database():
|
||||
session.add(admin)
|
||||
session.commit()
|
||||
|
||||
# Gerar QR code
|
||||
totp = pyotp.totp.TOTP(admin_otp_secret)
|
||||
provisioning_uri = totp.provisioning_uri("admin", issuer_name="Sistema de Controles")
|
||||
|
||||
import qrcode
|
||||
qr = qrcode.QRCode(version=1, box_size=10, border=5)
|
||||
qr.add_data(provisioning_uri)
|
||||
qr.make(fit=True)
|
||||
img = qr.make_image(fill_color="black", back_color="white")
|
||||
img.save('admin_qr.png')
|
||||
# Gerar QR code apenas se não existir
|
||||
if not os.path.exists(qr_path):
|
||||
totp = pyotp.totp.TOTP(admin_otp_secret)
|
||||
provisioning_uri = totp.provisioning_uri("admin", issuer_name="Sistema de Controles")
|
||||
|
||||
qr = qrcode.QRCode(version=1, box_size=10, border=5)
|
||||
qr.add_data(provisioning_uri)
|
||||
qr.make(fit=True)
|
||||
img = qr.make_image(fill_color="black", back_color="white")
|
||||
img.save(qr_path)
|
||||
|
||||
print("=== Usuário Admin Criado ===")
|
||||
print(f"Username: admin")
|
||||
print(f"Senha: admin123")
|
||||
print(f"Email: {admin.email}")
|
||||
print(f"OTP Secret: {admin_otp_secret}")
|
||||
print(f"QR Code: admin_qr.png")
|
||||
print(f"QR Code: {qr_path}")
|
||||
|
||||
# Importar e executar o seed após criar todas as dependências
|
||||
from seed_data import seed_database
|
||||
|
||||
Reference in New Issue
Block a user