Adição da função de configuração de email e whatts

This commit is contained in:
2026-08-11 13:31:22 -03:00
parent e8f470f878
commit e530815377
27 changed files with 1461 additions and 92 deletions

View File

@@ -1,10 +1,27 @@
# app/services/notificacao_service.rb
#
# Envia notificações aos motoristas quando uma consolidação é finalizada.
# Canais controlados pelas configurações: notificacao_whatsapp / notificacao_email.
# Falhas de envio NUNCA quebram o fluxo de finalização (apenas logam).
# 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
@@ -16,106 +33,73 @@ class NotificacaoService
def initialize(consolidacao)
@consolidacao = consolidacao
@config = ConfiguracaoNotificacao.instancia
end
def notificar_todos
@consolidacao.consolidacao_motoristas.ativos.each do |cm|
user = User.motorista.ativos.find_by('LOWER(nome) = ?', cm.motorista_nome.downcase)
next unless user
enviar_whatsapp(user, cm) if whatsapp_ativo?
enviar_email(user, cm) if email_ativo? && user.email.present?
end
@consolidacao.consolidacao_motoristas.ativos.each { |cm| notificar(cm, :fechado) }
end
def enviar_aviso_pagamento(cm)
user = User.motorista.ativos.find_by('LOWER(nome) = ?', cm.motorista_nome.downcase)
return unless user
enviar_whatsapp_pagamento(user, cm) if whatsapp_ativo?
enviar_email_pagamento(user, cm) if email_ativo? && user.email.present?
def enviar_aviso_pagamento(consolidacao_motorista)
notificar(consolidacao_motorista, :pago)
end
private
def whatsapp_ativo?
Configuracao.valor('notificacao_whatsapp') == 'true' &&
ENV['TWILIO_ACCOUNT_SID'].present?
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 email_ativo?
Configuracao.valor('notificacao_email') == 'true'
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(v)
inteiro, decimais = format('%.2f', v.to_f).split('.')
def moeda(valor)
inteiro, decimais = format('%.2f', valor.to_f).split('.')
inteiro = inteiro.reverse.gsub(/(\d{3})(?=\d)/, '\1.').reverse
"R$ #{inteiro},#{decimais}"
end
def mensagem(user, cm)
valor = moeda(cm.valor_total)
"Olá #{user.nome.split.first}! 🚚\n" \
"Seu pagamento de entregas foi fechado.\n" \
"📋 #{@consolidacao.nome}\n" \
"💰 Valor: #{valor}\n" \
"Acesse seu painel para baixar o extrato: " \
"https://#{ENV.fetch('APP_HOST', 'localhost:3000')}/motorista"
end
def enviar_whatsapp(user, cm)
return if user.telefone.blank?
require 'twilio-ruby'
cliente = Twilio::REST::Client.new(ENV['TWILIO_ACCOUNT_SID'], ENV['TWILIO_AUTH_TOKEN'])
cliente.messages.create(
from: ENV['TWILIO_WHATSAPP_FROM'],
to: "whatsapp:#{user.telefone}",
body: mensagem(user, cm)
)
Rails.logger.info("[Notificacao] WhatsApp enviado para #{user.nome}")
rescue => e
Rails.logger.error("[Notificacao] Falha WhatsApp #{user.nome}: #{e.message}")
end
def enviar_email(user, cm)
ConsolidacaoMailer.pagamento_fechado(user, @consolidacao, cm).deliver_later
Rails.logger.info("[Notificacao] Email agendado para #{user.email}")
rescue => e
Rails.logger.error("[Notificacao] Falha email #{user.email}: #{e.message}")
end
# ── Aviso de pagamento efetuado ─────────────────────────────
def mensagem_pagamento(user, cm)
valor = moeda(cm.valor_total)
"Olá #{user.nome.split.first}! ✅\n" \
"Seu pagamento foi efetuado.\n" \
"📋 #{@consolidacao.nome}\n" \
"💰 Valor: #{valor}\n" \
"Acesse seu painel para conferir: " \
"https://#{ENV.fetch('APP_HOST', 'localhost:3000')}/motorista"
end
def enviar_whatsapp_pagamento(user, cm)
return if user.telefone.blank?
require 'twilio-ruby'
cliente = Twilio::REST::Client.new(ENV['TWILIO_ACCOUNT_SID'], ENV['TWILIO_AUTH_TOKEN'])
cliente.messages.create(
from: ENV['TWILIO_WHATSAPP_FROM'],
to: "whatsapp:#{user.telefone}",
body: mensagem_pagamento(user, cm)
)
Rails.logger.info("[Notificacao] WhatsApp pagamento enviado para #{user.nome}")
rescue => e
Rails.logger.error("[Notificacao] Falha WhatsApp pagamento #{user.nome}: #{e.message}")
end
def enviar_email_pagamento(user, cm)
ConsolidacaoMailer.pagamento_efetuado(user, @consolidacao, cm).deliver_later
Rails.logger.info("[Notificacao] Email pagamento agendado para #{user.email}")
rescue => e
Rails.logger.error("[Notificacao] Falha email pagamento #{user.email}: #{e.message}")
end
end