Implantação da geração de mensagem de forma livre e mudança na engine de mensagem
This commit is contained in:
119
app/models/evento_notificacao.rb
Normal file
119
app/models/evento_notificacao.rb
Normal file
@@ -0,0 +1,119 @@
|
||||
# app/models/evento_notificacao.rb
|
||||
#
|
||||
# Um evento que dispara mensagem. O ADM cadastra quantos quiser e liga cada um a
|
||||
# grupos de contato — mas o GATILHO sai de GATILHOS, porque gatilho é código.
|
||||
#
|
||||
# manual → botão "disparar agora" (aviso pontual)
|
||||
# consolidacao_finalizada → NotificacaoService.notificar_finalizacao
|
||||
# pagamento_efetuado → NotificacaoService.notificar_pagamento
|
||||
# valor_alterado → edição de lançamento / desconto após o fechamento
|
||||
# operacao_alterada → NF que entrou/saiu, entrega que mudou de status
|
||||
# agendado → resumo periódico (frequencia + hora)
|
||||
#
|
||||
# `sistema: true` marca os que nascem com o app: editáveis e desligáveis, mas
|
||||
# não apagáveis — apagar deixaria o código disparando no vazio.
|
||||
class EventoNotificacao < ApplicationRecord
|
||||
self.table_name = 'eventos_notificacao'
|
||||
|
||||
GATILHOS = %w[manual consolidacao_finalizada pagamento_efetuado
|
||||
valor_alterado operacao_alterada agendado].freeze
|
||||
|
||||
GATILHO_LABEL = {
|
||||
'manual' => 'Disparo manual (botão)',
|
||||
'consolidacao_finalizada' => 'Consolidação finalizada',
|
||||
'pagamento_efetuado' => 'Pagamento efetuado',
|
||||
'valor_alterado' => 'Valor alterado no fechamento',
|
||||
'operacao_alterada' => 'Dados da operação mudaram',
|
||||
'agendado' => 'Agendado (resumo periódico)'
|
||||
}.freeze
|
||||
|
||||
FREQUENCIAS = %w[diaria semanal].freeze
|
||||
|
||||
# Gatilhos que se referem a UMA pessoa específica (o motorista do pagamento),
|
||||
# e não só a grupos. Só neles `notificar_envolvido` faz sentido.
|
||||
GATILHOS_COM_ENVOLVIDO = %w[consolidacao_finalizada pagamento_efetuado valor_alterado].freeze
|
||||
|
||||
has_many :assinaturas, class_name: 'GrupoEventoAssinatura', dependent: :destroy
|
||||
has_many :grupos_contato, through: :assinaturas, source: :grupo_contato
|
||||
has_many :notificacao_envios, dependent: :nullify
|
||||
has_many :mensagem_templates, dependent: :destroy
|
||||
|
||||
accepts_nested_attributes_for :assinaturas, allow_destroy: true
|
||||
|
||||
validates :nome, presence: true
|
||||
validates :chave, presence: true, uniqueness: { case_sensitive: false }
|
||||
validates :gatilho, inclusion: { in: GATILHOS }
|
||||
validates :frequencia, inclusion: { in: FREQUENCIAS }, if: :agendado?
|
||||
validates :hora, numericality: { only_integer: true, greater_than_or_equal_to: 0,
|
||||
less_than_or_equal_to: 23 }, allow_nil: true
|
||||
validates :dia_semana, numericality: { only_integer: true, greater_than_or_equal_to: 0,
|
||||
less_than_or_equal_to: 6 }, allow_nil: true
|
||||
validate :semanal_tem_dia
|
||||
|
||||
before_validation :normalizar
|
||||
|
||||
scope :ativos, -> { where(ativo: true) }
|
||||
scope :ordenados, -> { order(Arel.sql('LOWER(nome)')) }
|
||||
scope :do_gatilho, ->(g) { ativos.where(gatilho: g) }
|
||||
|
||||
def agendado? = gatilho == 'agendado'
|
||||
def manual? = gatilho == 'manual'
|
||||
def envolvido_aplicavel? = GATILHOS_COM_ENVOLVIDO.include?(gatilho)
|
||||
def gatilho_label = GATILHO_LABEL[gatilho] || gatilho
|
||||
|
||||
# Só pode apagar o que o ADM criou.
|
||||
def apagavel? = !sistema?
|
||||
|
||||
# Template do canal, criando um vazio em memória quando ainda não existe —
|
||||
# assim a tela do editor abre igual para evento novo e evento já configurado.
|
||||
def template(canal)
|
||||
mensagem_templates.find { |t| t.canal == canal.to_s } ||
|
||||
mensagem_templates.build(canal: canal.to_s, blocos: [])
|
||||
end
|
||||
|
||||
# O corpo configurado no editor vence o texto padrão do código. Um template
|
||||
# ativo porém VAZIO não conta (mandaria mensagem em branco).
|
||||
def template_utilizavel(canal)
|
||||
t = mensagem_templates.detect { |x| x.canal == canal.to_s }
|
||||
t&.utilizavel? ? t : nil
|
||||
end
|
||||
|
||||
def variaveis = Notificacao::Variaveis.para(gatilho)
|
||||
|
||||
# Contatos que devem receber este evento, sem repetição — a mesma pessoa pode
|
||||
# estar em dois grupos assinantes.
|
||||
def destinatarios(canal)
|
||||
ids = assinaturas.where(ativo: true)
|
||||
.select { |a| a.cobre_canal?(canal) }
|
||||
.map(&:grupo_contato_id)
|
||||
return Contato.none if ids.empty?
|
||||
|
||||
Contato.ativos.where(grupo_contato_id: ids).com_canal(canal).distinct
|
||||
end
|
||||
|
||||
# Já passou da hora de disparar hoje/esta semana?
|
||||
def vencido?(agora = Time.current)
|
||||
return false unless agendado? && ativo?
|
||||
return false unless agora.hour >= hora.to_i
|
||||
return false if frequencia == 'semanal' && agora.wday != dia_semana.to_i
|
||||
return true if ultimo_disparo_em.blank?
|
||||
|
||||
ultimo_disparo_em < agora.beginning_of_day
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def normalizar
|
||||
self.nome = nome.to_s.strip.squeeze(' ').presence
|
||||
self.chave = chave.presence || nome.to_s.parameterize(separator: '_').presence
|
||||
self.chave = chave.to_s.strip.downcase.presence
|
||||
self.dia_semana = nil unless agendado? && frequencia == 'semanal'
|
||||
self.frequencia = nil unless agendado?
|
||||
end
|
||||
|
||||
def semanal_tem_dia
|
||||
return unless agendado? && frequencia == 'semanal' && dia_semana.blank?
|
||||
|
||||
errors.add(:dia_semana, 'é obrigatório na frequência semanal')
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user