+ <%= render 'components/breadcrumb', crumbs: [
+ { name: 'Accueil', path: root_path },
+ { name: 'Événements', path: events_path },
+ { name: @order.event.name, path: event_path(@order.event.slug, @order.event) },
+ { name: "Commande ##{@order.id}", path: nil }
+ ] %>
-
Récapitulatif de votre commande
+
+
Récapitulatif de votre commande
<% @tickets.each do |ticket| %>
@@ -99,12 +81,46 @@
<% end %>
+
+ <% if @order.promotion_codes.any? %>
+
+ <% @order.promotion_codes.each do |promo_code| %>
+
+
+
+ Code: <%= promo_code.code %>
+
+ -<%= promo_code.discount_amount_euros %>€
+
+ <% end %>
+
+ <% end %>
+
-
+
+
+ Sous-total
+ <%= @order.subtotal_amount_euros %>€
+
+
+
+ <% if @order.discount_amount_cents > 0 %>
+
+ Réduction
+ -<%= @order.discount_amount_euros %>€
+
+ <% end %>
+
+
+
Total
- <%= @order.total_amount_euros %>€
+ <% if @order.total_amount_cents == 0 %>
+ GRATUIT
+ <% else %>
+ <%= @order.total_amount_euros %>€
+ <% end %>
TVA incluse
@@ -150,7 +166,11 @@
>
- Payer <%= @order.total_amount_euros %>€
+ <% if @order.total_amount_cents == 0 %>
+ Confirmer la commande
+ <% else %>
+ Payer <%= @order.total_amount_euros %>€
+ <% end %>
@@ -251,7 +271,11 @@ const stripeResult = await stripe.redirectToCheckout({
button.innerHTML = `
- Payer <%= @order.total_amount_euros %>€
+ <% if @order.total_amount_cents == 0 %>
+ Confirmer la commande
+ <% else %>
+ Payer <%= @order.total_amount_euros %>€
+ <% end %>
`;
alert('Erreur: ' + error.message);
diff --git a/app/views/orders/payment_success.html.erb b/app/views/orders/payment_success.html.erb
index 4bdb2f4..e0af3e2 100644
--- a/app/views/orders/payment_success.html.erb
+++ b/app/views/orders/payment_success.html.erb
@@ -123,13 +123,58 @@
<% end %>
-
-
+
+ <% if @order.promotion_codes.any? %>
+
+
+
+ Codes promotionnels appliqués
+
+ <% @order.promotion_codes.each do |promo_code| %>
+
+
+
+
+ <%= promo_code.code %>
+
+
+
-<%= promo_code.discount_amount_euros %>€
+
+ <% end %>
+
+ <% end %>
+
+
+
+
Détail du paiement
-
+
+
+ Sous-total
+ <%= @order.subtotal_amount_euros %>€
+
+
+
+ <% if @order.discount_amount_cents > 0 %>
+
+ Réduction
+ -<%= @order.discount_amount_euros %>€
+
+ <% end %>
+
+
+
Total payé
-
- <%= @order.total_amount_euros %>€
+
+ <% if @order.total_amount_cents == 0 %>
+ GRATUIT
+ <% else %>
+ <%= @order.total_amount_euros %>€
+ <% end %>
diff --git a/app/views/orders/show.html.erb b/app/views/orders/show.html.erb
index ebaf2d3..1708cf5 100644
--- a/app/views/orders/show.html.erb
+++ b/app/views/orders/show.html.erb
@@ -94,14 +94,57 @@
<% end %>
-
+
+ <% if @order.promotion_codes.any? %>
+
+
+
+ Codes promotionnels appliqués
+
+ <% @order.promotion_codes.each do |promo_code| %>
+
+
+
+
+ <%= promo_code.code %>
+
+
+
-<%= promo_code.discount_amount_euros %>€
+
+ <% end %>
+
+ <% end %>
+
+
-
+
Détail du paiement
+
+
+
+ Sous-total
+ <%= @order.subtotal_amount_euros %>€
+
+
+
+ <% if @order.discount_amount_cents > 0 %>
+
+ Réduction
+ -<%= @order.discount_amount_euros %>€
+
+ <% end %>
+
+
+
Total <%= @order.status == 'paid' || @order.status == 'completed' ? 'payé' : 'à payer' %>
- <%= @order.total_amount_euros %>€
+ <% if @order.total_amount_cents == 0 %>
+ GRATUIT
+ <% else %>
+ <%= @order.total_amount_euros %>€
+ <% end %>
+
diff --git a/app/views/pages/dashboard.html.erb b/app/views/pages/dashboard.html.erb
index 39e0612..b0942ed 100755
--- a/app/views/pages/dashboard.html.erb
+++ b/app/views/pages/dashboard.html.erb
@@ -7,11 +7,11 @@
{ name: 'Tableau de bord', path: dashboard_path }
] %>
-
+
-
Mon tableau de bord
+
Mon tableau de bord promoteur
Gérez vos commandes et accédez à vos billets
@@ -76,7 +76,9 @@
+
+ <%= link_to promoter_events_path do %>
Brouillons
@@ -86,7 +88,9 @@
-
+ <% end %>
+
+
@@ -273,6 +277,16 @@
<% end %>
+
+
+
+
+
Mon tableau de bord
+
Accédez à vos billets et évenements
+
+
+
+
diff --git a/app/views/promoter/events/show.html.erb b/app/views/promoter/events/show.html.erb
index ce0b4a1..f1dc632 100644
--- a/app/views/promoter/events/show.html.erb
+++ b/app/views/promoter/events/show.html.erb
@@ -209,6 +209,42 @@
+
+
+
Actions rapides
+
+ <%= link_to promoter_event_ticket_types_path(@event), class: "w-full inline-flex items-center justify-center px-4 py-3 bg-purple-600 text-white font-medium text-sm rounded-lg hover:bg-purple-700 transition-colors duration-200" do %>
+
+ Gérer les types de billets
+ <% end %>
+
+ <%= link_to promoter_event_promotion_codes_path(@event), class: "w-full inline-flex items-center justify-center px-4 py-3 bg-green-600 text-white font-medium text-sm rounded-lg hover:bg-green-700 transition-colors duration-200" do %>
+
+ Gérer les codes de réduction
+ <% end %>
+
+ <% if @event.sold_out? %>
+ <%= button_to mark_available_promoter_event_path(@event), method: :patch, class: "w-full inline-flex items-center justify-center px-4 py-3 bg-blue-50 text-blue-700 font-medium text-sm rounded-lg hover:bg-blue-100 transition-colors duration-200" do %>
+
+ Marquer comme disponible
+ <% end %>
+ <% elsif @event.published? %>
+ <%= button_to mark_sold_out_promoter_event_path(@event), method: :patch, class: "w-full inline-flex items-center justify-center px-4 py-3 bg-gray-50 text-gray-700 font-medium text-sm rounded-lg hover:bg-gray-100 transition-colors duration-200" do %>
+
+ Marquer comme complet
+ <% end %>
+ <% end %>
+
+
+ <%= button_to promoter_event_path(@event), method: :delete,
+ data: { confirm: "Êtes-vous sûr de vouloir supprimer cet événement ? Cette action est irréversible." },
+ class: "w-full inline-flex items-center justify-center px-4 py-3 text-red-600 font-medium text-sm rounded-lg hover:bg-red-50 transition-colors duration-200" do %>
+
+ Supprimer l'événement
+ <% end %>
+
+
+
Statistiques
@@ -269,36 +305,6 @@
-
-
-
Actions rapides
-
- <%= link_to promoter_event_ticket_types_path(@event), class: "w-full inline-flex items-center justify-center px-4 py-3 bg-purple-600 text-white font-medium text-sm rounded-lg hover:bg-purple-700 transition-colors duration-200" do %>
-
- Gérer les types de billets
- <% end %>
-
- <% if @event.sold_out? %>
- <%= button_to mark_available_promoter_event_path(@event), method: :patch, class: "w-full inline-flex items-center justify-center px-4 py-3 bg-blue-50 text-blue-700 font-medium text-sm rounded-lg hover:bg-blue-100 transition-colors duration-200" do %>
-
- Marquer comme disponible
- <% end %>
- <% elsif @event.published? %>
- <%= button_to mark_sold_out_promoter_event_path(@event), method: :patch, class: "w-full inline-flex items-center justify-center px-4 py-3 bg-gray-50 text-gray-700 font-medium text-sm rounded-lg hover:bg-gray-100 transition-colors duration-200" do %>
-
- Marquer comme complet
- <% end %>
- <% end %>
-
-
- <%= button_to promoter_event_path(@event), method: :delete,
- data: { confirm: "Êtes-vous sûr de vouloir supprimer cet événement ? Cette action est irréversible." },
- class: "w-full inline-flex items-center justify-center px-4 py-3 text-red-600 font-medium text-sm rounded-lg hover:bg-red-50 transition-colors duration-200" do %>
-
- Supprimer l'événement
- <% end %>
-
-
diff --git a/app/views/promoter/promotion_codes/edit.html.erb b/app/views/promoter/promotion_codes/edit.html.erb
index cd90cdb..2a50d69 100644
--- a/app/views/promoter/promotion_codes/edit.html.erb
+++ b/app/views/promoter/promotion_codes/edit.html.erb
@@ -54,8 +54,8 @@
- <%= form.label :discount_amount_cents, "Montant de la réduction (en euros)", class: "block text-sm font-medium text-gray-700 mb-2" %>
- <%= form.number_field :discount_amount_cents, class: "w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-colors", placeholder: "10", min: 0, step: "0.01", value: number_with_precision(@promotion_code.discount_amount_cents.to_f / 100, precision: 2) %>
+ <%= form.label :discount_amount_euros, "Montant de la réduction (en euros)", class: "block text-sm font-medium text-gray-700 mb-2" %>
+ <%= form.number_field :discount_amount_euros, class: "w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-colors", placeholder: "10", min: 0, step: "0.01", value: number_with_precision(@promotion_code.discount_amount_cents.to_f / 100, precision: 2) %>
Entrez le montant en euros (ex: 10, 5.50, 25)
diff --git a/app/views/promoter/promotion_codes/index.html.erb b/app/views/promoter/promotion_codes/index.html.erb
index ff57f9f..36dae47 100644
--- a/app/views/promoter/promotion_codes/index.html.erb
+++ b/app/views/promoter/promotion_codes/index.html.erb
@@ -51,7 +51,7 @@
- <%= link_to promotion_code.code, promoter_event_promotion_code_path(@event, promotion_code), class: "hover:text-purple-600 transition-colors" %>
+ <%= promotion_code.code %>
Réduction de <%= number_to_currency(promotion_code.discount_amount_cents / 100.0, unit: "€") %>
diff --git a/app/views/promoter/promotion_codes/new.html.erb b/app/views/promoter/promotion_codes/new.html.erb
index 039086b..2b9453a 100644
--- a/app/views/promoter/promotion_codes/new.html.erb
+++ b/app/views/promoter/promotion_codes/new.html.erb
@@ -49,14 +49,14 @@
<%= form.label :code, "Code de réduction", class: "block text-sm font-medium text-gray-700 mb-2" %>
- <%= form.text_field :code, class: "w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-colors", placeholder: "Ex: SUMMER2024, BIENVENUE10, etc." %>
-
Ce code sera visible par les clients lors du paiement
+ <%= form.text_field :code, class: "w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-colors", placeholder: "Ex: BIENVENUE10, VIP20" %>
+
Ce code sera à appliquer par le client lors du paiement.
- <%= form.label :discount_amount_cents, "Montant de la réduction (en euros)", class: "block text-sm font-medium text-gray-700 mb-2" %>
- <%= form.number_field :discount_amount_cents, class: "w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-colors", placeholder: "10", min: 0, step: "0.01", value: number_with_precision(@promotion_code.discount_amount_cents.to_f / 100, precision: 2) %>
-
Entrez le montant en euros (ex: 10, 5.50, 25)
+ <%= form.label :discount_amount_euros, "Montant de la réduction (en euros)", class: "block text-sm font-medium text-gray-700 mb-2" %>
+ <%= form.number_field :discount_amount_euros, class: "w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-colors", placeholder: "10", min: 0, step: "0.01", value: number_with_precision(@promotion_code.discount_amount_cents.to_f / 100, precision: 2) %>
+
Entrez le montant en euros
@@ -93,4 +93,4 @@
<% end %>
-
\ No newline at end of file
+
diff --git a/app/views/promoter/promotion_codes/show.html.erb b/app/views/promoter/promotion_codes/show.html.erb
deleted file mode 100644
index 69f3789..0000000
--- a/app/views/promoter/promotion_codes/show.html.erb
+++ /dev/null
@@ -1,212 +0,0 @@
-<% content_for(:title, "Code de réduction #{@promotion_code.code} - #{@event.name}") %>
-
-
-
-
- <%= render 'components/breadcrumb', crumbs: [
- { name: 'Accueil', path: root_path },
- { name: 'Tableau de bord', path: dashboard_path },
- { name: 'Mes événements', path: promoter_events_path },
- { name: @event.name, path: promoter_event_path(@event) },
- { name: 'Codes de réduction', path: promoter_event_promotion_codes_path(@event) },
- { name: @promotion_code.code }
- ] %>
-
-
-
-
- <%= link_to promoter_event_promotion_codes_path(@event), class: "text-gray-400 hover:text-gray-600 transition-colors" do %>
-
- <% end %>
-
-
Détails du code de réduction
-
- <%= @promotion_code.code %> pour <%= link_to @event.name, promoter_event_path(@event), class: "text-purple-600 hover:text-purple-800" %>
-
-
-
-
-
-
-
-
-
-
-
Informations du code
-
-
-
-
Code
-
- <%= @promotion_code.code %>
-
-
-
-
-
Statut
-
- <% if @promotion_code.active? && (promotion_code.expires_at.nil? || promotion_code.expires_at > Time.current) %>
-
-
- Actif
-
- <% elsif @promotion_code.expires_at && @promotion_code.expires_at <= Time.current %>
-
-
- Expiré
-
- <% else %>
-
-
- Inactif
-
- <% end %>
-
-
-
-
-
Montant de la réduction
-
- <%= number_to_currency(@promotion_code.discount_amount_cents / 100.0, unit: "€") %>
-
-
-
-
-
Événement
-
- <%= link_to @event.name, promoter_event_path(@event), class: "text-purple-600 hover:text-purple-800" %>
-
-
-
-
-
-
-
-
Statistiques d'utilisation
-
-
-
-
- <%= @promotion_code.uses_count %>
-
-
Utilisations
-
-
-
-
- <% if @promotion_code.usage_limit %>
- <%= @promotion_code.usage_limit - @promotion_code.uses_count %>
- <% else %>
- ∞
- <% end %>
-
-
Restants
-
-
-
-
- <%= @promotion_code.orders.count %>
-
-
Commandes
-
-
-
-
- <%= number_to_currency(@promotion_code.orders.sum(:total_amount_cents) / 100.0, unit: "€") %>
-
-
Montant total
-
-
-
-
-
- <% if @promotion_code.orders.any? %>
-
-
Commandes utilisant ce code
-
- <% @promotion_code.orders.includes(:user).order(created_at: :desc).limit(5).each do |order| %>
-
-
-
Commande #<%= order.id %>
-
- <%= order.user.email %> • <%= l(order.created_at, format: :short) %>
-
-
-
-
<%= number_to_currency(order.total_amount_cents / 100.0, unit: "€") %>
-
<%= order.status %>
-
-
- <% end %>
- <% if @promotion_code.orders.count > 5 %>
-
-
- Et <%= @promotion_code.orders.count - 5 %> autres commandes...
-
-
- <% end %>
-
-
- <% end %>
-
-
-
-
-
-
-
Informations supplémentaires
-
-
-
Créé par
-
<%= @promotion_code.user.email %>
-
-
-
Créé le
-
<%= l(@promotion_code.created_at, format: :long) %>
-
-
-
Modifié le
-
<%= l(@promotion_code.updated_at, format: :long) %>
-
- <% if @promotion_code.expires_at %>
-
-
Date d'expiration
-
<%= l(@promotion_code.expires_at, format: :long) %>
-
- <% else %>
-
-
Date d'expiration
-
Jamais
-
- <% end %>
-
-
-
-
-
-
Actions
-
- <%= link_to edit_promoter_event_promotion_code_path(@event, @promotion_code), class: "w-full inline-flex items-center justify-center px-4 py-3 bg-gray-900 text-white font-medium rounded-lg hover:bg-gray-800 transition-colors duration-200" do %>
-
- Modifier
- <% end %>
-
- <% if @promotion_code.orders.empty? %>
- <%= button_to promoter_event_promotion_code_path(@event, @promotion_code), method: :delete,
- data: { confirm: "Êtes-vous sûr de vouloir supprimer ce code de réduction ?" },
- class: "w-full inline-flex items-center justify-center px-4 py-3 text-red-600 font-medium rounded-lg hover:bg-red-50 transition-colors duration-200" do %>
-
- Supprimer
- <% end %>
- <% end %>
-
- <%= link_to promoter_event_promotion_codes_path(@event), class: "w-full inline-flex items-center justify-center px-4 py-3 border border-gray-300 text-gray-700 font-medium rounded-lg hover:bg-gray-50 transition-colors duration-200" do %>
-
- Retour à la liste
- <% end %>
-
-
-
-
-
-
\ No newline at end of file
diff --git a/config/routes.rb b/config/routes.rb
index ce1b6b6..06f050d 100755
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -91,6 +91,16 @@ Rails.application.routes.draw do
post :duplicate
end
end
+
+ # Nested promotion codes routes
+ resources :promotion_codes, except: [ :show ]
+ end
+ end
+
+ # === Promotion Codes Routes ===
+ resources :promotion_codes, only: [ :index ] do
+ member do
+ post :apply
end
end
diff --git a/db/migrate/20250823170409_create_orders.rb b/db/migrate/20250823170409_create_orders.rb
index 950ab23..45992fb 100644
--- a/db/migrate/20250823170409_create_orders.rb
+++ b/db/migrate/20250823170409_create_orders.rb
@@ -1,14 +1,15 @@
class CreateOrders < ActiveRecord::Migration[8.0]
def change
create_table :orders do |t|
- t.references :user, null: false, foreign_key: false
- t.references :event, null: false, foreign_key: false
t.string :status, null: false, default: "draft"
t.integer :total_amount_cents, null: false, default: 0
t.integer :payment_attempts, null: false, default: 0
t.timestamp :expires_at
t.timestamp :last_payment_attempt_at
+ t.references :user, null: false, foreign_key: false
+ t.references :event, null: false, foreign_key: false
+
t.timestamps
end
diff --git a/db/migrate/20250928180837_create_promotion_codes.rb b/db/migrate/20250928180837_create_promotion_codes.rb
index 95e25ec..41ecafd 100644
--- a/db/migrate/20250928180837_create_promotion_codes.rb
+++ b/db/migrate/20250928180837_create_promotion_codes.rb
@@ -7,8 +7,12 @@ class CreatePromotionCodes < ActiveRecord::Migration[8.0]
t.boolean :active, default: true, null: false
t.integer :usage_limit, default: nil
t.integer :uses_count, default: 0, null: false
- t.datetime :created_at, null: false
- t.datetime :updated_at, null: false
+
+ # Reference user(promoter) who has created the promotion code
+ t.references :user, null: false, foreign_key: true
+ t.references :event, null: false, foreign_key: true
+
+ t.timestamps
end
# Unique index for code
diff --git a/db/schema.rb b/db/schema.rb
index c47b075..ed5c678 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -44,13 +44,13 @@ ActiveRecord::Schema[8.0].define(version: 2025_09_28_181311) do
end
create_table "orders", charset: "utf8mb4", collation: "utf8mb4_uca1400_ai_ci", force: :cascade do |t|
- t.bigint "user_id", null: false
- t.bigint "event_id", null: false
t.string "status", default: "draft", null: false
t.integer "total_amount_cents", default: 0, null: false
t.integer "payment_attempts", default: 0, null: false
t.timestamp "expires_at"
t.timestamp "last_payment_attempt_at"
+ t.bigint "user_id", null: false
+ t.bigint "event_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["event_id", "status"], name: "idx_orders_event_status"
@@ -67,9 +67,13 @@ ActiveRecord::Schema[8.0].define(version: 2025_09_28_181311) do
t.boolean "active", default: true, null: false
t.integer "usage_limit"
t.integer "uses_count", default: 0, null: false
+ t.bigint "user_id", null: false
+ t.bigint "event_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["code"], name: "index_promotion_codes_on_code", unique: true
+ t.index ["event_id"], name: "index_promotion_codes_on_event_id"
+ t.index ["user_id"], name: "index_promotion_codes_on_user_id"
end
create_table "ticket_types", charset: "utf8mb4", collation: "utf8mb4_uca1400_ai_ci", force: :cascade do |t|
@@ -128,4 +132,6 @@ ActiveRecord::Schema[8.0].define(version: 2025_09_28_181311) do
add_foreign_key "order_promotion_codes", "orders"
add_foreign_key "order_promotion_codes", "promotion_codes"
+ add_foreign_key "promotion_codes", "events"
+ add_foreign_key "promotion_codes", "users"
end
diff --git a/db/seeds.rb b/db/seeds.rb
index 65565e1..09af41d 100755
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -280,3 +280,26 @@ TicketType.find_or_create_by!(event: belle_epoque_october_event, name: "Entry 10
end
puts "Created 3 additional events from Bizouk with ticket types"
+
+# Create promotion codes for events
+# Promotion code for belle_epoque_event
+PromotionCode.find_or_create_by!(code: "BELLE10") do |pc|
+ pc.discount_amount_cents = 1000 # 10€ discount
+ pc.expires_at = belle_epoque_event.start_time + 1.day
+ pc.active = true
+ pc.usage_limit = 20
+ pc.user = promoter
+ pc.event = belle_epoque_october_event
+end
+
+# Promotion code for belle_epoque_october_event
+PromotionCode.find_or_create_by!(code: "OCTOBRE5") do |pc|
+ pc.discount_amount_cents = 500 # 5€ discount
+ pc.expires_at = belle_epoque_october_event.start_time + 1.day
+ pc.active = true
+ pc.usage_limit = 30
+ pc.user = promoter
+ pc.event = belle_epoque_october_event
+end
+
+puts "Created promotion codes for events"