Implandação da customização das permissões dos usuarios e das notificaçoes

This commit is contained in:
2026-08-26 17:24:25 -03:00
parent 808c2c7545
commit 5bb5d74e22
71 changed files with 2487 additions and 269 deletions

View File

@@ -0,0 +1,90 @@
# app/services/notificacao/resolvedor_variaveis.rb
#
# Completa o contexto de um disparo com as variáveis que o template REALMENTE
# usa. É o que permite escrever {{entregas_mes}} ou {{telefone_suporte}} numa
# mensagem sem que o gatilho precise saber dessas variáveis.
#
# SOB DEMANDA, de propósito: `{{entregas_mes}}` é uma query no espelho de
# rastreio. Resolver o catálogo inteiro em todo disparo faria dezenas de
# consultas para preencher variáveis que ninguém escreveu.
#
# Precedência (a primeira que responde vence):
# 1. o que o gatilho já mandou (contexto real do acontecimento);
# 2. variável de sistema (empresa, data, hora…);
# 3. variável de dados (consulta ao banco);
# 4. variável personalizada do ADM.
#
# ⚠️ NADA aqui levanta. Uma variável que falha vira string vazia — a mesma regra
# do renderizador, e pelo mesmo motivo: mensagem com buraco é ruim, disparo
# derrubado por causa de um texto é pior.
module Notificacao
module ResolvedorVariaveis
MARCADOR = /\{\{\s*(\w+)\s*\}\}/
module_function
# textos: tudo que será interpolado (blocos do template, assunto, corpo).
# dados: o contexto que o gatilho produziu.
def completar(textos, dados = {})
contexto = (dados || {}).transform_keys(&:to_s)
faltantes = usadas(textos) - contexto.keys
faltantes.each_with_object(contexto.dup) do |chave, resultado|
valor = resolver(chave)
resultado[chave] = valor unless valor.nil?
end
end
# Chaves {{assim}} encontradas em qualquer texto (String, Array ou Hash de
# blocos — o template é jsonb aninhado).
def usadas(textos)
varrer(textos).scan(MARCADOR).flatten.uniq
end
def resolver(chave)
chave = chave.to_s
valor = valor_de_sistema(chave) || valor_de_dados(chave) || valor_personalizado(chave)
valor&.to_s
end
# ── privados de módulo ──────────────────────────────────────
def varrer(objeto)
case objeto
when String then objeto
when Hash then objeto.values.map { |v| varrer(v) }.join(' ')
when Array then objeto.map { |v| varrer(v) }.join(' ')
else ''
end
end
def valor_de_sistema(chave)
meta = CatalogoVariaveis::SISTEMA[chave]
meta && executar(meta[:resolver], chave)
end
def valor_de_dados(chave)
meta = CatalogoVariaveis::DADOS[chave]
meta && executar(meta[:resolver], chave)
end
def valor_personalizado(chave)
return nil unless VariavelPersonalizada.table_exists?
VariavelPersonalizada.ativas.find_by(chave: chave)&.valor
rescue StandardError => e
Rails.logger.error("[Variaveis] personalizada #{chave}: #{e.class}: #{e.message}")
nil
end
def executar(bloco, chave)
return nil if bloco.nil?
resultado = bloco.call
# Número cru numa mensagem fica sem separador de milhar ("4977").
resultado.is_a?(Numeric) ? Formatador.numero(resultado) : resultado.to_s
rescue StandardError => e
Rails.logger.error("[Variaveis] #{chave}: #{e.class}: #{e.message}")
nil
end
end
end