Correção da data do dash principal
This commit is contained in:
BIN
Imagens para correção /Imagem colada (10).png
Normal file
BIN
Imagens para correção /Imagem colada (10).png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
BIN
Imagens para correção /Imagem colada (11).png
Normal file
BIN
Imagens para correção /Imagem colada (11).png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 189 KiB |
@@ -11,14 +11,15 @@ class ConsolidacaoEntregasController < ApplicationController
|
|||||||
authorize @consolidacao, :show?
|
authorize @consolidacao, :show?
|
||||||
@motorista = params[:motorista]
|
@motorista = params[:motorista]
|
||||||
|
|
||||||
# Entregas pagas do período no banco existente (read-only)
|
# Entregas pagas do período no banco existente (read-only).
|
||||||
|
# Período pela DATA REAL (checkout), não pela planejada.
|
||||||
@entregas = Entrega.pagas
|
@entregas = Entrega.pagas
|
||||||
.da_conta_gade
|
.da_conta_gade
|
||||||
.no_periodo(@consolidacao.data_inicio, @consolidacao.data_fim)
|
.no_periodo_checkout(@consolidacao.data_inicio, @consolidacao.data_fim)
|
||||||
.do_motorista(@motorista)
|
.do_motorista(@motorista)
|
||||||
@entregas = @entregas.da_veiculo(@consolidacao.vehicle_ids) if @consolidacao.vehicle_ids.present?
|
@entregas = @entregas.da_veiculo(@consolidacao.vehicle_ids) if @consolidacao.vehicle_ids.present?
|
||||||
@entregas = @entregas.da_operacoes(@consolidacao.operacoes) if @consolidacao.operacoes.present?
|
@entregas = @entregas.da_operacoes(@consolidacao.operacoes) if @consolidacao.operacoes.present?
|
||||||
@entregas = @entregas.order(:planned_date)
|
@entregas = @entregas.order(:checkout)
|
||||||
|
|
||||||
# Classificações já feitas — agrupadas por tracking_id (uma entrega pode ter
|
# Classificações já feitas — agrupadas por tracking_id (uma entrega pode ter
|
||||||
# vários pilares). { tracking_id => [ConsolidacaoEntrega, ...] }
|
# vários pilares). { tracking_id => [ConsolidacaoEntrega, ...] }
|
||||||
@@ -184,7 +185,7 @@ class ConsolidacaoEntregasController < ApplicationController
|
|||||||
return [] unless motorista.present?
|
return [] unless motorista.present?
|
||||||
|
|
||||||
rel = Entrega.pagas.da_conta_gade
|
rel = Entrega.pagas.da_conta_gade
|
||||||
.no_periodo(@consolidacao.data_inicio, @consolidacao.data_fim)
|
.no_periodo_checkout(@consolidacao.data_inicio, @consolidacao.data_fim)
|
||||||
.do_motorista(motorista)
|
.do_motorista(motorista)
|
||||||
rel = rel.da_veiculo(@consolidacao.vehicle_ids) if @consolidacao.vehicle_ids.present?
|
rel = rel.da_veiculo(@consolidacao.vehicle_ids) if @consolidacao.vehicle_ids.present?
|
||||||
rel = rel.da_operacoes(@consolidacao.operacoes) if @consolidacao.operacoes.present?
|
rel = rel.da_operacoes(@consolidacao.operacoes) if @consolidacao.operacoes.present?
|
||||||
|
|||||||
@@ -38,14 +38,18 @@ class DashboardController < ApplicationController
|
|||||||
@operacoes_agrupadas = Operacao.agrupadas_por_mes
|
@operacoes_agrupadas = Operacao.agrupadas_por_mes
|
||||||
@operacao_filtro = Operacao.sanitizar(params[:operacoes])
|
@operacao_filtro = Operacao.sanitizar(params[:operacoes])
|
||||||
|
|
||||||
# Entregas do período (tabela read-only) — restritas à conta Gade
|
# PAGAS pela DATA REAL (checkout) — base de toda a análise financeira por data.
|
||||||
entregas = Entrega.da_conta_gade.no_periodo(@periodo_inicio, @periodo_fim)
|
pagas = Entrega.da_conta_gade.pagas.no_periodo_checkout(@periodo_inicio, @periodo_fim)
|
||||||
entregas = entregas.da_operacoes(@operacao_filtro) if @operacao_filtro.present?
|
pagas = pagas.da_operacoes(@operacao_filtro) if @operacao_filtro.present?
|
||||||
|
|
||||||
|
# PENDENTES (não concluídas) pela data planejada — não têm checkout.
|
||||||
|
pendentes = Entrega.da_conta_gade.pendentes.no_periodo(@periodo_inicio, @periodo_fim)
|
||||||
|
pendentes = pendentes.da_operacoes(@operacao_filtro) if @operacao_filtro.present?
|
||||||
|
|
||||||
# Totais gerais
|
# Totais gerais
|
||||||
@total_entregas = entregas.count
|
@entregas_pagas = pagas.count
|
||||||
@entregas_pagas = entregas.pagas.count
|
@entregas_pendentes = pendentes.count
|
||||||
@entregas_pendentes = @total_entregas - @entregas_pagas
|
@total_entregas = @entregas_pagas + @entregas_pendentes
|
||||||
|
|
||||||
# Configurações de preço
|
# Configurações de preço
|
||||||
config = Configuracao.mapa_de_precos
|
config = Configuracao.mapa_de_precos
|
||||||
@@ -54,12 +58,11 @@ class DashboardController < ApplicationController
|
|||||||
@valor_estimado = (@entregas_pagas * config[:entrega]).round(2)
|
@valor_estimado = (@entregas_pagas * config[:entrega]).round(2)
|
||||||
|
|
||||||
# Por motorista (top 10)
|
# Por motorista (top 10)
|
||||||
@motoristas = entregas.pagas
|
@motoristas = pagas.group(:driver)
|
||||||
.group(:driver)
|
.count
|
||||||
.count
|
.sort_by { |_, v| -v }
|
||||||
.sort_by { |_, v| -v }
|
.first(10)
|
||||||
.first(10)
|
.map do |driver, qtd|
|
||||||
.map do |driver, qtd|
|
|
||||||
{
|
{
|
||||||
nome: driver,
|
nome: driver,
|
||||||
entregas: qtd,
|
entregas: qtd,
|
||||||
@@ -68,15 +71,14 @@ class DashboardController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Por local de entrega (contact_name)
|
# Por local de entrega (contact_name)
|
||||||
@por_operacao = entregas.pagas
|
@por_operacao = pagas.group(:contact_name)
|
||||||
.group(:contact_name)
|
.count
|
||||||
.count
|
.sort_by { |_, v| -v }
|
||||||
.sort_by { |_, v| -v }
|
.first(6)
|
||||||
.first(6)
|
.to_h
|
||||||
.to_h
|
|
||||||
|
|
||||||
# Evolução diária no período (para Chart.js)
|
# Evolução diária no período (para Chart.js) — por data real (checkout)
|
||||||
@grafico_diario = build_grafico_diario(entregas, config[:entrega])
|
@grafico_diario = build_grafico_diario(pagas, config[:entrega])
|
||||||
|
|
||||||
# Consolidações cujo período (data_inicio..data_fim) cruza o período do dashboard
|
# Consolidações cujo período (data_inicio..data_fim) cruza o período do dashboard
|
||||||
# — independe de quando foram criadas (created_at).
|
# — independe de quando foram criadas (created_at).
|
||||||
@@ -174,18 +176,20 @@ class DashboardController < ApplicationController
|
|||||||
.sort_by { |_, v| -v }.first(10)
|
.sort_by { |_, v| -v }.first(10)
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_grafico_diario(entregas, preco_entrega)
|
# `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)
|
||||||
dias = (@periodo_inicio..@periodo_fim).to_a
|
dias = (@periodo_inicio..@periodo_fim).to_a
|
||||||
|
|
||||||
if dias.size <= MAX_DIAS_GRAFICO
|
if dias.size <= MAX_DIAS_GRAFICO
|
||||||
# Granularidade diária (períodos curtos)
|
# Granularidade diária (períodos curtos)
|
||||||
contagem = entregas.pagas.group("DATE(planned_date)").count.transform_keys(&:to_s)
|
contagem = pagas.group("DATE(checkout)").count.transform_keys(&:to_s)
|
||||||
labels = dias.map { |d| d.strftime('%d/%m') }
|
labels = dias.map { |d| d.strftime('%d/%m') }
|
||||||
valores = dias.map { |d| ((contagem[d.to_s] || 0) * preco_entrega).round(2) }
|
valores = dias.map { |d| ((contagem[d.to_s] || 0) * preco_entrega).round(2) }
|
||||||
qtds = dias.map { |d| contagem[d.to_s] || 0 }
|
qtds = dias.map { |d| contagem[d.to_s] || 0 }
|
||||||
else
|
else
|
||||||
# Período longo: agrega por mês para o gráfico não ficar vazio nem poluído.
|
# Período longo: agrega por mês para o gráfico não ficar vazio nem poluído.
|
||||||
contagem = entregas.pagas.group("TO_CHAR(planned_date, 'YYYY-MM')").count
|
contagem = pagas.group("TO_CHAR(checkout, 'YYYY-MM')").count
|
||||||
meses = meses_no_periodo
|
meses = meses_no_periodo
|
||||||
labels = meses.map { |m| Date.strptime(m, '%Y-%m').strftime('%m/%Y') }
|
labels = meses.map { |m| Date.strptime(m, '%Y-%m').strftime('%m/%Y') }
|
||||||
valores = meses.map { |m| ((contagem[m] || 0) * preco_entrega).round(2) }
|
valores = meses.map { |m| ((contagem[m] || 0) * preco_entrega).round(2) }
|
||||||
|
|||||||
@@ -27,6 +27,14 @@ class Entrega < ApplicationRecord
|
|||||||
where(planned_date: inicio.to_date.beginning_of_day..fim.to_date.end_of_day)
|
where(planned_date: inicio.to_date.beginning_of_day..fim.to_date.end_of_day)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Período pela DATA REAL da entrega (checkout) — usada nas análises financeiras
|
||||||
|
# ("quando a entrega foi concluída"). Comparação naïve com Date (intervalo
|
||||||
|
# meio-aberto: >= início e < fim+1), SEM conversão de fuso — bate com a análise
|
||||||
|
# feita direto no banco. Só faz sentido sobre entregas .pagas (checkout != nil).
|
||||||
|
scope :no_periodo_checkout, ->(inicio, fim) {
|
||||||
|
where('checkout >= ? AND checkout < ?', inicio.to_date, fim.to_date + 1)
|
||||||
|
}
|
||||||
|
|
||||||
scope :do_motorista, ->(nome) {
|
scope :do_motorista, ->(nome) {
|
||||||
where(driver: nome)
|
where(driver: nome)
|
||||||
}
|
}
|
||||||
@@ -98,9 +106,10 @@ class Entrega < ApplicationRecord
|
|||||||
base.distinct.order(:vehicle).pluck(:vehicle).compact.reject(&:empty?)
|
base.distinct.order(:vehicle).pluck(:vehicle).compact.reject(&:empty?)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Contagem de entregas pagas para cálculo estimado
|
# Contagem de entregas pagas para cálculo estimado.
|
||||||
|
# Período pela DATA REAL da entrega (checkout) — ver no_periodo_checkout.
|
||||||
def self.contar_pagas(inicio:, fim:, motorista: nil, vehicle: nil, operacoes: nil)
|
def self.contar_pagas(inicio:, fim:, motorista: nil, vehicle: nil, operacoes: nil)
|
||||||
base = pagas.da_conta_gade.no_periodo(inicio, fim)
|
base = pagas.da_conta_gade.no_periodo_checkout(inicio, fim)
|
||||||
base = base.do_motorista(motorista) if motorista.present?
|
base = base.do_motorista(motorista) if motorista.present?
|
||||||
base = base.da_veiculo(vehicle) if vehicle.present?
|
base = base.da_veiculo(vehicle) if vehicle.present?
|
||||||
base = base.da_operacoes(operacoes) if operacoes.present?
|
base = base.da_operacoes(operacoes) if operacoes.present?
|
||||||
|
|||||||
@@ -74,11 +74,14 @@ class Operacao
|
|||||||
return vazio if validas.empty?
|
return vazio if validas.empty?
|
||||||
|
|
||||||
entregas = Entrega.da_conta_gade.da_operacoes(validas)
|
entregas = Entrega.da_conta_gade.da_operacoes(validas)
|
||||||
|
pagas = entregas.pagas
|
||||||
{
|
{
|
||||||
motoristas: entregas.distinct.order(:driver).pluck(:driver).compact.reject(&:blank?),
|
motoristas: entregas.distinct.order(:driver).pluck(:driver).compact.reject(&:blank?),
|
||||||
veiculos: entregas.distinct.order(:vehicle).pluck(:vehicle).compact.reject(&:blank?),
|
veiculos: entregas.distinct.order(:vehicle).pluck(:vehicle).compact.reject(&:blank?),
|
||||||
inicio: entregas.minimum(:planned_date)&.to_date,
|
# Período sugerido pela DATA REAL (checkout), igual ao filtro de
|
||||||
fim: entregas.maximum(:planned_date)&.to_date
|
# elegibilidade; cai para planned_date se ainda não houver pagas.
|
||||||
|
inicio: (pagas.minimum(:checkout) || entregas.minimum(:planned_date))&.to_date,
|
||||||
|
fim: (pagas.maximum(:checkout) || entregas.maximum(:planned_date))&.to_date
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<p class="text-gray-400 text-xs truncate">📍 <%= e.address.presence || 'sem endereço' %></p>
|
<p class="text-gray-400 text-xs truncate">📍 <%= e.address.presence || 'sem endereço' %></p>
|
||||||
<p class="text-gray-500 text-xs">
|
<p class="text-gray-500 text-xs">
|
||||||
📅 <%= e.planned_date %> · 🚚 <%= e.vehicle.presence || 'sem veículo' %>
|
📅 <%= e.checkout&.strftime('%d/%m/%Y') || '—' %> · 🚚 <%= e.vehicle.presence || 'sem veículo' %>
|
||||||
<% if e.atraso_minutos > 0 %> · ⏱️ atraso <%= e.atraso_minutos %>min<% end %>
|
<% if e.atraso_minutos > 0 %> · ⏱️ atraso <%= e.atraso_minutos %>min<% end %>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user