class EventsController < ApplicationController before_action :authenticate_user!, only: [ :checkout, :collect_names, :process_names, :payment_success, :download_ticket ] before_action :set_event, only: [ :show, :checkout, :collect_names, :process_names ] # Display all events def index @events = Event.includes(:user).upcoming.page(params[:page]).per(12) end # Display desired event def show # Event is set by set_event callback end # Handle checkout process - Collect names if needed or create Stripe session def checkout # Convert cart parameter to proper hash cart_param = params[:cart] cart_data = if cart_param.is_a?(String) JSON.parse(cart_param) elsif cart_param.is_a?(ActionController::Parameters) cart_param.to_unsafe_h else {} end if cart_data.empty? redirect_to event_path(@event.slug, @event), alert: "Veuillez sélectionner au moins un billet" return end # Check if any ticket types require names requires_names = false cart_data.each do |ticket_type_id, item| ticket_type = @event.ticket_types.find_by(id: ticket_type_id) next unless ticket_type quantity = item["quantity"].to_i next if quantity <= 0 if ticket_type.requires_id requires_names = true break end end # If names are required, redirect to name collection if requires_names session[:pending_cart] = cart_data redirect_to event_collect_names_path(@event.slug, @event) return end # Otherwise proceed directly to payment process_payment(cart_data) end # Display form to collect names for tickets def collect_names @cart_data = session[:pending_cart] || {} if @cart_data.empty? redirect_to event_path(@event.slug, @event), alert: "Veuillez sélectionner au moins un billet" return end # Build list of tickets requiring names @tickets_needing_names = [] @cart_data.each do |ticket_type_id, item| ticket_type = @event.ticket_types.find_by(id: ticket_type_id) next unless ticket_type quantity = item["quantity"].to_i next if quantity <= 0 if ticket_type.requires_id quantity.times do |i| @tickets_needing_names << { ticket_type_id: ticket_type.id, ticket_type_name: ticket_type.name, index: i } end end end end # Process submitted names and create Stripe session def process_names cart_data = session[:pending_cart] || {} if cart_data.empty? redirect_to event_path(@event.slug, @event), alert: "Veuillez sélectionner au moins un billet" return end # Store names in session for later use if params[:ticket_names].present? # Convert ActionController::Parameters to hash if params[:ticket_names].is_a?(ActionController::Parameters) session[:ticket_names] = params[:ticket_names].to_unsafe_h else session[:ticket_names] = params[:ticket_names] end end # Proceed to payment process_payment(cart_data) end # Handle successful payment def payment_success session_id = params[:session_id] event_id = params[:event_id] # Check if Stripe is properly configured unless stripe_configured? redirect_to event_path(@event.slug, @event), alert: "Le système de paiement n'est pas correctement configuré. Veuillez contacter l'administrateur." return end # Initialize Stripe during checkout unless initialize_stripe redirect_to event_path(@event.slug, @event), alert: "Impossible d'initialiser le système de paiement. Veuillez réessayer plus tard." return end begin session = Stripe::Checkout::Session.retrieve(session_id) if session.payment_status == "paid" # Create tickets @event = Event.find(event_id) order_items = JSON.parse(session.metadata["order_items"]) @tickets = [] # Get names from session if they exist ticket_names = session.metadata["ticket_names"] ? JSON.parse(session.metadata["ticket_names"]) : {} order_items.each do |item| ticket_type = TicketType.find(item["ticket_type_id"]) item["quantity"].times do |i| # Get names if this ticket type requires them first_name = nil last_name = nil if ticket_type.requires_id name_key = "#{ticket_type.id}_#{i}" names = ticket_names[name_key] || {} first_name = names["first_name"] last_name = names["last_name"] end ticket = Ticket.create!( user: current_user, ticket_type: ticket_type, status: "active", first_name: first_name, last_name: last_name ) @tickets << ticket # Send confirmation email for each ticket TicketMailer.purchase_confirmation(ticket).deliver_now end end # Clear session data session.delete(:pending_cart) session.delete(:ticket_names) render "payment_success" else redirect_to event_path(@event.slug, @event), alert: "Le paiement n'a pas été complété avec succès" end rescue Stripe::StripeError => e redirect_to dashboard_path, alert: "Erreur lors du traitement de votre confirmation de paiement : #{e.message}" rescue => e redirect_to dashboard_path, alert: "Une erreur inattendue s'est produite : #{e.message}" end end # Download ticket PDF def download_ticket @ticket = current_user.tickets.find(params[:ticket_id]) respond_to do |format| format.pdf do pdf = @ticket.to_pdf send_data pdf, filename: "ticket-#{@ticket.event.name.parameterize}-#{@ticket.qr_code[0..7]}.pdf", type: "application/pdf", disposition: "attachment" end end end private def set_event @event = Event.includes(:ticket_types).find(params[:id]) end # Process payment and create Stripe session def process_payment(cart_data) # Create order items from cart line_items = [] order_items = [] total_amount = 0 cart_data.each do |ticket_type_id, item| ticket_type = @event.ticket_types.find_by(id: ticket_type_id) next unless ticket_type quantity = item["quantity"].to_i next if quantity <= 0 # Check availability available = ticket_type.quantity - ticket_type.tickets.count if quantity > available redirect_to event_path(@event.slug, @event), alert: "Pas assez de billets disponibles pour #{ticket_type.name}" return end # Create Stripe line item line_items << { price_data: { currency: "eur", product_data: { name: "#{@event.name} - #{ticket_type.name}", description: ticket_type.description }, unit_amount: ticket_type.price_cents }, quantity: quantity } # Store for ticket creation order_items << { ticket_type_id: ticket_type.id, ticket_type_name: ticket_type.name, quantity: quantity, price_cents: ticket_type.price_cents } total_amount += ticket_type.price_cents * quantity end if order_items.empty? redirect_to event_path(@event.slug, @event), alert: "Commande invalide" return end # Get ticket names from session if they exist ticket_names = session[:ticket_names] || {} # Check if Stripe is properly configured unless stripe_configured? redirect_to event_path(@event.slug, @event), alert: "Le système de paiement n'est pas correctement configuré. Veuillez contacter l'administrateur." return end # Initialize Stripe during checkout unless initialize_stripe redirect_to event_path(@event.slug, @event), alert: "Impossible d'initialiser le système de paiement. Veuillez réessayer plus tard." return end begin # Create Stripe Checkout Session session = Stripe::Checkout::Session.create({ payment_method_types: [ "card" ], line_items: line_items, mode: "payment", success_url: payment_success_url(event_id: @event.id, session_id: "{CHECKOUT_SESSION_ID}"), cancel_url: event_url(@event.slug, @event), customer_email: current_user.email, metadata: { event_id: @event.id, user_id: current_user.id, order_items: order_items.to_json, ticket_names: ticket_names.to_json } }) redirect_to session.url, allow_other_host: true rescue Stripe::StripeError => e redirect_to event_path(@event.slug, @event), alert: "Erreur de traitement du paiement : #{e.message}" end end end