185 lines
6.4 KiB
Python
185 lines
6.4 KiB
Python
import uuid
|
|
from fastapi import FastAPI, Request, UploadFile, File
|
|
from fastapi.templating import Jinja2Templates
|
|
from fastapi.responses import HTMLResponse, JSONResponse
|
|
from fastapi.staticfiles import StaticFiles
|
|
import os, shutil
|
|
from sqlalchemy import text
|
|
from fastapi import Depends
|
|
from fastapi.responses import StreamingResponse
|
|
from io import BytesIO
|
|
import pandas as pd
|
|
from app.models import ParametrosFormula
|
|
from sqlalchemy.future import select
|
|
from app.database import AsyncSessionLocal
|
|
from app.models import Fatura
|
|
from app.processor import (
|
|
fila_processamento,
|
|
processar_em_lote,
|
|
status_arquivos,
|
|
limpar_arquivos_processados
|
|
)
|
|
from app.parametros import router as parametros_router
|
|
|
|
app = FastAPI()
|
|
templates = Jinja2Templates(directory="app/templates")
|
|
app.mount("/static", StaticFiles(directory="app/static"), name="static")
|
|
|
|
UPLOAD_DIR = "uploads/temp"
|
|
os.makedirs(UPLOAD_DIR, exist_ok=True)
|
|
|
|
@app.get("/", response_class=HTMLResponse)
|
|
def dashboard(request: Request):
|
|
indicadores = [
|
|
{"titulo": "Total de Faturas", "valor": 124},
|
|
{"titulo": "Faturas com ICMS", "valor": "63%"},
|
|
{"titulo": "Valor Total", "valor": "R$ 280.000,00"},
|
|
]
|
|
|
|
analise_stf = {
|
|
"antes": {"percentual_com_icms": 80, "media_valor": 1200},
|
|
"depois": {"percentual_com_icms": 20, "media_valor": 800},
|
|
}
|
|
|
|
return templates.TemplateResponse("dashboard.html", {
|
|
"request": request,
|
|
"cliente_atual": "",
|
|
"clientes": ["Cliente A", "Cliente B"],
|
|
"indicadores": indicadores,
|
|
"analise_stf": analise_stf
|
|
})
|
|
|
|
@app.get("/upload", response_class=HTMLResponse)
|
|
def upload_page(request: Request):
|
|
app_env = os.getenv("APP_ENV", "dev") # Captura variável de ambiente
|
|
return templates.TemplateResponse("upload.html", {
|
|
"request": request,
|
|
"app_env": app_env # Passa para o template
|
|
})
|
|
|
|
@app.get("/relatorios", response_class=HTMLResponse)
|
|
def relatorios_page(request: Request):
|
|
return templates.TemplateResponse("relatorios.html", {"request": request})
|
|
|
|
@app.get("/parametros", response_class=HTMLResponse)
|
|
async def parametros_page(request: Request):
|
|
async with AsyncSessionLocal() as session:
|
|
result = await session.execute(select(ParametrosFormula))
|
|
parametros = result.scalars().first()
|
|
return templates.TemplateResponse("parametros.html", {
|
|
"request": request,
|
|
"parametros": parametros or {}
|
|
})
|
|
|
|
@app.post("/upload-files")
|
|
async def upload_files(files: list[UploadFile] = File(...)):
|
|
for file in files:
|
|
temp_path = os.path.join(UPLOAD_DIR, f"{uuid.uuid4()}_{file.filename}")
|
|
with open(temp_path, "wb") as f:
|
|
shutil.copyfileobj(file.file, f)
|
|
await fila_processamento.put({
|
|
"caminho_pdf": temp_path,
|
|
"nome_original": file.filename
|
|
})
|
|
return {"message": "Arquivos enviados para fila"}
|
|
|
|
@app.post("/process-queue")
|
|
async def process_queue():
|
|
resultados = await processar_em_lote()
|
|
return {"message": "Processamento concluído", "resultados": resultados}
|
|
|
|
@app.get("/get-status")
|
|
async def get_status():
|
|
files = []
|
|
for nome, status in status_arquivos.items():
|
|
if isinstance(status, dict):
|
|
files.append({
|
|
"nome": nome,
|
|
"status": status.get("status", "Erro"),
|
|
"mensagem": status.get("mensagem", "---"),
|
|
"tempo": status.get("tempo", "---") # ✅ AQUI
|
|
})
|
|
else:
|
|
files.append({
|
|
"nome": nome,
|
|
"status": status,
|
|
"mensagem": "---" if status == "Concluído" else status,
|
|
"tempo": "---" # ✅ AQUI também
|
|
})
|
|
is_processing = not fila_processamento.empty()
|
|
return JSONResponse(content={"is_processing": is_processing, "files": files})
|
|
|
|
|
|
@app.post("/clear-all")
|
|
async def clear_all():
|
|
limpar_arquivos_processados()
|
|
for f in os.listdir(UPLOAD_DIR):
|
|
os.remove(os.path.join(UPLOAD_DIR, f))
|
|
return {"message": "Fila e arquivos limpos"}
|
|
|
|
@app.get("/export-excel")
|
|
async def export_excel():
|
|
async with AsyncSessionLocal() as session:
|
|
result = await session.execute(select(Fatura))
|
|
faturas = result.scalars().all()
|
|
|
|
dados = []
|
|
for f in faturas:
|
|
dados.append({
|
|
"Nome": f.nome,
|
|
"UC": f.unidade_consumidora,
|
|
"Referência": f.referencia,
|
|
"Nota Fiscal": f.nota_fiscal,
|
|
"Valor Total": f.valor_total,
|
|
"ICMS (%)": f.icms_aliq,
|
|
"ICMS (R$)": f.icms_valor,
|
|
"Base ICMS": f.icms_base,
|
|
"PIS (%)": f.pis_aliq,
|
|
"PIS (R$)": f.pis_valor,
|
|
"Base PIS": f.pis_base,
|
|
"COFINS (%)": f.cofins_aliq,
|
|
"COFINS (R$)": f.cofins_valor,
|
|
"Base COFINS": f.cofins_base,
|
|
"Consumo (kWh)": f.consumo,
|
|
"Tarifa": f.tarifa,
|
|
"Cidade": f.cidade,
|
|
"Estado": f.estado,
|
|
"Distribuidora": f.distribuidora,
|
|
"Data Processamento": f.data_processamento,
|
|
})
|
|
|
|
df = pd.DataFrame(dados)
|
|
output = BytesIO()
|
|
df.to_excel(output, index=False, sheet_name="Faturas")
|
|
output.seek(0)
|
|
|
|
return StreamingResponse(
|
|
output,
|
|
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
headers={"Content-Disposition": "attachment; filename=relatorio_faturas.xlsx"}
|
|
)
|
|
|
|
from app.parametros import router as parametros_router
|
|
app.include_router(parametros_router)
|
|
|
|
def is_homolog():
|
|
return os.getenv("APP_ENV", "dev") == "homolog"
|
|
|
|
@app.post("/limpar-faturas")
|
|
async def limpar_faturas():
|
|
app_env = os.getenv("APP_ENV", "dev")
|
|
if app_env not in ["homolog", "dev", "local"]:
|
|
return JSONResponse(status_code=403, content={"message": "Operação não permitida neste ambiente."})
|
|
|
|
async with AsyncSessionLocal() as session:
|
|
print("🧪 Limpando faturas do banco...")
|
|
await session.execute(text("DELETE FROM faturas.faturas"))
|
|
await session.commit()
|
|
|
|
upload_path = os.path.join("app", "uploads")
|
|
for nome in os.listdir(upload_path):
|
|
caminho = os.path.join(upload_path, nome)
|
|
if os.path.isfile(caminho):
|
|
os.remove(caminho)
|
|
|
|
return {"message": "Faturas e arquivos apagados com sucesso."} |