Alteração Para uso dos Usuarios
This commit is contained in:
@@ -5,7 +5,7 @@ class ConsolidacoesController < ApplicationController
|
||||
before_action :set_consolidacao,
|
||||
only: %i[show edit update destroy finalizar arquivar reativar wizard
|
||||
registrar_pagamento cancelar_pagamento
|
||||
preview_holerite gerar_pdf_relatorio gerar_pdf_holerite
|
||||
preview_extrato gerar_pdf_relatorio gerar_pdf_extrato
|
||||
gerar_pdf_financeiro]
|
||||
|
||||
# Formas de pagamento aceitas (o select da UI usa esta mesma lista).
|
||||
@@ -234,13 +234,22 @@ class ConsolidacoesController < ApplicationController
|
||||
forma = params[:forma_pagamento].presence_in(FORMAS_PAGAMENTO) || 'pix'
|
||||
alvos = motoristas_alvo.select { |cm| !cm.pago? }
|
||||
|
||||
# NF obrigatória por motorista. Se faltar para qualquer alvo, aborta sem
|
||||
# marcar nenhum (a NF vai pro painel do motorista e pro Extrato).
|
||||
notas = nf_por_motorista(alvos)
|
||||
if notas.nil?
|
||||
return redirect_to @consolidacao,
|
||||
alert: 'Informe o número da Nota Fiscal de cada motorista antes de marcar como pago.'
|
||||
end
|
||||
|
||||
alvos.each do |cm|
|
||||
cm.marcar_pago!(current_user, forma: forma)
|
||||
cm.marcar_pago!(current_user, forma: forma, nota_fiscal: notas[cm.id])
|
||||
NotificacaoService.notificar_pagamento(@consolidacao, cm)
|
||||
end
|
||||
|
||||
auditar!(:registrar_pagamento, @consolidacao,
|
||||
dados_novos: { motoristas: alvos.map(&:motorista_nome), forma: forma })
|
||||
dados_novos: { motoristas: alvos.map(&:motorista_nome), forma: forma,
|
||||
notas_fiscais: alvos.map { |cm| [cm.motorista_nome, notas[cm.id]] }.to_h })
|
||||
redirect_to @consolidacao, notice: pagamento_notice(alvos.size, :pago)
|
||||
end
|
||||
|
||||
@@ -285,27 +294,28 @@ class ConsolidacoesController < ApplicationController
|
||||
disposition: 'attachment'
|
||||
end
|
||||
|
||||
# GET /consolidacoes/:id/gerar_pdf_holerite?motorista=X
|
||||
def gerar_pdf_holerite
|
||||
autorizar_holerite!(params[:motorista])
|
||||
# GET /consolidacoes/:id/gerar_pdf_extrato?motorista=X
|
||||
def gerar_pdf_extrato
|
||||
autorizar_extrato!(params[:motorista])
|
||||
motorista = params[:motorista]
|
||||
user_mot = buscar_user_motorista(motorista)
|
||||
user_mot&.regenerar_login_token! if user_mot&.login_token.blank?
|
||||
cm = @consolidacao.consolidacao_motoristas.find_by(motorista_nome: motorista)
|
||||
|
||||
pdf = Pdf::HoleritePdf.new(consolidacao: @consolidacao, motorista: motorista,
|
||||
user_motorista: user_mot, app_host: ENV['APP_HOST'],
|
||||
pago_em: cm&.pago_em, forma_pagamento: cm&.forma_pagamento)
|
||||
auditar!(:editar, @consolidacao, dados_novos: { pdf: 'holerite', motorista: motorista })
|
||||
pdf = Pdf::ExtratoPdf.new(consolidacao: @consolidacao, motorista: motorista,
|
||||
user_motorista: user_mot, app_host: ENV['APP_HOST'],
|
||||
pago_em: cm&.pago_em, forma_pagamento: cm&.forma_pagamento,
|
||||
nota_fiscal: cm&.nota_fiscal)
|
||||
auditar!(:editar, @consolidacao, dados_novos: { pdf: 'extrato', motorista: motorista })
|
||||
|
||||
send_data pdf.render,
|
||||
filename: "holerite_#{motorista.parameterize}_#{@consolidacao.id}.pdf",
|
||||
filename: "extrato_#{motorista.parameterize}_#{@consolidacao.id}.pdf",
|
||||
type: 'application/pdf',
|
||||
disposition: 'attachment'
|
||||
end
|
||||
|
||||
# GET /consolidacoes/:id/preview_holerite?motorista=X — preview HTML antes do PDF
|
||||
def preview_holerite
|
||||
# GET /consolidacoes/:id/preview_extrato?motorista=X — preview HTML antes do PDF
|
||||
def preview_extrato
|
||||
authorize @consolidacao, :show?
|
||||
@motorista = params[:motorista]
|
||||
@entregas = @consolidacao.consolidacao_entregas.where(motorista_nome: @motorista)
|
||||
@@ -319,7 +329,7 @@ class ConsolidacoesController < ApplicationController
|
||||
# Acha o User motorista pelo nome para gerar o QR Code de acesso. O
|
||||
# motorista_nome vem dos dados externos de entrega e o users.nome é digitado
|
||||
# no admin — então toleramos diferenças de caixa e de espaços (extras/duplos).
|
||||
# Sem isso, qualquer divergência deixava user_mot nil e o QR sumia do holerite.
|
||||
# Sem isso, qualquer divergência deixava user_mot nil e o QR sumia do extrato.
|
||||
def buscar_user_motorista(nome)
|
||||
exato = User.motorista.find_by('LOWER(nome) = ?', nome.to_s.downcase.strip)
|
||||
return exato if exato
|
||||
@@ -332,9 +342,9 @@ class ConsolidacoesController < ApplicationController
|
||||
nome.to_s.strip.downcase.gsub(/\s+/, ' ')
|
||||
end
|
||||
|
||||
# Staff (show?) baixa qualquer holerite. O motorista baixa só o PRÓPRIO — o PDF
|
||||
# Staff (show?) baixa qualquer extrato. O motorista baixa só o PRÓPRIO — o PDF
|
||||
# já é filtrado pelo nome dele, então não há vazamento de dados de terceiros.
|
||||
def autorizar_holerite!(motorista_nome)
|
||||
def autorizar_extrato!(motorista_nome)
|
||||
if current_user.motorista?
|
||||
raise Pundit::NotAuthorizedError unless motorista_nome.to_s.casecmp?(current_user.nome.to_s)
|
||||
skip_authorization
|
||||
@@ -356,6 +366,18 @@ class ConsolidacoesController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
# Mapeia { cm.id => "numero da NF" } a partir de params[:notas_fiscais].
|
||||
# Retorna nil se a NF de QUALQUER alvo estiver em branco (pagamento bloqueado).
|
||||
def nf_por_motorista(alvos)
|
||||
informadas = params[:notas_fiscais] || {}
|
||||
alvos.each_with_object({}) do |cm, mapa|
|
||||
nf = informadas[cm.id.to_s].to_s.strip
|
||||
return nil if nf.blank?
|
||||
|
||||
mapa[cm.id] = nf
|
||||
end
|
||||
end
|
||||
|
||||
def pagamento_indisponivel
|
||||
redirect_to @consolidacao, alert: 'Só é possível registrar pagamento de uma consolidação finalizada.'
|
||||
end
|
||||
|
||||
@@ -100,11 +100,10 @@ class DashboardController < ApplicationController
|
||||
# Valor estimado total
|
||||
@valor_estimado = (@entregas_pagas * config[:entrega]).round(2)
|
||||
|
||||
# Por motorista (top 10)
|
||||
# Por motorista (todos)
|
||||
@motoristas = pagas.group(:driver)
|
||||
.count
|
||||
.sort_by { |_, v| -v }
|
||||
.first(10)
|
||||
.map do |driver, qtd|
|
||||
{
|
||||
nome: driver,
|
||||
@@ -214,9 +213,9 @@ class DashboardController < ApplicationController
|
||||
{ label: cfg[:label], valor: valor }
|
||||
end
|
||||
|
||||
# Custo por motorista (top 10)
|
||||
# Custo por motorista (todos)
|
||||
@fin_por_motorista = cms.group(:motorista_nome).sum(:valor_total)
|
||||
.sort_by { |_, v| -v }.first(10)
|
||||
.sort_by { |_, v| -v }
|
||||
end
|
||||
|
||||
# `pagas` já vem filtrado por checkout no período. Agrupa pela DATA REAL
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# app/controllers/motorista/sessoes_controller.rb
|
||||
#
|
||||
# Login do motorista por PIN de 4 dígitos ou por QR Code (token do holerite).
|
||||
# Login do motorista por PIN de 4 dígitos ou por QR Code (token do extrato).
|
||||
# Não usa Devise password — fluxo simplificado para público de baixo nível técnico.
|
||||
#
|
||||
module Motorista
|
||||
@@ -44,7 +44,7 @@ module Motorista
|
||||
redirect_to motorista_dashboard_path, notice: "Bem-vindo, #{user.nome.split.first}!"
|
||||
end
|
||||
|
||||
# GET /motorista/acesso/:token — abre o login a partir do QR Code do holerite.
|
||||
# GET /motorista/acesso/:token — abre o login a partir do QR Code do extrato.
|
||||
# SEGURANÇA: o QR apenas identifica o motorista; ele ainda precisa digitar o
|
||||
# PIN de 4 dígitos para entrar (antes o QR logava direto, sem PIN).
|
||||
def acesso_qr
|
||||
|
||||
@@ -24,12 +24,13 @@ class ConsolidacaoMotorista < ApplicationRecord
|
||||
pago_em.present?
|
||||
end
|
||||
|
||||
def marcar_pago!(user, forma:)
|
||||
update!(pago_em: Time.current, pago_por: user&.id, forma_pagamento: forma)
|
||||
def marcar_pago!(user, forma:, nota_fiscal:)
|
||||
update!(pago_em: Time.current, pago_por: user&.id, forma_pagamento: forma,
|
||||
nota_fiscal: nota_fiscal)
|
||||
end
|
||||
|
||||
def cancelar_pagamento!(_user)
|
||||
update!(pago_em: nil, pago_por: nil, forma_pagamento: nil)
|
||||
update!(pago_em: nil, pago_por: nil, forma_pagamento: nil, nota_fiscal: nil)
|
||||
end
|
||||
|
||||
def recalcular_valor
|
||||
|
||||
@@ -65,7 +65,7 @@ class User < ApplicationRecord
|
||||
admin? || gerente? || operador?
|
||||
end
|
||||
|
||||
# Token de login rápido via QR Code (holerite) — Fase 7/8
|
||||
# Token de login rápido via QR Code (extrato) — Fase 7/8
|
||||
def regenerar_login_token!
|
||||
update!(login_token: SecureRandom.urlsafe_base64(24))
|
||||
end
|
||||
|
||||
@@ -60,7 +60,7 @@ class NotificacaoService
|
||||
"Seu pagamento de entregas foi fechado.\n" \
|
||||
"📋 #{@consolidacao.nome}\n" \
|
||||
"💰 Valor: #{valor}\n" \
|
||||
"Acesse seu painel para baixar o holerite: " \
|
||||
"Acesse seu painel para baixar o extrato: " \
|
||||
"https://#{ENV.fetch('APP_HOST', 'localhost:3000')}/motorista"
|
||||
end
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
# app/services/pdf/holerite_pdf.rb
|
||||
# app/services/pdf/extrato_pdf.rb
|
||||
#
|
||||
# Holerite: resumo do valor a pagar ao motorista, estilo contracheque,
|
||||
# Extrato: resumo do valor a pagar ao motorista, estilo contracheque,
|
||||
# com QR Code para login rápido no painel do motorista.
|
||||
#
|
||||
require 'rqrcode'
|
||||
|
||||
module Pdf
|
||||
class HoleritePdf < BasePdf
|
||||
class ExtratoPdf < BasePdf
|
||||
VERDE = '22C55E'
|
||||
CINZA_BG = 'E5E7EB'
|
||||
|
||||
def initialize(consolidacao:, motorista:, user_motorista: nil, app_host: nil,
|
||||
pago_em: nil, forma_pagamento: nil)
|
||||
pago_em: nil, forma_pagamento: nil, nota_fiscal: nil)
|
||||
super()
|
||||
@consolidacao = consolidacao
|
||||
@motorista = motorista
|
||||
@@ -19,13 +19,14 @@ module Pdf
|
||||
@app_host = app_host || ENV.fetch('APP_HOST', 'localhost:3000')
|
||||
@pago_em = pago_em
|
||||
@forma_pagamento = forma_pagamento
|
||||
@nota_fiscal = nota_fiscal
|
||||
@entregas = consolidacao.consolidacao_entregas.where(motorista_nome: motorista)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def corpo
|
||||
secao "HOLERITE DE PAGAMENTO — ENTREGAS"
|
||||
secao "EXTRATO DE PAGAMENTO — ENTREGAS"
|
||||
|
||||
# Bloco de identificação (estilo contracheque)
|
||||
info = [
|
||||
@@ -34,6 +35,7 @@ module Pdf
|
||||
['Período', "#{@consolidacao.data_inicio.strftime('%d/%m/%Y')} a #{@consolidacao.data_fim.strftime('%d/%m/%Y')}"],
|
||||
['Emissão', Time.current.strftime('%d/%m/%Y')]
|
||||
]
|
||||
info << ['Nota Fiscal', @nota_fiscal] if @nota_fiscal.present?
|
||||
@pdf.table(info, width: @pdf.bounds.width, cell_style: { size: 10, padding: [4, 8] }) do |t|
|
||||
t.columns(0).font_style = :bold
|
||||
t.columns(0).background_color = 'F3F4F6'
|
||||
@@ -36,12 +36,12 @@
|
||||
<p style="text-align: center; margin: 24px 0;">
|
||||
<a href="<%= @link_painel %>"
|
||||
style="background: #0a0a0a; color: #f97316; text-decoration: none; padding: 14px 28px; border-radius: 8px; font-weight: bold; display: inline-block;">
|
||||
Ver meu painel e baixar holerite →
|
||||
Ver meu painel e baixar extrato →
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p style="color: #9ca3af; font-size: 12px; text-align: center;">
|
||||
Entre com seu PIN de 4 números ou escaneie o QR Code do seu holerite.
|
||||
Entre com seu PIN de 4 números ou escaneie o QR Code do seu extrato.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -30,12 +30,12 @@
|
||||
<p style="text-align: center; margin: 24px 0;">
|
||||
<a href="<%= @link_painel %>"
|
||||
style="background: #0a0a0a; color: #f97316; text-decoration: none; padding: 14px 28px; border-radius: 8px; font-weight: bold; display: inline-block;">
|
||||
Ver meu painel e baixar holerite →
|
||||
Ver meu painel e baixar extrato →
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p style="color: #9ca3af; font-size: 12px; text-align: center;">
|
||||
Entre com seu PIN de 4 números ou escaneie o QR Code do seu holerite.
|
||||
Entre com seu PIN de 4 números ou escaneie o QR Code do seu extrato.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<%# app/views/consolidacoes/preview_holerite.html.erb — renderizado sem layout, dentro do modal %>
|
||||
<%# app/views/consolidacoes/preview_extrato.html.erb — renderizado sem layout, dentro do modal %>
|
||||
<div class="bg-white text-black rounded-xl p-6 font-sans">
|
||||
|
||||
<%# Cabeçalho estilo PDF %>
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="w-2 h-12 bg-orange-500 rounded"></div>
|
||||
<div>
|
||||
<p class="text-white font-black text-lg leading-tight">REEM TRANSPORTE</p>
|
||||
<p class="text-orange-500 text-xs">Holerite de Pagamento — Entregas</p>
|
||||
<p class="text-orange-500 text-xs">Extrato de Pagamento — Entregas</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -51,12 +51,14 @@
|
||||
<div class="flex flex-col sm:flex-row sm:items-center gap-2 mt-4 bg-[#1a1a1a] border border-[#2a2a2a] rounded-xl p-4">
|
||||
<span class="text-gray-400 text-sm font-medium mr-1">💵 Operação inteira:</span>
|
||||
<% if @consolidacao.status_pagamento != :pago %>
|
||||
<%# Form único (id) — os inputs de NF e os botões "Marcar pago" de cada
|
||||
linha se associam a ele via atributo HTML5 form=, evitando <form> aninhado. %>
|
||||
<%= form_with url: registrar_pagamento_consolidacao_path(@consolidacao), method: :post,
|
||||
data: { turbo_confirm: 'Marcar TODOS os motoristas pendentes desta consolidação como PAGOS?' },
|
||||
class: 'flex items-center gap-2' do |f| %>
|
||||
id: 'form-pagar-tudo', class: 'flex items-center gap-2' do |f| %>
|
||||
<%= f.select :forma_pagamento, options_for_select(formas_pagamento, 'pix'),
|
||||
{}, class: 'bg-[#0a0a0a] border border-[#2a2a2a] text-white rounded-lg px-3 py-2.5 text-sm' %>
|
||||
<%= f.submit '💰 Marcar tudo como pago',
|
||||
data: { turbo_confirm: 'Marcar TODOS os motoristas pendentes desta consolidação como PAGOS? Confirme que a Nota Fiscal de cada um foi preenchida.' },
|
||||
class: 'bg-green-600 hover:bg-green-700 text-white font-bold px-4 py-2.5 rounded-lg text-sm cursor-pointer min-h-[44px]' %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
@@ -95,6 +97,9 @@
|
||||
<% if cm.forma_pagamento.present? %>via <%= cm.forma_pagamento.humanize %><% end %>
|
||||
<% if cm.pagador.present? %>por <%= cm.pagador.nome_display %><% end %>
|
||||
</p>
|
||||
<% if cm.nota_fiscal.present? %>
|
||||
<p class="text-gray-300 text-xs mt-0.5">🧾 NF <%= cm.nota_fiscal %></p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if pode_pagar %>
|
||||
@@ -104,21 +109,23 @@
|
||||
data: { turbo_confirm: "Estornar o pagamento de #{cm.motorista_nome}?" },
|
||||
class: 'text-gray-400 hover:text-white border border-[#2a2a2a] px-3 py-2 rounded-lg text-xs min-h-[40px]' %>
|
||||
<% else %>
|
||||
<%= form_with url: registrar_pagamento_consolidacao_path(@consolidacao, consolidacao_motorista_id: cm.id), method: :post,
|
||||
data: { turbo_confirm: "Marcar #{cm.motorista_nome} como pago?" },
|
||||
class: 'flex items-center gap-2' do |f| %>
|
||||
<%= f.select :forma_pagamento, options_for_select(formas_pagamento, 'pix'),
|
||||
{}, class: 'bg-[#0a0a0a] border border-[#2a2a2a] text-white rounded-lg px-2 py-2 text-xs' %>
|
||||
<%= f.submit '💰 Marcar pago',
|
||||
<%# Inputs/botão associados ao form único #form-pagar-tudo via atributo form=. %>
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<%= text_field_tag "notas_fiscais[#{cm.id}]", nil, form: 'form-pagar-tudo',
|
||||
placeholder: 'Nº Nota Fiscal',
|
||||
class: 'bg-[#0a0a0a] border border-[#2a2a2a] text-white rounded-lg px-2 py-2 text-xs w-36' %>
|
||||
<%= button_tag '💰 Marcar pago', type: :submit, form: 'form-pagar-tudo',
|
||||
name: 'consolidacao_motorista_id', value: cm.id,
|
||||
data: { turbo_confirm: "Marcar #{cm.motorista_nome} como pago?" },
|
||||
class: 'bg-green-600 hover:bg-green-700 text-white font-bold px-3 py-2 rounded-lg text-xs cursor-pointer min-h-[40px]' %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<%# Preview abre modal %>
|
||||
<button onclick="abrirPreview('<%= preview_holerite_consolidacao_path(@consolidacao, motorista: cm.motorista_nome) %>')"
|
||||
<button onclick="abrirPreview('<%= preview_extrato_consolidacao_path(@consolidacao, motorista: cm.motorista_nome) %>')"
|
||||
class="bg-[#0a0a0a] hover:bg-[#2a2a2a] text-white border border-orange-500 font-semibold px-4 py-3 rounded-lg text-sm min-h-[48px]">
|
||||
👁️ Ver antes de gerar
|
||||
</button>
|
||||
@@ -126,8 +133,8 @@
|
||||
gerar_pdf_relatorio_consolidacao_path(@consolidacao, motorista: cm.motorista_nome),
|
||||
data: { turbo: false },
|
||||
class: 'bg-orange-800 hover:bg-orange-700 text-white font-semibold px-4 py-3 rounded-lg text-sm min-h-[48px] flex items-center' %>
|
||||
<%= link_to '🧾 Gerar Holerite',
|
||||
gerar_pdf_holerite_consolidacao_path(@consolidacao, motorista: cm.motorista_nome),
|
||||
<%= link_to '🧾 Gerar Extrato',
|
||||
gerar_pdf_extrato_consolidacao_path(@consolidacao, motorista: cm.motorista_nome),
|
||||
data: { turbo: false },
|
||||
class: 'bg-orange-500 hover:bg-orange-600 text-black font-bold px-4 py-3 rounded-lg text-sm min-h-[48px] flex items-center' %>
|
||||
</div>
|
||||
@@ -188,7 +195,7 @@
|
||||
<div id="modal-preview" class="fixed inset-0 bg-black/80 z-50 hidden items-center justify-center p-4">
|
||||
<div class="bg-[#1a1a1a] border border-[#2a2a2a] rounded-2xl max-w-2xl w-full max-h-[85vh] flex flex-col">
|
||||
<div class="flex items-center justify-between px-6 py-4 border-b border-[#2a2a2a]">
|
||||
<h3 class="text-white font-bold">👁️ Pré-visualização do Holerite</h3>
|
||||
<h3 class="text-white font-bold">👁️ Pré-visualização do Extrato</h3>
|
||||
<button onclick="fecharPreview()" class="text-gray-400 hover:text-white text-2xl min-w-[44px] min-h-[44px]">✕</button>
|
||||
</div>
|
||||
<div id="modal-preview-conteudo" class="overflow-y-auto p-6 flex-1">
|
||||
@@ -220,7 +227,7 @@
|
||||
|
||||
// O link de confirmar aponta para o PDF do mesmo motorista
|
||||
document.getElementById('modal-confirmar').href =
|
||||
url.replace('preview_holerite', 'gerar_pdf_holerite');
|
||||
url.replace('preview_extrato', 'gerar_pdf_extrato');
|
||||
}
|
||||
function fecharPreview() {
|
||||
const modal = document.getElementById('modal-preview');
|
||||
|
||||
@@ -222,7 +222,7 @@
|
||||
|
||||
<%# Top motoristas %>
|
||||
<div class="bg-[#1a1a1a] rounded-2xl border border-white/5 p-6">
|
||||
<h2 class="text-lg font-semibold text-white mb-4">🏆 Top Motoristas</h2>
|
||||
<h2 class="text-lg font-semibold text-white mb-4">🏆 Motoristas</h2>
|
||||
|
||||
<% if @motoristas.any? %>
|
||||
<div class="space-y-3">
|
||||
@@ -234,7 +234,7 @@
|
||||
</span>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<span class="text-white text-sm font-medium truncate"><%= m[:nome].split.first %></span>
|
||||
<span class="text-white text-sm font-medium truncate"><%= m[:nome] %></span>
|
||||
<span class="text-[#f97316] text-sm font-semibold ml-2 flex-shrink-0">
|
||||
<%= moeda(m[:valor]) %>
|
||||
</span>
|
||||
@@ -287,7 +287,7 @@
|
||||
<%# Custo por motorista (barra) %>
|
||||
<div class="bg-[#1a1a1a] rounded-2xl border border-white/5 p-6">
|
||||
<h2 class="text-lg font-semibold text-white mb-1">👤 Custo por motorista</h2>
|
||||
<p class="text-gray-400 text-sm mb-4">Top 10 no período</p>
|
||||
<p class="text-gray-400 text-sm mb-4">Por motorista no período</p>
|
||||
<% if @fin_por_motorista.any? %>
|
||||
<div class="relative h-64"><canvas id="grafico-custo-motorista"></canvas></div>
|
||||
<% else %>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<p class="text-gray-300 text-sm">
|
||||
💰 <%= l cm.pago_em.to_date, format: :short %>
|
||||
<% if cm.forma_pagamento.present? %>· <%= cm.forma_pagamento.humanize %><% end %>
|
||||
<% if cm.nota_fiscal.present? %>· 🧾 NF <%= cm.nota_fiscal %><% end %>
|
||||
</p>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -78,11 +79,14 @@
|
||||
💰 Pago em <%= l cm.pago_em.to_date, format: :short %>
|
||||
<% if cm.forma_pagamento.present? %>via <%= cm.forma_pagamento.humanize %><% end %>
|
||||
</p>
|
||||
<% if cm.nota_fiscal.present? %>
|
||||
<p class="text-gray-300 text-sm mt-0.5">🧾 Nota Fiscal: <%= cm.nota_fiscal %></p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% if c.finalizada? %>
|
||||
<%= link_to '⬇️ Baixar meu holerite',
|
||||
gerar_pdf_holerite_consolidacao_path(c, motorista: current_user.nome),
|
||||
<%= link_to '⬇️ Baixar meu extrato',
|
||||
gerar_pdf_extrato_consolidacao_path(c, motorista: current_user.nome),
|
||||
data: { turbo: false },
|
||||
class: 'w-full md:w-auto bg-orange-500 hover:bg-orange-600 text-black font-bold text-base px-6 py-4 rounded-xl min-h-[52px] flex items-center justify-center text-center' %>
|
||||
<% else %>
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<% end %>
|
||||
|
||||
<p class="text-gray-300 text-base text-center mt-6">
|
||||
💡 Você também pode escanear o QR Code do seu holerite para entrar direto.
|
||||
💡 Você também pode escanear o QR Code do seu extrato para entrar direto.
|
||||
</p>
|
||||
<p class="text-center mt-4">
|
||||
<%= link_to 'Sou administrador/gerente →', new_user_session_path, class: 'text-orange-500 hover:text-orange-400 text-sm' %>
|
||||
|
||||
Reference in New Issue
Block a user