Implandação da customização das permissões dos usuarios e das notificaçoes
This commit is contained in:
196
app/services/notificacao/catalogo_variaveis.rb
Normal file
196
app/services/notificacao/catalogo_variaveis.rb
Normal file
@@ -0,0 +1,196 @@
|
||||
# app/services/notificacao/catalogo_variaveis.rb
|
||||
#
|
||||
# TODAS as variáveis que o editor de mensagem oferece, de quatro origens:
|
||||
#
|
||||
# :contexto — vêm com o disparo (motorista, consolidação, valor…). Só têm
|
||||
# valor nos gatilhos que as produzem; em outro gatilho saem
|
||||
# vazias, e a tela avisa isso.
|
||||
# :sistema — não dependem de contexto nenhum (empresa, data, hora, mês).
|
||||
# :dados — CONSULTAM O BANCO na hora do envio (entregas do mês, total a
|
||||
# pagar…). Resolvidas sob demanda: só a variável realmente
|
||||
# escrita no template vira query.
|
||||
# :personalizada — cadastradas pelo ADM (VariavelPersonalizada), valor fixo.
|
||||
#
|
||||
# Antes, `Notificacao::Variaveis::POR_GATILHO` amarrava a lista ao gatilho: o ADM
|
||||
# via 6 variáveis e nada mais, e qualquer texto com número (“entregas do mês”)
|
||||
# precisava de deploy. Aqui a lista é aberta — e o que não se aplica é MARCADO em
|
||||
# vez de escondido.
|
||||
#
|
||||
# ⚠️ Um `resolver` NUNCA pode levantar: notificação não derruba fechamento. O
|
||||
# ResolvedorVariaveis engole e devolve vazio.
|
||||
module Notificacao
|
||||
module CatalogoVariaveis
|
||||
ORIGENS = {
|
||||
contexto: 'Do que aconteceu',
|
||||
sistema: 'Empresa e data',
|
||||
dados: 'Números do sistema',
|
||||
personalizada: 'Suas variáveis'
|
||||
}.freeze
|
||||
|
||||
# ── Sistema: sempre disponíveis ───────────────────────────
|
||||
SISTEMA = {
|
||||
'empresa' => {
|
||||
descricao: 'Nome da empresa', amostra: 'Reem Transportes',
|
||||
resolver: -> { Configuracao.valor('empresa_nome').presence || 'Reem Transportes' }
|
||||
},
|
||||
'data' => {
|
||||
descricao: 'Data de hoje (dd/mm/aaaa)', amostra: '26/08/2026',
|
||||
resolver: -> { Date.current.strftime('%d/%m/%Y') }
|
||||
},
|
||||
'hora' => {
|
||||
descricao: 'Hora do envio', amostra: '14:35',
|
||||
resolver: -> { Time.current.strftime('%H:%M') }
|
||||
},
|
||||
'dia_semana' => {
|
||||
descricao: 'Dia da semana por extenso', amostra: 'quarta-feira',
|
||||
resolver: -> { I18n.l(Date.current, format: '%A') rescue Date::DAYNAMES[Date.current.wday] }
|
||||
},
|
||||
'mes' => {
|
||||
descricao: 'Mês por extenso', amostra: 'agosto',
|
||||
resolver: -> { I18n.l(Date.current, format: '%B') rescue Date::MONTHNAMES[Date.current.month] }
|
||||
},
|
||||
'mes_ano' => {
|
||||
descricao: 'Mês/ano (mm/aaaa)', amostra: '08/2026',
|
||||
resolver: -> { Date.current.strftime('%m/%Y') }
|
||||
},
|
||||
'link_sistema' => {
|
||||
descricao: 'Endereço do sistema', amostra: 'https://app.reemtransportes.com.br',
|
||||
resolver: -> { Configuracao.valor('url_sistema').presence || ENV.fetch('APP_URL', '') }
|
||||
}
|
||||
}.freeze
|
||||
|
||||
# ── Contexto: quem produz é o gatilho ─────────────────────
|
||||
# `gatilhos:` diz em quais a variável tem valor — é o que a tela usa para
|
||||
# avisar "esta sai vazia aqui".
|
||||
CONTEXTO = {
|
||||
'contato' => { descricao: 'Primeiro nome de quem recebe', amostra: 'Carlos', gatilhos: :todos },
|
||||
'quem' => { descricao: 'Quem executou a ação no sistema', amostra: 'Ana Paula', gatilhos: :todos },
|
||||
'motorista' => { descricao: 'Nome do motorista', amostra: 'Carlos Matheus Pimentel' },
|
||||
'consolidacao' => { descricao: 'Nome da consolidação', amostra: 'UBS NORTE 01–14/08' },
|
||||
'periodo' => { descricao: 'Período do fechamento', amostra: '01/08/2026 a 14/08/2026' },
|
||||
'valor' => { descricao: 'Valor do motorista', amostra: 'R$ 5.060,00' },
|
||||
'entregas' => { descricao: 'Entregas atendidas no fechamento', amostra: '280' },
|
||||
'link_painel' => { descricao: 'Link do painel do motorista', amostra: 'https://app.reem.com.br/motorista' },
|
||||
'o_que_mudou' => { descricao: 'O que foi alterado', amostra: 'Desconto de R$ 120,00 (avaria)' },
|
||||
'operacao' => { descricao: 'Operação afetada', amostra: 'UBS NORTE AGO 2026' },
|
||||
'nf' => { descricao: 'Nota fiscal', amostra: '85382' },
|
||||
'entregues' => { descricao: 'Notas entregues (resumo)', amostra: '4.851' },
|
||||
'recusas' => { descricao: 'Notas não entregues (resumo)', amostra: '122' },
|
||||
'pendentes' => { descricao: 'Notas em aberto (resumo)', amostra: '0' },
|
||||
'retentativas' => { descricao: 'Visitas além da primeira (resumo)', amostra: '4' },
|
||||
'fora_operacao' => { descricao: 'Notas fora da operação (resumo)', amostra: '2' }
|
||||
}.freeze
|
||||
|
||||
# Quais variáveis de contexto cada gatilho realmente preenche.
|
||||
POR_GATILHO = {
|
||||
'manual' => [],
|
||||
'consolidacao_finalizada' => %w[motorista consolidacao periodo valor entregas link_painel],
|
||||
'pagamento_efetuado' => %w[motorista consolidacao periodo valor entregas link_painel],
|
||||
'valor_alterado' => %w[motorista consolidacao periodo valor entregas link_painel o_que_mudou],
|
||||
'operacao_alterada' => %w[operacao o_que_mudou nf],
|
||||
'agendado' => %w[operacao periodo entregues recusas pendentes retentativas fora_operacao]
|
||||
}.freeze
|
||||
|
||||
# ── Dados: consultam o banco na hora do envio ─────────────
|
||||
# Cada uma responde a uma pergunta que o ADM hoje só conseguiria escrevendo à
|
||||
# mão — e que ficaria desatualizada na mensagem seguinte.
|
||||
DADOS = {
|
||||
'entregas_mes' => {
|
||||
descricao: 'Entregas atendidas no mês corrente', amostra: '4.977',
|
||||
resolver: -> { Entrega.atendidas.da_conta_gade.no_periodo_checkout(Date.current.beginning_of_month, Date.current).count }
|
||||
},
|
||||
'entregas_hoje' => {
|
||||
descricao: 'Entregas atendidas hoje', amostra: '213',
|
||||
resolver: -> { Entrega.atendidas.da_conta_gade.no_periodo_checkout(Date.current, Date.current).count }
|
||||
},
|
||||
'motoristas_ativos_mes' => {
|
||||
descricao: 'Motoristas com entrega no mês', amostra: '17',
|
||||
resolver: -> { Entrega.motoristas_ativos(inicio: Date.current.beginning_of_month, fim: Date.current).size }
|
||||
},
|
||||
'consolidacoes_abertas' => {
|
||||
descricao: 'Consolidações em rascunho', amostra: '3',
|
||||
resolver: -> { Consolidacao.ativas.rascunho.count }
|
||||
},
|
||||
'total_a_pagar_mes' => {
|
||||
descricao: 'Total a pagar no mês (fechado e não pago)', amostra: 'R$ 72.508,00',
|
||||
resolver: lambda {
|
||||
totais = Analytics::TotaisPorMotorista.new(inicio: Date.current.beginning_of_month,
|
||||
fim: Date.current.end_of_month)
|
||||
Formatador.moeda(totais.total_pendente)
|
||||
}
|
||||
},
|
||||
'total_pago_mes' => {
|
||||
descricao: 'Total já pago no mês', amostra: 'R$ 21.300,00',
|
||||
resolver: lambda {
|
||||
totais = Analytics::TotaisPorMotorista.new(inicio: Date.current.beginning_of_month,
|
||||
fim: Date.current.end_of_month)
|
||||
Formatador.moeda(totais.total_pago)
|
||||
}
|
||||
},
|
||||
'total_consolidado_mes' => {
|
||||
descricao: 'Total consolidado no mês', amostra: 'R$ 93.808,00',
|
||||
resolver: lambda {
|
||||
totais = Analytics::TotaisPorMotorista.new(inicio: Date.current.beginning_of_month,
|
||||
fim: Date.current.end_of_month)
|
||||
Formatador.moeda(totais.total_geral)
|
||||
}
|
||||
}
|
||||
}.freeze
|
||||
|
||||
module_function
|
||||
|
||||
# Todas as variáveis conhecidas, incluindo as que o ADM cadastrou.
|
||||
# { chave => { origem:, descricao:, amostra: } }
|
||||
def todas
|
||||
base = {}
|
||||
SISTEMA.each { |c, m| base[c] = { origem: :sistema, descricao: m[:descricao], amostra: m[:amostra] } }
|
||||
CONTEXTO.each { |c, m| base[c] = { origem: :contexto, descricao: m[:descricao], amostra: m[:amostra] } }
|
||||
DADOS.each { |c, m| base[c] = { origem: :dados, descricao: m[:descricao], amostra: m[:amostra] } }
|
||||
personalizadas.each do |v|
|
||||
base[v.chave] = { origem: :personalizada, descricao: v.descricao.presence || 'Sua variável', amostra: v.valor }
|
||||
end
|
||||
base
|
||||
end
|
||||
|
||||
# A variável tem valor NESTE gatilho? Contexto de outro gatilho sai vazio —
|
||||
# a tela mostra, em vez de esconder a variável (foi o pedido: liberdade com
|
||||
# aviso, não lista curta).
|
||||
def aplicavel?(chave, gatilho)
|
||||
meta = CONTEXTO[chave.to_s]
|
||||
return true if meta.nil? # sistema/dados/personalizada: sempre
|
||||
return true if meta[:gatilhos] == :todos
|
||||
|
||||
Array(POR_GATILHO[gatilho.to_s]).include?(chave.to_s)
|
||||
end
|
||||
|
||||
def origem(chave)
|
||||
todas.dig(chave.to_s, :origem)
|
||||
end
|
||||
|
||||
def existe?(chave) = todas.key?(chave.to_s)
|
||||
|
||||
# Agrupadas para a tela do editor, na ordem de ORIGENS.
|
||||
def por_origem(gatilho = nil)
|
||||
agrupadas = ORIGENS.keys.index_with { |o| [] }
|
||||
todas.each do |chave, meta|
|
||||
agrupadas[meta[:origem]] << meta.merge(chave: chave, aplicavel: gatilho.nil? || aplicavel?(chave, gatilho))
|
||||
end
|
||||
agrupadas
|
||||
end
|
||||
|
||||
# Contexto do PREVIEW: valores de amostra, nunca de envio real.
|
||||
def amostra(gatilho = nil)
|
||||
todas.filter_map { |chave, meta|
|
||||
[chave, meta[:amostra].to_s] if gatilho.nil? || aplicavel?(chave, gatilho)
|
||||
}.to_h
|
||||
end
|
||||
|
||||
def personalizadas
|
||||
return [] unless VariavelPersonalizada.table_exists?
|
||||
|
||||
VariavelPersonalizada.ativas.to_a
|
||||
rescue StandardError
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user