Atualiza exibição do tempo por processo e garante consistência da estrutura em app/
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-07-28 22:31:31 -03:00
parent d863d7f9e2
commit f3c2b08a69
82 changed files with 183 additions and 7786 deletions

View File

@@ -3,13 +3,14 @@ import os
import shutil
import asyncio
from sqlalchemy.future import select
from utils import extrair_dados_pdf
from database import AsyncSessionLocal
from models import Fatura, LogProcessamento
from app.utils import extrair_dados_pdf
from app.database import AsyncSessionLocal
from app.models import Fatura, LogProcessamento
import time
logger = logging.getLogger(__name__)
UPLOADS_DIR = os.path.join(os.getcwd(), "uploads")
UPLOADS_DIR = os.path.join("app", "uploads")
TEMP_DIR = os.path.join(UPLOADS_DIR, "temp")
fila_processamento = asyncio.Queue()
@@ -35,56 +36,92 @@ def salvar_em_uploads(caminho_pdf_temp, nome_original, nota_fiscal):
return caminho_pdf_temp
async def process_single_file(caminho_pdf_temp: str, nome_original: str):
inicio = time.perf_counter()
async with AsyncSessionLocal() as session:
try:
dados = extrair_dados_pdf(caminho_pdf_temp)
dados['arquivo_pdf'] = nome_original
# Verifica se a fatura já existe
existente_result = await session.execute(
select(Fatura).filter_by(nota_fiscal=dados['nota_fiscal'], unidade_consumidora=dados['unidade_consumidora'])
select(Fatura).filter_by(
nota_fiscal=dados['nota_fiscal'],
unidade_consumidora=dados['unidade_consumidora']
)
)
if existente_result.scalar_one_or_none():
duracao = round(time.perf_counter() - inicio, 2)
remover_arquivo_temp(caminho_pdf_temp)
return {"status": "Duplicado", "dados": dados}
return {
"status": "Duplicado",
"dados": dados,
"tempo": f"{duracao}s"
}
# Salva arquivo final
caminho_final = salvar_em_uploads(caminho_pdf_temp, nome_original, dados['nota_fiscal'])
dados['link_arquivo'] = caminho_final
# Salva fatura
fatura = Fatura(**dados)
session.add(fatura)
session.add(LogProcessamento(
status="Sucesso",
mensagem="Fatura processada com sucesso",
nome_arquivo=nome_original,
acao="PROCESSAMENTO"
))
await session.commit()
remover_arquivo_temp(caminho_pdf_temp)
return {"status": "Concluído", "dados": dados}
duracao = round(time.perf_counter() - inicio, 2)
return {
"status": "Concluído",
"dados": dados,
"tempo": f"{duracao}s"
}
except Exception as e:
erro_str = traceback.format_exc()
duracao = round(time.perf_counter() - inicio, 2)
await session.rollback()
session.add(LogProcessamento(
status="Erro",
mensagem=str(e),
nome_arquivo=nome_original,
acao="PROCESSAMENTO"
))
await session.commit()
logger.error(f"Erro ao processar fatura: {e}", exc_info=True)
remover_arquivo_temp(caminho_pdf_temp)
return {"status": "Erro", "mensagem": str(e)}
print(f"\n📄 ERRO no arquivo: {nome_original}")
print(f"⏱ Tempo até erro: {duracao}s")
print(f"❌ Erro detalhado:\n{erro_str}")
return {
"status": "Erro",
"mensagem": str(e),
"tempo": f"{duracao}s",
"trace": erro_str
}
async def processar_em_lote():
import traceback # para exibir erros
resultados = []
while not fila_processamento.empty():
item = await fila_processamento.get()
resultado = await process_single_file(item['caminho_pdf'], item['nome_original'])
status_arquivos[item['nome_original']] = resultado.get("status", "Erro")
resultados.append(resultado)
try:
resultado = await process_single_file(item['caminho_pdf'], item['nome_original'])
status_arquivos[item['nome_original']] = {
"status": resultado.get("status"),
"mensagem": resultado.get("mensagem", ""),
"tempo": resultado.get("tempo", "---")
}
resultados.append(status_arquivos[item['nome_original']])
except Exception as e:
status_arquivos[item['nome_original']] = {
"status": "Erro",
"mensagem": str(e),
"tempo": "---"
}
resultados.append({
"nome": item['nome_original'],
"status": "Erro",
"mensagem": str(e)
})
print(f"Erro ao processar {item['nome_original']}: {e}")
print(traceback.format_exc())
return resultados
def limpar_arquivos_processados():