Romaneio: lista de veículos visível, busca com contador e logo escolhível

Traz para a tela as funções do programa original (Romaneiro PDF), na linha de
design do projeto:
- Veículos deixam de ser um <select> e viram lista visível com a contagem de
  paradas de cada carro — que é a conferência feita antes de imprimir e ficava
  invisível mostrando um veículo por vez. Cada item é link (?veiculo=), então
  sobrevive ao 'voltar' e ao F5. No celular vira faixa horizontal.
- Na mesma coluna: motorista do veículo, 'PDF deste veículo' e 'PDF de TODOS'.
- Busca ganha 'Limpar busca' e contador vivo ('4 de 31 paradas'). A contagem
  saiu do cabeçalho da tabela: dois números para a mesma coisa, um atualizando e
  o outro não, é a divergência que a diretriz 1 proíbe.
- Logo do cabeçalho escolhível (Configuracao 'romaneio_logo', separado do
  empresa_logo — o romaneio é documento do cliente). PNG/JPG até 2MB, gravado em
  storage/logos/ e não em public/, com nome gerado pelo sistema.
This commit is contained in:
2026-08-27 19:20:49 -03:00
parent 7fa2336b35
commit b3464e3acd
11 changed files with 274 additions and 65 deletions

View File

@@ -17,6 +17,9 @@ class Admin::RomaneiosController < ApplicationController
@romaneios = Romaneio.recentes.includes(:romaneio_veiculos).limit(50)
@operacoes_agrupadas = Operacao.agrupadas_por_mes
@data_padrao = Date.current
# 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
end
def show
@@ -61,6 +64,47 @@ class Admin::RomaneiosController < ApplicationController
redirect_to admin_romaneios_path, alert: e.message
end
# ── Logo do cabeçalho ──────────────────────────────────────────────────────
# O romaneio é documento do CLIENTE, não da Reem: quando a operação muda de
# contratante, trocar o logo não pode exigir deploy.
#
# 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
LOGO_TAMANHO_MAX = 2.megabytes
def atualizar_logo
authorize Romaneio
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
# 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)
config = Configuracao.find_or_initialize_by(chave: 'romaneio_logo')
config.update!(valor: nome, descricao: arquivo.original_filename.to_s.first(120),
updated_by: current_user&.id)
redirect_to admin_romaneios_path,
notice: "Logo atualizado: #{arquivo.original_filename}. Vale para os próximos PDFs."
end
# Rebusca o plano e reconcilia com o que já está editado (a regra está em
# Romaneios::Importador).
def reimportar