Compare commits

..

9 Commits

Author SHA256 Message Date
18239b133b Merge pull request 'teste' (#11) from teste into main
Reviewed-on: #11
2026-08-24 11:32:28 -03:00
7b3ec3e407 Documenta no README as correções do dashboard (20-21/08)
Registra o arco do insucesso no pagamento, que não estava documentado: a
mudança da base do dashboard de `pagas` para `atendidas` (completed +
failed), a troca do eixo de planned_date para checkout, o mesmo ajuste no
painel do motorista, a aba Consolidado no ranking e a correção da barra.

Inclui a conferência com dados reais do ambiente de teste — a aba
Consolidado fecha em R$ 72.508,00 / 3.858 entregas, idêntico aos KPIs do
topo — e deixa explícito que a suíte continua pendente de execução, com o
roteiro para rodar no Docker.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:23:24 -03:00
e9db6b7164 Correção da barra do ranking de motoristas
A barra era proporcional à QUANTIDADE de entregas, mas as duas abas do card
são ordenadas por VALOR. Na aba Estimado dá no mesmo (valor = qtd × preço),
mas na Consolidada bônus/retirada/termo mudam o preço unitário: com os dados
do teste a barra do 3º (290 entregas, R$ 5.250) saía MAIOR que a do 2º
(261 entregas, R$ 5.260), contradizendo a ordem do ranking. Invertia em três
pontos da lista.

Passa a escalar pelo valor, que é o número que ordena — as barras encurtam
sempre de cima para baixo. Mantida a guarda de divisão por zero.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:21:08 -03:00
dd5621a215 Merge pull request 'teste' (#10) from teste into main
Reviewed-on: #10
2026-07-22 11:40:17 -03:00
a020f89ef1 Merge pull request 'teste' (#9) from teste into main
Reviewed-on: #9
2026-07-21 00:31:16 -03:00
2346fed20a Merge pull request 'teste' (#8) from teste into main
Reviewed-on: #8
2026-07-20 22:26:50 -03:00
7deac237d3 Merge pull request 'teste' (#7) from teste into main
Reviewed-on: #7
2026-07-15 19:30:25 -03:00
a98e7868d2 Merge pull request 'teste' (#6) from teste into main
Reviewed-on: #6
2026-07-13 12:57:26 -03:00
cb47d1c294 Merge pull request 'teste' (#5) from teste into main
Reviewed-on: #5
2026-07-03 10:52:51 -03:00
2 changed files with 178 additions and 6 deletions

169
README.md
View File

@@ -1944,3 +1944,172 @@ docker-compose exec app bundle exec rails runner \
</details> </details>
---
<details>
<summary><strong>💰 Entrega sem sucesso entra no pagamento + aba Consolidado no ranking (2021/08/2026)</strong></summary>
> ⚠️ **STATUS: no ar no ambiente de teste e conferido com dados reais** (17 motoristas,
> 4.976 entregas de agosto). O que **continua pendente é a suíte** — não há Ruby nem Postgres na
> máquina de desenvolvimento, então os specs novos foram validados só na sintaxe. Roteiro no fim
> desta seção.
### 🎯 O problema
A Reem **paga a entrega sem sucesso**: o motorista foi até o local, teve o deslocamento e o custo,
e o insucesso é só o desfecho da visita. A **consolidação** já tratava assim desde sempre
(`Entrega::STATUS_ATENDIDO` = `completed` + `failed`), mas o **dashboard não** — mostrava um valor
**menor que o do fechamento**, e ninguém sabia explicar a diferença.
### 🔴 Correções
**1. Dashboard principal contava só as concluídas** — `dashboard_controller.rb` (commit `cebd6e2`)
A base financeira era `Entrega.pagas` (só `completed`). Passou a ser `.atendidas`
(`completed` + `failed`, com checkout) — **o mesmo recorte que a consolidação considera elegível**,
que é justamente o ponto: tela e fechamento agora partem do mesmo conjunto.
**2. A falhada caía no período errado** — mesmo commit
As falhas eram filtradas por `planned_date`, e as concluídas por `checkout`. **Falhada TEM
checkout** (o motorista fechou a visita com motivo de insucesso), então o eixo correto é o mesmo
das concluídas. Uma entrega planejada em 31/07 e fechada em 01/08 pertence a agosto — como a
consolidação sempre entendeu.
**3. O painel do motorista ficou para trás** — `motorista/dashboard_controller.rb` (commit `4965931`)
Continuava em `Entrega.pagas` + `no_periodo` (planned_date), ou seja, a lógica antiga inteira.
O motorista via **menos do que ia receber** — no mês corrente, 124 entregas (~R$ 2.232,00)
invisíveis — e a diferença só aparecia no fechamento. Passou para `.atendidas` +
`no_periodo_checkout`, e o rótulo *"N entregas feitas e confirmadas"*, que mentia sobre o número
novo, virou:
```
R$ 20,00
2 entregas atendidas
1 entregues · 1 sem sucesso (pagas também)
```
A segunda linha não é enfeite: sem ela o motorista vê um total maior e não tem como conferir de
onde veio.
**4. A barra do ranking contradizia a ordem do ranking** — `_ranking_motoristas.html.erb` (commit `e9db6b7`)
A barra era proporcional à **quantidade**, mas o card é ordenado por **valor**. Na aba Estimado dá
no mesmo (valor = qtd × preço); na Consolidada, bônus/retirada/termo mudam o preço unitário e a
barra do 3º (290 entregas, R$ 5.250) saía **maior** que a do 2º (261 entregas, R$ 5.260).
Invertia em três pontos da lista. Agora escala pelo valor, que é o número que ordena.
### 🆕 Aba "Consolidado" no ranking de motoristas
O card **Motoristas** ganhou duas abas — a dúvida recorrente era justamente *"esse ranking mostra o
estimado ou o consolidado?"*:
| Aba | O que mostra | De onde vem |
|-----|--------------|-------------|
| **Estimado** | entregas atendidas × preço da entrega | espelho de rastreio (`Entrega.atendidas`) |
| **Consolidado** | valor **realmente fechado** + quantidade exata de entregas | `consolidacao_motoristas` / `consolidacao_entregas` |
Os números divergem **de propósito**: o estimado cobre tudo que foi atendido no período; o
consolidado, só o que já entrou em consolidação **finalizada**, com bônus/desconto/retirada
aplicados. Cada aba diz na tela de onde vem o seu número.
Dois detalhes decidem se a quantidade sai certa:
- **`DISTINCT tracking_id`, não contagem de linhas.** Uma entrega pode ter vários pilares —
Normal + Bônus + Retirada são **3 linhas** em `consolidacao_entregas` para **1 entrega**.
Contar linhas inflaria o número.
- **Só motoristas ativos.** O ranking parte de `@fin_por_motorista` (que vem de
`ConsolidacaoMotorista.ativos`), então **arquivado não aparece** — ele saiu do fechamento e não
tem valor a exibir. Isso também garante que a aba soma exatamente o KPI "Custo total" do topo.
O markup da lista virou a partial `_ranking_motoristas.html.erb`, usada pelas duas abas: os dois
conjuntos têm a mesma forma (`:nome`, `:valor`, `:entregas`) e duplicar o HTML faria as abas
divergirem visualmente na primeira alteração.
### ✅ Conferência com dados reais (teste.reemtransportes.com.br, 21/08/2026)
**Dashboard principal — período 01/08 a 21/08:**
| Card | Na tela | Confere |
|------|---------|---------|
| Valor Estimado | R$ 89.568,00 | 4.976 × R$ 18,00 exato |
| — subtítulo | 4.976 entregas atendidas | 4.852 + 124 |
| Total Entregas | 4.977 | 4.976 atendidas + 1 pendente |
O teste decisivo: 4.852 concluídas × R$ 18 dariam **R$ 87.336,00**. A tela mostra **R$ 89.568,00** —
exatamente **R$ 2.232,00 a mais, que são as 124 sem sucesso**. O insucesso entra no dinheiro, não
só na contagem.
**Consistência interna** (as falhas entram em todo lugar, não só no card):
- Ranking por motorista: os 17 motoristas somam **exatamente 4.976**; se contasse só sucesso daria
4.852.
- Gráfico "Evolução do custo": a série diária soma **R$ 69.408,00**, idêntico ao valor estimado do
período 0114/08 — as falhas caem nos dias certos (eixo checkout).
- Sem dupla contagem: o scope `pendentes` exclui `failed`, então entregue / pendente / sem sucesso
não se sobrepõem.
**Aba Consolidado — reconciliação com os KPIs:**
| | Soma da aba | KPI do topo |
|---|---|---|
| Valores | **R$ 72.508,00** | R$ 72.508,00 ("Custo total") ✅ |
| Entregas | **3.858** | 3.858 ("entregas classificadas") ✅ |
Bate à vírgula e à unidade. Isso explica também a diferença **3.858 consolidadas × 3.856 atendidas**:
são 2 entregas que entraram no fechamento sem estar na janela de checkout do período (apontamento
manual de NF fora do período, ou consolidação que extrapola as datas). **Não é erro de contagem —
são bases diferentes**, e agora dá para ver as duas lado a lado.
### 🧪 Specs — ⏳ pendentes de execução
`spec/requests/dashboard_spec.rb` (+4 casos) e `spec/requests/motorista_dashboard_spec.rb` (novo,
5 casos). Usam o harness `spec/support/espelho_rastreio.rb`, que monta uma cópia descartável de
`db_reem_simplerout_2026` no banco de teste — sem ele só daria para mockar o método, o que não pega
regressão de **SQL**, que é onde moram os bugs de eixo de data.
O que fica travado:
- a sem sucesso soma no valor e na quantidade;
- entra pelo **checkout** (planejada 31/07 + checkout 01/08 → conta em agosto) e sai quando o
checkout cai fora;
- pendente sem checkout não vira dinheiro;
- entrega de outro motorista não vaza para o painel;
- na aba Consolidado: 3 linhas de 2 `tracking_id` = **"2 entregas"**, desconto subtraindo,
arquivado fora da lista, rascunho não entrando.
> As asserções da aba Consolidado são escopadas ao `#ranking-painel-consolidado` via Nokogiri — a
> aba Estimado renderiza o **mesmo markup** (moeda + "N entregas"), então asserção no `body` inteiro
> passaria por acidente.
O painel do motorista não tem filtro de período (é sempre "do dia 1º até hoje"), então o spec
congela a data com `travel_to`; sem isso ele quebraria sozinho ao rodar no dia 1º.
### 📂 Arquivos
```
app/controllers/dashboard_controller.rb (atendidas + eixo checkout; @ranking_consolidado)
app/controllers/motorista/dashboard_controller.rb (atendidas + no_periodo_checkout; quebra do card)
app/models/entrega.rb (scopes atendidas / falhadas / no_periodo_checkout)
app/views/dashboard/index.html.erb (abas Estimado/Consolidado + JS da troca)
app/views/dashboard/_ranking_motoristas.html.erb (NOVO — lista compartilhada pelas duas abas)
app/views/motorista/dashboard/index.html.erb (rótulo "atendidas" + linha da quebra)
spec/requests/dashboard_spec.rb (+ aba Consolidado)
spec/requests/motorista_dashboard_spec.rb (NOVO)
spec/support/espelho_rastreio.rb (harness da tabela externa)
```
> **Sem migration e sem gem nova** — só controllers, views e specs.
### ⏳ Pendente — roteiro
```bash
# 1. Suíte (única coisa que não pôde ser executada)
docker compose exec app bundle exec rspec \
spec/requests/dashboard_spec.rb spec/requests/motorista_dashboard_spec.rb
# 2. Depois do deploy: conferir a barra do ranking na aba Consolidado
# (deve encurtar sempre de cima para baixo)
# 3. Painel do motorista com dado real — logar como motorista no teste e
# conferir a linha "N entregues · N sem sucesso (pagas também)"
```
</details>

View File

@@ -6,11 +6,14 @@
Locais: itens (array de hashes), vazio (texto do estado sem dados). %> Locais: itens (array de hashes), vazio (texto do estado sem dados). %>
<% if itens.any? %> <% if itens.any? %>
<div class="space-y-3"> <div class="space-y-3">
<%# Base da barra: o MAIOR nº de entregas da aba, não o primeiro item — a aba <%# A barra é proporcional ao VALOR, que é o número pelo qual as duas abas são
consolidada é ordenada por VALOR, então o primeiro pode não ser o maior em ordenadas — assim ela sempre encurta de cima para baixo.
quantidade e a barra passaria de 100%. Sem entregas (só bônus/desconto, ⚠️ Não voltar a usar :entregas aqui: na aba Estimado dá no mesmo (valor =
por exemplo) a barra fica vazia em vez de dividir por zero. %> qtd × preço), mas na Consolidada quem tem mais entregas nem sempre tem o
<% max = itens.map { |x| x[:entregas].to_i }.max.to_f %> maior valor (bônus/retirada/termo mudam o preço unitário) e a barra do 3º
ficava MAIOR que a do 2º, contradizendo a ordem do ranking.
Zero vira barra vazia em vez de divisão por zero. %>
<% max = itens.map { |x| x[:valor].to_f }.max.to_f %>
<% itens.each_with_index do |m, i| %> <% itens.each_with_index do |m, i| %>
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<span class="text-xs font-bold w-5 text-center <span class="text-xs font-bold w-5 text-center
@@ -27,7 +30,7 @@
<%# Barra de progresso %> <%# Barra de progresso %>
<div class="w-full bg-white/5 rounded-full h-1.5"> <div class="w-full bg-white/5 rounded-full h-1.5">
<div class="h-1.5 rounded-full bg-[#f97316]" <div class="h-1.5 rounded-full bg-[#f97316]"
style="width: <%= max.zero? ? 0 : [(m[:entregas] / max * 100).round, 100].min %>%"></div> style="width: <%= max.zero? ? 0 : [(m[:valor] / max * 100).round, 100].min %>%"></div>
</div> </div>
<span class="text-gray-400 text-xs"><%= m[:entregas] %> entregas</span> <span class="text-gray-400 text-xs"><%= m[:entregas] %> entregas</span>
</div> </div>