from fastapi import APIRouter, Request from fastapi.templating import Jinja2Templates from sqlalchemy import create_engine, text import os from datetime import date # Usa o avaliador de fórmulas já existente from app.utils import avaliar_formula router = APIRouter() templates = Jinja2Templates(directory="app/templates") # Conexão com o banco (use a mesma DATABASE_URL do restante do app) DATABASE_URL = os.getenv("DATABASE_URL") engine = create_engine(DATABASE_URL) def _parse_referencia(ref: str): """Aceita 'JAN/2024', '01/2024' ou '202401'. Retorna (ano, mes).""" meses = {'JAN':1,'FEV':2,'MAR':3,'ABR':4,'MAI':5,'JUN':6,'JUL':7,'AGO':8,'SET':9,'OUT':10,'NOV':11,'DEZ':12} ref = (ref or "").strip().upper() if "/" in ref: a, b = ref.split("/") if a.isdigit(): mes, ano = int(a), int(b) else: mes, ano = meses.get(a, 1), int(b) else: ano, mes = int(ref[:4]), int(ref[4:]) if len(ref) >= 6 else 1 return ano, mes def _fator_selic_acumulado(conn, ano_inicio, mes_inicio, hoje): selic = conn.execute(text(""" SELECT ano, mes, percentual FROM faturas.selic_mensal """)).mappings().all() selic_map = {(r["ano"], r["mes"]): float(r["percentual"]) for r in selic} fator = 1.0 ano, mes = int(ano_inicio), int(mes_inicio) while (ano < hoje.year) or (ano == hoje.year and mes <= hoje.month): perc = selic_map.get((ano, mes)) if perc is not None: fator *= (1 + perc/100.0) mes += 1 if mes > 12: mes = 1; ano += 1 return fator @router.get("/dashboard") def dashboard(request: Request, cliente: str | None = None): with engine.begin() as conn: # Lista de clientes (distinct nome) clientes = [r[0] for r in conn.execute(text(""" SELECT DISTINCT nome FROM faturas.faturas ORDER BY nome """)).fetchall()] # Carrega fórmulas (ativas) formula_pis = conn.execute(text(""" SELECT formula FROM faturas.parametros_formula WHERE nome = 'Cálculo PIS sobre ICMS' AND ativo = TRUE LIMIT 1 """)).scalar_one_or_none() formula_cofins = conn.execute(text(""" SELECT formula FROM faturas.parametros_formula WHERE nome = 'Cálculo COFINS sobre ICMS' AND ativo = TRUE LIMIT 1 """)).scalar_one_or_none() # Carrega faturas (com filtro opcional de cliente) params = {} sql = "SELECT * FROM faturas.faturas" if cliente: sql += " WHERE nome = :cliente" params["cliente"] = cliente faturas = conn.execute(text(sql), params).mappings().all() total_faturas = len(faturas) # Cálculos de restituição e % ICMS na base hoje = date.today() soma_corrigida = 0.0 qtd_icms_na_base = 0 for f in faturas: contexto = dict(f) # usa colunas como variáveis da fórmula # PIS sobre ICMS v_pis_icms = avaliar_formula(formula_pis, contexto) if formula_pis else None # COFINS sobre ICMS v_cofins_icms = avaliar_formula(formula_cofins, contexto) if formula_cofins else None # Contagem para % ICMS na base: considera PIS_sobre_ICMS > 0 if v_pis_icms and float(v_pis_icms) > 0: qtd_icms_na_base += 1 # Corrigir pela SELIC desde a referência da fatura try: ano, mes = _parse_referencia(f.get("referencia")) fator = _fator_selic_acumulado(conn, ano, mes, hoje) except Exception: fator = 1.0 valor_bruto = (float(v_pis_icms) if v_pis_icms else 0.0) + (float(v_cofins_icms) if v_cofins_icms else 0.0) soma_corrigida += valor_bruto * fator percentual_icms_base = (qtd_icms_na_base / total_faturas * 100.0) if total_faturas else 0.0 valor_restituicao_corrigida = soma_corrigida # --- Análise STF (mantida) --- def media_percentual_icms(inicio: str, fim: str): # Aproximação: base PIS = base ICMS => configurado como proxy “com ICMS na base” q = text(f""" SELECT ROUND(AVG(CASE WHEN icms_base IS NOT NULL AND pis_base = icms_base THEN 100.0 ELSE 0.0 END), 2) AS percentual_com_icms, ROUND(AVG(COALESCE(pis_valor,0) + COALESCE(cofins_valor,0)), 2) AS media_valor FROM faturas.faturas WHERE data_processamento::date BETWEEN :inicio AND :fim { "AND nome = :cliente" if cliente else "" } """) params = {"inicio": inicio, "fim": fim} if cliente: params["cliente"] = cliente r = conn.execute(q, params).mappings().first() or {} return {"percentual_com_icms": r.get("percentual_com_icms", 0), "media_valor": r.get("media_valor", 0)} analise_stf = { "antes": media_percentual_icms("2000-01-01", "2017-03-15"), "depois": media_percentual_icms("2017-03-16", "2099-12-31") } return templates.TemplateResponse("dashboard.html", { "request": request, "clientes": clientes, "cliente_atual": cliente or "", "total_faturas": total_faturas, "valor_restituicao_corrigida": valor_restituicao_corrigida, "percentual_icms_base": percentual_icms_base, "analise_stf": analise_stf })