# config/routes.rb Rails.application.routes.draw do # Devise — login padrão para admin/gerente/operador devise_for :users, path: 'auth', controllers: { sessions: 'users/sessions' }, path_names: { sign_in: 'login', sign_out: 'logout', password: 'senha' } # Root — redireciona por role root 'dashboard#index' # Fim de linha para quem está autenticado mas o perfil não libera nenhuma tela. # Existe para o "acesso negado" ter para onde ir sem cair em loop com a raiz. get '/sem-acesso', to: 'paginas#sem_acesso', as: :sem_acesso # Dashboard principal (admin/gerente/operador) get '/dashboard', to: 'dashboard#index', as: :dashboard get '/dashboard/relatorio_financeiro', to: 'dashboard#relatorio_financeiro', as: :dashboard_relatorio_financeiro # Entregas em aberto do período (o que há por trás do card "N pendentes") get '/dashboard/pendentes', to: 'dashboard#pendentes', as: :dashboard_pendentes # Dashboard de análise de entregas por operação (UBS Norte, EMAD, ...) get '/dashboard/operacoes', to: 'operacoes_dashboard#index', as: :operacoes_dashboard # Planilha da operação (tabela espelho pesquisável, página própria) get '/dashboard/operacoes/planilha', to: 'operacoes_dashboard#planilha', as: :operacoes_planilha # Download .xlsx da planilha Entregas preenchida (modelo entregue ao cliente) get '/dashboard/operacoes/planilha/baixar', to: 'operacoes_dashboard#baixar_planilha', as: :operacoes_planilha_baixar # Painel motorista get '/motorista', to: 'motorista/dashboard#index', as: :motorista_dashboard # Extrato do período do motorista em PDF (o painel já mostra o total e as # consolidações que compõem o valor na própria tela). get '/motorista/totais/pdf', to: 'motorista/dashboard#totais_pdf', as: :motorista_totais_pdf # Login motorista — PIN de 4 dígitos + acesso via QR Code do extrato get '/motorista/login', to: 'motorista/sessoes#new', as: :motorista_login post '/motorista/login', to: 'motorista/sessoes#create' get '/motorista/acesso/:token', to: 'motorista/sessoes#acesso_qr', as: :motorista_acesso_qr # Consolidações resources :consolidacoes do collection do get :veiculos_disponiveis # JSON — veículos do(s) motorista(s) no período (form nova consolidação) get :operacoes_disponiveis # JSON — tabelas de operação (gade_entregas_*) get :dados_da_operacao # JSON — motoristas/veículos/período da(s) operação(ões) get :buscar_nf # JSON — busca a NF na rastreio (nota avulsa) post :avulsa # cria consolidação avulsa a partir de uma NF get :arquivadas # Histórico — consolidações arquivadas # PDF do modo de visualização "Por motorista" (/consolidacoes?visao= # motoristas): o total de cada um no período e as consolidações que # compõem o valor. get :totais_pdf end member do get :wizard # Passo 1 — selecionar motorista post :finalizar post :finalizar_parcial # arquiva veículos pendentes e finaliza (só os consolidados) post :arquivar post :reativar # Restaura uma consolidação arquivada post :registrar_pagamento # Marca 1 motorista (ou todos) como pago post :cancelar_pagamento # Estorna o pagamento de 1 motorista (ou todos) post :arquivar_motorista # Arquiva 1 motorista da consolidação (reversível) post :desarquivar_motorista # Restaura um motorista arquivado delete :excluir_motorista # Exclui de vez 1 motorista (admin/gerente) post :adicionar_motorista # Adiciona/restaura 1 motorista nesta consolidação get :preview_extrato get :gerar_pdf_relatorio get :gerar_pdf_extrato get :gerar_pdf_financeiro # relatório financeiro da consolidação end resources :consolidacao_entregas, only: [] do collection do get :validar # Passo 2 — toggles de classificação post :classificar # toggle individual (JSON) post :classificar_em_massa # ações em massa (JSON) get :revisar # Passo 3 — revisão do motorista post :fechar_veiculo # consolida (fecha) um veículo do motorista post :reabrir_veiculo # reabre um veículo já consolidado post :arquivar_veiculo # tira um veículo do gate (reversível) post :desarquivar_veiculo # restaura um veículo arquivado get :buscar_nf # JSON — busca a NF na SimpleRoute (apontamento manual) post :apontar # cria apontamento manual a partir da NF post :apontar_manual # apontamento 100% manual (sem rastreio) post :apontar_termo # lança N entregas de termo (sem NF/código) delete :remover_apontamento # remove um apontamento manual (por id) end end end # Configurações (apenas admin/gerente) namespace :admin do resources :usuarios, except: [:show] do member { patch :toggle_ativo } end resources :configuracoes, only: [:index, :edit, :update] do collection { post :toggle_tema } end resources :auditoria_logs, only: [:index] # Perfis de acesso: o ADM monta o conjunto de permissões e atribui ao # usuário. Rota `perfis` (e não `perfis_acesso`) pelo mesmo motivo de # `grupos`/`eventos` mais abaixo — nome de rota curto evita o sufixo `_index` # que o Inflector cria quando singular == plural. resources :perfis, except: [:show], controller: 'perfis_acesso' # SMTP e WhatsApp (Twilio) gravados no banco — só admin. # Sem rotas `testar_*`: os botões de teste são submits do próprio form # (params[:acao]), para o teste usar exatamente o que está na tela. resource :configuracao_notificacao, only: [:show, :update], controller: 'configuracao_notificacoes' # Edição de lançamento do SimpliRoute (correção de status/motivo/comentário) # — só admin. Grava direto na API do SimpliRoute + AuditoriaLog. resource :edicao_lancamento, only: [:show], controller: 'edicao_lancamentos' do get :buscar # NF -> lançamentos daquela NF (JSON; pode haver + de um) get :carregar # visit_id -> card de um lançamento escolhido (JSON) patch :atualizar # aplica a alteração na API get :historico # histórico da visita na API (JSON, best-effort) end # Geração da planilha de carga do SimpliRoute (download .xlsx a partir de uma # operação vigente + lat/long do mês anterior). resource :planilha_simpli_route, only: [:show], controller: 'planilhas_simpli_route' do get :baixar end # Romaneio "CONTROLE DE ENTREGA": uma folha A4 paisagem por veículo, assinada # pelo motorista na retirada. O plano vem do SimpliRoute (API ou espelho de # rastreio); o .xlsx é o plano B para quando o plano do dia ainda não foi # publicado. As bases externas continuam somente leitura — o que gravamos são # as tabelas `romaneio*`, nossas. resources :romaneios, only: %i[index show create destroy] do collection do post :importar_planilha # caminho B: upload do .xlsx do plano post :atualizar_logo # troca o logo impresso no cabeçalho end member do # ?veiculo=GADE_001 -> inline (é a prévia do editor); sem veiculo -> download # do romaneio inteiro. Uma rota só porque é o mesmo documento. get :pdf post :reimportar # Vincula a operação do mês DEPOIS da importação e preenche APARELHO com # o que a gade_entregas_* sabe — sem depender do plano estar disponível # de novo (ver Romaneios::VinculadorDeOperacao). patch :vincular_operacao patch :atualizar_linha # JSON — um campo de uma parada patch :atualizar_veiculo # JSON — motorista da folha patch :atualizar_rotulo # JSON — o texto "PLANO:" do cabeçalho end end # ── Notificações: quem recebe, o quê e por qual canal ────────────────── # Grupos e contatos são a lista de destinatários cadastrada à mão; eventos # ligam um gatilho aos grupos; a sessão do WhatsApp é o pareamento por QR. # # ⚠️ Os nomes das rotas (`grupos`, `eventos`, `envios`) NÃO são os nomes dos # controllers de propósito: `grupos_contato` e `eventos_notificacao` têm # singular igual ao plural para o Inflector (que não fala português), e aí # o Rails sufixa o helper de index com `_index` — pegadinha silenciosa. resources :grupos, except: [:show], controller: 'grupos_contato' resources :contatos, except: [:show] do # Grupos do WhatsApp de que o número conectado participa (JSON). Carregado # sob demanda pelo form: se fosse no render da tela, uma ponte fora do ar # faria o cadastro de contato inteiro esperar o timeout. collection { get :grupos_whatsapp } end # Variáveis {{assim}} criadas pelo ADM, usáveis em qualquer mensagem. resources :variaveis, except: [:show], controller: 'variaveis_personalizadas' resources :eventos, except: [:show], controller: 'eventos_notificacao' do member do post :disparar # gatilho `manual` — manda mensagem de verdade # Editor de blocos. O template é identificado pelo CANAL, não por id: # existe no máximo um por evento+canal (índice único), então uma URL com # id seria um identificador a mais para o mesmo par. get 'template/:canal', to: 'mensagem_templates#edit', as: :template patch 'template/:canal', to: 'mensagem_templates#update' post 'template/:canal/preview', to: 'mensagem_templates#preview', as: :preview_template end end resources :envios, only: [:index], controller: 'notificacao_envios' # Pareamento do WhatsApp por QR code (ponte Baileys). `show` faz polling do # status via JSON enquanto o QR não é lido. resource :whatsapp_sessao, only: [:show], controller: 'whatsapp_sessoes' do get :status # JSON { conectado, numero, qr } post :testar # envia uma mensagem de teste delete :desconectar end end # API interna — Dashboard métricas namespace :api do namespace :v1 do get 'dashboard/metricas', to: 'dashboard#metricas' end end # Health check (Docker) get '/health', to: proc { [200, {}, ['OK']] } end