diff --git a/README.md b/README.md index 8c94f2d..55bc655 100644 --- a/README.md +++ b/README.md @@ -3737,3 +3737,201 @@ a contagem e o motivo camada por camada. 3. Atualizar este README (marcar fases entregues) e o perfil "Cliente" nos seeds. + +--- + +
+🧾 28/08/2026 (sessão 2) — Financeiro, seleção em massa, plano por nome e o 404 que fingia ser outra coisa + +| Sintoma | Causa real | Onde se resolveu | +|---|---|---| +| Custo total e "N entregas" do mesmo card discordavam | `ces` incluía motorista arquivado; `cms` não | `dashboard_controller.rb` (EXISTS por par) | +| Rosca de composição não fechava com o Custo total | desconto entrava como fatia **positiva** | desconto sai do gráfico + linha "já abatidos" | +| Ticket médio alto demais | lote de termo contava como **1** entrega | `#contar_entregas` | +| "Entrega de Termo" com a cor de "Entrega Normal" | 5 cores fixas para 7 tipos | `DashboardController::CORES_TIPO` | +| Arquivar consolidação uma a uma | não havia seleção múltipla | `arquivar_em_lote` + linha de seleção | +| Ter que acertar a DATA do plano | a API expõe os planos por NOME | seletor + filtro de período | +| "Trocar logo" → `404 (Not Found)` | `before_action` rodando em rota de coleção | `except:` do `carregar_romaneio` | +| Checkbox destoando do site | `accent-color` = checkbox do sistema | CSS global no layout | + +## 1. Financeiro: quatro números que discordavam + +O ponto comum das três primeiras: **`cms` (o dinheiro) filtrava motorista +arquivado e `ces` (as entregas) não**. `arquivar_motorista` é reversível e +**mantém** as linhas em `consolidacao_entregas` — quem apaga é o +`excluir_motorista`. Sem espelhar o recorte, o mesmo card mostrava R$ de um +conjunto e contagem de outro. + +O filtro é por **par** `(consolidacao_id, motorista_nome)`, não por nome: o mesmo +motorista pode estar ativo numa consolidação do período e arquivado em outra. + +**O desconto não é fatia.** No dinheiro ele SUBTRAI; como fatia positiva de uma +rosca — que se lê como partes de um todo — a soma das fatias ficava maior que o +Custo total logo acima. Saiu do gráfico e virou a linha *"− R$ X em descontos, já +abatidos no Custo total"*, que só aparece quando há desconto: a divergência é +legítima, então é explicada onde ela aparece (diretriz 1). + +**Lote de termo vale N, não 1.** Um lote é UMA linha com `quantidade = N` e +`valor_aplicado = N × preço`. Contado por `DISTINCT tracking_id`, um lote de 20 +entrava como 1 no denominador e o ticket médio saía 20× maior. A conta agora é +`DISTINCT tracking_id` (para os pilares múltiplos, que já estava certo) **mais** +`SUM(quantidade)` dos tipos em lote — a mesma unidade que +`Analytics::TotaisPorMotorista` sempre usou. + +> ⚠️ **Os números do dashboard MUDAM depois disso, para melhor.** "Entregas +> classificadas" pode subir e o ticket médio cair. Se alguém já conhecia o número +> antigo, avise — número que muda sozinho vira desconfiança do sistema inteiro. + +## 2. Consolidações: arquivamento em lote + +Linha de seleção sempre visível acima da lista (some para quem não tem +`consolidacao.arquivar`): *Selecionar todas* · contador · *Arquivar selecionadas*. + +- O card deixou de ser **um `` só**: com o link envolvendo tudo, clicar no + checkbox navegava em vez de marcar. A caixinha virou irmã do link. +- Os checkboxes usam `form="form-arquivar-lote"`, então o formulário não precisa + envolver a lista nem o carrossel. +- **Sem JS o essencial continua**: marcar na mão e enviar funciona, e o botão + nasce habilitado de propósito — quem desabilita é o Stimulus. Dado o histórico + de asset 404 em produção, o contrário deixaria a função inalcançável. +- Arquivar é reversível, então a confirmação aponta para "Arquivadas". + +## 3. Romaneio: escolher o plano pelo NOME + +Ver também a seção corrigida *"Sobre buscar o plano por nome na API"*. A tela +trocou o campo **"Data do plano"** por um seletor dos planos, mais um filtro de +período. + +**Por que a data era impossível de acertar** — o plano tem uma JANELA, e o dia +das rotas ora é o começo dela, ora o fim: + +| plano | janela | dia real das rotas | +|---|---|---| +| EMAD SETEMBRO 2026 | 31/08 → 08/09 | **31/08** (início) | +| UBS OESTE AGOSTO 2026 | 18/08 → 20/08 | **20/08** (fim) | +| UBS NORTE AGOSTO 2026 | 17/08 → 20/08 | **20/08** (fim) | + +Agora quem descobre o dia é a API (uma chamada — todas as rotas de um plano +dividem o mesmo dia). A importação são **3 chamadas**, e o filtro pelas rotas do +plano não é otimização: dois planos podem cair no mesmo dia, e sem ele o romaneio +de um sairia com as paradas do outro. + +Sem período, os **5 mais recentes** (a ferramenta é usada logo depois de lançar +uma operação). Com período, **todos** os da faixa — critério é a janela **cruzar** +o período, como `Consolidacao.cruzando_periodo`. Medido: agosto/2026 = 8 planos, +março/2026 = 13. Os planos "Automático" ficam na lista. + +Conferido ponta a ponta contra a API real: EMAD SETEMBRO 2026 → 31/08/2026, 2047 +visitas, 73 veículos, GADE_001 com 29 paradas, primeira NF 90158 — igual à tela. + +## 4. "Trocar logo" dava 404 — e não era rota + +```ruby +before_action :carregar_romaneio, except: %i[index create importar_planilha] +``` + +`atualizar_logo` foi adicionada ao `collection` do `routes.rb` e **esquecida +aqui**. `carregar_romaneio` faz `Romaneio.find(params[:id])`, e em rota de coleção +não existe `:id` → `RecordNotFound` → **404**. + +Como 404 parece "rota errada", a procura foi para todo lado menos para o +`before_action`. A prova de que a rota estava certa é um POST sem sessão: + +``` +POST /admin/romaneios/atualizar_logo -> 422 (existe, barrou no CSRF) +POST /admin/romaneios/rota_que_nao_existe -> 404 (essa sim não existe) +``` + +E fecha o sintoma anterior — *"subi outro logo e o PDF não mudou"*: não mudou +porque **o upload nunca acontecia**. + +Junto vieram as redes que faltavam nesse caminho: formato detectado pela +**assinatura do arquivo** (o `content_type` do navegador manda +`application/octet-stream` para PNG válido, e a validação antiga recusava um PNG +dizendo "precisa ser PNG"); gravação com `rescue SystemCallError` que nomeia a +falha em vez de página 500; `require 'fileutils'` explícito; e o token CSRF +global, que era o único formulário da tela sem ele. + +> O Prawn embute **só PNG e JPEG**. WebP/SVG/GIF são reconhecidos para a mensagem +> poder dizer *"o arquivo é WebP, salve como PNG"* — suportá-los de verdade exige +> gem de conversão (o `libvips` já está no Dockerfile, falta o driver). + +## 5. Checkbox do sistema, no site inteiro + +O nativo com `accent-color` continua sendo o do sistema operacional: quadrado +duro e azul-acinzentado no hover, o único elemento denunciando "formulário cru" +numa tela toda de cantos 12px e laranja. + +Vale por **seletor de elemento** no `