This fixes the 'data must be a String, QRSegment, or an Array' error that was preventing checkout completion. Changes: - Move email sending outside payment transaction to avoid rollback on email failure - Add error handling around PDF generation in mailers - Improve QR code data building with multiple fallback strategies - Use direct foreign key access instead of through associations for reliability - Add comprehensive logging for debugging QR code issues - Ensure checkout succeeds even if email/PDF generation fails The payment process will now complete successfully regardless of email issues, while still attempting to send confirmation emails with PDF attachments.
149 lines
4.5 KiB
Ruby
Executable File
149 lines
4.5 KiB
Ruby
Executable File
require "prawn"
|
|
require "prawn/qrcode"
|
|
require "rqrcode"
|
|
|
|
# PDF ticket generator service using Prawn
|
|
#
|
|
# Generates PDF tickets with QR codes for event entry validation
|
|
# Includes event details, venue information, and unique QR code for each ticket
|
|
class TicketPdfGenerator
|
|
# Suppress Prawn's internationalization warning for built-in fonts
|
|
Prawn::Fonts::AFM.hide_m17n_warning = true
|
|
attr_reader :ticket
|
|
|
|
def initialize(ticket)
|
|
@ticket = ticket
|
|
end
|
|
|
|
def generate
|
|
Prawn::Document.new(page_size: [ 350, 600 ], margin: 20) do |pdf|
|
|
# Header
|
|
pdf.fill_color "2D1B69"
|
|
pdf.font "Helvetica", style: :bold, size: 24
|
|
pdf.text "ApéroNight", align: :center
|
|
pdf.move_down 10
|
|
|
|
# Event name
|
|
pdf.fill_color "000000"
|
|
pdf.font "Helvetica", style: :bold, size: 18
|
|
pdf.text ticket.event.name, align: :center
|
|
pdf.move_down 20
|
|
|
|
# Ticket info box
|
|
pdf.stroke_color "E5E7EB"
|
|
pdf.fill_color "F9FAFB"
|
|
pdf.rounded_rectangle [ 0, pdf.cursor ], 310, 120, 10
|
|
pdf.fill_and_stroke
|
|
|
|
pdf.move_down 10
|
|
pdf.fill_color "000000"
|
|
pdf.font "Helvetica", size: 12
|
|
|
|
# Ticket details
|
|
pdf.text "Ticket Type:", style: :bold
|
|
pdf.text ticket.ticket_type.name
|
|
pdf.move_down 8
|
|
|
|
pdf.text "Price:", style: :bold
|
|
pdf.text "€#{ticket.price_euros}"
|
|
pdf.move_down 8
|
|
|
|
pdf.text "Date & Time:", style: :bold
|
|
pdf.text ticket.event.start_time.strftime("%B %d, %Y at %I:%M %p")
|
|
pdf.move_down 20
|
|
|
|
# Venue information
|
|
pdf.fill_color "374151"
|
|
pdf.font "Helvetica", style: :bold, size: 14
|
|
pdf.text "Venue Information"
|
|
pdf.move_down 8
|
|
|
|
pdf.font "Helvetica", size: 11
|
|
pdf.text ticket.event.venue_name, style: :bold
|
|
pdf.text ticket.event.venue_address
|
|
pdf.move_down 20
|
|
|
|
# QR Code
|
|
pdf.fill_color "000000"
|
|
pdf.font "Helvetica", style: :bold, size: 14
|
|
pdf.text "Ticket QR Code", align: :center
|
|
pdf.move_down 10
|
|
|
|
# Ensure all required data is present before generating QR code
|
|
if ticket.qr_code.blank?
|
|
raise "Ticket QR code is missing"
|
|
end
|
|
|
|
# Build QR code data with safe association loading
|
|
qr_code_data = build_qr_code_data(ticket)
|
|
|
|
# Validate QR code data before creating QR code
|
|
if qr_code_data.blank? || qr_code_data == "{}"
|
|
Rails.logger.error "QR code data is empty: ticket_id=#{ticket.id}, qr_code=#{ticket.qr_code}, event_id=#{ticket.ticket_type&.event_id}, user_id=#{ticket.order&.user_id}"
|
|
raise "QR code data is empty or invalid"
|
|
end
|
|
|
|
# Ensure qr_code_data is a proper string for QR code generation
|
|
unless qr_code_data.is_a?(String) && qr_code_data.length > 2
|
|
Rails.logger.error "QR code data is not a valid string: #{qr_code_data.inspect} (class: #{qr_code_data.class})"
|
|
raise "QR code data must be a valid string"
|
|
end
|
|
|
|
qrcode = RQRCode::QRCode.new(qr_code_data)
|
|
pdf.print_qr_code(qrcode, extent: 120, align: :center)
|
|
|
|
pdf.move_down 15
|
|
|
|
# QR code text
|
|
pdf.font "Helvetica", size: 8
|
|
pdf.fill_color "6B7280"
|
|
pdf.text "QR Code: #{ticket.qr_code[0..7]}...", align: :center
|
|
|
|
# Footer
|
|
pdf.move_down 30
|
|
pdf.stroke_color "E5E7EB"
|
|
pdf.horizontal_line 0, 310
|
|
pdf.move_down 10
|
|
|
|
pdf.font "Helvetica", size: 8
|
|
pdf.fill_color "6B7280"
|
|
pdf.text "This ticket is valid for one entry only.", align: :center
|
|
pdf.text "Present this ticket at the venue entrance.", align: :center
|
|
pdf.move_down 5
|
|
pdf.text "Generated on #{Time.current.strftime('%B %d, %Y at %I:%M %p')}", align: :center
|
|
end.render
|
|
end
|
|
|
|
private
|
|
|
|
def build_qr_code_data(ticket)
|
|
# Try multiple approaches to get valid QR code data
|
|
begin
|
|
# Primary approach: full JSON with all data
|
|
data = {
|
|
ticket_id: ticket.id,
|
|
qr_code: ticket.qr_code,
|
|
event_id: ticket.ticket_type&.event_id,
|
|
user_id: ticket.order&.user_id
|
|
}.compact
|
|
|
|
# Ensure we have the minimum required data
|
|
if data[:ticket_id] && data[:qr_code]
|
|
return data.to_json
|
|
end
|
|
rescue StandardError => e
|
|
Rails.logger.warn "Failed to build complex QR data: #{e.message}"
|
|
end
|
|
|
|
# Fallback approach: just use the ticket's QR code string
|
|
begin
|
|
return ticket.qr_code.to_s if ticket.qr_code.present?
|
|
rescue StandardError => e
|
|
Rails.logger.warn "Failed to use ticket QR code: #{e.message}"
|
|
end
|
|
|
|
# Final fallback: simple ticket identifier
|
|
"TICKET-#{ticket.id}"
|
|
end
|
|
end
|