Adição do botão de entrega manual

This commit is contained in:
2026-06-25 11:35:41 -03:00
parent 022aac2616
commit 0c5b5bcbe6
22 changed files with 615 additions and 67 deletions

View File

@@ -33,17 +33,17 @@ class Consolidacao < ApplicationRecord
# ── Filtro por status de pagamento (derivado dos motoristas) ─
# pago_em NÃO-nulo conta como pago; COUNT(pago_em) ignora os NULL.
scope :pagamento_pago, -> {
where(id: ConsolidacaoMotorista.group(:consolidacao_id)
where(id: ConsolidacaoMotorista.ativos.group(:consolidacao_id)
.having('COUNT(*) > 0 AND COUNT(*) = COUNT(pago_em)')
.select(:consolidacao_id))
}
scope :pagamento_pendente, -> {
where(id: ConsolidacaoMotorista.group(:consolidacao_id)
where(id: ConsolidacaoMotorista.ativos.group(:consolidacao_id)
.having('COUNT(pago_em) = 0')
.select(:consolidacao_id))
}
scope :pagamento_parcial, -> {
where(id: ConsolidacaoMotorista.group(:consolidacao_id)
where(id: ConsolidacaoMotorista.ativos.group(:consolidacao_id)
.having('COUNT(pago_em) > 0 AND COUNT(pago_em) < COUNT(*)')
.select(:consolidacao_id))
}
@@ -91,21 +91,21 @@ class Consolidacao < ApplicationRecord
# ── Pagamento (status derivado dos motoristas da consolidação) ──
# :pendente (nenhum pago) · :pago (todos pagos) · :parcial (alguns).
def status_pagamento
total = consolidacao_motoristas.count
total = consolidacao_motoristas.ativos.count
return :pendente if total.zero?
pagos = consolidacao_motoristas.pagos.count
pagos = consolidacao_motoristas.ativos.pagos.count
return :pendente if pagos.zero?
pagos >= total ? :pago : :parcial
end
def valor_pago
consolidacao_motoristas.pagos.sum(:valor_total)
consolidacao_motoristas.ativos.pagos.sum(:valor_total)
end
def valor_pendente
consolidacao_motoristas.pendentes.sum(:valor_total)
consolidacao_motoristas.ativos.pendentes.sum(:valor_total)
end
def finalizar!(user)
@@ -122,7 +122,7 @@ class Consolidacao < ApplicationRecord
# classificadas. (Antes era uma soma agregada com >=, que mascarava motoristas
# pendentes quando outro tinha entregas a mais.)
def todas_entregas_classificadas?
consolidacao_motoristas.all? do |cm|
consolidacao_motoristas.ativos.all? do |cm|
total = entregas_elegiveis_count(cm.motorista_nome)
total.zero? || classificadas_count(cm.motorista_nome) >= total
end
@@ -134,7 +134,7 @@ class Consolidacao < ApplicationRecord
end
def total_entregas_estimadas
@total_entregas_estimadas ||= consolidacao_motoristas.sum do |cm|
@total_entregas_estimadas ||= consolidacao_motoristas.ativos.sum do |cm|
entregas_elegiveis_count(cm.motorista_nome)
end
end
@@ -201,6 +201,49 @@ class Consolidacao < ApplicationRecord
motorista
end
# ── Apontamento 100% manual ─────────────────────────────────
# Lança uma entrega à mão SEM consultar a base de rastreio. Caso de uso: um
# motorista foi até o local mas a NF ficou registrada com outro motorista no
# rastreio — então a busca por NF nunca o encontra, mas ele também recebe.
# O motorista vem digitado (não de uma Entrega) e é incluído se ainda não
# estiver. tracking_id é sintético (não há Entrega), e a NF/observação ficam
# guardadas em nf_manual/obs_manual.
def adicionar_apontamento_manual!(motorista:, tipos:, user:, nf: nil, obs: nil, valor_extra: nil)
tipos_validos = Array(tipos).map(&:to_s).select { |t| ConsolidacaoEntrega.tipos.key?(t) }.uniq
raise ArgumentError, 'Selecione ao menos uma classificação.' if tipos_validos.empty?
nome = motorista.to_s.strip
raise ArgumentError, 'Informe o motorista do apontamento.' if nome.blank?
tracking = "MAN-#{SecureRandom.uuid}" # sintético: agrupa os pilares como UMA entrega
transaction do
consolidacao_motoristas.find_or_create_by!(motorista_nome: nome)
tipos_validos.each do |tipo|
valor = if tipo == 'extraordinaria' && valor_extra.present?
valor_extra
else
ConsolidacaoEntrega.valor_para(tipo)
end
consolidacao_entregas.create!(
tracking_id: tracking,
tipo: tipo,
motorista_nome: nome,
valor_aplicado: valor,
manual: true,
nf_manual: nf.presence,
obs_manual: obs.presence,
created_by: user&.id
)
end
recalcular_motorista!(nome)
end
nome
end
# Recalcula o valor de um motorista (soma dos pilares, desconto subtrai) e o
# total da consolidação. Fonte única usada pelo wizard e pelos apontamentos.
def recalcular_motorista!(nome)
@@ -211,7 +254,7 @@ class Consolidacao < ApplicationRecord
e.desconto? ? -e.valor_aplicado : e.valor_aplicado
end
cm.update_column(:valor_total, total)
update_column(:valor_total, consolidacao_motoristas.sum(:valor_total))
update_column(:valor_total, consolidacao_motoristas.ativos.sum(:valor_total))
end
private
@@ -222,6 +265,6 @@ class Consolidacao < ApplicationRecord
end
def recalcular_valor_total
self.valor_total = consolidacao_motoristas.sum(:valor_total)
self.valor_total = consolidacao_motoristas.ativos.sum(:valor_total)
end
end