teste #3

Merged
victor merged 20 commits from teste into main 2026-07-02 15:31:51 -03:00
Showing only changes of commit ac0524d60f - Show all commits

View File

@@ -1032,7 +1032,7 @@ docker-compose exec app bundle exec rails db:migrate
</details>
<details open>
<details>
<summary><strong>🔧 Atualização 29/06/2026 — Responsividade da tela de Validar (telas menores)</strong></summary>
Correção da **quebra de layout** dos cards de NF na tela **Passo 2 (Validar)** em telas pequenas e
@@ -1062,3 +1062,77 @@ em tablets, reportada nos prints `Imagens para correção/Imagem colada (16).png
</details>
<details open>
<summary><strong>🆕 Atualização 29/06/2026 — Dashboard de Operações (análise de entregas + mapa)</strong></summary>
Nova página **`/dashboard/operacoes`** (link **📈 Operações** no menu), separada do dashboard
financeiro, focada na **qualidade das entregas** por operação (UBS Norte, EMAD, …). Reproduz os
painéis das imagens de referência (`Imagens para implantação/`) e adiciona análise comparativa e mapa.
Acessível a todos menos motorista (`DashboardPolicy#operacoes?`).
### 🆕 Funcionalidades
- **3 modos na mesma página** (abas):
- **🏥 Operação** — uma operação por vez. **Sem filtro de data**: mostra o conjunto inteiro da
operação e o período exibido vem dos próprios dados (menor/maior `checkout`).
- **🌐 Global** — todas as operações agregadas, aí sim com **faixa de datas** (flatpickr + atalhos
Hoje/7d/Este mês/30d). A faixa de data **só vale no Global**.
- **⚖️ Comparar** — duas operações lado a lado com bloco **Comparativo** (tabela A | B | Δ com o
melhor valor de cada linha em verde + gráfico de barras agrupadas) e detalhe completo recolhível.
- **Painéis** (espelham as imagens 2 e 3): KPIs (Total / Sucesso / Recusas / Pendentes), donut
**Insucessos %**, **Índices de Falha** (por `observation`), **Por Status** (status_gade
RECORRENTE/NOVO), **NFs por Motorista**, **Entregas por STS/Unidade** (`contact_name`), **Entregas
por Dia** (barras empilhadas) e **Mapa**.
- **Cross-filter ao vivo (toggle)** — clicar em qualquer linha das tabelas (Motorista, Unidade,
Status, Observação) **refiltra todo o dashboard** por aquele valor; clicar de novo na linha ativa
**remove** o filtro. Chips removíveis + "Limpar tudo" no topo.
- **Mapa de entregas** com:
- alternância **🔥 Calor** (heatmap) ⇄ **📍 Pontos** (um balão por entrega na coordenada de
**check-out**);
- **camadas** 🌙 Escuro (padrão) / 🗺️ Claro / 🛰️ Satélite (todas grátis, sem chave);
- **tela cheia** (Fullscreen API);
- **popup** por entrega (NF, destinatário, endereço, unidade, motorista, data) com a **foto da
fachada** (coluna `foto_da_fachada`), aberta em tamanho cheio ao clicar.
- **Cores** dos gráficos na identidade da marca: laranja `#f97316` (completas) e vermelho `#ef4444`
(falhas); no comparativo A = laranja, B = azul.
### ⚙️ Como funciona (técnico)
- Núcleo de dados em **`app/services/analytics/operacao_metricas.rb`** (PORO). Monta um SQL que
**espelha a query de gestão**: CTE `ROW_NUMBER() OVER (PARTITION BY reference_id ORDER BY checkout
DESC)` sobre `db_reem_simplerout_2026` + `INNER JOIN` na tabela `gade_entregas_*` por
`reference_id::text = nota_fiscal`; agrega tudo em Ruby (visão `linhas` = registros após o
cross-filter).
- **Sem filtro de conta** (`account_id`): o INNER JOIN com a tabela da operação já restringe ao
cliente — replicar `da_conta_gade` zerava tudo quando `DB_EXISTING_ACCOUNT_ID` não batia.
- **Schema gade não-uniforme**: só `nota_fiscal` é garantida. Colunas opcionais (`status`,
`nome_completo`, `endereco_completo`) são detectadas por tabela (`conn.columns`) e viram `NULL`
quando não existem — assim o `UNION ALL` entre operações no Global não quebra
(era o erro `column g.status does not exist`).
- **Segurança**: nomes de tabela passam por `Operacao.sanitizar` + `quote_table_name`; a `foto_da_fachada`
é validada como URL `http(s)` antes de ir ao `<img>`, com escape de HTML no popup.
- **Performance do mapa**: marcadores criados **sob demanda** (só ao abrir "Pontos") e o popup é uma
**função** — a foto do S3 só é requisitada **ao clicar** no balão (nada é baixado no load). Limite
de 2000 marcadores.
- **Filtro de período** opcional no serviço (`inicio:`/`fim:`): aplicado só no Global.
### 📂 Arquivos
```
app/services/analytics/operacao_metricas.rb # NOVO — núcleo de dados/agregações
app/controllers/operacoes_dashboard_controller.rb # NOVO — modos + cross-filter
app/views/operacoes_dashboard/index.html.erb # NOVO — filtros, abas, charts, mapa (JS)
app/views/operacoes_dashboard/_painel.html.erb # NOVO — KPIs/donut/tabelas/gráfico
app/views/operacoes_dashboard/_comparativo.html.erb # NOVO — tabela A|B|Δ + barras agrupadas
app/views/operacoes_dashboard/_mapa.html.erb # NOVO — calor/pontos, camadas, tela cheia
app/views/operacoes_dashboard/_tabela_simples.html.erb # NOVO — tabela reutilizável + cross-filter
spec/services/analytics/operacao_metricas_spec.rb # NOVO — specs das agregações/cross-filter
spec/requests/operacoes_dashboard_spec.rb # NOVO — autorização por role + modos
config/routes.rb # rota get /dashboard/operacoes
app/policies/dashboard_policy.rb # operacoes? (todos menos motorista)
app/views/layouts/_navbar.html.erb # link "📈 Operações"
```
> **Sem migration** — tudo lê tabelas existentes (`db_reem_simplerout_2026` read-only e
> `gade_entregas_*`). Libs front via CDN (Chart.js, Leaflet + leaflet.heat, flatpickr).
> ⚠️ Em produção, **reiniciar o servidor** (Puma) após o deploy — o Rails cacheia classes/views.
</details>