From 19b7cc838f8c0b225300746a5e45d172a45239f3fed6286001198fba7c016e05 Mon Sep 17 00:00:00 2001
From: victor
Date: Tue, 16 Jun 2026 02:17:25 -0300
Subject: [PATCH] =?UTF-8?q?Pagamento=20por=20checkout=20+=20consolida?=
=?UTF-8?q?=C3=A7=C3=A3o=20por=20ve=C3=ADculo=20(em=20vez=20de=20rota)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Regra de pagamento:
- Entrega.pagas agora exige status='completed' E checkout preenchido
(antes era checkin). Afeta dashboard, painel do motorista, job 1h e
elegibilidade das consolidações de forma consistente.
Veículo no lugar de rota na consolidação:
- migration troca consolidacoes.route_ids por vehicle_ids (jsonb + gin)
- Entrega: da_veiculo/veiculos_unicos; contar_pagas usa vehicle
- new.html.erb: filtro "Veículos" (multi-select por vehicle)
- validar.html.erb: mostra o veículo em vez do código da rota
- filtros/elegibilidade do controller passam a usar vehicle_ids
Docs/diagnóstico atualizados.
Co-Authored-By: Claude Opus 4.8
---
CLAUDE.md | 2 +-
.../consolidacao_entregas_controller.rb | 8 +++---
app/controllers/consolidacoes_controller.rb | 10 ++++----
app/controllers/dashboard_controller.rb | 2 +-
app/jobs/atualizar_historico_estimado_job.rb | 2 +-
app/models/consolidacao.rb | 4 +--
app/models/entrega.rb | 25 ++++++++++---------
.../consolidacao_entregas/validar.html.erb | 2 +-
app/views/consolidacoes/new.html.erb | 15 ++++++-----
...te_ids_for_vehicle_ids_on_consolidacoes.rb | 19 ++++++++++++++
lib/tasks/diagnostico.rake | 4 +--
11 files changed, 58 insertions(+), 35 deletions(-)
create mode 100644 db/migrate/20260616000001_swap_route_ids_for_vehicle_ids_on_consolidacoes.rb
diff --git a/CLAUDE.md b/CLAUDE.md
index de05f33..d8621e6 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -54,7 +54,7 @@ Default credentials (change in production): `admin@gade.com` / `Gade@2026!`
The table `public.db_reem_simplerout_2026` is owned by an external system (SimpleRoute) that updates it every hour. **NEVER** create migrations for it, and never run INSERT/UPDATE/DELETE/DROP/TRUNCATE on it.
-`Entrega` (app/models/entrega.rb) maps to this table and enforces `readonly? = true`. All queries go through its scopes — the most important being `.pagas` (`status='completed' AND checkin IS NOT NULL`), which defines payment eligibility.
+`Entrega` (app/models/entrega.rb) maps to this table and enforces `readonly? = true`. All queries go through its scopes — the most important being `.pagas` (`status='completed' AND checkout IS NOT NULL`), which defines payment eligibility. Consolidations filter eligible deliveries by **vehicle** (`vehicle` column → `Consolidacao#vehicle_ids`), not by route.
## Architecture
diff --git a/app/controllers/consolidacao_entregas_controller.rb b/app/controllers/consolidacao_entregas_controller.rb
index fd0d1de..069f53b 100644
--- a/app/controllers/consolidacao_entregas_controller.rb
+++ b/app/controllers/consolidacao_entregas_controller.rb
@@ -16,7 +16,7 @@ class ConsolidacaoEntregasController < ApplicationController
.da_conta_gade
.no_periodo(@consolidacao.data_inicio, @consolidacao.data_fim)
.do_motorista(@motorista)
- @entregas = @entregas.da_rota(@consolidacao.route_ids) if @consolidacao.route_ids.present?
+ @entregas = @entregas.da_veiculo(@consolidacao.vehicle_ids) if @consolidacao.vehicle_ids.present?
@entregas = @entregas.order(:planned_date)
# Classificações já feitas — indexadas por tracking_id
@@ -139,18 +139,18 @@ class ConsolidacaoEntregasController < ApplicationController
nome.present? && @consolidacao.consolidacao_motoristas.exists?(motorista_nome: nome)
end
- # tracking_ids pagos/elegíveis para o motorista no período (respeita rotas)
+ # tracking_ids pagos/elegíveis para o motorista no período (respeita veículos)
def tracking_ids_elegiveis(motorista)
return [] unless motorista.present?
rel = Entrega.pagas.da_conta_gade
.no_periodo(@consolidacao.data_inicio, @consolidacao.data_fim)
.do_motorista(motorista)
- rel = rel.da_rota(@consolidacao.route_ids) if @consolidacao.route_ids.present?
+ rel = rel.da_veiculo(@consolidacao.vehicle_ids) if @consolidacao.vehicle_ids.present?
rel.pluck(:tracking_id)
end
- # Valida que a entrega pertence ao motorista informado e ao período/rota da
+ # Valida que a entrega pertence ao motorista informado e ao período/veículo da
# consolidação — impede classificar tracking_ids arbitrários via requisição.
def entrega_elegivel?(motorista, tracking_id)
motorista_na_consolidacao?(motorista) &&
diff --git a/app/controllers/consolidacoes_controller.rb b/app/controllers/consolidacoes_controller.rb
index b160e0c..5571c03 100644
--- a/app/controllers/consolidacoes_controller.rb
+++ b/app/controllers/consolidacoes_controller.rb
@@ -22,8 +22,8 @@ class ConsolidacoesController < ApplicationController
@consolidacoes = @consolidacoes.where(id: ids)
end
- if params[:route_id].present?
- @consolidacoes = @consolidacoes.where('route_ids @> ?', [params[:route_id]].to_json)
+ if params[:vehicle].present?
+ @consolidacoes = @consolidacoes.where('vehicle_ids @> ?', [params[:vehicle]].to_json)
end
end
@@ -35,7 +35,7 @@ class ConsolidacoesController < ApplicationController
data_fim: Date.current
)
@motoristas = Entrega.motoristas_ativos
- @rotas = Entrega.rotas_unicas
+ @veiculos = Entrega.veiculos_unicos
end
# POST /consolidacoes
@@ -160,10 +160,10 @@ class ConsolidacoesController < ApplicationController
def preparar_form_new
@motoristas = Entrega.motoristas_ativos
- @rotas = Entrega.rotas_unicas
+ @veiculos = Entrega.veiculos_unicos
end
def consolidacao_params
- params.require(:consolidacao).permit(:nome, :data_inicio, :data_fim, route_ids: [])
+ params.require(:consolidacao).permit(:nome, :data_inicio, :data_fim, vehicle_ids: [])
end
end
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 72ee361..536e8e5 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -61,7 +61,7 @@ class DashboardController < ApplicationController
}
end
- # Por operação (route_id → contact_name)
+ # Por local de entrega (contact_name)
@por_operacao = entregas.pagas
.group(:contact_name)
.count
diff --git a/app/jobs/atualizar_historico_estimado_job.rb b/app/jobs/atualizar_historico_estimado_job.rb
index 4a6708d..841d150 100644
--- a/app/jobs/atualizar_historico_estimado_job.rb
+++ b/app/jobs/atualizar_historico_estimado_job.rb
@@ -1,7 +1,7 @@
# app/jobs/atualizar_historico_estimado_job.rb
#
# Roda a cada 1 hora (via Whenever → rake historico:atualizar).
-# Lógica: conta entregas do dia com status='completed' E checkin IS NOT NULL,
+# Lógica: conta entregas do dia com status='completed' E checkout IS NOT NULL,
# multiplica pelo preco_entrega configurado e persiste em historico_estimados.
#
class AtualizarHistoricoEstimadoJob < ApplicationJob
diff --git a/app/models/consolidacao.rb b/app/models/consolidacao.rb
index 089fc35..a0bebba 100644
--- a/app/models/consolidacao.rb
+++ b/app/models/consolidacao.rb
@@ -73,14 +73,14 @@ class Consolidacao < ApplicationRecord
end
# Entregas pagas elegíveis para um motorista no período, respeitando o filtro
- # de rotas da consolidação (quando houver). Fonte única usada pelo wizard,
+ # de veículos da consolidação (quando houver). Fonte única usada pelo wizard,
# pela revisão e pelo gate de finalização.
def entregas_elegiveis_count(motorista)
Entrega.contar_pagas(
inicio: data_inicio,
fim: data_fim,
motorista: motorista,
- route_id: route_ids.presence
+ vehicle: vehicle_ids.presence
)
end
diff --git a/app/models/entrega.rb b/app/models/entrega.rb
index fd6f5f0..f384028 100644
--- a/app/models/entrega.rb
+++ b/app/models/entrega.rb
@@ -15,8 +15,9 @@ class Entrega < ApplicationRecord
# ── Scopes ──────────────────────────────────────────────────
scope :concluidas, -> { where(status: 'completed') }
- scope :com_checkin, -> { where.not(checkin: nil) }
- scope :pagas, -> { concluidas.com_checkin }
+ scope :com_checkout, -> { where.not(checkout: nil) }
+ # Pagamento = entrega concluída com checkout registrado
+ scope :pagas, -> { concluidas.com_checkout }
scope :pendentes, -> { where.not(status: 'completed') }
scope :no_periodo, ->(inicio, fim) {
@@ -27,8 +28,8 @@ class Entrega < ApplicationRecord
where(driver: nome)
}
- scope :da_rota, ->(route_id) {
- where(route_id: route_id)
+ scope :da_veiculo, ->(vehicle) {
+ where(vehicle: vehicle)
}
scope :do_mes, ->(data = Date.current) {
@@ -48,18 +49,18 @@ class Entrega < ApplicationRecord
base.distinct.order(:driver).pluck(:driver).compact.reject(&:empty?)
end
- # Lista rotas únicas (route_id → descrição)
- def self.rotas_unicas(inicio: nil, fim: nil)
+ # Lista veículos únicos (para selects/filtros de consolidação)
+ def self.veiculos_unicos(inicio: nil, fim: nil)
base = da_conta_gade
base = base.no_periodo(inicio, fim) if inicio && fim
- base.distinct.pluck(:route_id).compact
+ base.distinct.order(:vehicle).pluck(:vehicle).compact.reject(&:empty?)
end
# Contagem de entregas pagas para cálculo estimado
- def self.contar_pagas(inicio:, fim:, motorista: nil, route_id: nil)
+ def self.contar_pagas(inicio:, fim:, motorista: nil, vehicle: nil)
base = pagas.da_conta_gade.no_periodo(inicio, fim)
base = base.do_motorista(motorista) if motorista.present?
- base = base.da_rota(route_id) if route_id.present?
+ base = base.da_veiculo(vehicle) if vehicle.present?
base.count
end
@@ -77,12 +78,12 @@ class Entrega < ApplicationRecord
status == 'completed'
end
- def checkin_registrado?
- checkin.present?
+ def checkout_registrado?
+ checkout.present?
end
def elegivel_pagamento?
- concluida? && checkin_registrado?
+ concluida? && checkout_registrado?
end
def atraso_minutos
diff --git a/app/views/consolidacao_entregas/validar.html.erb b/app/views/consolidacao_entregas/validar.html.erb
index 33ea077..f4dba69 100644
--- a/app/views/consolidacao_entregas/validar.html.erb
+++ b/app/views/consolidacao_entregas/validar.html.erb
@@ -85,7 +85,7 @@
NF <%= e.numero_nf %> · <%= e.local %>