Criação da visão geral da consolidação por motorista e Estilização
This commit is contained in:
@@ -13,10 +13,21 @@ class ConsolidacoesController < ApplicationController
|
||||
# Formas de pagamento aceitas (o select da UI usa esta mesma lista).
|
||||
FORMAS_PAGAMENTO = %w[pix transferencia dinheiro].freeze
|
||||
|
||||
# GET /consolidacoes — lista com filtros
|
||||
# GET /consolidacoes?visao=lista|motoristas — a MESMA tela em dois modos de
|
||||
# visualização, com os mesmos filtros:
|
||||
#
|
||||
# lista → um card por CONSOLIDAÇÃO (o de sempre);
|
||||
# motoristas → um card por MOTORISTA, com o total dele no período e, ao
|
||||
# clicar, as consolidações que compõem aquele valor.
|
||||
#
|
||||
# São duas leituras do mesmo recorte: o trabalho é organizado por consolidação,
|
||||
# mas o pagamento é por motorista — antes, para saber quanto um motorista tinha
|
||||
# fechado no mês, era preciso abrir consolidação por consolidação e somar à mão.
|
||||
def index
|
||||
authorize Consolidacao
|
||||
|
||||
@visao = params[:visao] == 'motoristas' ? 'motoristas' : 'lista'
|
||||
|
||||
@consolidacoes = Consolidacao.ativas.recentes.includes(:criador)
|
||||
|
||||
# Filtros
|
||||
@@ -38,42 +49,25 @@ class ConsolidacoesController < ApplicationController
|
||||
if %w[pago pendente parcial].include?(params[:pagamento])
|
||||
@consolidacoes = @consolidacoes.public_send("pagamento_#{params[:pagamento]}")
|
||||
end
|
||||
|
||||
montar_totais if @visao == 'motoristas'
|
||||
end
|
||||
|
||||
# GET /consolidacoes/totais?inicio=&fim=&motorista=&rascunhos=1
|
||||
#
|
||||
# "Quanto cada motorista somou no período". A lista de consolidações mostra um
|
||||
# card por CONSOLIDAÇÃO, mas o pagamento é por MOTORISTA: para saber quanto um
|
||||
# motorista fechou no mês era preciso abrir consolidação por consolidação e
|
||||
# somar à mão. Aqui o total vem pronto e, clicando no motorista (?motorista=),
|
||||
# a tela abre as consolidações que compõem aquele valor.
|
||||
def totais
|
||||
authorize Consolidacao, :index?
|
||||
|
||||
@inicio, @fim = periodo_totais
|
||||
@incluir_rascunhos = params[:rascunhos] == '1'
|
||||
@motorista = params[:motorista].presence
|
||||
@totais = Analytics::TotaisPorMotorista.new(
|
||||
inicio: @inicio, fim: @fim, incluir_rascunhos: @incluir_rascunhos
|
||||
)
|
||||
# Drill-down: as consolidações do motorista clicado (a tabela geral continua
|
||||
# na tela, então o service é montado sem recorte de motorista).
|
||||
@detalhe = @motorista ? @totais.consolidacoes_de(@motorista) : nil
|
||||
end
|
||||
|
||||
# GET /consolidacoes/totais_pdf — o mesmo relatório em PDF. Com ?motorista=
|
||||
# sai só o extrato daquele motorista (com espaço de assinatura).
|
||||
# GET /consolidacoes/totais_pdf — o modo "Por motorista" em PDF, com os mesmos
|
||||
# filtros da tela. Com ?detalhe=NOME sai só o extrato daquele motorista (com
|
||||
# espaço de assinatura).
|
||||
def totais_pdf
|
||||
authorize Consolidacao, :index?
|
||||
|
||||
inicio, fim = periodo_totais
|
||||
totais = Analytics::TotaisPorMotorista.new(
|
||||
inicio: inicio, fim: fim,
|
||||
motorista: params[:motorista].presence,
|
||||
incluir_rascunhos: params[:rascunhos] == '1'
|
||||
motorista: params[:detalhe].presence,
|
||||
status: params[:status].presence || 'todos',
|
||||
busca: params[:motorista].presence
|
||||
)
|
||||
|
||||
nome = params[:motorista].presence&.parameterize(separator: '_')
|
||||
nome = params[:detalhe].presence&.parameterize(separator: '_')
|
||||
arquivo = ['totais', nome, inicio.strftime('%Y%m%d'), fim.strftime('%Y%m%d')].compact.join('_')
|
||||
send_data Pdf::TotaisMotoristaPdf.new(totais: totais, detalhar: params[:detalhar] != '0').render,
|
||||
filename: "#{arquivo}.pdf",
|
||||
@@ -490,6 +484,20 @@ class ConsolidacoesController < ApplicationController
|
||||
|
||||
private
|
||||
|
||||
# Modo "Por motorista": os totais saem do MESMO recorte da lista (período,
|
||||
# status e busca por motorista), para as duas visões nunca contarem coisas
|
||||
# diferentes. `detalhe` é o motorista aberto (o clique na linha).
|
||||
def montar_totais
|
||||
@inicio, @fim = periodo_totais
|
||||
@totais = Analytics::TotaisPorMotorista.new(
|
||||
inicio: @inicio, fim: @fim,
|
||||
status: params[:status].presence || 'todos',
|
||||
busca: params[:motorista].presence
|
||||
)
|
||||
@detalhe_motorista = params[:detalhe].presence
|
||||
@detalhe = @detalhe_motorista ? @totais.consolidacoes_de(@detalhe_motorista) : nil
|
||||
end
|
||||
|
||||
# Período do relatório de totais. Default: o MÊS CORRENTE INTEIRO — o fim é o
|
||||
# último dia do mês, não "hoje", porque o recorte exige a consolidação inteira
|
||||
# dentro da faixa (Consolidacao.no_periodo) e um fechamento que vai até 31/08
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user