Correção do dash board de acompanhamento diario das entregas

This commit is contained in:
2026-06-29 20:26:30 -03:00
parent 11531479f8
commit 59c0caa774
6 changed files with 77 additions and 35 deletions

View File

@@ -17,16 +17,29 @@ module Analytics
# Centro padrão do mapa quando não há coordenadas (Grande São Paulo).
SP_CENTRO = [-23.55, -46.63].freeze
def initialize(tabelas:, inicio:, fim:)
# inicio/fim são OPCIONAIS: quando nil, não há filtro de data e o conjunto é a
# própria operação inteira (visão de operação única). O filtro de período só é
# usado na visão Global.
def initialize(tabelas:, inicio: nil, fim: nil)
@tabelas = Operacao.sanitizar(Array(tabelas))
@inicio = inicio.to_date
@fim = fim.to_date
@inicio = inicio&.to_date
@fim = fim&.to_date
end
def operacoes_label
@tabelas.map { |t| Operacao.label(t) }.join(', ')
end
# Faixa real das entregas carregadas (pela data de checkout) — para exibir o
# período natural da operação no cabeçalho/painel.
def data_inicio
datas_checkout.min
end
def data_fim
datas_checkout.max
end
# Linhas cruas (Array de Hash com chave string) — base de todas as agregações.
def registros
@registros ||= carregar
@@ -128,6 +141,10 @@ module Analytics
private
def datas_checkout
@datas_checkout ||= registros.filter_map { |r| data_de(r['checkout']) }
end
def contagem(rows, coluna)
rows.group_by { |r| r[coluna].presence || '—' }
.map { |nome, grupo| { nome: nome, total: grupo.size } }
@@ -160,18 +177,19 @@ module Analytics
conn = ActiveRecord::Base.connection
unions = @tabelas.map do |tabela|
gade = conn.quote_table_name(tabela)
label = conn.quote(Operacao.label(tabela))
gade = conn.quote_table_name(tabela)
label = conn.quote(Operacao.label(tabela))
status = coluna_status_gade(conn, tabela)
<<~SQL.strip
SELECT #{label} AS operacao,
r.driver, r.status, r.observation, r.contact_name,
r.checkout, r.planned_date,
r.latitude, r.longitude,
r.checkout_latitude, r.checkout_longitude,
g.status AS status_gade
#{status} AS status_gade
FROM ultimo r
INNER JOIN #{gade} g ON r.reference_id::text = g.nota_fiscal
WHERE r.rn = 1 AND (#{periodo_sql(conn)})
WHERE r.rn = 1#{filtro_periodo(conn)}
SQL
end
@@ -188,16 +206,24 @@ module Analytics
conn.select_all(sql).to_a
end
# g.status existe só em ALGUMAS tabelas de operação (ex.: ubs_norte). Quando a
# coluna não existe, devolve NULL — o painel "Por Status" cai no rótulo "—".
# (A única coluna garantida em toda tabela gade é nota_fiscal.)
def coluna_status_gade(conn, tabela)
colunas = conn.columns(tabela).map(&:name)
colunas.include?('status') ? 'g.status' : 'CAST(NULL AS text)'
end
# Filtro de período OPCIONAL — usado só na visão Global (inicio/fim presentes).
# Concluídas/falhas pela DATA REAL (checkout); pendentes (sem checkout) pela
# data planejada. Espelha Entrega.no_periodo_checkout + no_periodo.
def periodo_sql(conn)
def filtro_periodo(conn)
return '' unless @inicio && @fim
ini = conn.quote(@inicio)
fim_excl = conn.quote(@fim + 1)
fim_dia = conn.quote(@fim.end_of_day)
<<~SQL.strip
(r.checkout >= #{ini} AND r.checkout < #{fim_excl})
OR (r.checkout IS NULL AND r.planned_date >= #{ini} AND r.planned_date <= #{fim_dia})
SQL
" AND ((r.checkout >= #{ini} AND r.checkout < #{fim_excl})" \
" OR (r.checkout IS NULL AND r.planned_date >= #{ini} AND r.planned_date <= #{fim_dia}))"
end
# Replica Entrega.da_conta_gade como fragmento "AND (account_id ...)".