From 94d8420bbd4a0c0f8d4b4725f7ee7e136ef4068974bb45fb4f2102639f401c0c Mon Sep 17 00:00:00 2001 From: victor Date: Mon, 22 Jun 2026 17:11:53 -0300 Subject: [PATCH] =?UTF-8?q?Corre=C3=A7=C3=A3o=20Dash=20board=20e=20implant?= =?UTF-8?q?a=C3=A7=C3=A3o=20Rela=C3=B3rio=20de=20ADM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../consolidacao_entregas_controller.rb | 19 ++- app/controllers/consolidacoes_controller.rb | 16 +- app/controllers/dashboard_controller.rb | 38 +++++ .../controllers/validacao_controller.js | 60 ++++++- app/models/configuracao.rb | 17 +- app/models/consolidacao_entrega.rb | 7 +- .../relatorio_financeiro_consolidacao_pdf.rb | 103 ++++++++++++ .../pdf/relatorio_financeiro_periodo_pdf.rb | 154 ++++++++++++++++++ .../consolidacao_entregas/revisar.html.erb | 11 +- .../consolidacao_entregas/validar.html.erb | 13 +- app/views/consolidacoes/index.html.erb | 9 +- app/views/consolidacoes/show.html.erb | 3 + app/views/consolidacoes/wizard.html.erb | 9 +- app/views/dashboard/index.html.erb | 30 +++- config/routes.rb | 2 + db/seeds.rb | 1 + 16 files changed, 453 insertions(+), 39 deletions(-) create mode 100644 app/services/pdf/relatorio_financeiro_consolidacao_pdf.rb create mode 100644 app/services/pdf/relatorio_financeiro_periodo_pdf.rb diff --git a/app/controllers/consolidacao_entregas_controller.rb b/app/controllers/consolidacao_entregas_controller.rb index 11e9288..f3c46b9 100644 --- a/app/controllers/consolidacao_entregas_controller.rb +++ b/app/controllers/consolidacao_entregas_controller.rb @@ -39,7 +39,8 @@ class ConsolidacaoEntregasController < ApplicationController entrega_normal: Configuracao.preco_entrega, retirada: Configuracao.preco_retirada, bonus: Configuracao.preco_bonus, - desconto: Configuracao.preco_desconto + desconto: Configuracao.preco_desconto, + extraordinaria: Configuracao.preco_extraordinaria } end @@ -62,7 +63,7 @@ class ConsolidacaoEntregasController < ApplicationController tracking_id: params[:tracking_id], motorista_nome: params[:motorista], tipo: params[:tipo], - valor_aplicado: valor_para_tipo(params[:tipo]), + valor_aplicado: valor_classificacao(params[:tipo]), created_by: current_user.id ) ativo = true @@ -106,7 +107,7 @@ class ConsolidacaoEntregasController < ApplicationController .destroy_all else # ADICIONA o pilar às entregas (não remove os demais já marcados). - valor = valor_para_tipo(tipo) + valor = valor_classificacao(tipo) tracking_ids.each do |tid| ce = @consolidacao.consolidacao_entregas.find_or_initialize_by(tracking_id: tid, tipo: tipo) ce.assign_attributes(motorista_nome: motorista, @@ -296,6 +297,18 @@ class ConsolidacaoEntregasController < ApplicationController ConsolidacaoEntrega.valor_para(tipo) end + # Valor a aplicar na classificação. Para o pilar "extraordinária" o admin pode + # informar um valor customizado (params[:valor]) por ser uma exceção; se vier + # ausente/inválido, cai no preço padrão de Configurações. Demais pilares usam + # sempre o preço configurado. + def valor_classificacao(tipo) + return valor_para_tipo(tipo) unless tipo.to_s == 'extraordinaria' + + valor = params[:valor].to_s.strip.tr(',', '.') + valor = BigDecimal(valor) rescue nil + valor.present? && valor >= 0 ? valor : Configuracao.preco_extraordinaria + end + def recalcular_motorista(nome) @consolidacao.recalcular_motorista!(nome) end diff --git a/app/controllers/consolidacoes_controller.rb b/app/controllers/consolidacoes_controller.rb index 9f28dca..2c8094c 100644 --- a/app/controllers/consolidacoes_controller.rb +++ b/app/controllers/consolidacoes_controller.rb @@ -5,7 +5,8 @@ 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_holerite gerar_pdf_relatorio gerar_pdf_holerite + gerar_pdf_financeiro] # Formas de pagamento aceitas (o select da UI usa esta mesma lista). FORMAS_PAGAMENTO = %w[pix transferencia dinheiro].freeze @@ -271,6 +272,19 @@ class ConsolidacoesController < ApplicationController disposition: 'attachment' end + # GET /consolidacoes/:id/gerar_pdf_financeiro — relatório financeiro da consolidação + def gerar_pdf_financeiro + authorize @consolidacao, :show? + + pdf = Pdf::RelatorioFinanceiroConsolidacaoPdf.new(consolidacao: @consolidacao) + auditar!(:editar, @consolidacao, dados_novos: { pdf: 'financeiro' }) + + send_data pdf.render, + filename: "financeiro_#{@consolidacao.nome.parameterize}_#{@consolidacao.id}.pdf", + type: 'application/pdf', + disposition: 'attachment' + end + # GET /consolidacoes/:id/gerar_pdf_holerite?motorista=X def gerar_pdf_holerite autorizar_holerite!(params[:motorista]) diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index f0cee71..677c16c 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -12,6 +12,44 @@ class DashboardController < ApplicationController carregar_dados_dashboard end + # GET /dashboard/relatorio_financeiro?inicio=&fim=&operacoes[]= + # Relatório financeiro do período (PDF) — mesmos números da tela. + def relatorio_financeiro + skip_authorization + return redirect_to(motorista_dashboard_path) if current_user.motorista? + + @periodo_inicio, @periodo_fim = periodo_selecionado + carregar_dados_dashboard + + op_label = @operacao_filtro.present? ? @operacao_filtro.map { |t| Operacao.label(t) }.join(', ') : 'Todas' + + dados = { + custo_total: @fin_custo_total, + ticket_medio: @fin_ticket_medio, + pago: @fin_pago, + pendente: @fin_pendente, + por_operacao: @fin_por_operacao, + por_motorista: @fin_por_motorista, + por_tipo: @fin_por_tipo, + pagamentos_feitos: @pagamentos_feitos, + pagamentos_pendentes: @pagamentos_pendentes, + pag_pago_valor: @pag_pago_valor, + pag_pago_qtd: @pag_pago_qtd, + pag_pend_valor: @pag_pend_valor, + pag_pend_qtd: @pag_pend_qtd + } + + pdf = Pdf::RelatorioFinanceiroPeriodoPdf.new( + periodo_inicio: @periodo_inicio, periodo_fim: @periodo_fim, + operacao_label: op_label, dados: dados + ) + + send_data pdf.render, + filename: "financeiro_#{@periodo_inicio.strftime('%Y%m%d')}_#{@periodo_fim.strftime('%Y%m%d')}.pdf", + type: 'application/pdf', + disposition: 'attachment' + end + private # Faixa de datas vinda do filtro de calendário (params inicio/fim). diff --git a/app/javascript/controllers/validacao_controller.js b/app/javascript/controllers/validacao_controller.js index d5ca85e..f84ffa5 100644 --- a/app/javascript/controllers/validacao_controller.js +++ b/app/javascript/controllers/validacao_controller.js @@ -9,14 +9,15 @@ export default class extends Controller { "linha", "checkbox", "selecionarTodos", "modoRemover", "rotuloAcao", "toggles", "barra", "percentual", "contadorClassificadas", "contadorTotal", - "qtdNormal", "qtdRetirada", "qtdBonus", "qtdDesconto", "valorTotal" + "qtdNormal", "qtdRetirada", "qtdBonus", "qtdDesconto", "qtdExtraordinaria", "valorTotal" ] static values = { - url: String, // POST classificar - massaUrl: String, // POST classificar_em_massa - motorista: String, - total: Number + url: String, // POST classificar + massaUrl: String, // POST classificar_em_massa + motorista: String, + total: Number, + precoExtraordinaria: Number // preço padrão sugerido no prompt } connect() { @@ -34,12 +35,21 @@ export default class extends Controller { const tracking = btn.dataset.tracking const tipo = btn.dataset.tipo + // Pilar extraordinária: ao ATIVAR (botão ainda sem ring-2), pergunta o valor. + const ativando = !btn.classList.contains("ring-2") + let valor = null + if (tipo === "extraordinaria" && ativando) { + valor = this.pedirValor() + if (valor === null) return // admin cancelou + } + btn.disabled = true try { const resp = await this.post(this.urlValue, { tracking_id: tracking, tipo: tipo, - motorista: this.motoristaValue + motorista: this.motoristaValue, + valor: valor }) // resp.ativo indica se o pilar ficou ligado ou desligado (toggle) this.setToggle(tracking, tipo, resp.ativo) @@ -58,11 +68,18 @@ export default class extends Controller { const verbo = remover ? "REMOVER de TODAS as entregas" : "Marcar TODAS as entregas como" if (!confirm(`${verbo} ${this.labelTipo(tipo)}?`)) return + let valor = null + if (tipo === "extraordinaria" && !remover) { + valor = this.pedirValor() + if (valor === null) return + } + const resp = await this.post(this.massaUrlValue, { tipo: tipo, motorista: this.motoristaValue, tracking_ids: [], // vazio = todas - acao: remover ? "remover" : "adicionar" + acao: remover ? "remover" : "adicionar", + valor: valor }) this.linhaTargets.forEach(l => this.setToggle(l.dataset.tracking, tipo, !remover)) this.atualizarResumo(resp) @@ -97,11 +114,19 @@ export default class extends Controller { } const remover = this.modoRemover + + let valor = null + if (tipo === "extraordinaria" && !remover) { + valor = this.pedirValor() + if (valor === null) return + } + const resp = await this.post(this.massaUrlValue, { tipo: tipo, motorista: this.motoristaValue, tracking_ids: ids, - acao: remover ? "remover" : "adicionar" + acao: remover ? "remover" : "adicionar", + valor: valor }) ids.forEach(id => this.setToggle(id, tipo, !remover)) this.checkboxTargets.forEach(c => c.checked = false) @@ -150,6 +175,8 @@ export default class extends Controller { this.qtdRetiradaTarget.textContent = porTipo["retirada"] || 0 this.qtdBonusTarget.textContent = porTipo["bonus"] || 0 this.qtdDescontoTarget.textContent = porTipo["desconto"] || 0 + if (this.hasQtdExtraordinariaTarget) + this.qtdExtraordinariaTarget.textContent = porTipo["extraordinaria"] || 0 const valor = dados.valor_total || 0 this.valorTotalTarget.textContent = @@ -171,6 +198,21 @@ export default class extends Controller { labelTipo(tipo) { return { entrega_normal: "Normal", retirada: "Retirada", - bonus: "Bônus", desconto: "Desconto" }[tipo] || tipo + bonus: "Bônus", desconto: "Desconto", + extraordinaria: "Extraordinária" }[tipo] || tipo + } + + // Pergunta o valor da entrega extraordinária (pré-preenchido com o padrão). + // Retorna o número (>= 0) ou null se o admin cancelar. + pedirValor() { + const padrao = (this.precoExtraordinariaValue || 0).toFixed(2).replace(".", ",") + const entrada = prompt("Valor desta entrega extraordinária (R$):", padrao) + if (entrada === null) return null + const num = parseFloat(entrada.replace(",", ".")) + if (isNaN(num) || num < 0) { + alert("Valor inválido. Informe um número maior ou igual a zero.") + return null + } + return num } } diff --git a/app/models/configuracao.rb b/app/models/configuracao.rb index fd84c68..1188bb3 100644 --- a/app/models/configuracao.rb +++ b/app/models/configuracao.rb @@ -8,6 +8,7 @@ class Configuracao < ApplicationRecord preco_retirada preco_bonus preco_desconto + preco_extraordinaria notificacao_whatsapp notificacao_email empresa_nome @@ -19,6 +20,7 @@ class Configuracao < ApplicationRecord preco_retirada preco_bonus preco_desconto + preco_extraordinaria ].freeze validates :chave, presence: true, inclusion: { in: CHAVES }, uniqueness: true @@ -46,13 +48,18 @@ class Configuracao < ApplicationRecord valor('preco_desconto').to_f end + def self.preco_extraordinaria + valor('preco_extraordinaria').to_f + end + # Mapa usado pelo DashboardController (Fase 3) def self.mapa_de_precos { - entrega: preco_entrega, - retirada: preco_retirada, - bonus: preco_bonus, - desconto: preco_desconto + entrega: preco_entrega, + retirada: preco_retirada, + bonus: preco_bonus, + desconto: preco_desconto, + extraordinaria: preco_extraordinaria } end @@ -61,6 +68,7 @@ class Configuracao < ApplicationRecord 'preco_retirada' => 'Retirada', 'preco_bonus' => 'Bônus', 'preco_desconto' => 'Desconto', + 'preco_extraordinaria' => 'Entrega Extraordinária', 'notificacao_whatsapp' => 'Notificação WhatsApp', 'notificacao_email' => 'Notificação E-mail', 'empresa_nome' => 'Nome da Empresa' @@ -71,6 +79,7 @@ class Configuracao < ApplicationRecord 'preco_retirada' => '📦', 'preco_bonus' => '⭐', 'preco_desconto' => '⚠️', + 'preco_extraordinaria' => '✨', 'notificacao_whatsapp' => '💬', 'notificacao_email' => '✉️', 'empresa_nome' => '🏢' diff --git a/app/models/consolidacao_entrega.rb b/app/models/consolidacao_entrega.rb index 45eeecb..980e58e 100644 --- a/app/models/consolidacao_entrega.rb +++ b/app/models/consolidacao_entrega.rb @@ -13,14 +13,16 @@ class ConsolidacaoEntrega < ApplicationRecord entrega_normal: 0, retirada: 1, bonus: 2, - desconto: 3 + desconto: 3, + extraordinaria: 4 } TIPO_CORES = { 'entrega_normal' => { bg: 'bg-orange-500', text: 'text-white', label: 'Entrega Normal' }, 'retirada' => { bg: 'bg-orange-800', text: 'text-white', label: 'Retirada' }, 'bonus' => { bg: 'bg-white border border-orange-500', text: 'text-black', label: 'Bônus' }, - 'desconto' => { bg: 'bg-gray-900', text: 'text-white', label: 'Desconto' } + 'desconto' => { bg: 'bg-gray-900', text: 'text-white', label: 'Desconto' }, + 'extraordinaria' => { bg: 'bg-purple-600', text: 'text-white', label: 'Entrega Extraordinária' } }.freeze # Uma entrega pode ter vários pilares (Normal + Bônus + Retirada…), @@ -47,6 +49,7 @@ class ConsolidacaoEntrega < ApplicationRecord when 'retirada' then Configuracao.preco_retirada when 'bonus' then Configuracao.preco_bonus when 'desconto' then Configuracao.preco_desconto + when 'extraordinaria' then Configuracao.preco_extraordinaria else 0 end end diff --git a/app/services/pdf/relatorio_financeiro_consolidacao_pdf.rb b/app/services/pdf/relatorio_financeiro_consolidacao_pdf.rb new file mode 100644 index 0000000..42a361a --- /dev/null +++ b/app/services/pdf/relatorio_financeiro_consolidacao_pdf.rb @@ -0,0 +1,103 @@ +# app/services/pdf/relatorio_financeiro_consolidacao_pdf.rb +# +# Relatório Financeiro de uma consolidação: resumo por motorista (pago x +# pendente), composição por tipo de lançamento e totais. Para o admin imprimir +# para conferência e histórico. +# +module Pdf + class RelatorioFinanceiroConsolidacaoPdf < BasePdf + VERDE = '22C55E' + + def initialize(consolidacao:) + super() + @consolidacao = consolidacao + @motoristas = consolidacao.consolidacao_motoristas.order(:motorista_nome) + @entregas = consolidacao.consolidacao_entregas + end + + private + + def corpo + secao "RELATÓRIO FINANCEIRO — CONSOLIDAÇÃO" + + @pdf.text "Consolidação: #{@consolidacao.nome}", size: 11, style: :bold + @pdf.text "Período: #{@consolidacao.data_inicio.strftime('%d/%m/%Y')} a #{@consolidacao.data_fim.strftime('%d/%m/%Y')}", size: 10 + @pdf.fill_color CINZA + @pdf.text "Status: #{@consolidacao.status.humanize} · Pagamento: #{@consolidacao.status_pagamento.to_s.humanize}", size: 10 + @pdf.fill_color '000000' + + secao "POR MOTORISTA (#{@motoristas.size})" + tabela_motoristas + + secao "COMPOSIÇÃO POR TIPO" + tabela_por_tipo + + @pdf.start_new_page if @pdf.cursor < 140 + secao "TOTAIS" + totais + end + + def tabela_motoristas + if @motoristas.any? + linhas = [['#', 'Motorista', 'Pagamento', 'Forma', 'Valor']] + @motoristas.each_with_index do |cm, i| + pagamento = cm.pago? ? "Pago em #{cm.pago_em.strftime('%d/%m/%Y')}" : 'Pendente' + linhas << [ + (i + 1).to_s, + cm.motorista_nome, + pagamento, + cm.forma_pagamento&.humanize || '—', + moeda(cm.valor_total) + ] + end + + @pdf.table(linhas, header: true, width: @pdf.bounds.width, + column_widths: { 0 => 22, 4 => 80 }, + 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(4).align = :right + t.row(1..-1).borders = [:bottom] + t.row(1..-1).border_color = 'DDDDDD' + end + else + @pdf.fill_color CINZA + @pdf.text 'Nenhum motorista nesta consolidação.', size: 10 + @pdf.fill_color '000000' + end + end + + def tabela_por_tipo + soma = @entregas.reorder(nil).group(:tipo).sum(:valor_aplicado) + qtd = @entregas.reorder(nil).group(:tipo).count + + linhas = [['Tipo', 'Quantidade', 'Valor']] + ConsolidacaoEntrega::TIPO_CORES.each do |tipo, cfg| + valor = soma[tipo].to_f + sinal = tipo == 'desconto' ? '-' : '' + linhas << [cfg[:label], (qtd[tipo] || 0).to_s, "#{sinal}#{moeda(valor)}"] + end + + @pdf.table(linhas, 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(2).align = :right + end + end + + def totais + linhas = [ + ['Custo total', moeda(@consolidacao.valor_total)], + ['Pago', moeda(@consolidacao.valor_pago)], + ['A pagar', moeda(@consolidacao.valor_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(1).text_color = VERDE + end + end + end +end diff --git a/app/services/pdf/relatorio_financeiro_periodo_pdf.rb b/app/services/pdf/relatorio_financeiro_periodo_pdf.rb new file mode 100644 index 0000000..6cc0466 --- /dev/null +++ b/app/services/pdf/relatorio_financeiro_periodo_pdf.rb @@ -0,0 +1,154 @@ +# 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 diff --git a/app/views/consolidacao_entregas/revisar.html.erb b/app/views/consolidacao_entregas/revisar.html.erb index 65d5543..c5707e4 100644 --- a/app/views/consolidacao_entregas/revisar.html.erb +++ b/app/views/consolidacao_entregas/revisar.html.erb @@ -12,12 +12,13 @@ <%# Resumo por tipo %> -
+
<% [ - ['entrega_normal', 'Normal', 'bg-orange-500 text-black'], - ['retirada', 'Retirada', 'bg-orange-800 text-white'], - ['bonus', 'Bônus', 'bg-white text-black'], - ['desconto', 'Desconto', 'bg-black text-white border border-gray-700'] + ['entrega_normal', 'Normal', 'bg-orange-500 text-black'], + ['retirada', 'Retirada', 'bg-orange-800 text-white'], + ['bonus', 'Bônus', 'bg-white text-black'], + ['desconto', 'Desconto', 'bg-black text-white border border-gray-700'], + ['extraordinaria', 'Extraordinária', 'bg-purple-600 text-white'] ].each do |tipo, label, cores| %>

