- app/routers/contatos.py: CLIENTE_CONTATO.TELEFONE passa a ser gravado
sempre com DDI 55 (normalizar_telefone_com_ddi, mesma normalização já
usada em CLIENTE.TELEFONE/CELULAR) — confirmado no node '10 - Validar
Telefones' do workflow n8n de produção (ER6Piy9yu93uOVuY) que o
telefone é usado exatamente como está gravado, sem nenhuma
normalização própria. Um contato cadastrado pelo painel sem o
funcionário digitar '55' na frente nunca recebia a chave automática
por WhatsApp — falha silenciosa, sem nenhum erro visível.
- app/db/clientes.py, app/db/contatos.py, app/db/funcionarios.py:
excluir_cliente/atualizar_contato/excluir_contato/redefinir_senha
passam a retornar bool (cur.rowcount > 0) em vez de None — um
ID inexistente não gera erro nenhum do MySQL (WHERE só não bate com
nada), então sem checar rowcount o router não tinha como saber que
não alterou/excluiu nada.
- app/routers/clientes.py, app/routers/contatos.py,
app/routers/funcionarios.py: editar/excluir/redefinir-senha/
alternar-ativo passam a checar essa existência e mostrar 'não
encontrado' em vez de registrar 'sucesso' no log e redirecionar pra
uma tela que também vai dizer que não encontrou nada.
- app/templates/clientes_lista.html: busca não estava com urlencode nos
links de paginação/ordenação — um termo de busca com '&' (comum em
razão social, ex. 'Fulano & Cia') cortava o resto da query string do
link, perdendo página/ordenação.
Suíte completa (192 testes) passando, com 13 testes novos cobrindo os
casos de 'não encontrado' e o DDI do telefone de contato.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Tabela LOG_PAINEL (nova, ja criada no banco de dev) + app/db/log.py:
toda criacao/edicao/exclusao de cliente e contato fica registrada
(usuario, acao, sucesso/erro, detalhe). Tela /log mostra esse
historico.
- app/n8n_client.py: leitura opcional (N8N_API_URL/N8N_API_KEY) da
Data Table pagamentos_processados do n8n, mostrando os envios
automaticos de chave na mesma tela /log. Degrada de forma segura
(lista vazia) se nao configurado ou se a chamada falhar.
- Lista de clientes ganha ordenacao configuravel (codigo/razao/
fantasia/CNPJ) via whitelist, alem da busca que ja existia.
- CODIGO duplicado agora BLOQUEIA de verdade na criacao/edicao (sem
bypass) — antes so avisava com opcao de confirmar mesmo assim.
- Formulario de novo cliente sugere o proximo CODIGO sequencial
(editavel), ignorando a faixa reservada para dados de teste
(>= 900000) para nao ser contaminado por sobra de teste no banco.
- IMPLANTACAO/MENSALIDADE/JUROS_MORA/JUROS_MULTA/DATA_CONTRATO/
VENCIMENTO_CONTRATO deixam de ser obrigatorios — em branco, gravam
default (0,00 / hoje) em vez de bloquear o cadastro. Só CODIGO/CNPJ/
RAZAO/FANTASIA continuam obrigatorios.
- Limpeza: removidas 10 linhas de teste vazadas (CODIGO 999902) que
ficaram no banco de dev por sessoes de teste interrompidas.
69/69 testes passando (16 novos).
CSRF: novo app/csrf.py + middleware em app/main.py garantem um cookie
csrf_token por navegador; todo formulario que muda estado (criar/editar/
excluir cliente, adicionar/editar/excluir contato) embute esse valor
como campo oculto, e Depends(exigir_csrf) confere no POST que o valor
enviado bate com o cookie antes de deixar a rota executar. Verificado
ponta a ponta com o app real rodando (curl): token errado -> 403,
token correto -> 303.
Paginacao: db_clientes.listar_clientes ganha offset, nova
contar_clientes(); GET /clientes aceita ?pagina=N (100 clientes por
pagina), template mostra Anterior/Proxima e o total.
53/53 testes passando (8 novos).