197 lines
6.5 KiB
Python
197 lines
6.5 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 fastapi.responses import StreamingResponse
|
||
|
|
from io import BytesIO
|
||
|
|
import pandas as pd
|
||
|
|
from sqlalchemy.future import select
|
||
|
|
from database import AsyncSessionLocal
|
||
|
|
from models import Fatura
|
||
|
|
from models import ParametrosFormula
|
||
|
|
from fastapi import Form
|
||
|
|
from types import SimpleNamespace
|
||
|
|
from processor import (
|
||
|
|
fila_processamento,
|
||
|
|
processar_em_lote,
|
||
|
|
status_arquivos,
|
||
|
|
limpar_arquivos_processados
|
||
|
|
)
|
||
|
|
|
||
|
|
app = FastAPI()
|
||
|
|
templates = Jinja2Templates(directory="templates")
|
||
|
|
app.mount("/static", StaticFiles(directory="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):
|
||
|
|
return templates.TemplateResponse("upload.html", {"request": request})
|
||
|
|
|
||
|
|
@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).limit(1))
|
||
|
|
parametros = result.scalar_one_or_none()
|
||
|
|
|
||
|
|
return templates.TemplateResponse("parametros.html", {
|
||
|
|
"request": request,
|
||
|
|
"parametros": parametros or SimpleNamespace(
|
||
|
|
aliquota_icms=None,
|
||
|
|
incluir_icms=True,
|
||
|
|
incluir_pis=True,
|
||
|
|
incluir_cofins=True
|
||
|
|
)
|
||
|
|
})
|
||
|
|
|
||
|
|
@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():
|
||
|
|
files.append({
|
||
|
|
"nome": nome,
|
||
|
|
"status": status,
|
||
|
|
"mensagem": "---" if status == "Concluído" else status
|
||
|
|
})
|
||
|
|
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"}
|
||
|
|
)
|
||
|
|
|
||
|
|
@app.post("/parametros", response_class=HTMLResponse)
|
||
|
|
async def salvar_parametros(
|
||
|
|
request: Request,
|
||
|
|
aliquota_icms: float = Form(...),
|
||
|
|
formula_pis: str = Form(...),
|
||
|
|
formula_cofins: str = Form(...)
|
||
|
|
):
|
||
|
|
async with AsyncSessionLocal() as session:
|
||
|
|
result = await session.execute(select(ParametrosFormula).limit(1))
|
||
|
|
existente = result.scalar_one_or_none()
|
||
|
|
|
||
|
|
if existente:
|
||
|
|
existente.aliquota_icms = aliquota_icms
|
||
|
|
existente.incluir_icms = 1
|
||
|
|
existente.incluir_pis = 1
|
||
|
|
existente.incluir_cofins = 1
|
||
|
|
existente.formula = f"PIS={formula_pis};COFINS={formula_cofins}"
|
||
|
|
mensagem = "Parâmetros atualizados com sucesso."
|
||
|
|
else:
|
||
|
|
novo = ParametrosFormula(
|
||
|
|
aliquota_icms=aliquota_icms,
|
||
|
|
incluir_icms=1,
|
||
|
|
incluir_pis=1,
|
||
|
|
incluir_cofins=1,
|
||
|
|
formula=f"PIS={formula_pis};COFINS={formula_cofins}"
|
||
|
|
)
|
||
|
|
session.add(novo)
|
||
|
|
mensagem = "Parâmetros salvos com sucesso."
|
||
|
|
|
||
|
|
await session.commit()
|
||
|
|
|
||
|
|
parametros = SimpleNamespace(
|
||
|
|
aliquota_icms=aliquota_icms,
|
||
|
|
incluir_icms=1,
|
||
|
|
incluir_pis=1,
|
||
|
|
incluir_cofins=1,
|
||
|
|
formula_pis=formula_pis,
|
||
|
|
formula_cofins=formula_cofins
|
||
|
|
)
|
||
|
|
|
||
|
|
return templates.TemplateResponse("parametros.html", {
|
||
|
|
"request": request,
|
||
|
|
"parametros": parametros,
|
||
|
|
"mensagem": mensagem
|
||
|
|
})
|