fix: busca de clientes restrita ao campo escolhido em ordenar_por

Antes, digitar qualquer coisa na busca comparava com CODIGO, CNPJ,
RAZAO e FANTASIA ao mesmo tempo (OR), entao escolher 'Ordenar por:
Codigo' e buscar '242' trazia tambem clientes cujo CNPJ ou Razao
continham '242' em outro lugar. Agora a busca usa so a coluna
selecionada no dropdown (mesma whitelist ja usada pra ordenacao).

listar_clientes()/contar_clientes() e o template ganharam o ajuste;
o dropdown mudou de rotulo pra 'Buscar/ordenar por' pra deixar claro
que controla os dois.

93/93 testes passando.
This commit is contained in:
Gustavo
2026-08-13 14:24:09 -03:00
parent 8d83122e98
commit 2f1d008404
6 changed files with 25 additions and 21 deletions
+10 -13
View File
@@ -34,21 +34,22 @@ class ClienteComDependenciasError(Exception):
def listar_clientes(
busca: str | None = None, limite: int = 100, offset: int = 0, ordenar_por: str = ORDENACAO_PADRAO
) -> list[dict]:
coluna_ordenacao = ORDENACOES_VALIDAS.get(ordenar_por, ORDENACOES_VALIDAS[ORDENACAO_PADRAO])
coluna = ORDENACOES_VALIDAS.get(ordenar_por, ORDENACOES_VALIDAS[ORDENACAO_PADRAO])
conn = get_connection()
try:
with conn.cursor() as cur:
if busca:
# A busca é restrita à mesma coluna escolhida em "ordenar_por"
# — selecionar "Código" busca só em CODIGO, não em todos os
# campos de uma vez.
sql = (
f"SELECT {_COLUNAS_SELECT} FROM CLIENTE "
"WHERE CODIGO LIKE %s OR CNPJ LIKE %s OR RAZAO LIKE %s OR FANTASIA LIKE %s "
f"ORDER BY {coluna_ordenacao} LIMIT %s OFFSET %s"
f"WHERE {coluna} LIKE %s ORDER BY {coluna} LIMIT %s OFFSET %s"
)
termo = f"%{busca}%"
cur.execute(sql, (termo, termo, termo, termo, limite, offset))
cur.execute(sql, (f"%{busca}%", limite, offset))
else:
cur.execute(
f"SELECT {_COLUNAS_SELECT} FROM CLIENTE ORDER BY {coluna_ordenacao} LIMIT %s OFFSET %s",
f"SELECT {_COLUNAS_SELECT} FROM CLIENTE ORDER BY {coluna} LIMIT %s OFFSET %s",
(limite, offset),
)
return cur.fetchall()
@@ -80,17 +81,13 @@ def proximo_codigo_sugerido() -> str:
return str(proximo).zfill(6)
def contar_clientes(busca: str | None = None) -> int:
def contar_clientes(busca: str | None = None, ordenar_por: str = ORDENACAO_PADRAO) -> int:
coluna = ORDENACOES_VALIDAS.get(ordenar_por, ORDENACOES_VALIDAS[ORDENACAO_PADRAO])
conn = get_connection()
try:
with conn.cursor() as cur:
if busca:
sql = (
"SELECT COUNT(*) AS total FROM CLIENTE "
"WHERE CODIGO LIKE %s OR CNPJ LIKE %s OR RAZAO LIKE %s OR FANTASIA LIKE %s"
)
termo = f"%{busca}%"
cur.execute(sql, (termo, termo, termo, termo))
cur.execute(f"SELECT COUNT(*) AS total FROM CLIENTE WHERE {coluna} LIKE %s", (f"%{busca}%",))
else:
cur.execute("SELECT COUNT(*) AS total FROM CLIENTE")
return cur.fetchone()["total"]
+1 -1
View File
@@ -90,7 +90,7 @@ def listar(
ordenar_por = db_clientes.ORDENACAO_PADRAO
pagina = max(pagina, 1)
total = db_clientes.contar_clientes(busca=busca or None)
total = db_clientes.contar_clientes(busca=busca or None, ordenar_por=ordenar_por)
total_paginas = max(math.ceil(total / TAMANHO_PAGINA), 1)
pagina = min(pagina, total_paginas)
offset = (pagina - 1) * TAMANHO_PAGINA
+2 -2
View File
@@ -4,14 +4,14 @@
{% block conteudo %}
<h1>Clientes</h1>
<form method="get" action="/clientes">
<input type="text" name="busca" value="{{ busca or '' }}" placeholder="Buscar por código, CNPJ, razão ou fantasia">
<label for="ordenar_por">Ordenar por</label>
<label for="ordenar_por">Buscar/ordenar por</label>
<select id="ordenar_por" name="ordenar_por">
<option value="razao" {% if ordenar_por == "razao" %}selected{% endif %}>Razão social</option>
<option value="codigo" {% if ordenar_por == "codigo" %}selected{% endif %}>Código</option>
<option value="fantasia" {% if ordenar_por == "fantasia" %}selected{% endif %}>Fantasia</option>
<option value="cnpj" {% if ordenar_por == "cnpj" %}selected{% endif %}>CNPJ</option>
</select>
<input type="text" name="busca" value="{{ busca or '' }}" placeholder="Buscar só no campo escolhido acima">
<button type="submit">Buscar</button>
</form>
<p><a class="botao" href="/clientes/novo">+ Novo cliente</a></p>