Correção e Adição do filtro ao vivo
This commit is contained in:
@@ -20,16 +20,39 @@ module Analytics
|
||||
# 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)
|
||||
#
|
||||
# filtros: Hash de cross-filter (coluna => valor) aplicado em memória — clicar
|
||||
# numa célula da tabela (motorista/STS/status/observação) refiltra TODO o
|
||||
# dashboard por aquele valor. Ex.: { 'driver' => 'Carlos' }.
|
||||
def initialize(tabelas:, inicio: nil, fim: nil, filtros: {})
|
||||
@tabelas = Operacao.sanitizar(Array(tabelas))
|
||||
@inicio = inicio&.to_date
|
||||
@fim = fim&.to_date
|
||||
@filtros = (filtros || {}).reject { |_, v| v.to_s.strip.empty? }
|
||||
end
|
||||
|
||||
def operacoes_label
|
||||
@tabelas.map { |t| Operacao.label(t) }.join(', ')
|
||||
end
|
||||
|
||||
# Linhas após o cross-filter — base de TODAS as agregações/KPIs.
|
||||
def linhas
|
||||
@linhas ||= if @filtros.empty?
|
||||
registros
|
||||
else
|
||||
registros.select { |r| @filtros.all? { |col, val| r[col].to_s == val.to_s } }
|
||||
end
|
||||
end
|
||||
|
||||
# Taxas (úteis no comparativo).
|
||||
def taxa_sucesso
|
||||
pct(sucesso, total)
|
||||
end
|
||||
|
||||
def taxa_insucesso
|
||||
pct(recusas, total)
|
||||
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
|
||||
@@ -51,15 +74,15 @@ module Analytics
|
||||
|
||||
# ── KPIs ─────────────────────────────────────────────────────
|
||||
def total
|
||||
registros.size
|
||||
linhas.size
|
||||
end
|
||||
|
||||
def sucesso
|
||||
registros.count { |r| r['status'] == 'completed' }
|
||||
linhas.count { |r| r['status'] == 'completed' }
|
||||
end
|
||||
|
||||
def recusas
|
||||
registros.count { |r| Entrega::STATUS_FALHA.include?(r['status']) }
|
||||
linhas.count { |r| Entrega::STATUS_FALHA.include?(r['status']) }
|
||||
end
|
||||
|
||||
# Em aberto: nem concluídas nem falhadas.
|
||||
@@ -79,7 +102,7 @@ module Analytics
|
||||
|
||||
# Falhas agrupadas por observação (motivo), % sobre o total de falhas.
|
||||
def indices_falha
|
||||
falhas = registros.select { |r| Entrega::STATUS_FALHA.include?(r['status']) }
|
||||
falhas = linhas.select { |r| Entrega::STATUS_FALHA.include?(r['status']) }
|
||||
total_falhas = falhas.size
|
||||
falhas.group_by { |r| r['observation'].presence || 'SEM OBSERVAÇÃO' }
|
||||
.map { |obs, rows| { observation: obs, total: rows.size, pct: pct(rows.size, total_falhas) } }
|
||||
@@ -88,25 +111,25 @@ module Analytics
|
||||
|
||||
# Contagem por status da tabela gade (RECORRENTE/NOVO/...).
|
||||
def por_status_gade
|
||||
registros.group_by { |r| r['status_gade'].presence || '—' }
|
||||
.map { |st, rows| { status: st, total: rows.size } }
|
||||
.sort_by { |h| -h[:total] }
|
||||
linhas.group_by { |r| r['status_gade'].presence || '—' }
|
||||
.map { |st, rows| { status: st, total: rows.size } }
|
||||
.sort_by { |h| -h[:total] }
|
||||
end
|
||||
|
||||
# NFs por motorista (todas as entregas), desc.
|
||||
def por_motorista
|
||||
contagem(registros, 'driver')
|
||||
contagem(linhas, 'driver')
|
||||
end
|
||||
|
||||
# Entregas CONCLUÍDAS por unidade (contact_name), desc.
|
||||
def por_sts
|
||||
contagem(registros.select { |r| r['status'] == 'completed' }, 'contact_name')
|
||||
contagem(linhas.select { |r| r['status'] == 'completed' }, 'contact_name')
|
||||
end
|
||||
|
||||
# Por dia (DATE do checkout): completas vs falhas — gráfico de barras.
|
||||
def por_dia
|
||||
por_data = Hash.new { |h, k| h[k] = { completed: 0, failed: 0 } }
|
||||
registros.each do |r|
|
||||
linhas.each do |r|
|
||||
d = data_de(r['checkout'])
|
||||
next unless d
|
||||
if r['status'] == 'completed'
|
||||
@@ -126,7 +149,7 @@ module Analytics
|
||||
# Pontos [lat, lng] das entregas concluídas para o heatmap.
|
||||
# Prefere as coordenadas de CHECKOUT (saída); cai para as de CHECKIN.
|
||||
def pontos_mapa
|
||||
@pontos_mapa ||= registros.filter_map do |r|
|
||||
@pontos_mapa ||= linhas.filter_map do |r|
|
||||
next unless r['status'] == 'completed'
|
||||
lat = num(r['checkout_latitude']) || num(r['latitude'])
|
||||
lng = num(r['checkout_longitude']) || num(r['longitude'])
|
||||
@@ -142,7 +165,7 @@ module Analytics
|
||||
private
|
||||
|
||||
def datas_checkout
|
||||
@datas_checkout ||= registros.filter_map { |r| data_de(r['checkout']) }
|
||||
@datas_checkout ||= linhas.filter_map { |r| data_de(r['checkout']) }
|
||||
end
|
||||
|
||||
def contagem(rows, coluna)
|
||||
|
||||
Reference in New Issue
Block a user