implantação da fase 2 e 3
This commit is contained in:
@@ -4,24 +4,26 @@ class ApplicationController < ActionController::Base
|
||||
|
||||
before_action :authenticate_user!
|
||||
before_action :set_tema
|
||||
after_action :verify_authorized, except: :index, unless: :skip_pundit?
|
||||
after_action :verify_policy_scoped, only: :index, unless: :skip_pundit?
|
||||
|
||||
# Pundit: redireciona se não autorizado
|
||||
rescue_from Pundit::NotAuthorizedError do |e|
|
||||
flash[:alert] = "Você não tem permissão para realizar esta ação."
|
||||
redirect_to root_path
|
||||
end
|
||||
rescue_from Pundit::NotAuthorizedError, with: :usuario_nao_autorizado
|
||||
|
||||
protect_from_forgery with: :exception
|
||||
|
||||
private
|
||||
|
||||
def set_tema
|
||||
@tema = current_user&.tema_preferido || 'dark'
|
||||
# Lê o tema da sessão (padrão: escuro)
|
||||
@tema = session[:tema] || 'dark'
|
||||
end
|
||||
|
||||
def after_sign_in_path_for(resource)
|
||||
if resource.motorista?
|
||||
motorista_dashboard_path
|
||||
else
|
||||
dashboard_path
|
||||
end
|
||||
def skip_pundit?
|
||||
devise_controller? || params[:controller] =~ /rails\/|action_mailbox|action_text/
|
||||
end
|
||||
|
||||
def usuario_nao_autorizado
|
||||
flash[:alert] = 'Acesso negado. Você não tem permissão para esta ação.'
|
||||
redirect_back(fallback_location: dashboard_path)
|
||||
end
|
||||
end
|
||||
|
||||
44
app/controllers/configuracoes_controller.rb
Normal file
44
app/controllers/configuracoes_controller.rb
Normal file
@@ -0,0 +1,44 @@
|
||||
# app/controllers/configuracoes_controller.rb
|
||||
class ConfiguracoesController < ApplicationController
|
||||
before_action :set_configuracao, only: [:edit, :update]
|
||||
|
||||
def index
|
||||
authorize Configuracao
|
||||
@configuracoes = Configuracao.all.order(:tipo)
|
||||
end
|
||||
|
||||
def edit
|
||||
authorize @configuracao
|
||||
end
|
||||
|
||||
def update
|
||||
authorize @configuracao
|
||||
|
||||
valor_anterior = @configuracao.valor
|
||||
|
||||
if @configuracao.update(configuracao_params)
|
||||
AuditoriaLog.registrar(current_user, 'editar_preco', request.remote_ip,
|
||||
detalhes: "#{@configuracao.tipo}: R$ #{valor_anterior} → R$ #{@configuracao.valor}")
|
||||
redirect_to configuracoes_path, notice: "Preço de #{@configuracao.tipo_label} atualizado."
|
||||
else
|
||||
render :edit, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
# POST /configuracoes/toggle_tema
|
||||
def toggle_tema
|
||||
skip_authorization
|
||||
session[:tema] = session[:tema] == 'light' ? 'dark' : 'light'
|
||||
redirect_back(fallback_location: dashboard_path)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_configuracao
|
||||
@configuracao = Configuracao.find(params[:id])
|
||||
end
|
||||
|
||||
def configuracao_params
|
||||
params.require(:configuracao).permit(:valor, :descricao)
|
||||
end
|
||||
end
|
||||
77
app/controllers/dashboard_controller.rb
Normal file
77
app/controllers/dashboard_controller.rb
Normal file
@@ -0,0 +1,77 @@
|
||||
# app/controllers/dashboard_controller.rb
|
||||
class DashboardController < ApplicationController
|
||||
def index
|
||||
skip_authorization
|
||||
|
||||
@data_referencia = params[:data] ? Date.parse(params[:data]) : Date.today
|
||||
@mes_inicio = @data_referencia.beginning_of_month
|
||||
@mes_fim = @data_referencia.end_of_month
|
||||
|
||||
carregar_dados_dashboard
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def carregar_dados_dashboard
|
||||
# Entregas do mês atual (da tabela read-only)
|
||||
entregas_mes = Entrega.do_mes(@data_referencia)
|
||||
|
||||
# Totais gerais
|
||||
@total_entregas = entregas_mes.count
|
||||
@entregas_pagas = entregas_mes.pagas.count
|
||||
@entregas_pendentes = @total_entregas - @entregas_pagas
|
||||
|
||||
# Configurações de preço
|
||||
config = Configuracao.mapa_de_precos
|
||||
|
||||
# Valor estimado total
|
||||
@valor_estimado = (@entregas_pagas * config[:entrega]).round(2)
|
||||
|
||||
# Por motorista (top 10)
|
||||
@motoristas = entregas_mes.pagas
|
||||
.group(:driver)
|
||||
.count
|
||||
.sort_by { |_, v| -v }
|
||||
.first(10)
|
||||
.map do |driver, qtd|
|
||||
{
|
||||
nome: driver,
|
||||
entregas: qtd,
|
||||
valor: (qtd * config[:entrega]).round(2)
|
||||
}
|
||||
end
|
||||
|
||||
# Por operação (route_id → contact_name)
|
||||
@por_operacao = entregas_mes.pagas
|
||||
.group(:contact_name)
|
||||
.count
|
||||
.sort_by { |_, v| -v }
|
||||
.first(6)
|
||||
|
||||
# Evolução diária do mês (para Chart.js)
|
||||
@grafico_diario = build_grafico_diario(entregas_mes, config[:entrega])
|
||||
|
||||
# Consolidações do mês
|
||||
@consolidacoes_mes = Consolidacao.do_mes(@data_referencia)
|
||||
@consolidacoes_abertas = @consolidacoes_mes.where(status: :aberta).count
|
||||
@consolidacoes_fechadas = @consolidacoes_mes.where(status: :fechada).count
|
||||
|
||||
# Histórico estimado mais recente
|
||||
@historico_recente = HistoricoEstimado.order(created_at: :desc).limit(5)
|
||||
end
|
||||
|
||||
def build_grafico_diario(entregas, preco_entrega)
|
||||
dias = ((@mes_inicio)..[@mes_fim, Date.today].min).map(&:to_s)
|
||||
|
||||
contagem = entregas.pagas
|
||||
.group("DATE(planned_date)")
|
||||
.count
|
||||
.transform_keys { |k| k.to_s }
|
||||
|
||||
labels = dias.map { |d| Date.parse(d).strftime('%d/%m') }
|
||||
valores = dias.map { |d| ((contagem[d] || 0) * preco_entrega).round(2) }
|
||||
qtds = dias.map { |d| contagem[d] || 0 }
|
||||
|
||||
{ labels: labels, valores: valores, qtds: qtds }
|
||||
end
|
||||
end
|
||||
42
app/controllers/motorista_controller.rb
Normal file
42
app/controllers/motorista_controller.rb
Normal file
@@ -0,0 +1,42 @@
|
||||
# app/controllers/motorista_controller.rb
|
||||
class MotoristaController < ApplicationController
|
||||
before_action :verificar_motorista
|
||||
|
||||
def index
|
||||
skip_authorization
|
||||
|
||||
@data_referencia = params[:data] ? Date.parse(params[:data]) : Date.today
|
||||
config = Configuracao.mapa_de_precos
|
||||
|
||||
# Entregas do motorista logado
|
||||
@entregas_mes = Entrega
|
||||
.do_mes(@data_referencia)
|
||||
.where("LOWER(driver) = ?", current_user.name.downcase)
|
||||
|
||||
@total_entregas = @entregas_mes.count
|
||||
@pagas = @entregas_mes.pagas.count
|
||||
@pendentes = @total_entregas - @pagas
|
||||
@valor_estimado = (@pagas * config[:entrega]).round(2)
|
||||
|
||||
# Últimas entregas
|
||||
@ultimas_entregas = @entregas_mes.pagas
|
||||
.order(planned_date: :desc)
|
||||
.limit(10)
|
||||
|
||||
# Consolidações do motorista
|
||||
@consolidacoes = ConsolidacaoMotorista
|
||||
.joins(:consolidacao)
|
||||
.where(user: current_user)
|
||||
.where(consolidacoes: { status: [:fechada, :aprovada] })
|
||||
.order('consolidacoes.created_at DESC')
|
||||
.limit(5)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def verificar_motorista
|
||||
unless current_user&.motorista?
|
||||
redirect_to dashboard_path, alert: 'Acesso restrito a motoristas.'
|
||||
end
|
||||
end
|
||||
end
|
||||
56
app/controllers/users/sessions_controller.rb
Normal file
56
app/controllers/users/sessions_controller.rb
Normal file
@@ -0,0 +1,56 @@
|
||||
# app/controllers/users/sessions_controller.rb
|
||||
class Users::SessionsController < Devise::SessionsController
|
||||
before_action :configure_sign_in_params, only: [:create]
|
||||
|
||||
# GET /users/sign_in
|
||||
def new
|
||||
@pin_login = params[:pin].present?
|
||||
super
|
||||
end
|
||||
|
||||
# POST /users/sign_in
|
||||
def create
|
||||
# PIN login para motoristas
|
||||
if params[:pin_login].present?
|
||||
handle_pin_login
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def after_sign_in_path_for(resource)
|
||||
case resource.role
|
||||
when 'motorista'
|
||||
motorista_path
|
||||
else
|
||||
dashboard_path
|
||||
end
|
||||
end
|
||||
|
||||
def after_sign_out_path_for(resource_or_scope)
|
||||
new_user_session_path
|
||||
end
|
||||
|
||||
def configure_sign_in_params
|
||||
devise_parameter_sanitizer.permit(:sign_in, keys: [:email, :password, :pin])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def handle_pin_login
|
||||
pin = params[:user][:pin].to_s.strip
|
||||
user = User.find_by(pin_acesso: pin, role: 'motorista')
|
||||
|
||||
if user&.active?
|
||||
sign_in(user)
|
||||
AuditoriaLog.registrar(user, 'login_pin', request.remote_ip)
|
||||
redirect_to motorista_path, notice: "Bem-vindo, #{user.nome_display}!"
|
||||
else
|
||||
flash.now[:alert] = 'PIN inválido ou motorista inativo.'
|
||||
@pin_login = true
|
||||
render :new, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
end
|
||||
88
app/controllers/usuarios_controller.rb
Normal file
88
app/controllers/usuarios_controller.rb
Normal file
@@ -0,0 +1,88 @@
|
||||
# app/controllers/usuarios_controller.rb
|
||||
class UsuariosController < ApplicationController
|
||||
before_action :set_usuario, only: [:show, :edit, :update, :destroy, :toggle_ativo]
|
||||
|
||||
def index
|
||||
authorize User
|
||||
@usuarios = policy_scope(User).order(:name).page(params[:page]).per(20)
|
||||
@roles = User.roles.keys
|
||||
end
|
||||
|
||||
def show
|
||||
authorize @usuario
|
||||
end
|
||||
|
||||
def new
|
||||
@usuario = User.new
|
||||
authorize @usuario
|
||||
end
|
||||
|
||||
def create
|
||||
@usuario = User.new(usuario_params)
|
||||
authorize @usuario
|
||||
|
||||
if @usuario.save
|
||||
AuditoriaLog.registrar(current_user, 'criar_usuario', request.remote_ip,
|
||||
detalhes: "Criou usuário #{@usuario.email} (#{@usuario.role})")
|
||||
redirect_to usuarios_path, notice: 'Usuário criado com sucesso.'
|
||||
else
|
||||
render :new, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
authorize @usuario
|
||||
end
|
||||
|
||||
def update
|
||||
authorize @usuario
|
||||
|
||||
if @usuario.update(usuario_params_update)
|
||||
AuditoriaLog.registrar(current_user, 'editar_usuario', request.remote_ip,
|
||||
detalhes: "Editou usuário #{@usuario.email}")
|
||||
redirect_to usuarios_path, notice: 'Usuário atualizado.'
|
||||
else
|
||||
render :edit, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
authorize @usuario
|
||||
|
||||
if @usuario == current_user
|
||||
redirect_to usuarios_path, alert: 'Você não pode excluir sua própria conta.'
|
||||
return
|
||||
end
|
||||
|
||||
@usuario.destroy
|
||||
AuditoriaLog.registrar(current_user, 'excluir_usuario', request.remote_ip,
|
||||
detalhes: "Excluiu usuário #{@usuario.email}")
|
||||
redirect_to usuarios_path, notice: 'Usuário removido.'
|
||||
end
|
||||
|
||||
def toggle_ativo
|
||||
authorize @usuario, :update?
|
||||
@usuario.update!(ativo: !@usuario.ativo)
|
||||
status = @usuario.ativo? ? 'ativado' : 'desativado'
|
||||
AuditoriaLog.registrar(current_user, "usuario_#{status}", request.remote_ip,
|
||||
detalhes: "#{@usuario.email} foi #{status}")
|
||||
redirect_to usuarios_path, notice: "Usuário #{status} com sucesso."
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_usuario
|
||||
@usuario = User.find(params[:id])
|
||||
end
|
||||
|
||||
def usuario_params
|
||||
params.require(:user).permit(:name, :email, :password, :password_confirmation,
|
||||
:role, :pin_acesso, :ativo)
|
||||
end
|
||||
|
||||
def usuario_params_update
|
||||
permitted = [:name, :email, :role, :pin_acesso, :ativo]
|
||||
permitted += [:password, :password_confirmation] if params[:user][:password].present?
|
||||
params.require(:user).permit(permitted)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user