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'
|
'nota_fiscal' => 'NOTA FISCAL'
|
||||||
}.freeze
|
}.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).
|
# Cabeçalho completo A..Z da aba ENTREGAS (gade + resultado do rastreio).
|
||||||
CABECALHO = (COLUNAS_GADE.values + ['STATUS', 'ENTREGA', 'DATA OCORRÊNCIA', 'OCORRÊNCIA']).freeze
|
CABECALHO = (COLUNAS_GADE.values + ['STATUS', 'ENTREGA', 'DATA OCORRÊNCIA', 'OCORRÊNCIA']).freeze
|
||||||
|
|
||||||
# Aba SimpliRoute: cabeçalho exato do modelo -> colunas candidatas na tabela
|
# Aba SimpliRoute: cabeçalho exato do modelo -> colunas candidatas na tabela
|
||||||
# de rastreio (a primeira que existir é usada; nenhuma existente = vazia).
|
# 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 = {
|
RASTREIO_COLUNAS = {
|
||||||
'Tracking ID' => %w[tracking_id],
|
'Tracking ID' => %w[tracking_id],
|
||||||
'Referência ID' => %w[reference_id],
|
'Referência ID' => %w[reference_id],
|
||||||
'Data prevista' => %w[planned_date],
|
'Data prevista' => %w[planned_date],
|
||||||
'Motorista' => %w[driver],
|
'Motorista' => %w[driver],
|
||||||
'Co-pilotos' => %w[copilots co_pilotos copilotos],
|
'Co-pilotos' => %w[codrivers copilots co_pilotos copilotos],
|
||||||
'Veículo' => %w[vehicle],
|
'Veículo' => %w[vehicle],
|
||||||
'Título' => %w[title titulo],
|
'Título' => %w[title titulo],
|
||||||
'Endereço' => %w[address],
|
'Endereço' => %w[address],
|
||||||
@@ -60,10 +78,10 @@ module Analytics
|
|||||||
'ETD' => %w[etd],
|
'ETD' => %w[etd],
|
||||||
'Checkin' => %w[checkin],
|
'Checkin' => %w[checkin],
|
||||||
'Checkout' => %w[checkout],
|
'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 estimado' => %w[estimated_service_time tempo_de_servico_estimado duration],
|
||||||
'Tempo de serviço realme' => %w[real_service_time tempo_de_servico_real],
|
'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],
|
'Atraso' => %w[delay atraso],
|
||||||
'Latitude' => %w[latitude],
|
'Latitude' => %w[latitude],
|
||||||
'Longitude' => %w[longitude],
|
'Longitude' => %w[longitude],
|
||||||
@@ -72,16 +90,16 @@ module Analytics
|
|||||||
'Load' => %w[load load_1 carga],
|
'Load' => %w[load load_1 carga],
|
||||||
'Load 2' => %w[load_2],
|
'Load 2' => %w[load_2],
|
||||||
'Load 3' => %w[load_3],
|
'Load 3' => %w[load_3],
|
||||||
'Load 4' => %w[load_4],
|
'Load 4' => %w[],
|
||||||
'Estado' => %w[status],
|
'Estado' => %w[status],
|
||||||
'Comentários' => %w[checkout_comment comments comentarios comment],
|
'Comentários' => %w[comments checkout_comment comentarios comment],
|
||||||
'Observações' => %w[observation observacoes],
|
'Observações' => %w[observation observacoes],
|
||||||
'Janela de horário Inicial 1' => %w[window_start window_start_1 janela_inicial_1],
|
'Janela de horário Inicial 1' => %w[start_of_time_window_1 window_start janela_inicial_1],
|
||||||
'Janela de horário Final 1' => %w[window_end window_end_1 janela_final_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[window_start_2 janela_inicial_2],
|
'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[window_end_2 janela_final_2],
|
'Janela de horário Final 2' => %w[end_of_time_window_2 window_end_2 janela_final_2],
|
||||||
'Habilidades necessárias' => %w[skills_required habilidades_necessarias],
|
'Habilidades necessárias' => %w[required_skills skills_required habilidades_necessarias],
|
||||||
'Habilidades adicionais' => %w[skills_optional habilidades_adicionais],
|
'Habilidades adicionais' => %w[optional_skills skills_optional habilidades_adicionais],
|
||||||
'Notas' => %w[notes notas],
|
'Notas' => %w[notes notas],
|
||||||
'Nome de contato' => %w[contact_name],
|
'Nome de contato' => %w[contact_name],
|
||||||
'Telefone de contato' => %w[contact_phone telefone_de_contato],
|
'Telefone de contato' => %w[contact_phone telefone_de_contato],
|
||||||
@@ -93,7 +111,10 @@ module Analytics
|
|||||||
'Termo de Recebimento' => %w[termo_de_recebimento],
|
'Termo de Recebimento' => %w[termo_de_recebimento],
|
||||||
'Foto da Fachada' => %w[foto_da_fachada],
|
'Foto da Fachada' => %w[foto_da_fachada],
|
||||||
'Relatório de visita' => %w[relatorio_de_visita visit_report],
|
'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
|
}.freeze
|
||||||
|
|
||||||
# Quadro do RESUMO — linhas fixas do modelo.
|
# Quadro do RESUMO — linhas fixas do modelo.
|
||||||
@@ -204,10 +225,13 @@ module Analytics
|
|||||||
end
|
end
|
||||||
|
|
||||||
# SELECT das colunas whitelisted; ausentes viram NULL com o mesmo alias.
|
# 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
|
def selects_gade
|
||||||
existentes = conn.columns(@tabela).map(&:name)
|
existentes = conn.columns(@tabela).map(&:name)
|
||||||
COLUNAS_GADE.keys.map do |c|
|
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.join(', ')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,9 @@ module Analytics
|
|||||||
# Cabeçalho da ENTREGAS
|
# Cabeçalho da ENTREGAS
|
||||||
@cab_azul = st.add_style(bg_color: '1155CC', fg_color: 'FFFFFF', b: true)
|
@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)
|
@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
|
end
|
||||||
|
|
||||||
# ── RESUMO ───────────────────────────────────────────────────
|
# ── RESUMO ───────────────────────────────────────────────────
|
||||||
@@ -183,19 +186,38 @@ module Analytics
|
|||||||
# Dump cru do rastreio (todas as visitas das NFs da operação), com o
|
# 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
|
# cabeçalho exato do modelo — sem estilo, como no original; cabeçalho sem
|
||||||
# coluna correspondente sai vazio.
|
# 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)
|
def aba_simpliroute(wb)
|
||||||
colunas = @planilha.colunas_rastreio
|
colunas = @planilha.colunas_rastreio
|
||||||
linhas = @planilha.linhas_rastreio
|
linhas = @planilha.linhas_rastreio
|
||||||
wb.add_worksheet(name: 'SimpliRoute') do |sheet|
|
wb.add_worksheet(name: 'SimpliRoute') do |sheet|
|
||||||
sheet.add_row(colunas.keys)
|
sheet.add_row(colunas.keys)
|
||||||
linhas.each do |r|
|
linhas.each do |r|
|
||||||
sheet.add_row(colunas.values.map { |col| col ? texto(r[col]) : '' },
|
valores = colunas.values.map { |col| col ? texto(r[col]) : '' }
|
||||||
types: Array.new(colunas.size, :string))
|
sheet.add_row(valores, types: Array.new(colunas.size, :string))
|
||||||
|
linkar_urls(sheet, valores)
|
||||||
end
|
end
|
||||||
sheet.auto_filter = "A1:#{Axlsx.col_ref(colunas.size - 1)}#{linhas.size + 1}"
|
sheet.auto_filter = "A1:#{Axlsx.col_ref(colunas.size - 1)}#{linhas.size + 1}"
|
||||||
end
|
end
|
||||||
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)
|
def texto(valor)
|
||||||
valor.respond_to?(:strftime) ? valor.strftime('%d/%m/%Y %H:%M') : valor.to_s
|
valor.respond_to?(:strftime) ? valor.strftime('%d/%m/%Y %H:%M') : valor.to_s
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user