Atualização do função de editar lançamento para quer consiga listar todas
This commit is contained in:
@@ -22,45 +22,34 @@ class Admin::EdicaoLancamentosController < ApplicationController
|
||||
@motivos = motivos_seguros
|
||||
end
|
||||
|
||||
# GET /admin/edicao_lancamento/buscar?nf=79774 → JSON com o estado atual.
|
||||
# GET /admin/edicao_lancamento/buscar?nf=79774 → JSON com TODOS os lançamentos
|
||||
# daquela NF.
|
||||
#
|
||||
# ⚠️ Uma NF pode ter mais de um lançamento: quando o plano é duplicado no
|
||||
# SimpliRoute nasce uma visita nova (outro tracking_id) com a mesma NF, e a
|
||||
# antiga — a que tem o motorista/checkout — continua existindo. Por isso a
|
||||
# busca devolve a LISTA e o ADM escolhe qual editar; assumir "1 NF = 1
|
||||
# lançamento" escondia justamente o lançamento antigo.
|
||||
#
|
||||
# Com um único lançamento já vem o card montado, para não custar um segundo
|
||||
# round-trip no caso comum.
|
||||
def buscar
|
||||
authorize :edicao_lancamento
|
||||
|
||||
nf = params[:nf].to_s.strip
|
||||
return render_erro('Informe o número da NF.') if nf.blank?
|
||||
|
||||
entrega = Entrega.por_nf(nf).first
|
||||
return render_erro("NF #{nf} não encontrada na base de rastreio.") if entrega.nil?
|
||||
entregas = Entrega.por_nf(nf).to_a
|
||||
return render_erro("NF #{nf} não encontrada na base de rastreio.") if entregas.empty?
|
||||
|
||||
id = client.resolver_id(entrega)
|
||||
visita = client.visita(id)
|
||||
# Segunda fonte de imagens (POD). Não é obrigatória: se falhar, vem {}.
|
||||
detalhe = client.detalhe_visita(id)
|
||||
ocorrencias = ocorrencias_da_nf(nf, entregas)
|
||||
unica = ocorrencias.first if ocorrencias.one? && ocorrencias.first[:id].present?
|
||||
|
||||
render json: {
|
||||
ok: true,
|
||||
visita: {
|
||||
id: id,
|
||||
nf: visita['reference'],
|
||||
titulo: visita['title'],
|
||||
endereco: visita['address'],
|
||||
status: visita['status'],
|
||||
checkout_observation: visita['checkout_observation'],
|
||||
checkout_comment: visita['checkout_comment'],
|
||||
notes: visita['notes'],
|
||||
checkout_time: visita['checkout_time'],
|
||||
checkout_latitude: visita['checkout_latitude'],
|
||||
checkout_longitude: visita['checkout_longitude'],
|
||||
planned_date: visita['planned_date'],
|
||||
contato: visita['contact_name'],
|
||||
telefone: visita['contact_phone'],
|
||||
# Galeria unificada — TODAS as fotos do lançamento, de todas as fontes,
|
||||
# cada uma etiquetada para o ADM saber o que está conferindo.
|
||||
fotos: fotos_do_lancamento(entrega, visita, detalhe),
|
||||
motorista: entrega.driver,
|
||||
veiculo: entrega.vehicle
|
||||
},
|
||||
motivos: motivos_seguros
|
||||
ok: true,
|
||||
ocorrencias: ocorrencias,
|
||||
visita: (unica && payload_visita(unica[:id], entrega_de(entregas, unica[:tracking_id]))),
|
||||
motivos: motivos_seguros
|
||||
}
|
||||
rescue SimpliRoute::NotFound => e
|
||||
render_erro(e.message)
|
||||
@@ -68,6 +57,23 @@ class Admin::EdicaoLancamentosController < ApplicationController
|
||||
render_erro("Erro ao consultar o SimpliRoute: #{e.message}", status: :bad_gateway)
|
||||
end
|
||||
|
||||
# GET /admin/edicao_lancamento/carregar?visit_id=871407488&tracking_id=SR...
|
||||
# Monta o card de UM lançamento escolhido na lista de ocorrências.
|
||||
def carregar
|
||||
authorize :edicao_lancamento
|
||||
|
||||
id = params[:visit_id].to_s.strip
|
||||
return render_erro('Lançamento não identificado.') if id.blank?
|
||||
|
||||
entrega = Entrega.find_by(tracking_id: params[:tracking_id]) if params[:tracking_id].present?
|
||||
|
||||
render json: { ok: true, visita: payload_visita(id, entrega), motivos: motivos_seguros }
|
||||
rescue SimpliRoute::NotFound => e
|
||||
render_erro(e.message)
|
||||
rescue SimpliRoute::Error => e
|
||||
render_erro("Erro ao consultar o SimpliRoute: #{e.message}", status: :bad_gateway)
|
||||
end
|
||||
|
||||
# PATCH /admin/edicao_lancamento/atualizar
|
||||
# HTML: fluxo de form clássico (fallback). JSON: salvar-por-campo do card
|
||||
# (click-to-edit) — o fetch manda visit_id + só o campo editado.
|
||||
@@ -146,6 +152,107 @@ class Admin::EdicaoLancamentosController < ApplicationController
|
||||
@client ||= SimpliRoute::Client.new
|
||||
end
|
||||
|
||||
# Todos os lançamentos da NF, cruzando as DUAS fontes:
|
||||
# • espelho de rastreio (Entrega) — traz motorista/veículo;
|
||||
# • API do SimpliRoute, nas datas desses lançamentos — pega a visita
|
||||
# duplicada que a sincronização ainda não trouxe para o espelho.
|
||||
#
|
||||
# A API não tem busca global por NF (só por data), então as datas vêm do
|
||||
# espelho: 1 chamada por data distinta (plano duplicado costuma cair no mesmo
|
||||
# dia, e aí é 1 chamada só).
|
||||
def ocorrencias_da_nf(nf, entregas)
|
||||
datas = entregas.filter_map { |e| e.planned_date&.to_date }.uniq
|
||||
trackings = entregas.map { |e| e.tracking_id.to_s }
|
||||
do_dia = datas.flat_map { |data| client.visitas_da_data(data) }
|
||||
|
||||
visitas = do_dia.select { |v| v['reference'].to_s == nf || trackings.include?(v['tracking_id'].to_s) }
|
||||
.uniq { |v| v['id'] }
|
||||
|
||||
achadas = visitas.map { |v| ocorrencia_da_api(v, entrega_de(entregas, v['tracking_id'])) }
|
||||
|
||||
# Lançamento que existe no espelho mas não apareceu na API (data sem plano,
|
||||
# visita removida): entra na lista como não editável, para o ADM ver que
|
||||
# ele existe em vez de sumir silenciosamente — que é o bug que estamos
|
||||
# corrigindo.
|
||||
vistos = visitas.map { |v| v['tracking_id'].to_s }
|
||||
orfas = entregas.reject { |e| vistos.include?(e.tracking_id.to_s) }.map { |e| ocorrencia_do_espelho(e) }
|
||||
|
||||
# Mais recente primeiro (a data vem como texto ISO da API e como timestamp
|
||||
# do espelho — os 10 primeiros caracteres normalizam as duas).
|
||||
(achadas + orfas).sort_by { |o| [o[:data].to_s[0, 10], o[:id].to_i] }.reverse
|
||||
end
|
||||
|
||||
def entrega_de(entregas, tracking_id)
|
||||
entregas.find { |e| e.tracking_id.to_s == tracking_id.to_s }
|
||||
end
|
||||
|
||||
# Resumo de um lançamento para a lista de escolha (não carrega fotos/detalhe —
|
||||
# isso só acontece quando o ADM abre um).
|
||||
def ocorrencia_da_api(visita, entrega)
|
||||
{
|
||||
id: visita['id'],
|
||||
tracking_id: visita['tracking_id'],
|
||||
titulo: visita['title'],
|
||||
endereco: visita['address'],
|
||||
status: visita['status'],
|
||||
data: visita['planned_date'],
|
||||
checkout_time: visita['checkout_time'],
|
||||
motorista: entrega&.driver,
|
||||
veiculo: entrega&.vehicle,
|
||||
editavel: true,
|
||||
# Está na API mas ainda não no espelho — daí não sabermos motorista/veículo.
|
||||
aviso: entrega ? nil : 'Ainda não sincronizado no painel'
|
||||
}
|
||||
end
|
||||
|
||||
def ocorrencia_do_espelho(entrega)
|
||||
{
|
||||
id: nil,
|
||||
tracking_id: entrega.tracking_id,
|
||||
titulo: entrega.local,
|
||||
endereco: entrega.address,
|
||||
status: entrega.status,
|
||||
data: entrega.planned_date,
|
||||
checkout_time: entrega.checkout,
|
||||
motorista: entrega.driver,
|
||||
veiculo: entrega.vehicle,
|
||||
editavel: false,
|
||||
aviso: 'Não localizado na API do SimpliRoute — não é editável'
|
||||
}
|
||||
end
|
||||
|
||||
# Estado completo de UMA visita para o card (inclui a galeria de fotos, que
|
||||
# custa uma chamada extra ao POD). `entrega` pode ser nil quando a visita
|
||||
# ainda não sincronizou no espelho.
|
||||
def payload_visita(id, entrega)
|
||||
visita = client.visita(id)
|
||||
# Segunda fonte de imagens (POD). Não é obrigatória: se falhar, vem {}.
|
||||
detalhe = client.detalhe_visita(id)
|
||||
|
||||
{
|
||||
id: id,
|
||||
tracking_id: visita['tracking_id'],
|
||||
nf: visita['reference'],
|
||||
titulo: visita['title'],
|
||||
endereco: visita['address'],
|
||||
status: visita['status'],
|
||||
checkout_observation: visita['checkout_observation'],
|
||||
checkout_comment: visita['checkout_comment'],
|
||||
notes: visita['notes'],
|
||||
checkout_time: visita['checkout_time'],
|
||||
checkout_latitude: visita['checkout_latitude'],
|
||||
checkout_longitude: visita['checkout_longitude'],
|
||||
planned_date: visita['planned_date'],
|
||||
contato: visita['contact_name'],
|
||||
telefone: visita['contact_phone'],
|
||||
# Galeria unificada — TODAS as fotos do lançamento, de todas as fontes,
|
||||
# cada uma etiquetada para o ADM saber o que está conferindo.
|
||||
fotos: fotos_do_lancamento(entrega, visita, detalhe),
|
||||
motorista: entrega&.driver,
|
||||
veiculo: entrega&.vehicle
|
||||
}
|
||||
end
|
||||
|
||||
# Monta o hash de PATCH só com os campos que vieram no form E que realmente
|
||||
# mudaram em relação ao estado atual — PATCH mínimo, sem sobrescrever à toa.
|
||||
def mudancas(anterior)
|
||||
|
||||
Reference in New Issue
Block a user