chore: baseline import of existing Coordenador GLPI V1 project
Snapshot of the pre-existing, working V1 automation (n8n workflow + SQL query + docker-compose + README) exactly as found on disk, before any V2 changes. .env is intentionally not tracked (gitignored, contains local secrets). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
N8N_PORT=5678
|
||||
N8N_HOST=localhost
|
||||
N8N_PROTOCOL=http
|
||||
GENERIC_TIMEZONE=America/Sao_Paulo
|
||||
TZ=America/Sao_Paulo
|
||||
|
||||
N8N_BASIC_AUTH_ACTIVE=true
|
||||
N8N_BASIC_AUTH_USER=admin
|
||||
N8N_BASIC_AUTH_PASSWORD=troque-esta-senha
|
||||
N8N_ENCRYPTION_KEY=troque-esta-chave-com-32-caracteres
|
||||
@@ -0,0 +1 @@
|
||||
.env
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,248 @@
|
||||
# Coordenador GLPI - Chamados Abertos
|
||||
|
||||
Projeto n8n para atuar como coordenador diario de Suporte de TI, analisando chamados abertos no GLPI e enviando no Slack os 10 chamados que precisam de acao imediata.
|
||||
|
||||
## Objetivo
|
||||
|
||||
Todos os dias uteis, o workflow consulta o banco do GLPI, calcula um score operacional para cada chamado aberto e envia uma lista priorizada no Slack.
|
||||
|
||||
O foco nao e apenas listar chamados antigos. O ranking considera:
|
||||
|
||||
- SLA vencido ou proximo de vencer
|
||||
- tempo sem interacao humana
|
||||
- prioridade, urgencia e impacto
|
||||
- idade do chamado
|
||||
- chamado sem tecnico atribuido
|
||||
- chamados em categorias e entidades reais do GLPI
|
||||
|
||||
## Arquivos
|
||||
|
||||
- `Coordenador GLPI - Chamados Abertos Slack.n8n.json`: workflow importavel no n8n
|
||||
- `sql/top_10_chamados_abertos_glpi.sql`: query base usada pelo workflow
|
||||
- `.env.example`: variaveis para subir n8n localmente
|
||||
- `docker-compose.yml`: n8n local via Docker
|
||||
|
||||
## Como configurar
|
||||
|
||||
1. Suba o n8n local, se necessario:
|
||||
|
||||
```powershell
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
2. Acesse:
|
||||
|
||||
```text
|
||||
http://localhost:5678
|
||||
```
|
||||
|
||||
3. Importe o workflow:
|
||||
|
||||
```text
|
||||
Coordenador GLPI - Chamados Abertos Slack.n8n.json
|
||||
```
|
||||
|
||||
4. Configure a credencial MySQL no node:
|
||||
|
||||
```text
|
||||
MySQL - Top 10 chamados abertos
|
||||
```
|
||||
|
||||
5. Abra o node `Config - Coordenador GLPI` e preencha:
|
||||
|
||||
- `slack_webhook_url`: webhook do canal Slack
|
||||
- `dias_sem_interacao_alerta`: padrao `2`
|
||||
- `horas_sla_risco`: padrao `8`
|
||||
|
||||
6. Execute pelo `Manual Trigger` para validar.
|
||||
|
||||
7. Ative o workflow para rodar pelo `Schedule Trigger - Dias uteis 08h`.
|
||||
|
||||
## Metodologia de priorizacao
|
||||
|
||||
Cada chamado aberto recebe um `score_criticidade`, mas a lista final nao e mais apenas o top 10 geral. O workflow monta a lista por blocos para evitar que chamados muito antigos monopolizem todos os dias.
|
||||
|
||||
Blocos do top 10:
|
||||
|
||||
- 3 chamados com SLA vencido mais criticos
|
||||
- 3 chamados com maior tempo sem interacao
|
||||
- 2 chamados sem tecnico atribuido
|
||||
- 2 chamados de prioridade alta mais recentes
|
||||
|
||||
Se algum bloco nao tiver chamados suficientes, o complemento vem do ranking geral.
|
||||
|
||||
O mesmo chamado nao entra duas vezes. Se ele ja apareceu em um bloco anterior, e removido dos blocos seguintes.
|
||||
|
||||
### Score
|
||||
|
||||
Pesos principais:
|
||||
|
||||
- SLA vencido: `+100`
|
||||
- SLA vencendo nas proximas horas configuradas: `+45`
|
||||
- chamado sem interacao ha 7 dias ou mais: `+35`
|
||||
- chamado sem interacao ha 3 a 6 dias: `+25`
|
||||
- chamado sem interacao ha 1 a 2 dias: `+10`
|
||||
- prioridade GLPI: `priority * 8`
|
||||
- urgencia GLPI: `urgency * 5`
|
||||
- impacto GLPI: `impact * 5`
|
||||
- idade do chamado: ate `+30`
|
||||
- sem tecnico atribuido: `+25`
|
||||
|
||||
O resultado e ordenado por:
|
||||
|
||||
1. `score_criticidade` desc
|
||||
2. chamados com SLA vencido primeiro
|
||||
3. maior tempo sem interacao
|
||||
4. chamados mais antigos
|
||||
|
||||
## Reincidencia
|
||||
|
||||
O workflow controla reincidencia usando `staticData` global do n8n, sem gravar nada no banco do GLPI.
|
||||
|
||||
Regra:
|
||||
|
||||
- apareceu 1 vez: normal
|
||||
- apareceu 2 dias seguidos: marcado como reincidente
|
||||
- apareceu 3 dias seguidos ou mais: escalar para coordenacao
|
||||
|
||||
Campos salvos no `staticData`:
|
||||
|
||||
- `ultima_data_disparo`
|
||||
- `ultimos_chamados_enviados`
|
||||
- `reincidencia_chamados`
|
||||
|
||||
Se o workflow for duplicado, recriado ou importado como novo workflow, esse historico pode ser perdido porque pertence ao workflow no n8n.
|
||||
|
||||
## Tempo sem interacao
|
||||
|
||||
O campo `dias_sem_interacao` considera a maior data encontrada entre:
|
||||
|
||||
- followups publicos do chamado: `date`, `date_mod`, `date_creation`
|
||||
- tarefas do chamado: `date`, `date_mod`, `date_creation`
|
||||
- modificacao do chamado: `glpi_tickets.date_mod`
|
||||
- abertura do chamado: `glpi_tickets.date`
|
||||
|
||||
Isso evita marcar um chamado como parado quando alguem acabou de adicionar ou alterar uma tarefa no GLPI, mesmo que a tarefa esteja planejada para outro dia.
|
||||
|
||||
Se a maior data encontrada estiver no futuro por causa de uma tarefa planejada, o contador fica em `0` dias sem interacao, evitando valores negativos no relatorio.
|
||||
|
||||
## Regra de chamados abertos
|
||||
|
||||
O SQL considera abertos todos os chamados com:
|
||||
|
||||
```sql
|
||||
is_deleted = false
|
||||
AND status NOT IN (5, 6)
|
||||
```
|
||||
|
||||
Este gatilho principal ignora chamados das categorias:
|
||||
|
||||
- `ADMINISTRATIVO`
|
||||
- `DESENVOLVIMENTO`
|
||||
- `INFRA`
|
||||
|
||||
O filtro usa o nome completo da categoria (`completename`) ou o nome simples (`name`) iniciando com esses termos, entao tambem remove subcategorias dessas filas.
|
||||
|
||||
No GLPI, normalmente:
|
||||
|
||||
- `5`: solucionado
|
||||
- `6`: fechado
|
||||
|
||||
## Campos usados
|
||||
|
||||
A query usa tabelas comuns do GLPI:
|
||||
|
||||
- `glpi_tickets`
|
||||
- `glpi_itilcategories`
|
||||
- `glpi_entities`
|
||||
- `glpi_itilfollowups`
|
||||
- `glpi_tickettasks`
|
||||
- `glpi_tickets_users`
|
||||
- `glpi_users`
|
||||
|
||||
Se sua versao do GLPI tiver customizacoes, valide primeiro a query `sql/top_10_chamados_abertos_glpi.sql` diretamente no banco.
|
||||
|
||||
## Saida no Slack
|
||||
|
||||
O Slack recebe uma mensagem curta com:
|
||||
|
||||
- top 10 chamados para atacar hoje
|
||||
- tecnico atribuido, quando existir
|
||||
- SLA
|
||||
- dias sem interacao
|
||||
- dias aberto
|
||||
- reincidencia
|
||||
- link do chamado, se `glpi_base_url` estiver configurado no workflow
|
||||
|
||||
Campos removidos da mensagem para reduzir ruido:
|
||||
|
||||
- motivo
|
||||
- acao
|
||||
- prazo
|
||||
|
||||
Se o agente de IA falhar, o workflow envia a mensagem curta gerada por codigo, sem depender da IA.
|
||||
|
||||
## Agente de IA do n8n com Z IA
|
||||
|
||||
O workflow usa o node:
|
||||
|
||||
```text
|
||||
AI Agent - Revisar mensagem
|
||||
```
|
||||
|
||||
Por padrao, ele esta conectado ao node:
|
||||
|
||||
```text
|
||||
Z IA Chat Model
|
||||
```
|
||||
|
||||
Esse node usa o chat model compativel com OpenAI do n8n, mas a credencial deve ser configurada para a Z IA.
|
||||
|
||||
A IA nao monta mais a mensagem do zero. O node `Code - Reincidencia e mensagem curta` monta a mensagem final de forma deterministica, e a IA apenas revisa clareza e reduz texto.
|
||||
|
||||
Regras do prompt:
|
||||
|
||||
- nao adicionar fatos
|
||||
- nao criar motivo
|
||||
- nao criar acao
|
||||
- nao criar prazo
|
||||
- nao alterar IDs, tecnicos, datas, SLA, dias, reincidencia ou links
|
||||
- nao usar tom agressivo
|
||||
|
||||
No n8n, abra o node:
|
||||
|
||||
```text
|
||||
Z IA Chat Model
|
||||
```
|
||||
|
||||
Configure:
|
||||
|
||||
- credencial `Z IA`
|
||||
- endpoint/base URL da Z IA, se a credencial permitir
|
||||
- modelo correto disponibilizado pela Z IA, por exemplo `glm-4.5-flash`
|
||||
|
||||
No arquivo importavel deixei o modelo como `glm-4.5-flash`. Se sua conta Z IA usar outro nome de modelo, troque pelo nome exato exibido na plataforma.
|
||||
|
||||
Se aparecer `The resource you are requesting could not be found`, revise principalmente:
|
||||
|
||||
- Base URL da credencial: normalmente `https://api.z.ai/api/paas/v4`
|
||||
- Modelo: precisa existir na sua conta, por exemplo `glm-4.5-flash`
|
||||
- Chave API: precisa ser da Z IA, nao da OpenAI
|
||||
- Node usado: mantenha `Z IA Chat Model` conectado ao `AI Agent - Revisar mensagem`
|
||||
|
||||
Se a Z IA aparecer no seu n8n como node proprio, mantenha o `AI Agent - Revisar mensagem` e substitua somente o subnode `Z IA Chat Model` pelo modelo oficial da Z IA.
|
||||
|
||||
## Recomendacao direta
|
||||
|
||||
Nao trate isso como relatorio bonito. Trate como fila diaria de comando.
|
||||
|
||||
Minha sugestao operacional:
|
||||
|
||||
- rodar as 08h no canal da lideranca de suporte
|
||||
- exigir responsavel e prazo para cada um dos 10 chamados ate 10h
|
||||
- repetir apenas os chamados que continuarem parados no dia seguinte
|
||||
- se um chamado aparecer 3 dias seguidos, escalar para coordenacao/gestao
|
||||
- separar um segundo workflow para chamados sem tecnico atribuido, porque isso e falha de triagem, nao backlog comum
|
||||
- criar outro alerta intradiario para SLA vencendo nas proximas 2 horas
|
||||
|
||||
Se quiser resultado real, nao basta notificar. Tem que transformar a mensagem do Slack em ritual diario de cobranca.
|
||||
@@ -0,0 +1,22 @@
|
||||
services:
|
||||
n8n:
|
||||
image: docker.n8n.io/n8nio/n8n:latest
|
||||
container_name: n8n-coordenador-glpi
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${N8N_PORT:-5678}:5678"
|
||||
environment:
|
||||
- GENERIC_TIMEZONE=${GENERIC_TIMEZONE:-America/Sao_Paulo}
|
||||
- TZ=${TZ:-America/Sao_Paulo}
|
||||
- N8N_HOST=${N8N_HOST:-localhost}
|
||||
- N8N_PORT=5678
|
||||
- N8N_PROTOCOL=${N8N_PROTOCOL:-http}
|
||||
- N8N_BASIC_AUTH_ACTIVE=${N8N_BASIC_AUTH_ACTIVE:-true}
|
||||
- N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER:-admin}
|
||||
- N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD:-troque-esta-senha}
|
||||
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY:-troque-esta-chave-com-32-caracteres}
|
||||
volumes:
|
||||
- n8n_data:/home/node/.n8n
|
||||
|
||||
volumes:
|
||||
n8n_data:
|
||||
@@ -0,0 +1,213 @@
|
||||
-- Top 10 chamados abertos por blocos operacionais.
|
||||
-- Blocos:
|
||||
-- - 3 chamados com SLA vencido mais criticos
|
||||
-- - 3 chamados com maior tempo sem interacao
|
||||
-- - 2 chamados sem tecnico atribuido
|
||||
-- - 2 chamados de prioridade alta mais recentes
|
||||
-- Se faltar item em algum bloco, o complemento vem do ranking geral.
|
||||
--
|
||||
-- Ajuste os parametros abaixo no workflow n8n:
|
||||
-- {DIAS_SEM_INTERACAO_ALERTA}
|
||||
-- {HORAS_SLA_RISCO}
|
||||
-- {GLPI_BASE_URL}
|
||||
|
||||
WITH ultima_interacao AS (
|
||||
SELECT
|
||||
tickets_id,
|
||||
MAX(data_interacao) AS ultima_interacao_em
|
||||
FROM (
|
||||
SELECT tickets_id, MAX(data_interacao) AS data_interacao
|
||||
FROM (
|
||||
SELECT items_id AS tickets_id, date AS data_interacao
|
||||
FROM glpi_itilfollowups
|
||||
WHERE itemtype = 'Ticket'
|
||||
AND is_private = 0
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT items_id AS tickets_id, date_mod AS data_interacao
|
||||
FROM glpi_itilfollowups
|
||||
WHERE itemtype = 'Ticket'
|
||||
AND is_private = 0
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT items_id AS tickets_id, date_creation AS data_interacao
|
||||
FROM glpi_itilfollowups
|
||||
WHERE itemtype = 'Ticket'
|
||||
AND is_private = 0
|
||||
) followup_datas
|
||||
WHERE data_interacao IS NOT NULL
|
||||
GROUP BY tickets_id
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT tickets_id, MAX(data_interacao) AS data_interacao
|
||||
FROM (
|
||||
SELECT tickets_id, date AS data_interacao
|
||||
FROM glpi_tickettasks
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT tickets_id, date_mod AS data_interacao
|
||||
FROM glpi_tickettasks
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT tickets_id, date_creation AS data_interacao
|
||||
FROM glpi_tickettasks
|
||||
) task_datas
|
||||
WHERE data_interacao IS NOT NULL
|
||||
GROUP BY tickets_id
|
||||
) interacoes
|
||||
GROUP BY tickets_id
|
||||
), tecnicos AS (
|
||||
SELECT
|
||||
tu.tickets_id,
|
||||
GROUP_CONCAT(TRIM(CONCAT(COALESCE(u.firstname, ''), ' ', COALESCE(u.realname, u.name))) SEPARATOR ', ') AS tecnicos
|
||||
FROM glpi_tickets_users tu
|
||||
LEFT JOIN glpi_users u ON u.id = tu.users_id
|
||||
WHERE tu.type = 2
|
||||
GROUP BY tu.tickets_id
|
||||
), chamados_base AS (
|
||||
SELECT
|
||||
t.id,
|
||||
t.name AS titulo,
|
||||
t.status,
|
||||
CASE t.status
|
||||
WHEN 1 THEN 'Novo'
|
||||
WHEN 2 THEN 'Em atendimento'
|
||||
WHEN 3 THEN 'Planejado'
|
||||
WHEN 4 THEN 'Pendente'
|
||||
ELSE CONCAT('Status ', t.status)
|
||||
END AS status_nome,
|
||||
t.date AS aberto_em,
|
||||
t.date_mod AS modificado_em,
|
||||
t.time_to_resolve AS sla_resolver_ate,
|
||||
t.priority,
|
||||
t.urgency,
|
||||
t.impact,
|
||||
COALESCE(e.completename, e.name, 'Nao informado') AS entidade,
|
||||
COALESCE(c.completename, c.name, 'Sem categoria') AS categoria,
|
||||
COALESCE(tecnicos.tecnicos, 'Sem tecnico atribuido') AS tecnico_atribuido,
|
||||
GREATEST(
|
||||
COALESCE(ultima_interacao.ultima_interacao_em, '1970-01-01 00:00:00'),
|
||||
COALESCE(t.date_mod, '1970-01-01 00:00:00'),
|
||||
COALESCE(t.date, '1970-01-01 00:00:00')
|
||||
) AS ultima_interacao_em,
|
||||
TIMESTAMPDIFF(DAY, t.date, NOW()) AS dias_aberto,
|
||||
GREATEST(TIMESTAMPDIFF(DAY, GREATEST(
|
||||
COALESCE(ultima_interacao.ultima_interacao_em, '1970-01-01 00:00:00'),
|
||||
COALESCE(t.date_mod, '1970-01-01 00:00:00'),
|
||||
COALESCE(t.date, '1970-01-01 00:00:00')
|
||||
), NOW()), 0) AS dias_sem_interacao,
|
||||
TIMESTAMPDIFF(HOUR, NOW(), t.time_to_resolve) AS horas_ate_sla,
|
||||
CASE WHEN t.time_to_resolve IS NOT NULL AND t.time_to_resolve < NOW() THEN 1 ELSE 0 END AS sla_vencido,
|
||||
CASE
|
||||
WHEN t.time_to_resolve IS NOT NULL
|
||||
AND t.time_to_resolve >= NOW()
|
||||
AND TIMESTAMPDIFF(HOUR, NOW(), t.time_to_resolve) <= {HORAS_SLA_RISCO} THEN 1
|
||||
ELSE 0
|
||||
END AS sla_em_risco,
|
||||
CASE WHEN tecnicos.tecnicos IS NULL THEN 1 ELSE 0 END AS sem_tecnico,
|
||||
CONCAT('{GLPI_BASE_URL}', '/front/ticket.form.php?id=', t.id) AS link_glpi
|
||||
FROM glpi_tickets t
|
||||
LEFT JOIN glpi_entities e ON e.id = t.entities_id
|
||||
LEFT JOIN glpi_itilcategories c ON c.id = t.itilcategories_id
|
||||
LEFT JOIN ultima_interacao ON ultima_interacao.tickets_id = t.id
|
||||
LEFT JOIN tecnicos ON tecnicos.tickets_id = t.id
|
||||
WHERE t.is_deleted = false
|
||||
AND t.status NOT IN (5, 6)
|
||||
AND COALESCE(c.completename, c.name, '') NOT LIKE 'ADMINISTRATIVO%'
|
||||
AND COALESCE(c.completename, c.name, '') NOT LIKE 'DESENVOLVIMENTO%'
|
||||
AND COALESCE(c.completename, c.name, '') NOT LIKE 'INFRA%'
|
||||
), chamados_ranked AS (
|
||||
SELECT
|
||||
id,
|
||||
titulo,
|
||||
status_nome,
|
||||
aberto_em,
|
||||
modificado_em,
|
||||
ultima_interacao_em,
|
||||
dias_aberto,
|
||||
dias_sem_interacao,
|
||||
sla_resolver_ate,
|
||||
horas_ate_sla,
|
||||
sla_vencido,
|
||||
sla_em_risco,
|
||||
priority AS prioridade,
|
||||
urgency AS urgencia,
|
||||
impact AS impacto,
|
||||
entidade,
|
||||
categoria,
|
||||
tecnico_atribuido,
|
||||
sem_tecnico,
|
||||
link_glpi,
|
||||
(
|
||||
CASE WHEN sla_vencido = 1 THEN 100 ELSE 0 END
|
||||
+ CASE WHEN sla_em_risco = 1 THEN 45 ELSE 0 END
|
||||
+ CASE
|
||||
WHEN dias_sem_interacao >= 7 THEN 35
|
||||
WHEN dias_sem_interacao >= 3 THEN 25
|
||||
WHEN dias_sem_interacao >= {DIAS_SEM_INTERACAO_ALERTA} THEN 10
|
||||
ELSE 0
|
||||
END
|
||||
+ LEAST(dias_aberto, 30)
|
||||
+ (priority * 8)
|
||||
+ (urgency * 5)
|
||||
+ (impact * 5)
|
||||
+ CASE WHEN sem_tecnico = 1 THEN 25 ELSE 0 END
|
||||
) AS score_criticidade
|
||||
FROM chamados_base
|
||||
), sla_top AS (
|
||||
SELECT *, 'SLA vencido' AS bloco_origem, 1 AS bloco_ordem
|
||||
FROM chamados_ranked
|
||||
WHERE sla_vencido = 1
|
||||
ORDER BY score_criticidade DESC, dias_sem_interacao DESC, dias_aberto DESC
|
||||
LIMIT 3
|
||||
), sem_interacao_top AS (
|
||||
SELECT *, 'Sem interacao' AS bloco_origem, 2 AS bloco_ordem
|
||||
FROM chamados_ranked
|
||||
WHERE id NOT IN (SELECT id FROM sla_top)
|
||||
ORDER BY dias_sem_interacao DESC, score_criticidade DESC, dias_aberto DESC
|
||||
LIMIT 3
|
||||
), sem_tecnico_top AS (
|
||||
SELECT *, 'Sem tecnico' AS bloco_origem, 3 AS bloco_ordem
|
||||
FROM chamados_ranked
|
||||
WHERE sem_tecnico = 1
|
||||
AND id NOT IN (SELECT id FROM sla_top)
|
||||
AND id NOT IN (SELECT id FROM sem_interacao_top)
|
||||
ORDER BY score_criticidade DESC, dias_sem_interacao DESC, dias_aberto DESC
|
||||
LIMIT 2
|
||||
), prioridade_alta_recente_top AS (
|
||||
SELECT *, 'Prioridade alta recente' AS bloco_origem, 4 AS bloco_ordem
|
||||
FROM chamados_ranked
|
||||
WHERE prioridade >= 4
|
||||
AND id NOT IN (SELECT id FROM sla_top)
|
||||
AND id NOT IN (SELECT id FROM sem_interacao_top)
|
||||
AND id NOT IN (SELECT id FROM sem_tecnico_top)
|
||||
ORDER BY aberto_em DESC, score_criticidade DESC
|
||||
LIMIT 2
|
||||
), selecionados AS (
|
||||
SELECT * FROM sla_top
|
||||
UNION ALL
|
||||
SELECT * FROM sem_interacao_top
|
||||
UNION ALL
|
||||
SELECT * FROM sem_tecnico_top
|
||||
UNION ALL
|
||||
SELECT * FROM prioridade_alta_recente_top
|
||||
), complemento AS (
|
||||
SELECT *, 'Ranking geral' AS bloco_origem, 5 AS bloco_ordem
|
||||
FROM chamados_ranked
|
||||
WHERE id NOT IN (SELECT id FROM selecionados)
|
||||
ORDER BY score_criticidade DESC, sla_vencido DESC, dias_sem_interacao DESC, dias_aberto DESC
|
||||
LIMIT 10
|
||||
)
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT * FROM selecionados
|
||||
UNION ALL
|
||||
SELECT * FROM complemento
|
||||
) ranking_final
|
||||
ORDER BY bloco_ordem ASC, score_criticidade DESC, dias_sem_interacao DESC, dias_aberto DESC
|
||||
LIMIT 10;
|
||||
Reference in New Issue
Block a user