correção de bugs
This commit is contained in:
@@ -76,35 +76,43 @@ class DashboardController < ApplicationController
|
||||
@operacoes_agrupadas = Operacao.agrupadas_por_mes
|
||||
@operacao_filtro = Operacao.sanitizar(params[:operacoes])
|
||||
|
||||
# PAGAS pela DATA REAL (checkout) — base de toda a análise financeira por data.
|
||||
pagas = Entrega.da_conta_gade.pagas.no_periodo_checkout(@periodo_inicio, @periodo_fim)
|
||||
pagas = pagas.da_operacoes(@operacao_filtro) if @operacao_filtro.present?
|
||||
# ATENDIDAS pela DATA REAL (checkout) — base de toda a análise financeira.
|
||||
#
|
||||
# Atendida = o motorista FOI ao local e fechou a visita, com sucesso
|
||||
# (`completed`) OU insucesso (`failed`). É exatamente o conjunto que a
|
||||
# consolidação considera elegível e paga (ver Entrega::STATUS_ATENDIDO,
|
||||
# Entrega.contar_atendidas e Consolidacao#veiculos_do_motorista), por isso o
|
||||
# dashboard usa o MESMO recorte — usava só `pagas` (concluídas) e mostrava
|
||||
# um valor menor que o do fechamento.
|
||||
atendidas = Entrega.da_conta_gade.atendidas.no_periodo_checkout(@periodo_inicio, @periodo_fim)
|
||||
atendidas = atendidas.da_operacoes(@operacao_filtro) if @operacao_filtro.present?
|
||||
|
||||
# PENDENTES (em aberto, nem concluídas nem falhadas) pela data planejada.
|
||||
# PENDENTES (em aberto, nem concluídas nem falhadas) pela data planejada —
|
||||
# é o único recorte sem checkout, então planned_date é o eixo correto aqui.
|
||||
pendentes = Entrega.da_conta_gade.pendentes.no_periodo(@periodo_inicio, @periodo_fim)
|
||||
pendentes = pendentes.da_operacoes(@operacao_filtro) if @operacao_filtro.present?
|
||||
|
||||
# FALHADAS (insucesso) pela data planejada — também não têm checkout.
|
||||
falhadas = Entrega.da_conta_gade.falhadas.no_periodo(@periodo_inicio, @periodo_fim)
|
||||
falhadas = falhadas.da_operacoes(@operacao_filtro) if @operacao_filtro.present?
|
||||
|
||||
# Totais gerais
|
||||
@entregas_pagas = pagas.count
|
||||
# Quebra do total entre sucesso e insucesso (ambos já dentro de `atendidas`).
|
||||
# ⚠️ Falhada TEM checkout: o motorista foi ao local e fechou a visita com
|
||||
# motivo de insucesso. Por isso o eixo é checkout, igual às concluídas — antes
|
||||
# as falhas eram filtradas por planned_date e caíam no período errado.
|
||||
@entregas_pagas = atendidas.concluidas.count
|
||||
@entregas_falhadas = atendidas.falhadas.count
|
||||
@entregas_atendidas = @entregas_pagas + @entregas_falhadas
|
||||
@entregas_pendentes = pendentes.count
|
||||
@entregas_falhadas = falhadas.count
|
||||
@total_entregas = @entregas_pagas + @entregas_pendentes + @entregas_falhadas
|
||||
@total_entregas = @entregas_atendidas + @entregas_pendentes
|
||||
|
||||
# Configurações de preço
|
||||
config = Configuracao.mapa_de_precos
|
||||
|
||||
# Valor estimado total
|
||||
@valor_estimado = (@entregas_pagas * config[:entrega]).round(2)
|
||||
@valor_estimado = (@entregas_atendidas * config[:entrega]).round(2)
|
||||
|
||||
# Por motorista (todos)
|
||||
@motoristas = pagas.group(:driver)
|
||||
.count
|
||||
.sort_by { |_, v| -v }
|
||||
.map do |driver, qtd|
|
||||
@motoristas = atendidas.group(:driver)
|
||||
.count
|
||||
.sort_by { |_, v| -v }
|
||||
.map do |driver, qtd|
|
||||
{
|
||||
nome: driver,
|
||||
entregas: qtd,
|
||||
@@ -113,14 +121,14 @@ class DashboardController < ApplicationController
|
||||
end
|
||||
|
||||
# Por local de entrega (contact_name)
|
||||
@por_operacao = pagas.group(:contact_name)
|
||||
.count
|
||||
.sort_by { |_, v| -v }
|
||||
.first(6)
|
||||
.to_h
|
||||
@por_operacao = atendidas.group(:contact_name)
|
||||
.count
|
||||
.sort_by { |_, v| -v }
|
||||
.first(6)
|
||||
.to_h
|
||||
|
||||
# Evolução diária no período (para Chart.js) — por data real (checkout)
|
||||
@grafico_diario = build_grafico_diario(pagas, config[:entrega])
|
||||
@grafico_diario = build_grafico_diario(atendidas, config[:entrega])
|
||||
|
||||
# Consolidações cujo período (data_inicio..data_fim) cruza o período do dashboard
|
||||
# — independe de quando foram criadas (created_at).
|
||||
@@ -221,20 +229,21 @@ class DashboardController < ApplicationController
|
||||
.sort_by { |_, v| -v }
|
||||
end
|
||||
|
||||
# `pagas` já vem filtrado por checkout no período. Agrupa pela DATA REAL
|
||||
# (DATE(checkout)) — DATE() sobre timestamp não faz conversão de fuso.
|
||||
def build_grafico_diario(pagas, preco_entrega)
|
||||
# `atendidas` já vem filtrado por checkout no período (concluídas + falhadas).
|
||||
# Agrupa pela DATA REAL (DATE(checkout)) — DATE() sobre timestamp não faz
|
||||
# conversão de fuso.
|
||||
def build_grafico_diario(atendidas, preco_entrega)
|
||||
dias = (@periodo_inicio..@periodo_fim).to_a
|
||||
|
||||
if dias.size <= MAX_DIAS_GRAFICO
|
||||
# Granularidade diária (períodos curtos)
|
||||
contagem = pagas.group("DATE(checkout)").count.transform_keys(&:to_s)
|
||||
contagem = atendidas.group("DATE(checkout)").count.transform_keys(&:to_s)
|
||||
labels = dias.map { |d| d.strftime('%d/%m') }
|
||||
valores = dias.map { |d| ((contagem[d.to_s] || 0) * preco_entrega).round(2) }
|
||||
qtds = dias.map { |d| contagem[d.to_s] || 0 }
|
||||
else
|
||||
# Período longo: agrega por mês para o gráfico não ficar vazio nem poluído.
|
||||
contagem = pagas.group("TO_CHAR(checkout, 'YYYY-MM')").count
|
||||
contagem = atendidas.group("TO_CHAR(checkout, 'YYYY-MM')").count
|
||||
meses = meses_no_periodo
|
||||
labels = meses.map { |m| Date.strptime(m, '%Y-%m').strftime('%m/%Y') }
|
||||
valores = meses.map { |m| ((contagem[m] || 0) * preco_entrega).round(2) }
|
||||
|
||||
@@ -121,12 +121,20 @@ class Entrega < ApplicationRecord
|
||||
|
||||
# Veículos usados pelo(s) motorista(s) selecionado(s) no período — alimenta o
|
||||
# filtro dinâmico de veículos na criação de consolidação.
|
||||
#
|
||||
# ⚠️ Precisa usar EXATAMENTE o mesmo recorte da elegibilidade
|
||||
# (`atendidas` + `no_periodo_checkout`, ver contar_atendidas e
|
||||
# Consolidacao#veiculos_do_motorista). Usava `no_periodo` (planned_date), e o
|
||||
# descasamento sumia com veículo do filtro: entrega planejada em 31/07 e
|
||||
# entregue em 01/08 é elegível numa consolidação 01/08–14/08 (checkout dentro),
|
||||
# mas o veículo dela não aparecia (planned_date fora) — sem opção de marcar,
|
||||
# a entrega ficava de fora do fechamento SEM aviso, e o financeiro não batia.
|
||||
def self.veiculos_de_motoristas(motoristas, inicio: nil, fim: nil)
|
||||
nomes = Array(motoristas).reject(&:blank?)
|
||||
return [] if nomes.empty?
|
||||
|
||||
base = da_conta_gade.where(driver: nomes)
|
||||
base = base.no_periodo(inicio, fim) if inicio.present? && fim.present?
|
||||
base = base.atendidas.no_periodo_checkout(inicio, fim) if inicio.present? && fim.present?
|
||||
base.distinct.order(:vehicle).pluck(:vehicle).compact.reject(&:empty?)
|
||||
end
|
||||
|
||||
|
||||
@@ -134,8 +134,14 @@
|
||||
<p class="text-3xl lg:text-4xl font-black text-white mb-1 break-words">
|
||||
<%= moeda(@valor_estimado) %>
|
||||
</p>
|
||||
<%# "Atendidas" = concluídas + falhadas (motorista foi ao local e fechou
|
||||
a visita). É a mesma base que a consolidação paga, por isso o rótulo
|
||||
NÃO pode voltar a dizer "concluídas": o valor acima inclui as falhas. %>
|
||||
<p class="text-orange-200 text-sm">
|
||||
<%= @entregas_pagas %> entregas concluídas
|
||||
<%= @entregas_atendidas %> entregas atendidas
|
||||
</p>
|
||||
<p class="text-orange-200/80 text-xs">
|
||||
<%= @entregas_pagas %> concluídas · <%= @entregas_falhadas %> falhadas
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user