# Handle order management and checkout process # # This controller manages the order lifecycle from checkout to payment completion # Orders group multiple tickets together for better transaction management class OrdersController < ApplicationController before_action :authenticate_user! before_action :set_order, only: [:show, :checkout, :retry_payment] # Display order summary def show @tickets = @order.tickets.includes(:ticket_type) end # Display payment page for an order # # Display a summary of all tickets in the order and permit user # to proceed to payment via Stripe def checkout # Handle expired orders if @order.expired? @order.expire_if_overdue! return redirect_to event_path(@order.event.slug, @order.event), alert: "Votre commande a expiré. Veuillez recommencer." end @tickets = @order.tickets.includes(:ticket_type) @total_amount = @order.total_amount_cents @expiring_soon = @order.expiring_soon? # Create Stripe checkout session if Stripe is configured if Rails.application.config.stripe[:secret_key].present? begin @checkout_session = create_stripe_session @order.increment_payment_attempt! rescue => e error_message = e.message.present? ? e.message : "Erreur Stripe inconnue" Rails.logger.error "Stripe checkout session creation failed: #{error_message}" flash[:alert] = "Erreur lors de la création de la session de paiement" end end end # Allow users to retry payment for failed/cancelled payments def retry_payment unless @order.can_retry_payment? redirect_to event_path(@order.event.slug, @order.event), alert: "Cette commande ne peut plus être payée" return end redirect_to order_checkout_path(@order) end # Handle successful payment def payment_success session_id = params[:session_id] # Check if Stripe is properly configured stripe_configured = Rails.application.config.stripe[:secret_key].present? Rails.logger.debug "Payment success - Stripe configured: #{stripe_configured}" unless stripe_configured redirect_to dashboard_path, alert: "Le système de paiement n'est pas correctement configuré. Veuillez contacter l'administrateur." return end begin stripe_session = Stripe::Checkout::Session.retrieve(session_id) if stripe_session.payment_status == "paid" # Get order_id from session metadata order_id = stripe_session.metadata["order_id"] unless order_id.present? redirect_to dashboard_path, alert: "Informations de commande manquantes" return end # Find and update the order @order = current_user.orders.includes(tickets: :ticket_type).find(order_id) @order.mark_as_paid! # Send confirmation emails @order.tickets.each do |ticket| TicketMailer.purchase_confirmation(ticket).deliver_now end # Clear session data session.delete(:pending_cart) session.delete(:ticket_names) session.delete(:draft_order_id) render "payment_success" else redirect_to dashboard_path, alert: "Le paiement n'a pas été complété avec succès" end rescue Stripe::StripeError => e error_message = e.message.present? ? e.message : "Erreur Stripe inconnue" redirect_to dashboard_path, alert: "Erreur lors du traitement de votre confirmation de paiement : #{error_message}" rescue => e error_message = e.message.present? ? e.message : "Erreur inconnue" Rails.logger.error "Payment success error: #{e.class} - #{error_message}" redirect_to dashboard_path, alert: "Une erreur inattendue s'est produite : #{error_message}" end end # Handle payment failure/cancellation def payment_cancel order_id = session[:draft_order_id] if order_id.present? order = current_user.orders.find_by(id: order_id, status: "draft") if order&.can_retry_payment? redirect_to order_checkout_path(order), alert: "Le paiement a été annulé. Vous pouvez réessayer." else session.delete(:draft_order_id) redirect_to dashboard_path, alert: "Le paiement a été annulé et votre commande a expiré." end else redirect_to dashboard_path, alert: "Le paiement a été annulé" end end private def set_order @order = current_user.orders.includes(:tickets, :event).find(params[:id]) rescue ActiveRecord::RecordNotFound redirect_to dashboard_path, alert: "Commande non trouvée" end def create_stripe_session line_items = @order.tickets.map do |ticket| { price_data: { currency: "eur", product_data: { name: "#{@order.event.name} - #{ticket.ticket_type.name}", description: ticket.ticket_type.description }, unit_amount: ticket.price_cents }, quantity: 1 } end Stripe::Checkout::Session.create( payment_method_types: ["card"], line_items: line_items, mode: "payment", success_url: order_payment_success_url + "?session_id={CHECKOUT_SESSION_ID}", cancel_url: order_payment_cancel_url, metadata: { order_id: @order.id, user_id: current_user.id } ) end end