Correção do relatório que é gerado para envio gade
This commit is contained in:
@@ -42,17 +42,35 @@ module Analytics
|
||||
'nota_fiscal' => 'NOTA FISCAL'
|
||||
}.freeze
|
||||
|
||||
# Colunas da gade cujo nome real difere da chave de COLUNAS_GADE (a chave é
|
||||
# o alias usado no SELECT e na leitura da linha). As tabelas do cliente
|
||||
# gravam a geo como `lat`/`long`, não `latitude`/`longitude` — sem isso as
|
||||
# duas colunas saíam vazias. Ordem = preferência; a 1ª que existir é usada.
|
||||
ALIAS_GADE = {
|
||||
'latitude' => %w[latitude lat],
|
||||
'longitude' => %w[longitude long]
|
||||
}.freeze
|
||||
|
||||
# Cabeçalho completo A..Z da aba ENTREGAS (gade + resultado do rastreio).
|
||||
CABECALHO = (COLUNAS_GADE.values + ['STATUS', 'ENTREGA', 'DATA OCORRÊNCIA', 'OCORRÊNCIA']).freeze
|
||||
|
||||
# Aba SimpliRoute: cabeçalho exato do modelo -> colunas candidatas na tabela
|
||||
# de rastreio (a primeira que existir é usada; nenhuma existente = vazia).
|
||||
#
|
||||
# O 1º candidato de cada linha é o nome REAL conferido na
|
||||
# db_reem_simplerout_2026 (o espelho usa os nomes do export do SimpliRoute:
|
||||
# `codrivers`, `responsible_person`, `advance`, `start_of_time_window_1`,
|
||||
# `required_skills`...). Os demais candidatos são só rede de segurança para
|
||||
# o dia em que o espelho for recriado com outra grafia.
|
||||
#
|
||||
# 'Load 4' fica sem candidato de propósito: essa coluna NÃO existe no
|
||||
# espelho (só load, load_2 e load_3) — sai vazia, preservando o layout.
|
||||
RASTREIO_COLUNAS = {
|
||||
'Tracking ID' => %w[tracking_id],
|
||||
'Referência ID' => %w[reference_id],
|
||||
'Data prevista' => %w[planned_date],
|
||||
'Motorista' => %w[driver],
|
||||
'Co-pilotos' => %w[copilots co_pilotos copilotos],
|
||||
'Co-pilotos' => %w[codrivers copilots co_pilotos copilotos],
|
||||
'Veículo' => %w[vehicle],
|
||||
'Título' => %w[title titulo],
|
||||
'Endereço' => %w[address],
|
||||
@@ -60,10 +78,10 @@ module Analytics
|
||||
'ETD' => %w[etd],
|
||||
'Checkin' => %w[checkin],
|
||||
'Checkout' => %w[checkout],
|
||||
'Responsável' => %w[receiver responsavel responsible],
|
||||
'Responsável' => %w[responsible_person receiver responsavel responsible],
|
||||
'Tempo de serviço estimado' => %w[estimated_service_time tempo_de_servico_estimado duration],
|
||||
'Tempo de serviço realme' => %w[real_service_time tempo_de_servico_real],
|
||||
'Antecipação' => %w[early antecipacao anticipation],
|
||||
'Antecipação' => %w[advance early antecipacao anticipation],
|
||||
'Atraso' => %w[delay atraso],
|
||||
'Latitude' => %w[latitude],
|
||||
'Longitude' => %w[longitude],
|
||||
@@ -72,16 +90,16 @@ module Analytics
|
||||
'Load' => %w[load load_1 carga],
|
||||
'Load 2' => %w[load_2],
|
||||
'Load 3' => %w[load_3],
|
||||
'Load 4' => %w[load_4],
|
||||
'Load 4' => %w[],
|
||||
'Estado' => %w[status],
|
||||
'Comentários' => %w[checkout_comment comments comentarios comment],
|
||||
'Comentários' => %w[comments checkout_comment comentarios comment],
|
||||
'Observações' => %w[observation observacoes],
|
||||
'Janela de horário Inicial 1' => %w[window_start window_start_1 janela_inicial_1],
|
||||
'Janela de horário Final 1' => %w[window_end window_end_1 janela_final_1],
|
||||
'Janela de horário Inicial 2' => %w[window_start_2 janela_inicial_2],
|
||||
'Janela de horário Final 2' => %w[window_end_2 janela_final_2],
|
||||
'Habilidades necessárias' => %w[skills_required habilidades_necessarias],
|
||||
'Habilidades adicionais' => %w[skills_optional habilidades_adicionais],
|
||||
'Janela de horário Inicial 1' => %w[start_of_time_window_1 window_start janela_inicial_1],
|
||||
'Janela de horário Final 1' => %w[end_of_time_window_1 window_end janela_final_1],
|
||||
'Janela de horário Inicial 2' => %w[start_of_time_window_2 window_start_2 janela_inicial_2],
|
||||
'Janela de horário Final 2' => %w[end_of_time_window_2 window_end_2 janela_final_2],
|
||||
'Habilidades necessárias' => %w[required_skills skills_required habilidades_necessarias],
|
||||
'Habilidades adicionais' => %w[optional_skills skills_optional habilidades_adicionais],
|
||||
'Notas' => %w[notes notas],
|
||||
'Nome de contato' => %w[contact_name],
|
||||
'Telefone de contato' => %w[contact_phone telefone_de_contato],
|
||||
@@ -93,7 +111,10 @@ module Analytics
|
||||
'Termo de Recebimento' => %w[termo_de_recebimento],
|
||||
'Foto da Fachada' => %w[foto_da_fachada],
|
||||
'Relatório de visita' => %w[relatorio_de_visita visit_report],
|
||||
'Número de Série da Base (Aparelho)' => %w[numero_de_serie_da_base_aparelho num_serie_base numero_serie_base]
|
||||
'Número de Série da Base (Aparelho)' => %w[numero_de_serie_da_base_aparelho num_serie_base numero_serie_base],
|
||||
# Campo do espelho que o modelo antigo do cliente ainda não tinha. Entra
|
||||
# DEPOIS das colunas do modelo para não deslocar o layout A..AT dele.
|
||||
'Protocolo de Entrega' => %w[protocolo_de_entrega]
|
||||
}.freeze
|
||||
|
||||
# Quadro do RESUMO — linhas fixas do modelo.
|
||||
@@ -204,10 +225,13 @@ module Analytics
|
||||
end
|
||||
|
||||
# SELECT das colunas whitelisted; ausentes viram NULL com o mesmo alias.
|
||||
# O nome real pode diferir da chave (ver ALIAS_GADE) — o alias no SELECT é
|
||||
# sempre a chave, então quem lê a linha não precisa saber da diferença.
|
||||
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}"
|
||||
real = (ALIAS_GADE[c] || [c]).find { |cand| existentes.include?(cand) }
|
||||
real ? "g.#{conn.quote_column_name(real)} AS #{c}" : "CAST(NULL AS text) AS #{c}"
|
||||
end.join(', ')
|
||||
end
|
||||
|
||||
|
||||
@@ -66,6 +66,9 @@ module Analytics
|
||||
# Cabeçalho da ENTREGAS
|
||||
@cab_azul = st.add_style(bg_color: '1155CC', fg_color: 'FFFFFF', b: true)
|
||||
@cab_verm = st.add_style(bg_color: 'C00000', fg_color: 'FFFFFF', b: true)
|
||||
|
||||
# Hiperlink (fotos/comprovantes do SimpliRoute) — azul sublinhado padrão.
|
||||
@link = st.add_style(fg_color: '0563C1', u: true)
|
||||
end
|
||||
|
||||
# ── RESUMO ───────────────────────────────────────────────────
|
||||
@@ -183,19 +186,38 @@ module Analytics
|
||||
# Dump cru do rastreio (todas as visitas das NFs da operação), com o
|
||||
# cabeçalho exato do modelo — sem estilo, como no original; cabeçalho sem
|
||||
# coluna correspondente sai vazio.
|
||||
#
|
||||
# As colunas de foto (Nota Fiscal, Termo de Recebimento, Foto da Fachada,
|
||||
# Relatório de visita) guardam URLs do S3 do SimpliRoute: viram HIPERLINK
|
||||
# clicável (azul sublinhado), para o cliente abrir o comprovante direto do
|
||||
# Excel em vez de copiar e colar a URL.
|
||||
def aba_simpliroute(wb)
|
||||
colunas = @planilha.colunas_rastreio
|
||||
linhas = @planilha.linhas_rastreio
|
||||
wb.add_worksheet(name: 'SimpliRoute') do |sheet|
|
||||
sheet.add_row(colunas.keys)
|
||||
linhas.each do |r|
|
||||
sheet.add_row(colunas.values.map { |col| col ? texto(r[col]) : '' },
|
||||
types: Array.new(colunas.size, :string))
|
||||
valores = colunas.values.map { |col| col ? texto(r[col]) : '' }
|
||||
sheet.add_row(valores, types: Array.new(colunas.size, :string))
|
||||
linkar_urls(sheet, valores)
|
||||
end
|
||||
sheet.auto_filter = "A1:#{Axlsx.col_ref(colunas.size - 1)}#{linhas.size + 1}"
|
||||
end
|
||||
end
|
||||
|
||||
# Transforma em hiperlink toda célula da linha recém-adicionada cujo valor
|
||||
# seja uma URL http(s) — mesma checagem do foto_url do OperacaoMetricas,
|
||||
# para não jogar lixo dentro do <hyperlink> do arquivo.
|
||||
def linkar_urls(sheet, valores)
|
||||
linha = sheet.rows.size
|
||||
valores.each_with_index do |valor, i|
|
||||
next unless valor.to_s.match?(%r{\Ahttps?://\S+\z}i)
|
||||
|
||||
sheet.add_hyperlink(location: valor, ref: "#{Axlsx.col_ref(i)}#{linha}")
|
||||
sheet.rows.last.cells[i].style = @link
|
||||
end
|
||||
end
|
||||
|
||||
def texto(valor)
|
||||
valor.respond_to?(:strftime) ? valor.strftime('%d/%m/%Y %H:%M') : valor.to_s
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user