Sistema automatizado de processamento de comprovantes financeiros com:
Responsabilidade: Todas as constantes, credenciais e bancos de dados
Contenido:
Uso:
from config import (
PASTA_ENTRADA, EMAIL_REMETENTE,
DB_FORNECEDORES_CATEGORIA
)
Por que separado?
Responsabilidade: Define todas as estruturas com type hints
Classes principais:
Pagamento - Um pagamento individualComprovante - Um arquivo PDF processadoClassificacao - Resultado da classificaçãoExtrato - Resumo financeiroResumoProcessamento - Resultado da execuçãoEnums:
EmpresaPagadora (LALUA, SOLAR)FontePagamento (fornecedores, folha, etc)StatusComprovante (não processado, processado, erro, etc)Uso:
from models import Pagamento, Comprovante
pagamento = Pagamento(
nome="João Silva",
valor=1000.00,
categoria="12201 - Salários"
)
Por que separado?
Responsabilidade: Ler PDFs, aplicar OCR, extrair texto e dados
Classes principais:
OCRProcessor - Processa PDFs com/sem OCR
extrair_texto_pdf() - Extrai textocalcular_hash_arquivo() - Detec duplicatasprocessar_comprovante() - Pipeline completoExtratorDados - Extrai dados estruturados
extrair_data() - Data do pagamentoextrair_valor() - Valor em reaisextrair_nome_recebedor() - Nome beneficiárioextrair_cnpj_cpf() - CNPJ/CPFUso:
processor = OCRProcessor()
comprovante = processor.processar_comprovante("comprovante.pdf")
dados = ExtratorDados.extrair_todos_dados(comprovante.texto_extraido)
Por que separado?
Responsabilidade: Classifica fornecedores por CNPJ/nome/heurísticas
Classes principais:
DataClassifier - Classificador automático
auto_classificar_fornecedor() - (Responsável, Categoria)classificar_colaborador() - Identifica colaborador e filialdefinir_categoria_pagamento() - Categoria RH/Geralclassificar_pagamento_completo() - Full pipelineEstratégia de classificação (em ordem):
Uso:
clf = DataClassifier()
classificacao = clf.auto_classificar_fornecedor(
"TEXTIL FAVERO LTDA",
"08.883.683/0001-84"
)
# → Classificacao(responsavel="COMPRAS", categoria="12101 - Tecidos")
Por que separado?
Responsabilidade: Todas as operações no banco de dados
Classes principais:
DatabaseManager - CRUD + queries
inserir_pagamento() / obter_pagamento()listar_pagamentos() com filtrosatualizar_pagamento() / deletar_pagamento()inserir_comprovante()comprovante_ja_existe() - Por hashSchema:
pagamentos - Registros de pagamentoscomprovantes - Documentos processadoscomprovante_pagamentos - Relacionamentoextratos - Resumos financeirosUso:
db = DatabaseManager()
db.criar_schema()
id_pag = db.inserir_pagamento(pagamento)
pagamentos, total = db.listar_pagamentos(
filtros=FiltrosPagamento(categoria="A CLASSIFICAR"),
limite=100
)
Por que separado?
Responsabilidade: Enviar emails via SMTP/Outlook
Classes principais:
EmailHandler - SMTP com templates HTML
enviar_email_smtp() - Envia via SMTPenviar_para_dp() - DP defaultenviar_extrato() - Template extratoenviar_resumo_processamento() - Template resumoenviar_alerta_saldo_critico() - Template alertaOutlookHandler - Outlook Desktop (win32com)
enviar() - Via OutlookUso:
email = EmailHandler()
email.enviar_resumo_processamento(
total_comprovantes=5,
total_pagamentos=10,
total_valor=5000.00,
sucesso=5,
erros=0,
tempo_segundos=45.2
)
Por que separado?
Responsabilidade: Move/copia/organiza arquivos
Classes principais:
FileOrganizer - Gerenciador de arquivos
criar_estrutura_pastas() - Initorganizar_comprovante() - Por filial/mêsarquivar_comprovante_processado() - Em PROCESSADOSfazer_backup_rede() - Backup em Z:\listar_arquivos_entrada() - Arquivos para processarobter_estatisticas_pastas() - Tamanho/countEstrutura de pastas:
ENTRADA/
├─ comprovante1.pdf
└─ comprovante2.pdf
SAIDA_ORGANIZADA/
├─ Filial_Barra/2026/01_Janeiro/
│ ├─ comp1.pdf
│ └─ comp2.pdf
└─ Filial_SDB/2026/01_Janeiro/
PROCESSADOS/
├─ SUCESSO/2026/01_Janeiro/
└─ ERRO/2026/01_Janeiro/
backup em Z:\01-Administrativo\02-Financeiro\04-Comprovantes/
Por que separado?
Responsabilidade: Interface gráfica do usuário
Classe principal:
Interface - GUI com abas
Features:
Uso:
root = tk.Tk()
interface = Interface(root)
interface.callback_processar = algumas_funcao
interface.adicionar_log("Mensagem ao usuário")
interface.atualizar_progresso(50, 100) # 50%
root.mainloop()
Por que separado?
Responsabilidade: Ponto de entrada e orquestração
Classe principal:
SistemaFinanceiro - Orquestrador central
processar_comprovantes() - Pipeline principallistar_pagamentos_recentes() - Query exemplogerar_relatorio() - Relatório em textoPipeline (dentro de processar_comprovantes()):
Uso:
if __name__ == "__main__":
sistema = SistemaFinanceiro()
sistema.executar() # Inicia GUI
Por que separado?
cd "c:\Users\Roberto\Desktop\CONTAS A PAGAR\PROJETOS\FINANCEIRO"
# Criar virtualenv (opcional)
python -m venv venv
venv\Scripts\activate
# Instalar dependências
pip install pypdf pytesseract pdf2image pillow openpyxl beautifulsoup4
python main.py
ENTRADA/SAIDA_ORGANIZADA/[main.py] inicia
↓
[SistemaFinanceiro.__init__()]
├─ OCRProcessor()
├─ DatabaseManager()
├─ DataClassifier()
├─ EmailHandler()
├─ FileOrganizer()
└─ Interface()
↓
[Interface.mainloop()] ← GUI aguarda
↓
[Usuário clica "Processar"]
↓
[SistemaFinanceiro.processar_comprovantes()]
├─ FileOrganizer.listar_arquivos_entrada()
└─ Para cada arquivo:
├─ OCRProcessor.processar_comprovante()
│ └─ ExtratorDados.extrair_*
├─ DataClassifier.classificar_pagamento_completo()
├─ DatabaseManager.inserir_*
├─ FileOrganizer.organizar_comprovante()
├─ FileOrganizer.fazer_backup_rede()
−─ Interface.atualizar_progresso()
└─ EmailHandler.enviar_resumo_processamento()
| Aspecto | v14 (Monolítico) | v2.0 (Modular) |
|---|---|---|
| Arquivos | 1 gigante (~1500 linhas) | 9 módulos especializados |
| Testabilidade | Impossível | ✓ Mock individual |
| Manutenção | Difícil | ✓ Fácil (responsabilidade única) |
| Reutilização | Não | ✓ Modules independentes |
| Performance | OK | ✓ Índices no DB |
| Type Hints | Não | ✓ Completo |
| Documentação | Inexistente | ✓ Docstrings |
| Escalabilidade | Limitada | ✓ Web backend fácil |
| CI/CD | Impossível | ✓ Cada módulo testável |
# test_classifier.py
def test_auto_classificar_por_cnpj():
clf = DataClassifier()
resultado = clf.auto_classificar_fornecedor("...", "08.883.683/0001-84")
assert resultado.responsavel == "COMPRAS"
import logging
logger = logging.getLogger(__name__)
logger.info("Comprovante processado")
@app.post("/processar")
def processar_via_api(arquivo: UploadFile):
... # Reutiliza SistemaFinanceiro
database.pypython-dotenv)logging module)Qualquer dúvida sobre arquitetura ou funcionamento, consulte os docstrings em cada módulo.
v2.0 - Reestruturação Completa Transformando monolítico em arquitetura modular