# app/services/pdf/relatorio_financeiro_periodo_pdf.rb # # Relatório Financeiro consolidado de um período: espelha a visão financeira do # dashboard (KPIs, custo por operação/motorista/tipo e pagamentos) num PDF para # o admin imprimir para conferência e histórico. Recebe os agregados já # calculados pelo DashboardController (mesma fonte de números da tela). # module Pdf class RelatorioFinanceiroPeriodoPdf < BasePdf VERDE = '22C55E' def initialize(periodo_inicio:, periodo_fim:, operacao_label:, dados:) super() @inicio = periodo_inicio @fim = periodo_fim @op = operacao_label @d = dados end private def corpo secao "RELATÓRIO FINANCEIRO — PERÍODO" @pdf.text "Período: #{@inicio.strftime('%d/%m/%Y')} a #{@fim.strftime('%d/%m/%Y')}", size: 11, style: :bold @pdf.fill_color CINZA @pdf.text "Operação: #{@op}", size: 10 @pdf.fill_color '000000' secao "INDICADORES" kpis secao "CUSTO POR OPERAÇÃO" tabela_pares(@d[:por_operacao], 'Operação') secao "CUSTO POR MOTORISTA" tabela_pares(@d[:por_motorista], 'Motorista') secao "COMPOSIÇÃO POR TIPO" tabela_por_tipo @pdf.start_new_page if @pdf.cursor < 160 secao "PAGAMENTOS REALIZADOS NO PERÍODO" tabela_pagamentos_feitos secao "PAGAMENTOS PENDENTES" tabela_pagamentos_pendentes end def kpis linhas = [ ['Custo total', moeda(@d[:custo_total])], ['Ticket médio', moeda(@d[:ticket_medio])], ['Pago', moeda(@d[:pago])], ['A pagar', moeda(@d[:pendente])] ] @pdf.table(linhas, width: 300, cell_style: { size: 11, padding: [6, 10] }) do |t| t.columns(0).font_style = :bold t.columns(1).align = :right t.row(2).text_color = VERDE end end # pares: Array de [label, valor] def tabela_pares(pares, titulo_col) if pares.present? linhas = [[titulo_col, 'Valor']] pares.each { |label, valor| linhas << [label.to_s, moeda(valor)] } @pdf.table(linhas, header: true, width: @pdf.bounds.width, cell_style: { size: 9, padding: [4, 8] }) do |t| t.row(0).background_color = LARANJA t.row(0).text_color = '000000' t.row(0).font_style = :bold t.columns(1).align = :right t.row(1..-1).borders = [:bottom] t.row(1..-1).border_color = 'DDDDDD' end else sem_dados end end def tabela_por_tipo if @d[:por_tipo].present? linhas = [['Tipo', 'Valor']] @d[:por_tipo].each { |h| linhas << [h[:label], moeda(h[:valor])] } @pdf.table(linhas, header: true, width: 360, cell_style: { size: 9, padding: [4, 8] }) do |t| t.row(0).background_color = LARANJA t.row(0).text_color = '000000' t.row(0).font_style = :bold t.columns(1).align = :right end else sem_dados end end def tabela_pagamentos_feitos registros = @d[:pagamentos_feitos] if registros.present? linhas = [['Pago em', 'Motorista', 'Consolidação', 'Forma', 'Valor']] registros.each do |cm| linhas << [ cm.pago_em.strftime('%d/%m/%Y'), cm.motorista_nome, cm.consolidacao.nome, cm.forma_pagamento&.humanize || '—', moeda(cm.valor_total) ] end tabela_listagem(linhas) @pdf.move_down 6 @pdf.fill_color VERDE @pdf.text "Total pago no período: #{moeda(@d[:pag_pago_valor])} · #{@d[:pag_pago_qtd]} pagamento(s)", size: 10, style: :bold @pdf.fill_color '000000' else sem_dados('Nenhum pagamento realizado neste período.') end end def tabela_pagamentos_pendentes registros = @d[:pagamentos_pendentes] if registros.present? linhas = [['Motorista', 'Consolidação', 'Valor']] registros.each do |cm| linhas << [cm.motorista_nome, cm.consolidacao.nome, moeda(cm.valor_total)] end tabela_listagem(linhas) @pdf.move_down 6 @pdf.text "Total a pagar: #{moeda(@d[:pag_pend_valor])} · #{@d[:pag_pend_qtd]} motorista(s)", size: 10, style: :bold else sem_dados('Nenhuma pendência no período.') end end def tabela_listagem(linhas) @pdf.table(linhas, header: true, width: @pdf.bounds.width, cell_style: { size: 8, padding: [4, 6] }) do |t| t.row(0).background_color = PRETO t.row(0).text_color = 'FFFFFF' t.row(0).font_style = :bold t.columns(-1).align = :right t.row(1..-1).borders = [:bottom] t.row(1..-1).border_color = 'DDDDDD' end end def sem_dados(msg = 'Sem dados no período.') @pdf.fill_color CINZA @pdf.text msg, size: 10 @pdf.fill_color '000000' end end end