# app/routers/clientes.py """ Rotas de gestão de CLIENTE: listar/buscar, criar, editar, ver detalhe (contatos + status de Clientes_Chaves), excluir. """ from typing import Optional from urllib.parse import urlencode from fastapi import APIRouter, Depends, Form, Request from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.templating import Jinja2Templates from ..auth import exigir_login from ..db import chaves as db_chaves from ..db import clientes as db_clientes from ..db import contatos as db_contatos from ..normalize import normalizar_documento, validar_dv_cpf, validar_dv_cnpj router = APIRouter(prefix="/clientes") templates = Jinja2Templates(directory="app/templates") def _redirect_com_mensagem(url: str, mensagem: str, tipo: str = "success") -> RedirectResponse: separador = "&" if "?" in url else "?" return RedirectResponse(url + separador + urlencode({"mensagem": mensagem, "mensagem_tipo": tipo}), status_code=303) def _ler_form_cliente(form: dict) -> dict: return {campo: (form.get(campo) or "").strip() for campo in db_clientes.CAMPOS_CLIENTE} @router.get("", response_class=HTMLResponse) def listar( request: Request, busca: Optional[str] = None, mensagem: Optional[str] = None, mensagem_tipo: Optional[str] = None, usuario: str = Depends(exigir_login), ): clientes = db_clientes.listar_clientes(busca=busca or None) return templates.TemplateResponse( request, "clientes_lista.html", {"clientes": clientes, "busca": busca, "mensagem": mensagem, "mensagem_tipo": mensagem_tipo}, ) @router.get("/novo", response_class=HTMLResponse) def form_novo(request: Request, usuario: str = Depends(exigir_login)): return templates.TemplateResponse( request, "cliente_form.html", {"cliente": None, "dados": {c: "" for c in db_clientes.CAMPOS_CLIENTE}, "campos": db_clientes.CAMPOS_CLIENTE}, ) @router.post("/novo") async def criar(request: Request, usuario: str = Depends(exigir_login)): form = dict((await request.form())) dados = _ler_form_cliente(form) confirmar_duplicado = form.get("confirmar_codigo_duplicado") == "1" if not confirmar_duplicado and db_clientes.codigo_em_uso(dados["CODIGO"]): return templates.TemplateResponse( request, "cliente_form.html", {"cliente": None, "dados": dados, "campos": db_clientes.CAMPOS_CLIENTE, "aviso_codigo_duplicado": True}, ) documento_normalizado, formato_valido, tipo = normalizar_documento(dados["CNPJ"]) dv_invalido = False if formato_valido: dv_invalido = not ( validar_dv_cpf(documento_normalizado) if tipo == "CPF" else validar_dv_cnpj(documento_normalizado) ) if dv_invalido and form.get("confirmar_dv_invalido") != "1": return templates.TemplateResponse( request, "cliente_form.html", {"cliente": None, "dados": dados, "campos": db_clientes.CAMPOS_CLIENTE, "aviso_dv_invalido": True}, ) novo_id = db_clientes.criar_cliente(dados) return _redirect_com_mensagem(f"/clientes/{novo_id}", "Cliente criado.") @router.get("/{cliente_id}", response_class=HTMLResponse) def detalhe( request: Request, cliente_id: int, mensagem: Optional[str] = None, mensagem_tipo: Optional[str] = None, usuario: str = Depends(exigir_login), ): cliente = db_clientes.obter_cliente(cliente_id) if cliente is None: return _redirect_com_mensagem("/clientes", "Cliente não encontrado.", "danger") contatos = db_contatos.listar_contatos_por_cliente(cliente_id) status = db_chaves.status_chaves(cliente["CODIGO"]) return templates.TemplateResponse( request, "cliente_detalhe.html", { "cliente": cliente, "contatos": contatos, "status_chaves": status, "mensagem": mensagem, "mensagem_tipo": mensagem_tipo, }, ) @router.get("/{cliente_id}/editar", response_class=HTMLResponse) def form_editar(request: Request, cliente_id: int, usuario: str = Depends(exigir_login)): cliente = db_clientes.obter_cliente(cliente_id) if cliente is None: return _redirect_com_mensagem("/clientes", "Cliente não encontrado.", "danger") return templates.TemplateResponse( request, "cliente_form.html", {"cliente": cliente, "dados": cliente, "campos": db_clientes.CAMPOS_CLIENTE}, ) @router.post("/{cliente_id}/editar") async def editar(request: Request, cliente_id: int, usuario: str = Depends(exigir_login)): form = dict((await request.form())) dados = _ler_form_cliente(form) confirmar_duplicado = form.get("confirmar_codigo_duplicado") == "1" if not confirmar_duplicado and db_clientes.codigo_em_uso(dados["CODIGO"], ignorar_id=cliente_id): return templates.TemplateResponse( request, "cliente_form.html", {"cliente": {"ID": cliente_id}, "dados": dados, "campos": db_clientes.CAMPOS_CLIENTE, "aviso_codigo_duplicado": True}, ) db_clientes.atualizar_cliente(cliente_id, dados) return _redirect_com_mensagem(f"/clientes/{cliente_id}", "Cliente atualizado.") @router.post("/{cliente_id}/excluir") def excluir(cliente_id: int, usuario: str = Depends(exigir_login)): try: db_clientes.excluir_cliente(cliente_id) except db_clientes.ClienteComDependenciasError as exc: return _redirect_com_mensagem(f"/clientes/{cliente_id}", str(exc), "danger") return _redirect_com_mensagem("/clientes", "Cliente excluído.")