<%= @resumo[tipo] || 0 %>

diff --git a/app/views/consolidacao_entregas/validar.html.erb b/app/views/consolidacao_entregas/validar.html.erb index 208023e..fffdd18 100644 --- a/app/views/consolidacao_entregas/validar.html.erb +++ b/app/views/consolidacao_entregas/validar.html.erb @@ -5,7 +5,8 @@ data-validacao-url-value="<%= classificar_consolidacao_consolidacao_entregas_path(@consolidacao) %>" data-validacao-massa-url-value="<%= classificar_em_massa_consolidacao_consolidacao_entregas_path(@consolidacao) %>" data-validacao-motorista-value="<%= @motorista %>" - data-validacao-total-value="<%= @total_entregas %>"> + data-validacao-total-value="<%= @total_entregas %>" + data-validacao-preco-extraordinaria-value="<%= @precos[:extraordinaria] %>"> <%# Header %>
@@ -68,6 +69,8 @@ class="bg-white text-black font-bold px-3 py-2 rounded-lg text-xs border border-orange-500 min-h-[44px]">Bônus +
@@ -111,7 +114,8 @@ ['entrega_normal', 'Normal', 'bg-orange-500 text-black'], ['retirada', 'Retirada', 'bg-orange-800 text-white'], ['bonus', 'Bônus', 'bg-white text-black border border-orange-500'], - ['desconto', 'Desc.', 'bg-black text-white border border-gray-700'] + ['desconto', 'Desc.', 'bg-black text-white border border-gray-700'], + ['extraordinaria', 'Extra', 'bg-purple-600 text-white'] ].each do |tipo, label, cores| %>
+
+ Extraordinária + 0 +
@@ -165,6 +173,7 @@

📦 Retirada: <%= moeda(@precos[:retirada]) %>

⭐ Bônus: <%= moeda(@precos[:bonus]) %>

⚠️ Desconto: -<%= moeda(@precos[:desconto]) %>

+

✨ Extraordinária: <%= moeda(@precos[:extraordinaria]) %> (valor por entrega)

diff --git a/app/views/consolidacoes/index.html.erb b/app/views/consolidacoes/index.html.erb index 47f844f..31dad30 100644 --- a/app/views/consolidacoes/index.html.erb +++ b/app/views/consolidacoes/index.html.erb @@ -50,10 +50,11 @@