- Replace Prawn PDF generation with Grover (Chrome headless) for better compatibility - Add HTML-based ticket template with embedded CSS styling - Implement robust Grover loading with fallback to HTML download - Add QR code generation methods to Ticket model - Remove legacy TicketPdfGenerator service and tests - Update PDF generation in TicketsController with proper error handling The new implementation provides: - Better HTML/CSS rendering for ticket layouts - More reliable PDF generation using Chrome engine - Fallback mechanism for better user experience - Cleaner separation of template rendering and PDF conversion 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
183 lines
6.6 KiB
Ruby
183 lines
6.6 KiB
Ruby
# Legacy tickets controller - redirects to new order system
|
|
#
|
|
# This controller now primarily handles legacy redirects and backward compatibility
|
|
# Most ticket creation functionality has been moved to OrdersController
|
|
class TicketsController < ApplicationController
|
|
before_action :authenticate_user!, only: [ :payment_success, :payment_cancel, :show, :download_ticket ]
|
|
before_action :set_event, only: [ :checkout, :retry_payment ]
|
|
|
|
|
|
# Redirect to order-based checkout
|
|
def checkout
|
|
# Check for draft order
|
|
if session[:draft_order_id].present?
|
|
order = current_user.orders.find_by(id: session[:draft_order_id], status: "draft")
|
|
if order.present?
|
|
redirect_to order_checkout_path(order)
|
|
return
|
|
end
|
|
end
|
|
|
|
# No order found
|
|
@event = Event.includes(:ticket_types).find(params[:id])
|
|
redirect_to event_path(@event.slug, @event), alert: "Aucun billet en attente de paiement"
|
|
end
|
|
|
|
# Redirect to order-based payment success
|
|
def payment_success
|
|
redirect_to order_payment_success_path(session_id: params[:session_id])
|
|
end
|
|
|
|
# Redirect to order-based payment cancel
|
|
def payment_cancel
|
|
redirect_to order_payment_cancel_path
|
|
end
|
|
|
|
# Redirect retry payment to order system
|
|
def retry_payment
|
|
@event = Event.includes(:ticket_types).find(params[:id])
|
|
|
|
# Look for draft order for this event
|
|
order = current_user.orders.find_by(event: @event, status: "draft")
|
|
|
|
if order&.can_retry_payment?
|
|
redirect_to retry_payment_order_path(order)
|
|
else
|
|
redirect_to event_path(@event.slug, @event),
|
|
alert: "Aucune commande disponible pour un nouveau paiement"
|
|
end
|
|
end
|
|
|
|
# Display ticket details
|
|
def show
|
|
@ticket = Ticket.joins(order: :user).includes(:event, :ticket_type, order: :user).find_by(
|
|
tickets: { id: params[:ticket_id] },
|
|
orders: { user_id: current_user.id }
|
|
)
|
|
@event = @ticket.event
|
|
rescue ActiveRecord::RecordNotFound
|
|
redirect_to dashboard_path, alert: "Billet non trouvé"
|
|
end
|
|
|
|
# Download PDF ticket - only accessible by ticket owner
|
|
# User must be authenticated to download ticket
|
|
# TODO: change ID to an unique identifier (UUID)
|
|
def download_ticket
|
|
# Find ticket and ensure it belongs to current user
|
|
@ticket = Ticket.joins(order: :user).includes(:event, :ticket_type, order: :user).find_by(
|
|
tickets: { id: params[:ticket_id] },
|
|
orders: { user_id: current_user.id }
|
|
)
|
|
|
|
if @ticket.nil?
|
|
redirect_to dashboard_path, alert: "Billet non trouvé ou vous n'avez pas l'autorisation d'accéder à ce billet"
|
|
return
|
|
end
|
|
|
|
# Generate PDF using Grover
|
|
begin
|
|
Rails.logger.info "Starting PDF generation for ticket ID: #{@ticket.id}"
|
|
|
|
# Render the HTML template
|
|
html = render_to_string(
|
|
partial: "tickets/pdf_ticket",
|
|
layout: false,
|
|
locals: { ticket: @ticket }
|
|
)
|
|
|
|
Rails.logger.info "HTML template rendered successfully, length: #{html.length}"
|
|
|
|
# Try to load and use Grover
|
|
begin
|
|
Rails.logger.info "Attempting to load Grover gem"
|
|
|
|
# Try different approaches to load grover
|
|
begin
|
|
require 'bundler'
|
|
Bundler.require(:default, Rails.env)
|
|
Rails.logger.info "Bundler required gems successfully"
|
|
rescue => bundler_error
|
|
Rails.logger.warn "Bundler require failed: #{bundler_error.message}"
|
|
end
|
|
|
|
# Direct path approach using bundle show
|
|
grover_gem_path = `bundle show grover`.strip
|
|
grover_path = File.join(grover_gem_path, 'lib', 'grover')
|
|
|
|
if File.exist?(grover_path + '.rb')
|
|
Rails.logger.info "Loading Grover from direct path: #{grover_path}"
|
|
require grover_path
|
|
else
|
|
Rails.logger.error "Grover not found at path: #{grover_path}"
|
|
raise LoadError, "Grover gem not available at expected path"
|
|
end
|
|
|
|
Rails.logger.info "Creating Grover instance with options"
|
|
grover = Grover.new(html,
|
|
format: 'A6',
|
|
margin: {
|
|
top: '10mm',
|
|
bottom: '10mm',
|
|
left: '10mm',
|
|
right: '10mm'
|
|
},
|
|
prefer_css_page_size: true,
|
|
emulate_media: 'print',
|
|
cache: false,
|
|
launch_args: ['--no-sandbox', '--disable-setuid-sandbox'] # For better compatibility
|
|
)
|
|
Rails.logger.info "Grover instance created successfully"
|
|
|
|
pdf_content = grover.to_pdf
|
|
Rails.logger.info "PDF generated successfully, length: #{pdf_content.length}"
|
|
|
|
# Send PDF as download
|
|
send_data pdf_content,
|
|
filename: "ticket_#{@ticket.id}_#{@ticket.event.name.parameterize}.pdf",
|
|
type: "application/pdf",
|
|
disposition: "attachment"
|
|
rescue LoadError => grover_error
|
|
Rails.logger.error "Failed to load Grover: #{grover_error.message}"
|
|
# Fallback: return HTML instead of PDF
|
|
send_data html,
|
|
filename: "ticket_#{@ticket.id}_#{@ticket.event.name.parameterize}.html",
|
|
type: "text/html",
|
|
disposition: "attachment"
|
|
end
|
|
rescue => e
|
|
Rails.logger.error "Error generating ticket PDF with Grover:"
|
|
Rails.logger.error "Message: #{e.message}"
|
|
Rails.logger.error "Backtrace: #{e.backtrace.join("\n")}"
|
|
redirect_to dashboard_path, alert: "Erreur lors de la génération du billet"
|
|
end
|
|
rescue ActiveRecord::RecordNotFound => e
|
|
Rails.logger.error "ActiveRecord::RecordNotFound error: #{e.message}"
|
|
redirect_to dashboard_path, alert: "Billet non trouvé"
|
|
rescue => e
|
|
Rails.logger.error "Unexpected error in download_ticket action:"
|
|
Rails.logger.error "Message: #{e.message}"
|
|
Rails.logger.error "Backtrace: #{e.backtrace.join("\n")}"
|
|
redirect_to dashboard_path, alert: "Erreur lors de la génération du billet"
|
|
end
|
|
|
|
private
|
|
|
|
def set_event
|
|
event_id = params[:id] || session[:event_id]
|
|
|
|
Rails.logger.debug "TicketsController#set_event - params[:id]: #{params[:id].inspect}, session[:event_id]: #{session[:event_id].inspect}"
|
|
|
|
unless event_id
|
|
Rails.logger.error "TicketsController#set_event - No event ID found"
|
|
redirect_to events_path, alert: "Aucun événement spécifié"
|
|
return
|
|
end
|
|
|
|
@event = Event.includes(:ticket_types).find(event_id)
|
|
Rails.logger.debug "TicketsController#set_event - Found event: #{@event.id} - #{@event.name}"
|
|
rescue ActiveRecord::RecordNotFound
|
|
Rails.logger.error "TicketsController#set_event - Event not found with ID: #{event_id}"
|
|
redirect_to events_path, alert: "Événement non trouvé"
|
|
end
|
|
end
|