Implantação da criação de romaneios
This commit is contained in:
@@ -40,6 +40,30 @@ if ! bundle check >/dev/null 2>&1; then
|
||||
fi
|
||||
|
||||
# ── 4. Migrations ────────────────────────────────────────────────────────────
|
||||
# ANTES de tentar, confere o DATABASE_URL. Este projeto NÃO tem
|
||||
# config/database.yml: a conexão inteira sai dessa única variável (as DB_HOST,
|
||||
# DB_USER etc. do .env não são lidas por ninguém — são só documentação).
|
||||
#
|
||||
# POR QUE ESTA CHECAGEM EXISTE: em 27/08/2026 o .env foi recriado a partir do
|
||||
# .env.example e o DATABASE_URL ficou com o valor de exemplo. O resultado foram
|
||||
# 10 tentativas cuspindo 40 linhas de backtrace até uma
|
||||
# `URI::InvalidURIError: ... SEU_IP` no fim — ilegível no log do Container
|
||||
# Manager. Placeholder e URL vazia não são "banco fora do ar": nenhuma espera
|
||||
# resolve, então falha na hora e diz o que fazer.
|
||||
if [ -z "${DATABASE_URL:-}" ]; then
|
||||
log "ERRO: DATABASE_URL vazia. Sem config/database.yml, é ela que define o banco."
|
||||
log " Formato: postgresql://USUARIO:SENHA@HOST:5432/NOME_DO_BANCO"
|
||||
exit 1
|
||||
fi
|
||||
case "$DATABASE_URL" in
|
||||
*SEU_IP*|*senha_segura*|*SEU_HOST*)
|
||||
log "ERRO: DATABASE_URL ainda está com o valor de EXEMPLO do .env.example:"
|
||||
log " $(printf '%s' "$DATABASE_URL" | sed 's|://[^@]*@|://***:***@|')"
|
||||
log " Preencha com o IP, o usuário e a senha reais do PostgreSQL."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# O PostgreSQL é EXTERNO ao compose: num reboot do servidor o Rails pode subir
|
||||
# antes do banco aceitar conexão. Sem a espera abaixo o container sairia com
|
||||
# erro e o `restart: unless-stopped` ficaria reiniciando em loop — parecendo
|
||||
|
||||
@@ -146,4 +146,73 @@ puts ' Compare com o espelho, no console do app:'
|
||||
puts " Entrega.da_conta_gade.no_periodo(Date.parse('#{data}'), Date.parse('#{data}'))" \
|
||||
'.distinct.count(:vehicle)'
|
||||
puts
|
||||
|
||||
# ── 4. O plano tem NOME? ────────────────────────────────────────────────────
|
||||
# POR QUE ISTO IMPORTA: a operação NÃO trabalha por data — ela identifica o
|
||||
# plano pelo NOME ("EMAD 09.2026" e afins), que é inclusive o texto impresso no
|
||||
# canto do romaneio. Hoje a tela pede a data porque é o único filtro que
|
||||
# sabemos que a API aceita (/v1/routes/visits/?planned_date=). Para trocar por
|
||||
# uma BUSCA POR NOME é preciso primeiro descobrir se existe endpoint de planos
|
||||
# e qual campo carrega o nome — é o que esta seção responde.
|
||||
#
|
||||
# As URLs abaixo são CANDIDATAS: a única rota /v1/plans/ que o app já usa é
|
||||
# /v1/plans/visits/<id>/detail/, então sabemos que o namespace existe, mas não
|
||||
# se ele lista planos. 404/403 aqui é resposta válida — significa "não dá por
|
||||
# esse caminho", e a busca por nome teria que ser feita filtrando as visitas.
|
||||
puts
|
||||
puts '[4] procurando um endpoint de PLANOS (para buscar por nome em vez de data)'
|
||||
|
||||
CHAVES_NOME = /name|title|label|descri|plan/i.freeze
|
||||
|
||||
candidatas = [
|
||||
'/v1/plans/',
|
||||
"/v1/plans/?planned_date=#{data}",
|
||||
'/v1/routes/plans/',
|
||||
"/v1/routes/plans/?planned_date=#{data}"
|
||||
]
|
||||
|
||||
achou_algum = false
|
||||
candidatas.each do |caminho|
|
||||
codigo, corpo, seg = get(caminho)
|
||||
puts " GET #{caminho}"
|
||||
puts " HTTP #{codigo} · #{corpo.bytesize} bytes · #{seg.round(2)}s"
|
||||
|
||||
dados = json(corpo)
|
||||
# A API é Django REST: ora devolve lista, ora {"results": [...]}.
|
||||
itens = dados.is_a?(Array) ? dados : (dados.is_a?(Hash) ? Array(dados['results']) : [])
|
||||
if itens.empty?
|
||||
puts " sem itens (#{corpo.slice(0, 120)})"
|
||||
next
|
||||
end
|
||||
|
||||
achou_algum = true
|
||||
item = itens.first
|
||||
next unless item.is_a?(Hash)
|
||||
|
||||
puts " itens: #{itens.size}"
|
||||
puts " chaves: #{item.keys.sort.join(', ')}"
|
||||
nomes = item.select { |k, v| k.to_s.match?(CHAVES_NOME) && !v.nil? && v.to_s.strip != '' }
|
||||
if nomes.empty?
|
||||
puts ' => nenhum campo de nome PREENCHIDO neste item'
|
||||
else
|
||||
puts ' => campos de nome preenchidos:'
|
||||
nomes.each { |k, v| puts " #{k} = #{v.inspect.slice(0, 90)}" }
|
||||
puts " => primeiros nomes: #{itens.filter_map { |i| i.is_a?(Hash) ? nomes.keys.filter_map { |k| i[k] }.first : nil }.first(5).inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
# Plano B: se não há endpoint de planos, o nome pode vir na própria visita.
|
||||
unless achou_algum
|
||||
puts ' nenhum endpoint de planos respondeu com itens.'
|
||||
puts ' procurando um campo de nome na VISITA (plano B — filtrar visitas pelo nome):'
|
||||
nomes_visita = primeira.select { |k, v| k.to_s.match?(CHAVES_NOME) && !v.nil? && v.to_s.strip != '' }
|
||||
if nomes_visita.empty?
|
||||
puts ' (nenhum) => busca por nome NÃO é possível pela API; a data continua sendo'
|
||||
puts ' o único filtro, e o nome fica só como rótulo do PDF.'
|
||||
else
|
||||
nomes_visita.each { |k, v| puts " #{k} = #{v.inspect.slice(0, 90)}" }
|
||||
end
|
||||
end
|
||||
|
||||
puts
|
||||
puts 'Anote o resultado no cabeçalho deste arquivo antes de commitar.'
|
||||
|
||||
Reference in New Issue
Block a user