diff --git a/app/controllers/invoices_controller.rb b/app/controllers/invoices_controller.rb index ed4171101..216d80903 100644 --- a/app/controllers/invoices_controller.rb +++ b/app/controllers/invoices_controller.rb @@ -20,6 +20,10 @@ def show # Authorize for authenticated access (integer ID), skip for token-based access authorize @invoice, :show? unless token_based_access + # Hide navbar when generating PDF + @show_navigationbar = params[:pdf].blank? + @show_extras = params[:pdf].blank? + respond_to do |format| format.html format.pdf { render_invoice_pdf } @@ -93,16 +97,14 @@ def permitted_attributes params.require(:invoice).permit(%i[user_id activity_id name_override email_override rows], rows_attributes: %i[name amount price]) end - def render_invoice_pdf # rubocop:disable Metrics/MethodLength, Metrics/AbcSize + # rubocop:disable Metrics/AbcSize, Metrics/MethodLength + def render_invoice_pdf token_based_access = !integer_id?(params[:id]) authorize @invoice, :download? unless token_based_access - html = render_to_string( - template: 'invoices/show', - formats: [:html], - layout: 'pdf' - ) - pdf = Grover.new(html).to_pdf + # Use token-based URL for unauthenticated Grover access + url = invoice_url(@invoice.token, pdf: true, only_path: false) + pdf = Grover.new(url).to_pdf send_data pdf, filename: "Factuur-#{@invoice.human_id}.pdf", type: 'application/pdf', disposition: 'attachment' rescue StandardError => e Rails.logger.error "Failed to generate PDF for invoice #{@invoice.id}: #{e.message}" @@ -113,4 +115,5 @@ def render_invoice_pdf # rubocop:disable Metrics/MethodLength, Metrics/AbcSize redirect_to invoice_path(@invoice) end end + # rubocop:enable Metrics/AbcSize, Metrics/MethodLength end diff --git a/app/mailers/invoice_mailer.rb b/app/mailers/invoice_mailer.rb index e14a6846d..d4b2032e5 100644 --- a/app/mailers/invoice_mailer.rb +++ b/app/mailers/invoice_mailer.rb @@ -10,12 +10,9 @@ def invoice_mail(invoice) # rubocop:disable Metrics/AbcSize, Metrics/MethodLengt end begin - html = render_to_string( - template: 'invoices/show', - formats: [:html], - layout: 'pdf' - ) - pdf = Grover.new(html).to_pdf + # Use token-based URL for unauthenticated Grover access + url = url_for(controller: 'invoices', action: 'show', id: invoice.token, pdf: true, only_path: false) + pdf = Grover.new(url).to_pdf attachments["#{invoice.human_id}.pdf"] = pdf rescue StandardError => e Rails.logger.error "Failed to generate PDF attachment for invoice #{invoice.id}: #{e.message}" diff --git a/app/views/invoices/show.html.erb b/app/views/invoices/show.html.erb index ad7676617..9d60067d6 100644 --- a/app/views/invoices/show.html.erb +++ b/app/views/invoices/show.html.erb @@ -48,6 +48,7 @@ <%= Rails.application.config.x.company_kvk %> + <% if current_user&.treasurer? %> Status @@ -60,10 +61,11 @@ <% end %> + <% end %> - <% unless @invoice.paid? %> + <% if !@invoice.paid? && Rails.application.config.x.mollie_api_key.present? %> <%= link_to pay_invoice_url @invoice.token do %> <% end %> diff --git a/app/views/layouts/pdf.html.erb b/app/views/layouts/pdf.html.erb deleted file mode 100644 index 411bfae16..000000000 --- a/app/views/layouts/pdf.html.erb +++ /dev/null @@ -1,37 +0,0 @@ - - - - - -<%= yield(:title) %> - <% - # Load CSS from both app/assets/builds (development) and public/assets (production/staging) - css = '' - candidates = [] - - # Add CSS from app/assets/builds (development) - candidates.concat(Dir.glob(Rails.root.join('app', 'assets', 'builds', '*.css').to_s)) - - # Add CSS from public/assets (production/staging with fingerprinted names) - candidates.concat(Dir.glob(Rails.root.join('public', 'assets', 'application-*.css').to_s)) - - # Read and combine all CSS files - css = candidates.filter_map do |path| - begin - File.read(path) - rescue => e - Rails.logger.warn "Could not read compiled CSS from #{path}: #{e.message}" - nil - end - end.join("\n") - - Rails.logger.warn "No CSS files found for PDF generation" if css.blank? - %> - - - - <%= yield %> - - diff --git a/config/initializers/grover.rb b/config/initializers/grover.rb index 2d5b4d343..aca52c7a6 100644 --- a/config/initializers/grover.rb +++ b/config/initializers/grover.rb @@ -1,31 +1,22 @@ -# Grover Global Configuration -# -# Use this to set up shared configuration options for your entire application. -# Any of the configuration options shown here can also be applied to single -# models by passing arguments to the Grover.new call. -# -# To learn more, check out the README: -# https://github.com/Studiosity/grover - Grover.configure do |config| - options = { - format: 'A4', + config.options = { + viewport: { + width: 794, # A4 width in pixels at 96 DPI (210mm) + height: 1123 # Starting height, will expand as needed + }, + emulate_media: 'screen', print_background: true, - prefer_css_page_size: false, - display_url: "https://#{Rails.application.config.x.sofia_host}" + executable_path: Rails.env.development? ? nil : '/usr/bin/chromium', + launch_args: if Rails.env.development? + [] + else + [ + '--no-sandbox', + '--disable-setuid-sandbox', + '--disable-dev-shm-usage', + '--disable-gpu', + '--disable-software-rasterizer' + ] + end } - - unless Rails.env.development? - options[:executable_path] = '/usr/bin/chromium' - options[:launch_args] = [ - '--no-sandbox', - '--disable-setuid-sandbox', - '--disable-dev-shm-usage', - '--disable-gpu', - '--disable-software-rasterizer', - '--hide-scrollbars' - ] - end - - config.options = options end