Files
Reem-Notas/app/models/operacao.rb

71 lines
2.4 KiB
Ruby

# app/models/operacao.rb
#
# Operações são as tabelas EXTERNAS que o cliente carrega no banco, uma por
# operação/mês (ex.: "gade_entregas_ubs_sul_leste_jun_2026"). Cada tabela tem a
# coluna `nota_fiscal`, que casa com db_reem_simplerout_2026.reference_id::text.
#
# Estas tabelas são SOMENTE LEITURA — apenas SELECT, nunca migration/INSERT/etc.
#
# Como o nome da tabela entra em SQL (FROM dinâmico), TODA entrada externa passa
# por uma whitelist (#nomes_validos) antes de ser usada — proteção anti-injection.
class Operacao
PREFIXO = ENV.fetch('OPERACOES_TABLE_PREFIX', 'gade_entregas_').freeze
class << self
# [{ tabela: 'gade_entregas_...', label: 'Ubs Sul Leste Jun 2026' }, ...]
def todas
nomes_validos.map { |t| { tabela: t, label: label(t) } }
end
# Nomes reais de tabelas no schema public que batem com o prefixo.
# Sem cache de processo: o cliente sobe novas tabelas de operação a qualquer
# momento e elas precisam aparecer sem reiniciar o servidor (a consulta ao
# catálogo é barata).
def nomes_validos
conn.select_values(
"SELECT table_name FROM information_schema.tables " \
"WHERE table_schema = 'public' AND table_name LIKE #{conn.quote("#{PREFIXO}%")} ORDER BY table_name"
)
end
# Interseção da lista recebida com as tabelas que existem de fato.
def sanitizar(lista)
Array(lista).map(&:to_s).uniq & nomes_validos
end
def valida?(nome)
nomes_validos.include?(nome.to_s)
end
# Rótulo amigável: tira o prefixo e formata.
def label(tabela)
tabela.to_s.delete_prefix(PREFIXO).tr('_', ' ').strip.titleize
end
# Dados agregados das entregas das operações informadas, para pré-preencher o
# formulário de nova consolidação. Une as NFs de todas as tabelas válidas.
def dados(tabelas)
validas = sanitizar(tabelas)
return vazio if validas.empty?
entregas = Entrega.da_conta_gade.da_operacoes(validas)
{
motoristas: entregas.distinct.order(:driver).pluck(:driver).compact.reject(&:blank?),
veiculos: entregas.distinct.order(:vehicle).pluck(:vehicle).compact.reject(&:blank?),
inicio: entregas.minimum(:planned_date)&.to_date,
fim: entregas.maximum(:planned_date)&.to_date
}
end
private
def vazio
{ motoristas: [], veiculos: [], inicio: nil, fim: nil }
end
def conn
ActiveRecord::Base.connection
end
end
end