Criação da visão geral da consolidação por motorista e Estilização

This commit is contained in:
2026-08-26 15:15:44 -03:00
parent cd99a22553
commit 7a8ec1bc16
14 changed files with 508 additions and 525 deletions

View File

@@ -3,47 +3,24 @@ module Motorista
class DashboardController < ApplicationController
before_action :garantir_motorista
# GET /motorista
# GET /motorista?inicio=&fim=
#
# UMA tela só: o motorista escolhe o período e vê, para aquele recorte, o que
# já foi FECHADO pela empresa, o que ainda é ESTIMATIVA e de onde vem cada
# centavo (os fechamentos que compõem o total). Antes o total ficava numa
# tela e a composição em outra — e nenhuma das duas tinha período.
def index
nome = current_user.nome
# Card 1 — Valor ESTIMADO (mês atual): entregas ATENDIDAS × preco_entrega.
#
# Atendida = o motorista FOI ao local e fechou a visita, com sucesso
# ('completed') OU insucesso ('failed') — no insucesso o deslocamento
# aconteceu e teve custo, então a empresa paga os dois. É o MESMO recorte do
# dashboard administrativo e da consolidação (ver Entrega::STATUS_ATENDIDO e
# Entrega.contar_atendidas): usava `pagas` (só concluídas) e o motorista via
# um valor MENOR que o do fechamento, sem entender de onde vinha a diferença.
#
# ⚠️ O eixo é o CHECKOUT (data real da visita), não planned_date: falhada TEM
# checkout, e uma entrega planejada em 31/07 mas fechada em 01/08 pertence a
# agosto — igual ao que a consolidação considera elegível.
@estimado_inicio = Date.current.beginning_of_month
@estimado_fim = Date.current
atendidas = Entrega.atendidas.da_conta_gade
.do_motorista(nome)
.no_periodo_checkout(@estimado_inicio, @estimado_fim)
@entregas_concluidas = atendidas.concluidas.count
@entregas_falhadas = atendidas.falhadas.count
@entregas_mes = @entregas_concluidas + @entregas_falhadas
@valor_estimado = @entregas_mes * Configuracao.preco_entrega
@inicio, @fim = periodo_selecionado
@faixa_total = faixa_completa(nome) # para o atalho "Tudo"
# Card 2 — Valor CONSOLIDADO: soma das consolidações finalizadas
@minhas_consolidacoes = Consolidacao.ativas
.joins(:consolidacao_motoristas)
.where(consolidacao_motoristas: { motorista_nome: nome, arquivado_em: nil })
.recentes
.distinct
@valor_consolidado = ConsolidacaoMotorista.ativos
.joins(:consolidacao)
.where(motorista_nome: nome,
consolidacoes: { status: :finalizada, deleted_at: nil })
.sum(:valor_total)
carregar_estimado(nome)
carregar_fechado(nome)
# Aviso in-app: pagamentos confirmados nos últimos 7 dias (notificação na
# própria página do motorista, além de WhatsApp/email).
# própria página do motorista, além de WhatsApp/email). Independe do
# período escolhido — é um aviso, não um relatório.
@pagamentos_recentes = ConsolidacaoMotorista
.joins(:consolidacao)
.where(motorista_nome: nome,
@@ -54,23 +31,11 @@ module Motorista
.includes(:consolidacao)
end
# GET /motorista/totais?inicio=&fim=
#
# "Quanto eu fechei neste período e de onde vem esse valor". O card do painel
# mostra só o total acumulado; aqui o motorista escolhe o período, vê o total
# FECHADO (consolidações finalizadas) e a lista de consolidações que compõem
# o valor — a mesma conta que o admin vê em /consolidacoes/totais, montada
# pelo mesmo service para os dois números não poderem divergir.
def totais
@inicio, @fim = periodo_totais
@totais = totais_do_periodo
@consolidacoes = @totais.consolidacoes_de(current_user.nome)
end
# GET /motorista/totais/pdf — o extrato do período em PDF (com assinatura),
# para o motorista guardar ou mandar por WhatsApp.
# GET /motorista/totais/pdf?inicio=&fim= — o extrato do período (total,
# composição e assinaturas), para guardar ou mandar por WhatsApp. Mesmo
# service da tela, então o papel e o painel nunca divergem.
def totais_pdf
inicio, fim = periodo_totais
inicio, fim = periodo_selecionado
totais = Analytics::TotaisPorMotorista.new(
inicio: inicio, fim: fim, motorista: current_user.nome
)
@@ -85,16 +50,65 @@ module Motorista
private
def totais_do_periodo
Analytics::TotaisPorMotorista.new(
inicio: @inicio, fim: @fim, motorista: current_user.nome
)
# Card ESTIMADO: entregas ATENDIDAS × preco_entrega dentro do período.
#
# Atendida = o motorista FOI ao local e fechou a visita, com sucesso
# ('completed') OU insucesso ('failed') — no insucesso o deslocamento
# aconteceu e teve custo, então a empresa paga os dois. É o MESMO recorte do
# dashboard administrativo e da consolidação (ver Entrega::STATUS_ATENDIDO e
# Entrega.contar_atendidas): usava `pagas` (só concluídas) e o motorista via
# um valor MENOR que o do fechamento, sem entender de onde vinha a diferença.
#
# ⚠️ O eixo é o CHECKOUT (data real da visita), não planned_date: falhada TEM
# checkout, e uma entrega planejada em 31/07 mas fechada em 01/08 pertence a
# agosto — igual ao que a consolidação considera elegível.
#
# O fim é limitado a HOJE: estimar entregas de dias que ainda não
# aconteceram não faz sentido (o período pode ir até o fim do mês).
def carregar_estimado(nome)
@estimado_inicio = @inicio
@estimado_fim = [@fim, Date.current].min
if @estimado_fim < @estimado_inicio
@entregas_concluidas = @entregas_falhadas = @entregas_mes = 0
@valor_estimado = 0
return
end
atendidas = Entrega.atendidas.da_conta_gade
.do_motorista(nome)
.no_periodo_checkout(@estimado_inicio, @estimado_fim)
@entregas_concluidas = atendidas.concluidas.count
@entregas_falhadas = atendidas.falhadas.count
@entregas_mes = @entregas_concluidas + @entregas_falhadas
@valor_estimado = @entregas_mes * Configuracao.preco_entrega
end
# Default: mês corrente INTEIRO (fim = último dia do mês). O recorte pede a
# Card FECHADO + composição: o mesmo service do modo "Por motorista" do
# admin, recortado neste motorista — os dois lados mostram o mesmo número.
def carregar_fechado(nome)
@totais = Analytics::TotaisPorMotorista.new(inicio: @inicio, fim: @fim, motorista: nome)
@consolidacoes = @totais.consolidacoes_de(nome)
@valor_consolidado = @totais.total_geral
end
# Primeira e última data de fechamento do motorista — alimenta o atalho
# "Tudo" com datas reais em vez de uma faixa inventada.
def faixa_completa(nome)
escopo = Consolidacao.ativas.finalizada
.joins(:consolidacao_motoristas)
.where(consolidacao_motoristas: { motorista_nome: nome, arquivado_em: nil })
inicio = escopo.minimum(:data_inicio)
fim = escopo.maximum(:data_fim)
return nil if inicio.nil? || fim.nil?
[inicio.to_date, fim.to_date]
end
# Default: mês corrente INTEIRO (fim = último dia do mês). O recorte exige a
# consolidação inteira dentro da faixa, então terminar em "hoje" esconderia
# um fechamento que vai até o fim do mês. Mesma regra do relatório do admin.
def periodo_totais
# um fechamento que vai até o fim do mês. Mesma regra do lado do admin.
def periodo_selecionado
inicio = parse_data(params[:inicio]) || Date.current.beginning_of_month
fim = parse_data(params[:fim]) || Date.current.end_of_month
inicio, fim = fim, inicio if fim < inicio