# 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