Impĺantação Da função de alteração de cada lancamento no banco da simplerout
This commit is contained in:
176
app/controllers/admin/edicao_lancamentos_controller.rb
Normal file
176
app/controllers/admin/edicao_lancamentos_controller.rb
Normal file
@@ -0,0 +1,176 @@
|
||||
# app/controllers/admin/edicao_lancamentos_controller.rb
|
||||
#
|
||||
# Correção de lançamentos do SimpliRoute pelo ADM. Busca a entrega pela NF (na
|
||||
# base de rastreio local), resolve o id numérico na API e grava a alteração
|
||||
# DIRETO na API do SimpliRoute — registrando tudo no AuditoriaLog.
|
||||
#
|
||||
# ⚠️ A base de rastreio local (Entrega) é só leitura e sincroniza depois: a
|
||||
# alteração só reflete no painel na próxima sincronização.
|
||||
class Admin::EdicaoLancamentosController < ApplicationController
|
||||
before_action :garantir_configurado
|
||||
|
||||
# Campos que o ADM pode editar (fase 1). checkout_observation = UUID do motivo.
|
||||
CAMPOS_EDITAVEIS = %w[
|
||||
status checkout_observation checkout_comment notes
|
||||
checkout_time checkout_latitude checkout_longitude
|
||||
].freeze
|
||||
|
||||
STATUS_VALIDOS = %w[pending partial completed failed canceled].freeze
|
||||
|
||||
def show
|
||||
authorize :edicao_lancamento
|
||||
@motivos = motivos_seguros
|
||||
end
|
||||
|
||||
# GET /admin/edicao_lancamento/buscar?nf=79774 → JSON com o estado atual.
|
||||
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?
|
||||
|
||||
id = client.resolver_id(entrega)
|
||||
visita = client.visita(id)
|
||||
|
||||
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']
|
||||
},
|
||||
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
|
||||
def atualizar
|
||||
authorize :edicao_lancamento
|
||||
|
||||
id = params[:visit_id].to_s.strip
|
||||
return redirect_to(admin_edicao_lancamento_path, alert: 'Visita não identificada.') if id.blank?
|
||||
|
||||
anterior = client.visita(id)
|
||||
attrs = mudancas(anterior)
|
||||
|
||||
if attrs.empty?
|
||||
return redirect_to(admin_edicao_lancamento_path, alert: 'Nenhuma alteração informada.')
|
||||
end
|
||||
if attrs['status'].present? && STATUS_VALIDOS.exclude?(attrs['status'])
|
||||
return redirect_to(admin_edicao_lancamento_path, alert: 'Status inválido.')
|
||||
end
|
||||
|
||||
atualizada = client.atualizar_visita(id, attrs)
|
||||
|
||||
AuditoriaLog.registrar(
|
||||
user: current_user,
|
||||
acao: 'editar',
|
||||
entidade: 'SimpliRoute::Visita',
|
||||
entidade_id: id,
|
||||
dados_anteriores: anterior.slice(*attrs.keys),
|
||||
dados_novos: atualizada.slice(*attrs.keys),
|
||||
request: request
|
||||
)
|
||||
|
||||
redirect_to admin_edicao_lancamento_path,
|
||||
notice: "Lançamento da NF #{atualizada['reference']} atualizado no SimpliRoute. " \
|
||||
'O painel refletirá na próxima sincronização.'
|
||||
rescue SimpliRoute::Error => e
|
||||
redirect_to admin_edicao_lancamento_path, alert: "Não foi possível atualizar: #{e.message}"
|
||||
end
|
||||
|
||||
# GET /admin/edicao_lancamento/historico?visit_id=123 → JSON (best-effort).
|
||||
def historico
|
||||
authorize :edicao_lancamento
|
||||
render json: { ok: true, historico: client.historico(params[:visit_id]) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def client
|
||||
@client ||= SimpliRoute::Client.new
|
||||
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)
|
||||
CAMPOS_EDITAVEIS.each_with_object({}) do |campo, memo|
|
||||
next unless params.key?(campo)
|
||||
|
||||
novo = normalizar(campo, params[campo])
|
||||
next if equivalente?(campo, novo, anterior[campo])
|
||||
|
||||
memo[campo] = novo
|
||||
end
|
||||
end
|
||||
|
||||
# Evita PATCH falso: nil/"" são equivalentes; datas comparadas por instante;
|
||||
# lat/long por valor numérico (o reparse difere do texto original da API).
|
||||
def equivalente?(campo, novo, atual)
|
||||
return true if novo.to_s == atual.to_s
|
||||
|
||||
case campo
|
||||
when 'checkout_time'
|
||||
a = (Time.zone.parse(novo.to_s) rescue nil)
|
||||
b = (Time.zone.parse(atual.to_s) rescue nil)
|
||||
a.present? && b.present? && a.to_i == b.to_i
|
||||
when 'checkout_latitude', 'checkout_longitude'
|
||||
novo.is_a?(Float) && atual.present? && (novo - atual.to_f).abs < 1e-9
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# Normaliza valores por campo. Campos em branco viram nil (permite LIMPAR o
|
||||
# motivo/comentário). checkout_time aceita datetime-local e vira ISO8601.
|
||||
def normalizar(campo, valor)
|
||||
valor = valor.to_s.strip
|
||||
return nil if valor.blank?
|
||||
|
||||
case campo
|
||||
when 'checkout_latitude', 'checkout_longitude'
|
||||
Float(valor) rescue valor
|
||||
when 'checkout_time'
|
||||
(Time.zone.parse(valor)&.iso8601 rescue nil) || valor
|
||||
else
|
||||
valor
|
||||
end
|
||||
end
|
||||
|
||||
# Lista de motivos; nunca quebra a tela se a API estiver fora.
|
||||
def motivos_seguros
|
||||
client.observations
|
||||
rescue SimpliRoute::Error
|
||||
[]
|
||||
end
|
||||
|
||||
def render_erro(msg, status: :unprocessable_entity)
|
||||
render json: { ok: false, erro: msg }, status: status
|
||||
end
|
||||
|
||||
# Sem token não há o que fazer — avisa e volta.
|
||||
def garantir_configurado
|
||||
return if SimpliRoute.configurado?
|
||||
|
||||
msg = 'Integração com o SimpliRoute não configurada (defina SIMPLIROUTE_TOKEN no servidor).'
|
||||
respond_to do |format|
|
||||
format.html { redirect_to dashboard_path, alert: msg }
|
||||
format.json { render json: { ok: false, erro: msg }, status: :service_unavailable }
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user