From aa68885b84accb68839b4cc2d24a67e4a286e17b Mon Sep 17 00:00:00 2001 From: kbe Date: Mon, 15 Sep 2025 21:17:24 +0200 Subject: [PATCH] Add event duplication feature with ticket types cloning Co-authored-by: Qwen-Coder --- app/controllers/promoter/events_controller.rb | 13 ++++- app/models/event.rb | 27 ++++++++++ app/views/promoter/events/show.html.erb | 5 ++ config/routes.rb | 1 + .../promoter/events_controller_test.rb | 50 +++++++++++++++++++ test/models/event_test.rb | 24 +++++++++ 6 files changed, 119 insertions(+), 1 deletion(-) diff --git a/app/controllers/promoter/events_controller.rb b/app/controllers/promoter/events_controller.rb index 170fa13..9a8510e 100644 --- a/app/controllers/promoter/events_controller.rb +++ b/app/controllers/promoter/events_controller.rb @@ -5,7 +5,7 @@ class Promoter::EventsController < ApplicationController before_action :authenticate_user! before_action :ensure_can_manage_events! - before_action :set_event, only: [ :show, :edit, :update, :destroy, :publish, :unpublish, :cancel, :mark_sold_out ] + before_action :set_event, only: [ :show, :edit, :update, :destroy, :publish, :unpublish, :cancel, :mark_sold_out, :duplicate ] # Display all events for the current promoter def index @@ -93,6 +93,17 @@ class Promoter::EventsController < ApplicationController end end + # Duplicate an event and all its ticket types + def duplicate + @new_event = @event.duplicate + + if @new_event + redirect_to edit_promoter_event_path(@new_event), notice: "Événement dupliqué avec succès! Vous pouvez maintenant modifier les détails de l'événement copié." + else + redirect_to promoter_event_path(@event), alert: "Erreur lors de la duplication de l'événement." + end + end + private def ensure_can_manage_events! diff --git a/app/models/event.rb b/app/models/event.rb index 35bb3a2..9fff976 100755 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -102,6 +102,33 @@ class Event < ApplicationRecord !!allow_booking_during_event end + # Duplicate an event with all its ticket types + def duplicate + # Duplicate the event + new_event = self.dup + new_event.name = "Copie de #{name}" + new_event.slug = "#{slug}-copy-#{Time.current.to_i}" + new_event.state = :draft + new_event.created_at = Time.current + new_event.updated_at = Time.current + + Event.transaction do + if new_event.save + # Duplicate all ticket types + ticket_types.each do |ticket_type| + new_ticket_type = ticket_type.dup + new_ticket_type.event = new_event + new_ticket_type.save! + end + new_event + else + nil + end + end + rescue + nil + end + private # Determine if we should perform server-side geocoding diff --git a/app/views/promoter/events/show.html.erb b/app/views/promoter/events/show.html.erb index b87da97..b6fa621 100644 --- a/app/views/promoter/events/show.html.erb +++ b/app/views/promoter/events/show.html.erb @@ -39,6 +39,11 @@ Modifier <% end %> + <%= button_to duplicate_promoter_event_path(@event), method: :post, class: "w-full sm:w-auto inline-flex items-center justify-center px-4 py-2 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 transition-colors duration-200" do %> + + Dupliquer + <% end %> + <% if @event.draft? %> <% if @event.ticket_types.blank? %> <%= button_to publish_promoter_event_path(@event), method: :patch, disabled: true, class: "w-full sm:w-auto inline-flex items-center justify-center px-4 py-2 bg-gray-400 text-white font-medium rounded-lg cursor-not-allowed transition-colors duration-200", title: "Vous devez créer au moins un type de billet avant de publier" do %> diff --git a/config/routes.rb b/config/routes.rb index b152192..d4bf3be 100755 --- a/config/routes.rb +++ b/config/routes.rb @@ -81,6 +81,7 @@ Rails.application.routes.draw do patch :unpublish patch :cancel patch :mark_sold_out + post :duplicate end # Nested ticket types routes diff --git a/test/controllers/promoter/events_controller_test.rb b/test/controllers/promoter/events_controller_test.rb index 2a6928a..5731acf 100644 --- a/test/controllers/promoter/events_controller_test.rb +++ b/test/controllers/promoter/events_controller_test.rb @@ -26,5 +26,55 @@ class Promoter::EventsControllerTest < ActionDispatch::IntegrationTest assert_not_includes assigns(:events), other_event end + test "should duplicate an event with ticket types" do + sign_in @promoter + + # Create ticket types for the event + ticket_type1 = TicketType.create!( + name: "Standard Ticket", + description: "A standard ticket for the event with all the basic access", + price_cents: 2000, + quantity: 100, + sale_start_at: 1.day.ago, + sale_end_at: @event.start_time - 1.hour, + event: @event + ) + + ticket_type2 = TicketType.create!( + name: "VIP Ticket", + description: "A VIP ticket for the event with special access", + price_cents: 5000, + quantity: 50, + sale_start_at: 1.day.ago, + sale_end_at: @event.start_time - 1.hour, + event: @event + ) + + # Verify that ticket types were created successfully + assert ticket_type1.valid? + assert ticket_type2.valid? + + # Duplicate the event + assert_difference('Event.count', 1) do + post duplicate_promoter_event_path(@event) + end + + # Check that the new event was created + assert_redirected_to edit_promoter_event_path(Event.last) + assert_equal "Événement dupliqué avec succès! Vous pouvez maintenant modifier les détails de l'événement copié.", flash[:notice] + + # Check that the new event has the correct attributes + new_event = Event.last + assert_equal "Copie de #{@event.name}", new_event.name + assert_equal "draft", new_event.state + assert_equal @event.venue_name, new_event.venue_name + assert_equal @event.venue_address, new_event.venue_address + + # Check that ticket types were duplicated + assert_equal 2, new_event.ticket_types.count + assert_equal "Standard Ticket", new_event.ticket_types.find_by(name: "Standard Ticket").name + assert_equal "VIP Ticket", new_event.ticket_types.find_by(name: "VIP Ticket").name + end + # Add tests for new, create, etc. as needed end diff --git a/test/models/event_test.rb b/test/models/event_test.rb index 0f94404..1778fbf 100755 --- a/test/models/event_test.rb +++ b/test/models/event_test.rb @@ -271,4 +271,28 @@ class EventTest < ActiveSupport::TestCase event = Event.new assert_not event.allow_booking_during_event? end + + test "should duplicate event with ticket types" do + user = User.create!(email: "test@example.com", password: "password123", password_confirmation: "password123") + event = Event.create!(name: "Original Event", slug: "original", description: "A description that is sufficiently long", venue_name: "v", venue_address: "a", user: user, latitude: 48.0, longitude: 2.0, start_time: 1.week.from_now, state: :published) + + # Create ticket types + ticket_type1 = TicketType.create!(name: "Standard", description: "A standard ticket for the event", price_cents: 2000, quantity: 100, sale_start_at: 1.day.ago, sale_end_at: event.start_time - 1.hour, event: event) + ticket_type2 = TicketType.create!(name: "VIP", description: "A VIP ticket for the event", price_cents: 5000, quantity: 50, sale_start_at: 1.day.ago, sale_end_at: event.start_time - 1.hour, event: event) + + # Duplicate the event + duplicated_event = event.duplicate + + # Check that duplication was successful + assert_not_nil duplicated_event + assert_equal "Copie de #{event.name}", duplicated_event.name + assert_equal "draft", duplicated_event.state + assert_equal event.venue_name, duplicated_event.venue_name + assert_equal event.venue_address, duplicated_event.venue_address + + # Check that ticket types were duplicated + assert_equal 2, duplicated_event.ticket_types.count + assert_equal "Standard", duplicated_event.ticket_types.find_by(name: "Standard").name + assert_equal "VIP", duplicated_event.ticket_types.find_by(name: "VIP").name + end end