Compare commits
2 Commits
4965931c13
...
7b3ec3e407
| Author | SHA256 | Date | |
|---|---|---|---|
| 7b3ec3e407 | |||
| e9db6b7164 |
169
README.md
169
README.md
@@ -1944,3 +1944,172 @@ docker-compose exec app bundle exec rails runner \
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
---
|
||||
|
||||
<details>
|
||||
<summary><strong>💰 Entrega sem sucesso entra no pagamento + aba Consolidado no ranking (20–21/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 01–14/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>
|
||||
|
||||
@@ -6,11 +6,14 @@
|
||||
Locais: itens (array de hashes), vazio (texto do estado sem dados). %>
|
||||
<% if itens.any? %>
|
||||
<div class="space-y-3">
|
||||
<%# Base da barra: o MAIOR nº de entregas da aba, não o primeiro item — a aba
|
||||
consolidada é ordenada por VALOR, então o primeiro pode não ser o maior em
|
||||
quantidade e a barra passaria de 100%. Sem entregas (só bônus/desconto,
|
||||
por exemplo) a barra fica vazia em vez de dividir por zero. %>
|
||||
<% max = itens.map { |x| x[:entregas].to_i }.max.to_f %>
|
||||
<%# A barra é proporcional ao VALOR, que é o número pelo qual as duas abas são
|
||||
ordenadas — assim ela sempre encurta de cima para baixo.
|
||||
⚠️ Não voltar a usar :entregas aqui: na aba Estimado dá no mesmo (valor =
|
||||
qtd × preço), mas na Consolidada quem tem mais entregas nem sempre tem o
|
||||
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| %>
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-xs font-bold w-5 text-center
|
||||
@@ -27,7 +30,7 @@
|
||||
<%# Barra de progresso %>
|
||||
<div class="w-full bg-white/5 rounded-full h-1.5">
|
||||
<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>
|
||||
<span class="text-gray-400 text-xs"><%= m[:entregas] %> entregas</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user