, Correçoes na busca da API para ver os ultimos planos
This commit is contained in:
@@ -18,10 +18,22 @@ class Admin::RomaneiosController < ApplicationController
|
||||
@operacoes_agrupadas = Operacao.agrupadas_por_mes
|
||||
@data_padrao = Date.current
|
||||
|
||||
# Os 5 planos mais recentes, para o operador ESCOLHER em vez de adivinhar a
|
||||
# data. Best-effort de propósito: API fora do ar devolve [] e a tela cai no
|
||||
# campo de data de sempre — a importação nunca fica bloqueada por isso.
|
||||
@planos = SimpliRoute::Client.new.planos(limite: 5)
|
||||
# Os planos para o operador ESCOLHER em vez de adivinhar a data.
|
||||
#
|
||||
# Sem período: os 5 mais recentes — a ferramenta é usada logo depois de
|
||||
# lançar uma operação, então o que ele quer está sempre entre os últimos, e
|
||||
# o caso comum fica em zero clique.
|
||||
# Com período: TODOS os planos da faixa. É assim que se alcança um plano
|
||||
# antigo sem saber o dia dele — e é o mesmo recorte da tela do SimpliRoute,
|
||||
# para o operador não ter que traduzir nada entre as duas.
|
||||
@plano_inicio = params[:plano_inicio].presence
|
||||
@plano_fim = params[:plano_fim].presence
|
||||
@planos = SimpliRoute::Client.new.planos(limite: 5, inicio: @plano_inicio, fim: @plano_fim)
|
||||
@planos_filtrados = @plano_inicio.present? && @plano_fim.present?
|
||||
|
||||
# O logo escolhido sumiu do disco? A tela precisa dizer — foi exatamente
|
||||
# assim que o PDF saiu com o logo antigo sem ninguém entender (28/08/2026).
|
||||
_, @logo_problema = Pdf::RomaneioPdf.logo_configurado
|
||||
# Nome ORIGINAL do logo escolhido (a descricao), para a tela mostrar o mesmo
|
||||
# que o operador enviou; nil = ainda usando o logo da GADE do repositório.
|
||||
@logo_atual = Configuracao.find_by(chave: 'romaneio_logo')&.descricao
|
||||
@@ -87,7 +99,28 @@ class Admin::RomaneiosController < ApplicationController
|
||||
#
|
||||
# PNG/JPG apenas porque é o que o Prawn embute — um SVG aceito aqui sairia como
|
||||
# folha SEM logo, sem erro nenhum, e ninguém descobriria antes de imprimir.
|
||||
LOGO_TIPOS = { 'image/png' => '.png', 'image/jpeg' => '.jpg' }.freeze
|
||||
# ⚠️ O FORMATO É DECIDIDO PELO CONTEÚDO DO ARQUIVO, não pelo `content_type`
|
||||
# que o navegador manda. O content_type é entrada do usuário: Windows e alguns
|
||||
# navegadores mandam `application/octet-stream` para um PNG perfeitamente
|
||||
# válido, e a versão antiga (`LOGO_TIPOS[arquivo.content_type]`) RECUSAVA esse
|
||||
# arquivo dizendo "precisa ser PNG ou JPG" — para um PNG. Assinatura de arquivo
|
||||
# não mente.
|
||||
#
|
||||
# A lista é curta porque quem manda aqui é o Prawn: ele embute **PNG e JPEG**,
|
||||
# e só. Formato que ele não embute não pode ser aceito "para ver no que dá" —
|
||||
# viraria um PDF quebrado na hora de imprimir, ou um logo que some sem aviso.
|
||||
# Os outros formatos são RECONHECIDOS mesmo assim, para a mensagem poder dizer
|
||||
# o que a pessoa mandou e o que fazer, em vez de repetir "PNG ou JPG".
|
||||
ASSINATURAS = [
|
||||
["\x89PNG\r\n\x1a\n".b, '.png', 'PNG', true],
|
||||
["\xFF\xD8\xFF".b, '.jpg', 'JPEG', true],
|
||||
['RIFF'.b, nil, 'WebP', false], # confirmado abaixo pelo 'WEBP'
|
||||
['GIF8'.b, nil, 'GIF', false],
|
||||
['BM'.b, nil, 'BMP', false],
|
||||
['%PDF'.b, nil, 'PDF', false],
|
||||
['<?xml'.b, nil, 'SVG', false],
|
||||
['<svg'.b, nil, 'SVG', false]
|
||||
].freeze
|
||||
LOGO_TAMANHO_MAX = 2.megabytes
|
||||
|
||||
def atualizar_logo
|
||||
@@ -96,23 +129,36 @@ class Admin::RomaneiosController < ApplicationController
|
||||
arquivo = params[:logo]
|
||||
return redirect_to(admin_romaneios_path, alert: 'Escolha o arquivo do logo (PNG ou JPG).') if arquivo.blank?
|
||||
|
||||
extensao = LOGO_TIPOS[arquivo.content_type.to_s]
|
||||
if extensao.nil?
|
||||
return redirect_to(admin_romaneios_path,
|
||||
alert: 'O logo precisa ser PNG ou JPG — é o que o PDF consegue embutir.')
|
||||
end
|
||||
if arquivo.size > LOGO_TAMANHO_MAX
|
||||
return redirect_to(admin_romaneios_path,
|
||||
alert: 'Logo acima de 2 MB. Reduza a imagem antes de enviar.')
|
||||
end
|
||||
|
||||
# Lê tudo UMA vez: o mesmo conteúdo serve para identificar o formato e para
|
||||
# gravar. Reler o upload depois de `read` devolveria vazio.
|
||||
conteudo = arquivo.read.to_s.b
|
||||
extensao, formato, aceito = identificar_imagem(conteudo)
|
||||
|
||||
if extensao.nil?
|
||||
recado = if formato
|
||||
"O arquivo é #{formato}, e o PDF só embute PNG ou JPG. " \
|
||||
'Salve o logo como PNG (qualquer editor exporta) e envie de novo.'
|
||||
else
|
||||
'Não reconheci esse arquivo como imagem. O logo precisa ser PNG ou JPG.'
|
||||
end
|
||||
return redirect_to(admin_romaneios_path, alert: recado)
|
||||
end
|
||||
# `aceito` existe para o dia em que alguém adicionar conversão: hoje só
|
||||
# chega aqui o que o Prawn embute.
|
||||
return redirect_to(admin_romaneios_path, alert: 'Formato não suportado.') unless aceito
|
||||
|
||||
# Nome GERADO por nós: o nome que vem do navegador é entrada do usuário e não
|
||||
# entra em caminho de arquivo. O original fica só na descrição, para a tela
|
||||
# mostrar "Logo: LOGOGADE.png" como o operador reconhece.
|
||||
nome = "logo-#{Time.current.strftime('%Y%m%d%H%M%S')}#{extensao}"
|
||||
destino = Pdf::RomaneioPdf.pasta_logos
|
||||
FileUtils.mkdir_p(destino)
|
||||
File.binwrite(destino.join(nome), arquivo.read)
|
||||
File.binwrite(destino.join(nome), conteudo)
|
||||
|
||||
config = Configuracao.find_or_initialize_by(chave: 'romaneio_logo')
|
||||
config.update!(valor: nome, descricao: arquivo.original_filename.to_s.first(120),
|
||||
@@ -281,8 +327,7 @@ class Admin::RomaneiosController < ApplicationController
|
||||
data = params[:planned_date].presence
|
||||
|
||||
if params[:plano_id].present?
|
||||
@plano_escolhido = SimpliRoute::Client.new.planos(limite: 20)
|
||||
.find { |pl| pl['id'].to_s == params[:plano_id].to_s }
|
||||
@plano_escolhido = SimpliRoute::Client.new.plano(params[:plano_id])
|
||||
if @plano_escolhido.nil?
|
||||
redirect_to admin_romaneios_path,
|
||||
alert: 'Plano não encontrado no SimpliRoute — recarregue a página e escolha de novo.'
|
||||
@@ -342,6 +387,20 @@ class Admin::RomaneiosController < ApplicationController
|
||||
nil
|
||||
end
|
||||
|
||||
# Formato pela ASSINATURA do arquivo. Devolve [extensao, nome_do_formato,
|
||||
# aceito?] — com nome preenchido mesmo para o que não serve, para a mensagem
|
||||
# poder dizer "é WebP" em vez de "não é PNG ou JPG".
|
||||
def identificar_imagem(conteudo)
|
||||
achado = ASSINATURAS.find { |assinatura, _, _, _| conteudo.start_with?(assinatura) }
|
||||
return [nil, nil, false] if achado.nil?
|
||||
|
||||
_, extensao, formato, aceito = achado
|
||||
# RIFF é contêiner (WebP, WAV, AVI): o que diz que é WebP são os bytes 8..11.
|
||||
return [nil, nil, false] if formato == 'WebP' && conteudo[8, 4] != 'WEBP'
|
||||
|
||||
[extensao, formato, aceito]
|
||||
end
|
||||
|
||||
def importar(linhas, origem:)
|
||||
resultado = aplicar(linhas, origem: origem)
|
||||
auditar!(:criar, @romaneio, dados_novos: resultado.to_h)
|
||||
|
||||
Reference in New Issue
Block a user