Files
aperonight/app/controllers/orders_controller.rb
kbe 6965eb89fd fix: Only increment payment attempts when user actually attempts payment
- Remove payment attempt increment from checkout page load
- Add new increment_payment_attempt action triggered only on pay button click
- Update checkout JavaScript to make AJAX call before Stripe redirect
- Add proper error handling and button state management
- Prevent inflated payment attempt counts from page refreshes

This ensures payment attempts accurately reflect actual payment tries rather than page visits.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-02 23:16:31 +02:00

166 lines
5.5 KiB
Ruby

# 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, :increment_payment_attempt]
# 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
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
# Increment payment attempt - called via AJAX when user clicks pay button
def increment_payment_attempt
@order.increment_payment_attempt!
render json: { success: true, attempts: @order.payment_attempts }
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