# app/controllers/dashboard_controller.rb class DashboardController < ApplicationController MAX_DIAS_GRAFICO = 92 # limita a granularidade diária do gráfico (≈ 1 trimestre) def index skip_authorization # Motorista tem painel próprio — não enxerga o dashboard administrativo return redirect_to(motorista_dashboard_path) if current_user.motorista? @periodo_inicio, @periodo_fim = periodo_selecionado carregar_dados_dashboard end private # Faixa de datas vinda do filtro de calendário (params inicio/fim). # Default: do início do mês corrente até hoje. Datas inválidas caem no default # e a ordem é normalizada caso venham invertidas. def periodo_selecionado inicio = parse_data(params[:inicio]) || Date.current.beginning_of_month fim = parse_data(params[:fim]) || Date.current inicio, fim = fim, inicio if fim < inicio [inicio, fim] end # Parse tolerante: data inválida/ausente vira nil (para o default assumir). def parse_data(str) return nil if str.blank? Date.parse(str) rescue ArgumentError, TypeError nil end def carregar_dados_dashboard # Entregas do período (tabela read-only) — restritas à conta Gade entregas = Entrega.da_conta_gade.no_periodo(@periodo_inicio, @periodo_fim) # Totais gerais @total_entregas = entregas.count @entregas_pagas = entregas.pagas.count @entregas_pendentes = @total_entregas - @entregas_pagas # Configurações de preço config = Configuracao.mapa_de_precos # Valor estimado total @valor_estimado = (@entregas_pagas * config[:entrega]).round(2) # Por motorista (top 10) @motoristas = entregas.pagas .group(:driver) .count .sort_by { |_, v| -v } .first(10) .map do |driver, qtd| { nome: driver, entregas: qtd, valor: (qtd * config[:entrega]).round(2) } end # Por operação (route_id → contact_name) @por_operacao = entregas.pagas .group(:contact_name) .count .sort_by { |_, v| -v } .first(6) .to_h # Evolução diária no período (para Chart.js) @grafico_diario = build_grafico_diario(entregas, config[:entrega]) # Consolidações criadas no período @consolidacoes_mes = Consolidacao.ativas.where(created_at: @periodo_inicio.beginning_of_day..@periodo_fim.end_of_day) @consolidacoes_abertas = @consolidacoes_mes.where(status: :rascunho).count @consolidacoes_fechadas = @consolidacoes_mes.where(status: :finalizada).count # Histórico estimado mais recente @historico_recente = HistoricoEstimado.order(created_at: :desc).limit(5) end def build_grafico_diario(entregas, preco_entrega) # Em períodos muito longos, agrupa o gráfico de forma a não gerar centenas de pontos. dias = (@periodo_inicio..@periodo_fim).to_a return { labels: [], valores: [], qtds: [] } if dias.size > MAX_DIAS_GRAFICO contagem = entregas.pagas .group("DATE(planned_date)") .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 } { labels: labels, valores: valores, qtds: qtds } end end