Adição da opção de baixar a planilha preenchida para o cliente
This commit is contained in:
93
app/services/analytics/planilha_entregas.rb
Normal file
93
app/services/analytics/planilha_entregas.rb
Normal file
@@ -0,0 +1,93 @@
|
||||
# app/services/analytics/planilha_entregas.rb
|
||||
#
|
||||
# Monta as linhas da "planilha Entregas" entregue ao cliente (modelo
|
||||
# "Entregas SUDESTE MM.AAAA_FINAL.xlsx", aba ENTREGAS): as colunas A..V vêm da
|
||||
# própria tabela da operação (gade_entregas_* — espelho da planilha original) e
|
||||
# as colunas de resultado W..Z (STATUS/ENTREGA/DATA OCORRÊNCIA/OCORRÊNCIA) são
|
||||
# preenchidas com o ÚLTIMO status de cada NF no rastreio — o preenchimento que
|
||||
# hoje é feito manualmente.
|
||||
#
|
||||
# SEGURANÇA: tabela passa pela whitelist (Operacao.sanitizar) + quote_table_name;
|
||||
# colunas são whitelist fixa e as ausentes viram NULL (mesmo padrão do
|
||||
# OperacaoMetricas). Bases SOMENTE LEITURA.
|
||||
module Analytics
|
||||
class PlanilhaEntregas
|
||||
# Colunas da tabela gade (snake_case) -> cabeçalho exato do modelo (A..V).
|
||||
# Coluna que não existir em alguma operação sai vazia, preservando o layout.
|
||||
COLUNAS_GADE = {
|
||||
'ordem' => 'Ordem',
|
||||
'operacao' => 'Operação',
|
||||
'coordenadoria' => 'Coordenadoria',
|
||||
'supervisao' => 'Supervisão',
|
||||
'unidade' => 'Unidade',
|
||||
'data_cadastro' => 'Data Cadastro',
|
||||
'cartao_sus' => 'Cartão SUS',
|
||||
'nome_completo' => 'Nome Completo',
|
||||
'endereco_completo' => 'Endereço Completo',
|
||||
'nome_responsavel' => 'Nome Responsável',
|
||||
'telefones' => 'Telefones',
|
||||
'area_de_risco' => 'Área de Risco',
|
||||
'numero_ativo' => 'Numero Ativo',
|
||||
'num_serie_base' => 'Num Serie Base',
|
||||
'num_serie_pulverizador' => 'Num Serie Pulverizador',
|
||||
'observacoes' => 'Observações',
|
||||
'endereco_sem_complemento' => 'Endereço Sem Complemento',
|
||||
'complemento' => 'Complemento',
|
||||
'latitude' => 'Latitude',
|
||||
'longitude' => 'Longitude',
|
||||
'status' => 'STATUS',
|
||||
'nota_fiscal' => 'NOTA FISCAL'
|
||||
}.freeze
|
||||
|
||||
# Cabeçalho completo A..Z (gade + resultado do rastreio).
|
||||
CABECALHO = (COLUNAS_GADE.values + ['STATUS', 'ENTREGA', 'DATA OCORRÊNCIA', 'OCORRÊNCIA']).freeze
|
||||
|
||||
attr_reader :tabela
|
||||
|
||||
def initialize(tabela)
|
||||
@tabela = Operacao.sanitizar([tabela]).first
|
||||
raise ArgumentError, "Operação inválida: #{tabela}" unless @tabela
|
||||
end
|
||||
|
||||
def label
|
||||
Operacao.label(@tabela)
|
||||
end
|
||||
|
||||
# Array de hashes: chaves de COLUNAS_GADE + rastreio_status/checkout/observation.
|
||||
# ORDER BY g.ctid preserva a ordem física de importação — a mesma ordem da
|
||||
# planilha original do cliente (tabelas gade são read-only após o import).
|
||||
def linhas
|
||||
gade = conn.quote_table_name(@tabela)
|
||||
sql = <<~SQL
|
||||
WITH ultimo AS (
|
||||
SELECT *,
|
||||
ROW_NUMBER() OVER (PARTITION BY reference_id ORDER BY checkout DESC NULLS LAST) AS rn
|
||||
FROM #{conn.quote_table_name(Entrega.table_name)}
|
||||
WHERE reference_id IS NOT NULL
|
||||
)
|
||||
SELECT #{selects_gade},
|
||||
r.status AS rastreio_status,
|
||||
r.checkout AS rastreio_checkout,
|
||||
r.observation AS rastreio_observation
|
||||
FROM #{gade} g
|
||||
LEFT JOIN ultimo r ON r.rn = 1 AND r.reference_id::text = g.nota_fiscal
|
||||
ORDER BY g.ctid
|
||||
SQL
|
||||
conn.select_all(sql).to_a
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def conn
|
||||
ActiveRecord::Base.connection
|
||||
end
|
||||
|
||||
# SELECT das colunas whitelisted; ausentes viram NULL com o mesmo alias.
|
||||
def selects_gade
|
||||
existentes = conn.columns(@tabela).map(&:name)
|
||||
COLUNAS_GADE.keys.map do |c|
|
||||
existentes.include?(c) ? "g.#{c} AS #{c}" : "CAST(NULL AS text) AS #{c}"
|
||||
end.join(', ')
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user