diff --git a/app/main.py b/app/main.py index 7f531e7..816c496 100644 --- a/app/main.py +++ b/app/main.py @@ -24,10 +24,12 @@ from fastapi.responses import FileResponse from app.models import Fatura, SelicMensal, ParametrosFormula from datetime import date from app.utils import avaliar_formula +from app.routes import clientes app = FastAPI() templates = Jinja2Templates(directory="app/templates") +app.state.templates = templates app.mount("/static", StaticFiles(directory="app/static"), name="static") UPLOAD_DIR = "uploads/temp" @@ -419,6 +421,7 @@ async def export_excel(): from app.parametros import router as parametros_router app.include_router(parametros_router) +app.include_router(clientes.router) def is_homolog(): return os.getenv("APP_ENV", "dev") == "homolog" diff --git a/app/models.py b/app/models.py index 9feb83d..0092e17 100755 --- a/app/models.py +++ b/app/models.py @@ -80,3 +80,15 @@ class SelicMensal(Base): ano = Column(Integer, primary_key=True) mes = Column(Integer, primary_key=True) percentual = Column(Numeric(6, 4)) + +class Cliente(Base): + __tablename__ = "clientes" + __table_args__ = {"schema": "faturas"} + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + nome_fantasia = Column(String, nullable=False) + cnpj = Column(String(14), unique=True) + ativo = Column(Boolean, default=True) + data_criacao = Column(DateTime, default=datetime.utcnow) + data_atualizacao = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) + diff --git a/app/routes/clientes.py b/app/routes/clientes.py new file mode 100644 index 0000000..a7b1a2f --- /dev/null +++ b/app/routes/clientes.py @@ -0,0 +1,72 @@ +# app/routes/clientes.py +from fastapi import APIRouter, Request, Depends, HTTPException, Query +from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy import select, or_ +from app.database import get_session +from app.models import Cliente +from pydantic import BaseModel +from uuid import UUID +import uuid +from fastapi.responses import HTMLResponse + +router = APIRouter() + +@router.get("/clientes") +async def clientes_page(request: Request): + return request.app.state.templates.TemplateResponse("clientes.html", {"request": request}) + +class ClienteIn(BaseModel): + nome_fantasia: str + cnpj: str | None = None + ativo: bool = True + +@router.get("/api/clientes") +async def listar( + busca: str = Query(default="", description="Filtro por nome ou CNPJ"), + session: AsyncSession = Depends(get_session), +): + stmt = select(Cliente).order_by(Cliente.nome_fantasia) + if busca: + pattern = f"%{busca}%" + stmt = select(Cliente).where( + or_( + Cliente.nome_fantasia.ilike(pattern), + Cliente.cnpj.ilike(pattern), + ) + ).order_by(Cliente.nome_fantasia) + + res = await session.execute(stmt) + clientes = res.scalars().all() + return [ + { + "id": str(c.id), + "nome_fantasia": c.nome_fantasia, + "cnpj": c.cnpj, + "ativo": c.ativo, + } + for c in clientes + ] + +@router.post("/api/clientes") +async def criar_cliente(body: ClienteIn, session: AsyncSession = Depends(get_session)): + cliente = Cliente(**body.dict()) + session.add(cliente) + await session.commit() + return {"id": str(cliente.id)} + +@router.put("/api/clientes/{id}") +async def editar_cliente(id: UUID, body: ClienteIn, session: AsyncSession = Depends(get_session)): + await session.execute( + Cliente.__table__.update().where(Cliente.id == id).values(**body.dict()) + ) + await session.commit() + return {"ok": True} + +@router.delete("/api/clientes/{id}") +async def excluir(id: uuid.UUID, session: AsyncSession = Depends(get_session)): + obj = await session.get(Cliente, id) + if not obj: + raise HTTPException(404, "Cliente não encontrado") + await session.delete(obj) + await session.commit() + return {"ok": True} diff --git a/app/templates/clientes.html b/app/templates/clientes.html new file mode 100644 index 0000000..2989177 --- /dev/null +++ b/app/templates/clientes.html @@ -0,0 +1,502 @@ +{% extends "index.html" %} +{% block title %}Clientes{% endblock %} +{% block content %} +
| Cliente | +CNPJ | +Status | +Ações | +
|---|---|---|---|
| Nenhum cliente encontrado. | |||