Grande correção do filtro de veiculos na area de consolidação

This commit is contained in:
2026-07-03 09:58:59 -03:00
parent 83310e9e66
commit eca6df39eb
17 changed files with 681 additions and 41 deletions

View File

@@ -88,6 +88,7 @@ class ConsolidacaoEntregasController < ApplicationController
motorista_nome: params[:motorista],
tipo: params[:tipo],
valor_aplicado: valor_classificacao(params[:tipo]),
vehicle: veiculo_do_tracking(params[:tracking_id]), # snapshot p/ fechar por veículo
created_by: current_user.id
)
ativo = true
@@ -132,11 +133,13 @@ class ConsolidacaoEntregasController < ApplicationController
.destroy_all
else
# ADICIONA o pilar às entregas (não remove os demais já marcados).
valor = valor_classificacao(tipo)
valor = valor_classificacao(tipo)
veiculos = veiculos_dos_trackings(tracking_ids) # tracking_id => vehicle (snapshot)
tracking_ids.each do |tid|
ce = @consolidacao.consolidacao_entregas.find_or_initialize_by(tracking_id: tid, tipo: tipo)
ce.assign_attributes(motorista_nome: motorista,
valor_aplicado: valor, created_by: current_user.id)
ce.vehicle = veiculos[tid] if ce.vehicle.blank?
ce.save!
end
end
@@ -246,6 +249,7 @@ class ConsolidacaoEntregasController < ApplicationController
nf: params[:nf],
obs: params[:obs],
valor_extra: valor_extraordinaria_param,
vehicle: params[:vehicle], # veículo escolhido no lançamento (Q3)
user: current_user
)
auditar!(:editar, @consolidacao,
@@ -271,6 +275,7 @@ class ConsolidacaoEntregasController < ApplicationController
motorista = @consolidacao.adicionar_termos!(
motorista: params[:motorista].to_s.strip,
quantidade: params[:quantidade],
vehicle: params[:vehicle], # veículo escolhido no lançamento (Q3)
user: current_user
)
auditar!(:editar, @consolidacao,
@@ -315,12 +320,104 @@ class ConsolidacaoEntregasController < ApplicationController
end
end
# POST /consolidacoes/:consolidacao_id/consolidacao_entregas/fechar_veiculo
# Consolida (fecha) UM veículo do motorista. Exige que o veículo esteja 100%
# classificado. O pagamento continua sendo por motorista (não é pago aqui).
def fechar_veiculo
authorize @consolidacao, :update?
motorista = params[:motorista]
veiculo = params[:vehicle].to_s
return render_veiculo_erro('Veículo/motorista inválido.') unless motorista_na_consolidacao?(motorista) && veiculo.present?
status = veiculos_status(motorista).find { |v| v[:vehicle] == veiculo }
return render_veiculo_erro('Classifique todas as entregas deste veículo antes de consolidar.') if status && !status[:completo]
cv = @consolidacao.consolidacao_veiculos.find_or_create_by!(motorista_nome: motorista, vehicle: veiculo)
cv.fechar!(current_user)
auditar!(:editar, @consolidacao, dados_novos: { fechar_veiculo: veiculo, motorista: motorista })
responder_veiculo(motorista, "Veículo #{veiculo} consolidado.")
end
# POST .../reabrir_veiculo — reabre um veículo já consolidado (reversível).
def reabrir_veiculo
authorize @consolidacao, :update?
motorista = params[:motorista]
cv = @consolidacao.consolidacao_veiculos.find_by(motorista_nome: motorista, vehicle: params[:vehicle].to_s)
return render_veiculo_erro('Veículo não encontrado.') unless cv
cv.reabrir!(current_user)
auditar!(:editar, @consolidacao, dados_novos: { reabrir_veiculo: cv.vehicle, motorista: motorista })
responder_veiculo(motorista, "Veículo #{cv.vehicle} reaberto.")
end
# POST .../arquivar_veiculo — tira um veículo do gate de finalização (reversível).
# As entregas já classificadas dele continuam somando no pagamento do motorista.
def arquivar_veiculo
authorize @consolidacao, :update?
motorista = params[:motorista]
veiculo = params[:vehicle].to_s
return render_veiculo_erro('Veículo/motorista inválido.') unless motorista_na_consolidacao?(motorista) && veiculo.present?
cv = @consolidacao.consolidacao_veiculos.find_or_create_by!(motorista_nome: motorista, vehicle: veiculo)
cv.arquivar!(current_user)
auditar!(:editar, @consolidacao, dados_novos: { arquivar_veiculo: veiculo, motorista: motorista })
responder_veiculo(motorista, "Veículo #{veiculo} arquivado — fora da finalização.")
end
# POST .../desarquivar_veiculo — restaura um veículo arquivado.
def desarquivar_veiculo
authorize @consolidacao, :update?
motorista = params[:motorista]
cv = @consolidacao.consolidacao_veiculos.find_by(motorista_nome: motorista, vehicle: params[:vehicle].to_s)
return render_veiculo_erro('Veículo não encontrado.') unless cv
cv.desarquivar!(current_user)
auditar!(:editar, @consolidacao, dados_novos: { desarquivar_veiculo: cv.vehicle, motorista: motorista })
responder_veiculo(motorista, "Veículo #{cv.vehicle} restaurado.")
end
private
def set_consolidacao
@consolidacao = Consolidacao.find(params[:consolidacao_id])
end
# Resposta padrão das ações de veículo: JSON com o resumo atualizado (barra +
# chips com o novo estado) ou redirect de volta pra tela de validação.
def responder_veiculo(motorista, aviso)
respond_to do |format|
format.json { render json: resumo_json(motorista, vehicles: params[:vehicle_sel]) }
format.html do
redirect_to validar_consolidacao_consolidacao_entregas_path(
@consolidacao, motorista: motorista, vehicle: veiculos_param(params[:vehicle_sel]).presence
), notice: aviso
end
end
end
def render_veiculo_erro(msg)
respond_to do |format|
format.json { render json: { ok: false, erro: msg }, status: :unprocessable_entity }
format.html do
redirect_to validar_consolidacao_consolidacao_entregas_path(@consolidacao, motorista: params[:motorista]),
alert: msg
end
end
end
# Veículo (snapshot da rastreio) de UM tracking_id. nil para sintéticos.
def veiculo_do_tracking(tracking_id)
Entrega.da_conta_gade.find_by(tracking_id: tracking_id)&.vehicle
end
# Mapa tracking_id => vehicle para um lote (uma query só).
def veiculos_dos_trackings(ids)
return {} if ids.blank?
Entrega.da_conta_gade.where(tracking_id: ids).pluck(:tracking_id, :vehicle).to_h
end
def bloquear_se_finalizada
return unless @consolidacao.finalizada? && current_user.operador?
redirect_to @consolidacao, alert: 'Consolidação finalizada — apenas admin/gerente podem editar.'
@@ -367,6 +464,11 @@ class ConsolidacaoEntregasController < ApplicationController
# { vehicle:, eligible:, classificadas:, fechado: }. Fonte única do filtro de
# carros e do acompanhamento (chips). 2 queries: elegíveis (com a coluna do
# veículo) e as já classificadas (não-manuais).
# Status por veículo do motorista: { vehicle, eligible, classificadas, completo,
# fechado, arquivado }. `completo` = 100% classificado (verde, pode consolidar);
# `fechado` = veículo consolidado (cadeado, vem de consolidacao_veiculos);
# `arquivado` = fora do gate. Une os veículos com entregas elegíveis (rastreio)
# com os que só existem como linha de consolidacao_veiculos (arquivados/manuais).
def veiculos_status(motorista)
return [] unless motorista.present?
@@ -380,12 +482,17 @@ class ConsolidacaoEntregasController < ApplicationController
classificadas = @consolidacao.consolidacao_entregas
.where(motorista_nome: motorista, manual: false)
.distinct.pluck(:tracking_id).to_set
estados = @consolidacao.consolidacao_veiculos.where(motorista_nome: motorista).index_by(&:vehicle)
por_veiculo.map do |veiculo, linhas|
ids = linhas.map(&:first)
veiculos = (por_veiculo.keys + estados.keys).uniq
veiculos.map do |veiculo|
ids = (por_veiculo[veiculo] || []).map(&:first)
feito = ids.count { |id| classificadas.include?(id) }
cv = estados[veiculo]
{ vehicle: veiculo, eligible: ids.size, classificadas: feito,
fechado: ids.size.positive? && feito >= ids.size }
completo: ids.size.positive? && feito >= ids.size,
fechado: cv&.fechado? || false,
arquivado: cv&.arquivado? || false }
end.sort_by { |v| v[:vehicle] }
end

View File

@@ -159,6 +159,10 @@ class ConsolidacoesController < ApplicationController
@apontamentos = @consolidacao.consolidacao_entregas.apontamentos
.order(:motorista_nome, :tracking_id)
.group_by { |ce| [ce.motorista_nome, ce.tracking_id] }
# Veículos consolidados por motorista (breakdown informativo no card).
@veiculos_por_motorista = @consolidacao.consolidacao_veiculos.ativos
.order(:vehicle)
.group_by(&:motorista_nome)
end
# GET /consolidacoes/:id/wizard — PASSO 1: selecionar motorista
@@ -177,14 +181,20 @@ class ConsolidacoesController < ApplicationController
.apontamentos
.where(motorista_nome: cm.motorista_nome)
.distinct.count(:tracking_id)
# Status por veículo (para o breakdown do card) e estado de fechamento.
veiculos = @consolidacao.consolidacao_veiculos.ativos
.where(motorista_nome: cm.motorista_nome)
.order(:vehicle)
{
registro: cm,
total: total,
classificadas: classificadas,
apontamentos: apontamentos,
# Espelha o gate do servidor (todas_entregas_classificadas?): um motorista
# só com apontamento manual tem 0 entregas elegíveis e já está "completo".
completo: total.zero? || classificadas >= total
veiculos: veiculos,
veiculos_fechados: veiculos.count(&:fechado?),
# Espelha o gate do servidor (todas_entregas_classificadas?): exige tudo
# classificado E todos os veículos ativos fechados (consolidados).
completo: @consolidacao.motorista_completo?(cm.motorista_nome)
}
end
end
@@ -199,7 +209,7 @@ class ConsolidacoesController < ApplicationController
redirect_to @consolidacao, notice: 'Consolidação finalizada! Motoristas notificados.'
else
redirect_to wizard_consolidacao_path(@consolidacao),
alert: 'Não é possível finalizar: existem entregas não classificadas.'
alert: 'Não é possível finalizar: ainda há entregas não classificadas. Classifique-as ou arquive o veículo pendente.'
end
end
@@ -320,6 +330,7 @@ class ConsolidacoesController < ApplicationController
nome = cm.motorista_nome
ActiveRecord::Base.transaction do
@consolidacao.consolidacao_entregas.where(motorista_nome: nome).delete_all
@consolidacao.consolidacao_veiculos.where(motorista_nome: nome).delete_all
cm.destroy!
end
# cm já não existe — atualiza o total da consolidação direto (soma dos ativos).