106 lines
3.8 KiB
Ruby
106 lines
3.8 KiB
Ruby
# app/services/notificacao_service.rb
|
|
#
|
|
# Envia notificações aos motoristas quando uma consolidação é finalizada ou
|
|
# quando o pagamento é efetuado.
|
|
#
|
|
# Canais e credenciais vêm de ConfiguracaoNotificacao (tela /admin/
|
|
# configuracao_notificacao), com fallback para o .env.
|
|
#
|
|
# Falhas de envio NUNCA quebram o fluxo de finalização — apenas logam. Isso é
|
|
# intencional: um SMTP fora do ar não pode impedir o fechamento de um pagamento.
|
|
# Para DIAGNOSTICAR o envio, use os botões de teste da tela, que usam
|
|
# Notificacao::TesteEmail / Notificacao::TesteWhatsapp e mostram o erro real.
|
|
class NotificacaoService
|
|
EVENTOS = {
|
|
fechado: { mailer: :pagamento_fechado,
|
|
emoji: '🚚',
|
|
titulo: 'Seu pagamento de entregas foi fechado.',
|
|
cta: 'Acesse seu painel para baixar o extrato:' },
|
|
pago: { mailer: :pagamento_efetuado,
|
|
emoji: '✅',
|
|
titulo: 'Seu pagamento foi efetuado.',
|
|
cta: 'Acesse seu painel para conferir:' }
|
|
}.freeze
|
|
|
|
def self.notificar_finalizacao(consolidacao)
|
|
new(consolidacao).notificar_todos
|
|
end
|
|
|
|
# Avisa UM motorista de que o pagamento dele foi efetuado.
|
|
def self.notificar_pagamento(consolidacao, consolidacao_motorista)
|
|
new(consolidacao).enviar_aviso_pagamento(consolidacao_motorista)
|
|
end
|
|
|
|
def initialize(consolidacao)
|
|
@consolidacao = consolidacao
|
|
@config = ConfiguracaoNotificacao.instancia
|
|
end
|
|
|
|
def notificar_todos
|
|
@consolidacao.consolidacao_motoristas.ativos.each { |cm| notificar(cm, :fechado) }
|
|
end
|
|
|
|
def enviar_aviso_pagamento(consolidacao_motorista)
|
|
notificar(consolidacao_motorista, :pago)
|
|
end
|
|
|
|
private
|
|
|
|
def notificar(cm, evento)
|
|
user = motorista_de(cm)
|
|
return unless user
|
|
|
|
enviar_whatsapp(user, cm, evento) if @config.whatsapp_habilitado?
|
|
enviar_email(user, cm, evento) if @config.email_habilitado? && user.email.present?
|
|
end
|
|
|
|
def motorista_de(cm)
|
|
User.motorista.ativos.find_by('LOWER(nome) = ?', cm.motorista_nome.downcase)
|
|
end
|
|
|
|
def enviar_whatsapp(user, cm, evento)
|
|
# O telefone no cadastro pode estar como "(11) 92005-1157"; mandar esse
|
|
# texto cru para o Twilio devolve erro 21211 (destino inválido), que o
|
|
# rescue abaixo esconderia. Normalizar para E.164 é o que faz o envio
|
|
# realmente funcionar.
|
|
destino = ConfiguracaoNotificacao.canal(user.telefone)
|
|
return if destino.blank?
|
|
|
|
credenciais = @config.credenciais_whatsapp
|
|
return if credenciais.blank? || credenciais[:from].blank?
|
|
|
|
Notificacao::ClienteTwilio
|
|
.montar(credenciais[:sid], credenciais[:token])
|
|
.messages.create(from: credenciais[:from], to: destino, body: mensagem(user, cm, evento))
|
|
|
|
Rails.logger.info("[Notificacao] WhatsApp (#{evento}) enviado para #{user.nome}")
|
|
rescue StandardError => e
|
|
Rails.logger.error("[Notificacao] Falha WhatsApp (#{evento}) #{user.nome}: #{e.class}: #{e.message}")
|
|
end
|
|
|
|
def enviar_email(user, cm, evento)
|
|
ConsolidacaoMailer
|
|
.public_send(EVENTOS.fetch(evento)[:mailer], user, @consolidacao, cm)
|
|
.deliver_later
|
|
Rails.logger.info("[Notificacao] Email (#{evento}) agendado para #{user.email}")
|
|
rescue StandardError => e
|
|
Rails.logger.error("[Notificacao] Falha email (#{evento}) #{user.email}: #{e.class}: #{e.message}")
|
|
end
|
|
|
|
def mensagem(user, cm, evento)
|
|
evt = EVENTOS.fetch(evento)
|
|
"Olá #{user.nome.split.first}! #{evt[:emoji]}\n" \
|
|
"#{evt[:titulo]}\n" \
|
|
"📋 #{@consolidacao.nome}\n" \
|
|
"💰 Valor: #{moeda(cm.valor_total)}\n" \
|
|
"#{evt[:cta]} https://#{ENV.fetch('APP_HOST', 'localhost:3000')}/motorista"
|
|
end
|
|
|
|
# Moeda BR com separador de milhar: R$ 1.234,56
|
|
def moeda(valor)
|
|
inteiro, decimais = format('%.2f', valor.to_f).split('.')
|
|
inteiro = inteiro.reverse.gsub(/(\d{3})(?=\d)/, '\1.').reverse
|
|
"R$ #{inteiro},#{decimais}"
|
|
end
|
|
end
|