, correção da pagina de gerar romaneio
This commit is contained in:
@@ -20,7 +20,17 @@ module Romaneios
|
|||||||
class PlanoDoDia
|
class PlanoDoDia
|
||||||
# Chaves candidatas nos hashes da API. Só as usamos se vierem PREENCHIDAS —
|
# Chaves candidatas nos hashes da API. Só as usamos se vierem PREENCHIDAS —
|
||||||
# a API devolve chave existente com valor nil o tempo todo.
|
# a API devolve chave existente com valor nil o tempo todo.
|
||||||
CHAVES_VEICULO = %w[vehicle vehicle_name vehicle_id].freeze
|
#
|
||||||
|
# ⚠️ A ORDEM AQUI É O CONSERTO DE UM BUG REAL, não estilo. Na API o campo
|
||||||
|
# `vehicle` da rota é o **ID numérico** do veículo (630011), e o nome que a
|
||||||
|
# operação usa — o mesmo que a planilha do plano traz na coluna "Veículo" —
|
||||||
|
# é GADE_038. Com `vehicle` na frente, o ID ganhava sempre e o romaneio saía
|
||||||
|
# impresso "CONTROLE DE ENTREGA — 630011", com o motorista sem saber que
|
||||||
|
# carro pegar. Nome primeiro; ID só como último recurso, porque veículo
|
||||||
|
# vazio faz a linha ser descartada e o romaneio sair sem paradas.
|
||||||
|
CHAVES_VEICULO = %w[vehicle_name vehicle_label vehicle vehicle_id].freeze
|
||||||
|
# Dentro do objeto do veículo (quando a API aninha em vez de mandar o id).
|
||||||
|
CHAVES_NOME_VEIC = %w[name label display_name plate].freeze
|
||||||
CHAVES_MOTORISTA = %w[driver driver_name].freeze
|
CHAVES_MOTORISTA = %w[driver driver_name].freeze
|
||||||
CHAVES_ORDEM = %w[order sequence position route_order].freeze
|
CHAVES_ORDEM = %w[order sequence position route_order].freeze
|
||||||
|
|
||||||
@@ -59,7 +69,7 @@ module Romaneios
|
|||||||
return [] if visitas.empty?
|
return [] if visitas.empty?
|
||||||
|
|
||||||
linhas = por_rotas(cliente, visitas)
|
linhas = por_rotas(cliente, visitas)
|
||||||
linhas = por_visitas(visitas) if linhas.empty?
|
linhas = por_visitas(visitas, cliente) if linhas.empty?
|
||||||
@origem = 'api' if linhas.any?
|
@origem = 'api' if linhas.any?
|
||||||
linhas
|
linhas
|
||||||
rescue SimpliRoute::Error
|
rescue SimpliRoute::Error
|
||||||
@@ -77,7 +87,7 @@ module Romaneios
|
|||||||
linhas = []
|
linhas = []
|
||||||
|
|
||||||
rotas.each do |rota|
|
rotas.each do |rota|
|
||||||
veiculo = primeiro_valor(rota, CHAVES_VEICULO)
|
veiculo = nome_do_veiculo(rota, cliente)
|
||||||
next if veiculo.empty?
|
next if veiculo.empty?
|
||||||
|
|
||||||
ids = Array(rota['visits']).map { |v| v.is_a?(Hash) ? v['id'] : v }
|
ids = Array(rota['visits']).map { |v| v.is_a?(Hash) ? v['id'] : v }
|
||||||
@@ -96,11 +106,11 @@ module Romaneios
|
|||||||
|
|
||||||
# (b) A visita traz o veículo direto; a ordem sai de `order`/`sequence` ou,
|
# (b) A visita traz o veículo direto; a ordem sai de `order`/`sequence` ou,
|
||||||
# na falta, do horário estimado de chegada.
|
# na falta, do horário estimado de chegada.
|
||||||
def por_visitas(visitas)
|
def por_visitas(visitas, cliente)
|
||||||
com_veiculo = visitas.reject { |v| primeiro_valor(v, CHAVES_VEICULO).empty? }
|
com_veiculo = visitas.reject { |v| nome_do_veiculo(v, cliente).empty? }
|
||||||
return [] if com_veiculo.empty?
|
return [] if com_veiculo.empty?
|
||||||
|
|
||||||
com_veiculo.group_by { |v| primeiro_valor(v, CHAVES_VEICULO) }.flat_map do |veiculo, lista|
|
com_veiculo.group_by { |v| nome_do_veiculo(v, cliente) }.flat_map do |veiculo, lista|
|
||||||
ordenadas(lista).each_with_index.map do |visita, i|
|
ordenadas(lista).each_with_index.map do |visita, i|
|
||||||
monta(visita, veiculo, primeiro_valor(visita, CHAVES_MOTORISTA), i + 1)
|
monta(visita, veiculo, primeiro_valor(visita, CHAVES_MOTORISTA), i + 1)
|
||||||
end
|
end
|
||||||
@@ -123,6 +133,39 @@ module Romaneios
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# O NOME do veículo como a operação o conhece (GADE_038), nunca o id.
|
||||||
|
#
|
||||||
|
# Três formas já vistas/possíveis no mesmo campo, por isso as três camadas:
|
||||||
|
# { "vehicle_name" => "GADE_038" } -> nome direto
|
||||||
|
# { "vehicle" => { "name" => "GADE_038" } } -> aninhado
|
||||||
|
# { "vehicle" => 630011 } -> só o id, precisa resolver
|
||||||
|
#
|
||||||
|
# Quando sobra só o id, procuramos o nome na lista de veículos da conta. Se
|
||||||
|
# essa busca não responder, devolvemos o id mesmo: um romaneio com o número
|
||||||
|
# do carro é ruim, um romaneio VAZIO (que é o que acontece devolvendo "") é
|
||||||
|
# pior — a linha sem veículo é descartada.
|
||||||
|
def nome_do_veiculo(hash, cliente)
|
||||||
|
aninhado = hash['vehicle']
|
||||||
|
return primeiro_valor(aninhado, CHAVES_NOME_VEIC) if aninhado.is_a?(Hash)
|
||||||
|
|
||||||
|
valor = primeiro_valor(hash, CHAVES_VEICULO)
|
||||||
|
return valor unless valor.match?(/\A\d+\z/)
|
||||||
|
|
||||||
|
nomes_de_veiculo(cliente)[valor].presence || valor
|
||||||
|
end
|
||||||
|
|
||||||
|
# id (string) => nome. Uma chamada por importação, memoizada: são ~70 veículos
|
||||||
|
# e a alternativa seria uma consulta por rota.
|
||||||
|
def nomes_de_veiculo(cliente)
|
||||||
|
@nomes_de_veiculo ||= cliente.veiculos.each_with_object({}) do |v, memo|
|
||||||
|
next unless v.is_a?(Hash)
|
||||||
|
|
||||||
|
id = v['id'].to_s.strip
|
||||||
|
nome = primeiro_valor(v, CHAVES_NOME_VEIC)
|
||||||
|
memo[id] = nome unless id.empty? || nome.empty?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def primeiro_valor(hash, chaves)
|
def primeiro_valor(hash, chaves)
|
||||||
chaves.filter_map { |k| hash[k] }.map(&:to_s).find { |v| !v.strip.empty? }.to_s.strip
|
chaves.filter_map { |k| hash[k] }.map(&:to_s).find { |v| !v.strip.empty? }.to_s.strip
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -80,6 +80,19 @@ module SimpliRoute
|
|||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Veículos da conta, para traduzir o id numérico que vem nas rotas
|
||||||
|
# (`vehicle: 630011`) no nome que a operação usa (`GADE_038`).
|
||||||
|
#
|
||||||
|
# Best-effort pelo mesmo motivo de `rotas_da_data`: sem token na máquina de
|
||||||
|
# desenvolvimento não dá para verificar o caminho, então endpoint ausente
|
||||||
|
# devolve [] e Romaneios::PlanoDoDia segue com o id em vez de quebrar a
|
||||||
|
# importação inteira.
|
||||||
|
def veiculos
|
||||||
|
Array(get('/v1/routes/vehicles/'))
|
||||||
|
rescue Error
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
# Resolve o `id` numérico (usado na URL de escrita) a partir de uma Entrega
|
# Resolve o `id` numérico (usado na URL de escrita) a partir de uma Entrega
|
||||||
# do espelho local, que só tem tracking_id (SR...) + reference_id (NF) +
|
# do espelho local, que só tem tracking_id (SR...) + reference_id (NF) +
|
||||||
# planned_date. Casa pelo tracking_id; se não achar, tenta pela NF.
|
# planned_date. Casa pelo tracking_id; se não achar, tenta pela NF.
|
||||||
|
|||||||
@@ -145,9 +145,13 @@ O bloco "Operação do mês" tem que aparecer em todo romaneio, e o formulário
|
|||||||
precisa funcionar **sem JavaScript** (é `<details>` nativo + form comum):
|
precisa funcionar **sem JavaScript** (é `<details>` nativo + form comum):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
agent-browser eval "const d=[...document.querySelectorAll('details')].find(x=>x.textContent.includes('operação')); d ? 'existe | aberto:'+d.open+' | opcoes:'+d.querySelectorAll('option').length : 'AUSENTE'"
|
agent-browser eval "(()=>{const d=[...document.querySelectorAll('details')].find(x=>x.querySelector('select[name=operacao_tabela]')); return d ? 'existe | aberto:'+d.open+' | opcoes:'+d.querySelectorAll('option').length : 'AUSENTE';})()"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
⚠️ Procure pelo `select[name=operacao_tabela]`, **não** pelo texto "Operação do
|
||||||
|
mês": esse rótulo fica FORA do `<details>` e é renderizado em maiúsculas pelo
|
||||||
|
CSS, então busca por texto dá falso negativo (já aconteceu num diagnóstico).
|
||||||
|
|
||||||
**PASSOU se**: o bloco existe; num romaneio **sem** operação ele vem `aberto:true`
|
**PASSOU se**: o bloco existe; num romaneio **sem** operação ele vem `aberto:true`
|
||||||
(a pendência fica à vista) e num **com** operação vem `aberto:false`; a lista tem
|
(a pendência fica à vista) e num **com** operação vem `aberto:false`; a lista tem
|
||||||
mais de uma `option`.
|
mais de uma `option`.
|
||||||
|
|||||||
Reference in New Issue
Block a user