Cadastro da alíquota do ICMS correta. Inclusão da nova alíquota e comparação em todos os relatórios.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-08-11 18:45:57 -03:00
parent 950eb2a826
commit 4d2fcff4a8
5 changed files with 368 additions and 68 deletions

View File

@@ -1,5 +1,5 @@
# parametros.py
from fastapi import APIRouter, Request, Depends, Form
from fastapi import APIRouter, Request, Depends, Form, UploadFile, File
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_session
from app.models import AliquotaUF, ParametrosFormula, SelicMensal
@@ -9,7 +9,7 @@ import datetime
from fastapi.templating import Jinja2Templates
from sqlalchemy.future import select
from app.database import AsyncSessionLocal
from fastapi.responses import RedirectResponse
from fastapi.responses import RedirectResponse, JSONResponse
from app.models import Fatura
from fastapi import Body
from app.database import engine
@@ -21,6 +21,8 @@ import csv
from fastapi.responses import StreamingResponse
import pandas as pd
from io import BytesIO
from sqlalchemy import select
from decimal import Decimal
router = APIRouter()
@@ -100,6 +102,28 @@ async def editar_parametro(param_id: int, request: Request):
return {"success": True}
return {"success": False, "error": "Não encontrado"}
@router.post("/parametros/ativar/{param_id}")
async def ativar_parametro(param_id: int, request: Request):
data = await request.json()
ativo = bool(data.get("ativo", True))
async with AsyncSessionLocal() as session:
param = await session.get(ParametrosFormula, param_id)
if not param:
return JSONResponse(status_code=404, content={"error": "Parâmetro não encontrado"})
param.ativo = ativo
await session.commit()
return {"success": True}
@router.get("/parametros/delete/{param_id}")
async def deletar_parametro(param_id: int):
async with AsyncSessionLocal() as session:
param = await session.get(ParametrosFormula, param_id)
if not param:
return RedirectResponse("/parametros?erro=1&msg=Parâmetro não encontrado", status_code=303)
await session.delete(param)
await session.commit()
return RedirectResponse("/parametros?ok=1&msg=Parâmetro removido", status_code=303)
@router.post("/parametros/testar")
async def testar_formula(db: AsyncSession = Depends(get_session), data: dict = Body(...)):
formula = data.get("formula")
@@ -117,10 +141,18 @@ async def testar_formula(db: AsyncSession = Depends(get_session), data: dict = B
return {"success": False, "error": str(e)}
@router.get("/parametros/aliquotas", response_model=List[AliquotaUFSchema])
async def listar_aliquotas(db: AsyncSession = Depends(get_session)):
result = await db.execute(select(AliquotaUF).order_by(AliquotaUF.uf, AliquotaUF.exercicio))
return result.scalars().all()
@router.get("/parametros/aliquotas")
async def listar_aliquotas(uf: str | None = None, db: AsyncSession = Depends(get_session)):
stmt = select(AliquotaUF).order_by(AliquotaUF.uf, AliquotaUF.exercicio.desc())
if uf:
stmt = stmt.where(AliquotaUF.uf == uf)
rows = (await db.execute(stmt)).scalars().all()
return [
{"uf": r.uf, "exercicio": int(r.exercicio), "aliquota": float(r.aliq_icms)}
for r in rows
]
@router.post("/parametros/aliquotas")
async def adicionar_aliquota(aliq: AliquotaUFSchema, db: AsyncSession = Depends(get_session)):
@@ -227,5 +259,88 @@ def baixar_template_excel():
headers={"Content-Disposition": "attachment; filename=template_aliquotas.xlsx"}
)
@router.post("/parametros/aliquotas/salvar")
async def salvar_aliquota(payload: dict, db: AsyncSession = Depends(get_session)):
uf = (payload.get("uf") or "").strip().upper()
exercicio = int(payload.get("exercicio") or 0)
aliquota = Decimal(str(payload.get("aliquota") or "0"))
orig_uf = (payload.get("original_uf") or "").strip().upper() or uf
orig_ex = int(payload.get("original_exercicio") or 0) or exercicio
if not uf or not exercicio or aliquota <= 0:
return JSONResponse(status_code=400, content={"error": "UF, exercício e alíquota são obrigatórios."})
# busca pelo registro original (antes da edição)
stmt = select(AliquotaUF).where(
AliquotaUF.uf == orig_uf,
AliquotaUF.exercicio == orig_ex
)
existente = (await db.execute(stmt)).scalar_one_or_none()
if existente:
# atualiza (inclusive a chave, se mudou)
existente.uf = uf
existente.exercicio = exercicio
existente.aliq_icms = aliquota
else:
# não existia o original -> upsert padrão
db.add(AliquotaUF(uf=uf, exercicio=exercicio, aliq_icms=aliquota))
await db.commit()
return {"success": True}
@router.post("/parametros/aliquotas/importar")
async def importar_aliquotas_csv(arquivo: UploadFile = File(...), db: AsyncSession = Depends(get_session)):
content = await arquivo.read()
text = content.decode("utf-8", errors="ignore")
# tenta ; depois ,
sniffer = csv.Sniffer()
dialect = sniffer.sniff(text.splitlines()[0] if text else "uf;exercicio;aliquota")
reader = csv.DictReader(io.StringIO(text), dialect=dialect)
count = 0
for row in reader:
uf = (row.get("uf") or row.get("UF") or "").strip().upper()
exercicio_str = (row.get("exercicio") or row.get("ano") or "").strip()
try:
exercicio = int(exercicio_str)
except Exception:
continue
aliquota_str = (row.get("aliquota") or row.get("aliq_icms") or "").replace(",", ".").strip()
if not uf or not exercicio or not aliquota_str:
continue
try:
aliquota = Decimal(aliquota_str)
except Exception:
continue
stmt = select(AliquotaUF).where(AliquotaUF.uf == uf, AliquotaUF.exercicio == exercicio)
existente = (await db.execute(stmt)).scalar_one_or_none()
if existente:
existente.aliq_icms = aliquota
else:
db.add(AliquotaUF(uf=uf, exercicio=exercicio, aliq_icms=aliquota))
count += 1
await db.commit()
return {"success": True, "qtd": count}
@router.delete("/parametros/aliquotas/{uf}/{exercicio}")
async def excluir_aliquota(uf: str, exercicio: int, db: AsyncSession = Depends(get_session)):
stmt = select(AliquotaUF).where(
AliquotaUF.uf == uf.upper(),
AliquotaUF.exercicio == exercicio
)
row = (await db.execute(stmt)).scalar_one_or_none()
if not row:
return JSONResponse(status_code=404, content={"error": "Registro não encontrado."})
await db.delete(row)
await db.commit()
return {"success": True}