diff --git a/app/routers/clientes.py b/app/routers/clientes.py index bb0384a..306221f 100644 --- a/app/routers/clientes.py +++ b/app/routers/clientes.py @@ -15,7 +15,7 @@ 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 +from ..normalize import normalizar_documento, normalizar_telefone, validar_dv_cpf, validar_dv_cnpj router = APIRouter(prefix="/clientes") templates = Jinja2Templates(directory="app/templates") @@ -30,6 +30,20 @@ def _ler_form_cliente(form: dict) -> dict: return {campo: (form.get(campo) or "").strip() for campo in db_clientes.CAMPOS_CLIENTE} +def _normalizar_documento_e_telefones(dados: dict) -> None: + """ + Grava CNPJ/CPF e telefones sempre sem máscara (só dígitos/letras), + igual ao que CLIENTE_CONTATO.TELEFONE já faz — evita que CLIENTE fique + com dois formatos diferentes convivendo (achado da revisão final: + docs/superpowers/plans/2026-08-13-painel-clientes-web.md). Só afeta + escritas novas feitas por este painel; registros legados só passam a + ficar sem máscara quando forem reeditados e salvos aqui. + """ + dados["CNPJ"] = normalizar_documento(dados["CNPJ"])[0] + dados["TELEFONE"] = normalizar_telefone(dados["TELEFONE"]) + dados["CELULAR"] = normalizar_telefone(dados["CELULAR"]) + + @router.get("", response_class=HTMLResponse) def listar( request: Request, @@ -59,6 +73,7 @@ def form_novo(request: Request, usuario: str = Depends(exigir_login)): async def criar(request: Request, usuario: str = Depends(exigir_login)): form = dict((await request.form())) dados = _ler_form_cliente(form) + _normalizar_documento_e_telefones(dados) confirmar_duplicado = form.get("confirmar_codigo_duplicado") == "1" confirmar_dv = form.get("confirmar_dv_invalido") == "1" @@ -141,6 +156,7 @@ def form_editar(request: Request, cliente_id: int, usuario: str = Depends(exigir async def editar(request: Request, cliente_id: int, usuario: str = Depends(exigir_login)): form = dict((await request.form())) dados = _ler_form_cliente(form) + _normalizar_documento_e_telefones(dados) confirmar_duplicado = form.get("confirmar_codigo_duplicado") == "1" if not confirmar_duplicado and db_clientes.codigo_em_uso(dados["CODIGO"], ignorar_id=cliente_id): diff --git a/tests/test_router_clientes.py b/tests/test_router_clientes.py index f74768a..c571ed5 100644 --- a/tests/test_router_clientes.py +++ b/tests/test_router_clientes.py @@ -83,6 +83,71 @@ def test_criar_cliente_codigo_duplicado_exige_confirmacao(monkeypatch): assert criado.get("ok") is True +def test_criar_cliente_normaliza_cnpj_e_telefones(monkeypatch): + monkeypatch.setattr(router_clientes.db_clientes, "codigo_em_uso", lambda codigo, ignorar_id=None: False) + capturado = {} + monkeypatch.setattr( + router_clientes.db_clientes, "criar_cliente", lambda dados: capturado.setdefault("dados", dados) and 42 + ) + + dados_form = {campo: "x" for campo in router_clientes.db_clientes.CAMPOS_CLIENTE} + dados_form.update( + { + "CODIGO": "000001", + "CNPJ": "11.222.333/0001-81", + "TELEFONE": "(75) 3333-4444", + "CELULAR": "(75) 99909-1780", + "IMPLANTACAO": "0", + "MENSALIDADE": "100", + "JUROS_MORA": "0", + "JUROS_MULTA": "0", + "DATA_CONTRATO": "2026-01-01", + "VENCIMENTO_CONTRATO": "2027-01-01", + "DIA_VENCIMENTO": "10", + "confirmar_dv_invalido": "1", + } + ) + + resposta = client.post("/clientes/novo", data=dados_form) + assert resposta.status_code == 303 + assert capturado["dados"]["CNPJ"] == "11222333000181" + assert capturado["dados"]["TELEFONE"] == "7533334444" + assert capturado["dados"]["CELULAR"] == "75999091780" + + +def test_editar_cliente_normaliza_cnpj_e_telefones(monkeypatch): + monkeypatch.setattr(router_clientes.db_clientes, "codigo_em_uso", lambda codigo, ignorar_id=None: False) + capturado = {} + monkeypatch.setattr( + router_clientes.db_clientes, + "atualizar_cliente", + lambda cliente_id, dados: capturado.setdefault("dados", dados), + ) + + dados_form = {campo: "x" for campo in router_clientes.db_clientes.CAMPOS_CLIENTE} + dados_form.update( + { + "CODIGO": "000001", + "CNPJ": "111.444.777-35", + "TELEFONE": "(75) 3333-4444", + "CELULAR": "(75) 99909-1780", + "IMPLANTACAO": "0", + "MENSALIDADE": "100", + "JUROS_MORA": "0", + "JUROS_MULTA": "0", + "DATA_CONTRATO": "2026-01-01", + "VENCIMENTO_CONTRATO": "2027-01-01", + "DIA_VENCIMENTO": "10", + } + ) + + resposta = client.post("/clientes/1/editar", data=dados_form) + assert resposta.status_code == 303 + assert capturado["dados"]["CNPJ"] == "11144477735" + assert capturado["dados"]["TELEFONE"] == "7533334444" + assert capturado["dados"]["CELULAR"] == "75999091780" + + def test_excluir_cliente_com_dependencia_mostra_erro(monkeypatch): monkeypatch.setattr( router_clientes.db_clientes,