From 8d24a575794c8193026ad829b971fc27d1a604522f47201103c44a66f44db35b Mon Sep 17 00:00:00 2001 From: victor Date: Wed, 26 Aug 2026 10:56:07 -0300 Subject: [PATCH] =?UTF-8?q?Atualiza=C3=A7=C3=A3o=20do=20Para=20corre=C3=A7?= =?UTF-8?q?=C3=A3o=20do=20valor=20do=20dash=20da=20opera=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../operacoes_dashboard_controller.rb | 34 +++++++++---------- app/services/analytics/operacao_metricas.rb | 16 +++++++++ app/views/operacoes_dashboard/index.html.erb | 20 +++++++++-- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/app/controllers/operacoes_dashboard_controller.rb b/app/controllers/operacoes_dashboard_controller.rb index ca48bd0..31c53a4 100644 --- a/app/controllers/operacoes_dashboard_controller.rb +++ b/app/controllers/operacoes_dashboard_controller.rb @@ -35,13 +35,19 @@ class OperacoesDashboardController < ApplicationController @metricas_a = montar([@op_a]) if @op_a @metricas_b = montar([@op_b]) if @op_b else - # Operação única. Sem datas na URL o recorte é a operação inteira (o - # período vem dos próprios dados) — é o que mantém utilizável abrir uma - # operação de meses atrás. Quando o operador ESCOLHE um período, ele passa - # a valer aqui também: sem isso, comparar esta tela com o dashboard - # financeiro "no mesmo período" era impossível, porque a data era ignorada. + # Operação única: o recorte é SEMPRE a operação inteira, mesmo com + # inicio/fim na URL. É o que confere com os documentos físicos e com a + # planilha entregue ao cliente (Analytics::PlanilhaEntregas também não + # filtra data). Recortar pelo período derrubava as entregas que a operação + # executou fora do mês do nome dela — EMAD AGO 2026 rodou de 30/07 a + # 12/08, e "01/08 → hoje" mostrava 1146 das 2021 NFs. + # + # O período escolhido continua tendo função aqui: alimenta as "Notas fora + # da operação" e aparece no cabeçalho como REFERÊNCIA (quantas NFs da + # operação caíram na faixa), para comparar com o dashboard financeiro sem + # mexer no número que o cliente confere. @operacao = Operacao.sanitizar([params[:operacao]]).first || @tabelas_validas.first - @metricas = montar([@operacao], filtros: @filtros, data: @data_filtro, **faixa_ativa) if @operacao + @metricas = montar([@operacao], filtros: @filtros, data: @data_filtro) if @operacao @fora_operacao = Analytics::NotasForaOperacao.new(inicio: @periodo_inicio, fim: @periodo_fim) if @periodo_explicito end end @@ -63,8 +69,10 @@ class OperacoesDashboardController < ApplicationController if @modo == 'global' @metricas = montar(@tabelas_validas, inicio: @periodo_inicio, fim: @periodo_fim, filtros: @filtros, data: @data_filtro) else + # Mesma regra do #index: operação = operação inteira (a planilha espelho + # tem que bater com a que é entregue ao cliente). @operacao = Operacao.sanitizar([params[:operacao]]).first || @tabelas_validas.first - @metricas = montar([@operacao], filtros: @filtros, data: @data_filtro, **faixa_ativa) if @operacao + @metricas = montar([@operacao], filtros: @filtros, data: @data_filtro) if @operacao end montar_tabela_espelho if @metricas @@ -108,20 +116,12 @@ class OperacoesDashboardController < ApplicationController @espelho_linhas = linhas[(@espelho_pagina - 1) * ESPELHO_POR_PAGINA, ESPELHO_POR_PAGINA] || [] end - # Período escolhido pelo operador (veio na URL) x default da tela. Só o - # explícito é aplicado no modo Operação — ver o comentário no #index. + # Período escolhido pelo operador (veio na URL) x default da tela. No modo + # Operação ele não recorta os KPIs — ver o comentário no #index. def periodo_explicito? params[:inicio].present? || params[:fim].present? end - # Faixa a repassar para as métricas no modo Operação: vazia quando o operador - # não escolheu período (aí o recorte é a operação inteira). - def faixa_ativa - return {} unless @periodo_explicito - - { inicio: @periodo_inicio, fim: @periodo_fim } - end - def montar(tabelas, inicio: nil, fim: nil, filtros: {}, data: nil) Analytics::OperacaoMetricas.new(tabelas: tabelas, inicio: inicio, fim: fim, filtros: filtros, data: data) end diff --git a/app/services/analytics/operacao_metricas.rb b/app/services/analytics/operacao_metricas.rb index a2304b0..bef84b4 100644 --- a/app/services/analytics/operacao_metricas.rb +++ b/app/services/analytics/operacao_metricas.rb @@ -126,6 +126,22 @@ module Analytics total - sucesso - recusas end + # NFs da operação cujo resultado caiu dentro de uma faixa de datas — + # REFERÊNCIA para o cabeçalho da tela de operação única, onde o total + # continua sendo a operação inteira (é o que confere com a planilha do + # cliente). Mesma regra do filtro SQL: concluídas/falhas pela data real + # (checkout), pendentes pela data planejada. + def total_no_periodo(inicio, fim) + return total unless inicio && fim + + ini = inicio.to_date + fim = fim.to_date + linhas.count do |r| + d = data_de(r['checkout']) || data_de(r['planned_date']) + d && d >= ini && d <= fim + end + end + # ── Camada operacional (por VISITA, não por NF) ─────────────── # Os KPIs acima contam NOTAS porque é o que o cliente paga e confere. Estes # contam IDAS AO LOCAL — é o que o motorista recebe e o que o dashboard diff --git a/app/views/operacoes_dashboard/index.html.erb b/app/views/operacoes_dashboard/index.html.erb index d3e8abc..98d3638 100644 --- a/app/views/operacoes_dashboard/index.html.erb +++ b/app/views/operacoes_dashboard/index.html.erb @@ -57,7 +57,15 @@ <%= icone :comparar %> Comparação entre operações (cada uma no seu próprio período) <% elsif @metricas&.data_inicio %> <%= @metricas.operacoes_label %> · <%= @metricas.data_inicio.strftime('%d/%m/%Y') %> – <%= @metricas.data_fim.strftime('%d/%m/%Y') %> - <%= @periodo_explicito ? '(período filtrado)' : '(operação inteira)' %> + (operação inteira) + <%# O período escolhido NÃO recorta os KPIs desta tela (eles têm que + bater com a planilha entregue ao cliente); ele aparece aqui como + referência para comparar com o dashboard financeiro. %> + <% if @periodo_explicito %> + · + no período <%= @periodo_inicio.strftime('%d/%m') %>–<%= @periodo_fim.strftime('%d/%m/%Y') %>: + <%= @metricas.total_no_periodo(@periodo_inicio, @periodo_fim) %> NFs + <% end %> <% elsif @operacao %> <%= Operacao.label(@operacao) %> <% end %> @@ -75,6 +83,7 @@ <%= icone :calendario, espaco: false %> @@ -89,9 +98,14 @@ data: { turbo: false }, class: "px-3 py-2.5 rounded-xl text-sm whitespace-nowrap border #{ativo ? 'bg-orange-500 text-black border-orange-500 font-bold' : 'bg-[#1a1a1a] text-gray-300 border-white/10 hover:border-orange-500'}" %> <% end %> - <%# Volta ao recorte natural da operação (sem faixa de datas na URL). %> + <%# Limpa a faixa de datas da URL (os KPIs já são sempre da operação + inteira; sem período a tela também some com o painel de notas + fora da operação). %> <% if @modo == 'operacao' %> - <%= link_to 'Operação inteira', + <%# Rótulo é "Limpar período" e não "Operação inteira": o total já é + sempre o da operação inteira, o que este botão faz é tirar a + faixa de datas da URL. %> + <%= link_to 'Limpar período', operacoes_dashboard_path(ctx_ops.merge(modo: 'operacao')), data: { turbo: false }, class: "px-3 py-2.5 rounded-xl text-sm whitespace-nowrap border #{@periodo_explicito ? 'bg-[#1a1a1a] text-gray-300 border-white/10 hover:border-orange-500' : 'bg-orange-500 text-black border-orange-500 font-bold'}" %>