Files
Reem-Notas/app/services/pdf/holerite_pdf.rb

120 lines
4.5 KiB
Ruby

# app/services/pdf/holerite_pdf.rb
#
# Holerite: 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
def initialize(consolidacao:, motorista:, user_motorista: nil, app_host: nil)
super()
@consolidacao = consolidacao
@motorista = motorista
@user_motorista = user_motorista
@app_host = app_host || ENV.fetch('APP_HOST', 'localhost:3000')
@entregas = consolidacao.consolidacao_entregas.where(motorista_nome: motorista)
end
private
def corpo
secao "HOLERITE DE PAGAMENTO — ENTREGAS"
# Bloco de identificação (estilo contracheque)
info = [
['Motorista', @motorista],
['Consolidação', @consolidacao.nome],
['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')]
]
@pdf.table(info, width: @pdf.bounds.width, cell_style: { size: 10, padding: [5, 8] }) do |t|
t.columns(0).font_style = :bold
t.columns(0).background_color = 'F3F4F6'
t.columns(0).width = 120
end
secao "PROVENTOS E DESCONTOS"
resumo = @entregas.group(:tipo).count
por_tipo = ConsolidacaoEntrega::TIPO_CORES.map do |tipo, cfg|
qtd = resumo[tipo] || 0
next if qtd.zero?
valor = @entregas.where(tipo: tipo).sum(:valor_aplicado)
unit = qtd.zero? ? 0 : (valor / qtd)
sinal = tipo == 'desconto' ? '-' : '+'
[cfg[:label], qtd.to_s, moeda(unit), "#{sinal} #{moeda(valor)}"]
end.compact
linhas = [['Descrição', 'Qtd', 'Unit.', 'Valor']] + por_tipo
@pdf.table(linhas, header: true, width: @pdf.bounds.width,
cell_style: { size: 10, padding: [6, 8] }) do |t|
t.row(0).background_color = PRETO
t.row(0).text_color = 'FFFFFF'
t.row(0).font_style = :bold
t.columns(1..3).align = :right
end
total = @entregas.sum { |e| e.desconto? ? -e.valor_aplicado : e.valor_aplicado }
# Caixa do total — destaque laranja
@pdf.move_down 16
@pdf.fill_color LARANJA
@pdf.fill_rounded_rectangle [0, @pdf.cursor], @pdf.bounds.width, 50, 8
@pdf.fill_color '000000'
@pdf.text_box 'VALOR LÍQUIDO A RECEBER',
at: [16, @pdf.cursor - 10], size: 10, style: :bold
@pdf.text_box moeda(total),
at: [16, @pdf.cursor - 24], size: 22, style: :bold
@pdf.move_down 64
# Detalhamento: total de entregas e veículos atendidos no período
total_entregas = @entregas.count
veiculos = @entregas.map { |e| e.entrega_original&.vehicle }.compact.uniq
@pdf.fill_color CINZA
@pdf.text "Total de entregas: #{total_entregas}", size: 9
@pdf.text "Veículos atendidos: #{veiculos.any? ? veiculos.join(', ') : '—'}", size: 9
@pdf.fill_color '000000'
@pdf.move_down 8
# QR Code de login rápido
desenhar_qrcode if @user_motorista&.login_token.present?
assinaturas(motorista: @motorista)
end
# Monta a URL respeitando o esquema do APP_HOST. Se vier sem http(s)://
# (ex.: "100.75.222.23:3000") assume http — produção em IP:porta normalmente
# não tem TLS. Defina APP_HOST com "https://" se o servidor usar HTTPS.
def url_acesso
raw = @app_host.to_s.strip
protocolo = raw.start_with?('https://') ? 'https' : 'http'
host = raw.sub(%r{\Ahttps?://}, '').chomp('/')
"#{protocolo}://#{host}/motorista/acesso/#{@user_motorista.login_token}"
end
def desenhar_qrcode
url = url_acesso
qr = RQRCode::QRCode.new(url)
png = qr.as_png(size: 220, border_modules: 2)
arquivo = Tempfile.new(['qr', '.png'])
arquivo.binmode
arquivo.write(png.to_s)
arquivo.rewind
secao "ACESSO RÁPIDO AO SEU PAINEL"
@pdf.image arquivo.path, width: 110, position: :left
@pdf.move_up 95
@pdf.text_box "Escaneie este QR Code com a câmera do celular para entrar\n" \
"no seu painel e acompanhar seus pagamentos.\n\n" \
"Ou acesse: #{@app_host.to_s.sub(%r{\Ahttps?://}, '').chomp('/')}/motorista\ne use seu PIN de 4 dígitos.",
at: [130, @pdf.cursor], width: @pdf.bounds.width - 130, size: 9
@pdf.move_down 100
ensure
arquivo&.close
arquivo&.unlink
end
end
end