From 87ccebf229c038ed077698c6a22c845f24bbe05a Mon Sep 17 00:00:00 2001 From: kbe Date: Mon, 29 Sep 2025 15:25:52 +0200 Subject: [PATCH] feat(promotion code): Promotion code system done I added the features for users to use promotion code and for promoters to create on their events. May be rewrite to discount code? --- BACKLOG.md | 1 - .../promoter/promotion_codes_controller.rb | 82 +++++++ app/models/event.rb | 1 + app/models/order.rb | 28 ++- app/models/promotion_code.rb | 19 ++ app/views/orders/checkout.html.erb | 86 ++++--- app/views/orders/payment_success.html.erb | 55 ++++- app/views/orders/show.html.erb | 49 +++- app/views/pages/dashboard.html.erb | 20 +- app/views/promoter/events/show.html.erb | 66 +++--- .../promoter/promotion_codes/edit.html.erb | 4 +- .../promoter/promotion_codes/index.html.erb | 2 +- .../promoter/promotion_codes/new.html.erb | 12 +- .../promoter/promotion_codes/show.html.erb | 212 ------------------ config/routes.rb | 10 + db/migrate/20250823170409_create_orders.rb | 5 +- .../20250928180837_create_promotion_codes.rb | 8 +- db/schema.rb | 10 +- db/seeds.rb | 23 ++ 19 files changed, 391 insertions(+), 302 deletions(-) create mode 100644 app/controllers/promoter/promotion_codes_controller.rb delete mode 100644 app/views/promoter/promotion_codes/show.html.erb diff --git a/BACKLOG.md b/BACKLOG.md index 1cf6e4e..fe3794b 100755 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -8,7 +8,6 @@ ### Medium Priority -- [ ] feat: Promotion code on ticket - [ ] feat: Promoter system with event creation, ticket types creation and metrics display - [ ] feat: Multiple ticket types (early bird, VIP, general admission) - [ ] feat: Refund management system diff --git a/app/controllers/promoter/promotion_codes_controller.rb b/app/controllers/promoter/promotion_codes_controller.rb new file mode 100644 index 0000000..c168923 --- /dev/null +++ b/app/controllers/promoter/promotion_codes_controller.rb @@ -0,0 +1,82 @@ +class Promoter::PromotionCodesController < ApplicationController + before_action :authenticate_user! + before_action :set_event + before_action :set_promotion_code, only: [ :edit, :update, :destroy ] + + # GET /promoter/events/:event_id/promotion_codes + # Display all promotion codes for a specific event + def index + @promotion_codes = @event.promotion_codes.includes(:user) + end + + + # GET /promoter/events/:event_id/promotion_codes/new + # Show form to create a new promotion code + def new + @promotion_code = @event.promotion_codes.new + end + + # GET /promoter/events/:event_id/promotion_codes/:id/edit + # Show form to edit an existing promotion code + def edit + end + + # POST /promoter/events/:event_id/promotion_codes + # Create a new promotion code for the event + def create + @promotion_code = @event.promotion_codes.new(promotion_code_params_with_conversion) + @promotion_code.user = current_user + + if @promotion_code.save + redirect_to promoter_event_promotion_codes_path(@event), notice: "Promotion code was successfully created." + else + render :new, status: :unprocessable_entity + end + end + + # PATCH/PUT /promoter/events/:event_id/promotion_codes/:id + # Update an existing promotion code + def update + if @promotion_code.update(promotion_code_params_with_conversion) + redirect_to promoter_event_promotion_codes_path(@event), notice: "Promotion code was successfully updated." + else + render :edit, status: :unprocessable_entity + end + end + + # DELETE /promoter/events/:event_id/promotion_codes/:id + # Delete a promotion code + def destroy + @promotion_code.destroy + redirect_to promoter_event_promotion_codes_path(@event), notice: "Promotion code was successfully destroyed." + end + + private + + # Find the event based on the URL parameter + def set_event + @event = Event.find(params[:event_id]) + end + + # Find the promotion code based on the URL parameter + def set_promotion_code + @promotion_code = @event.promotion_codes.find(params[:id]) + end + + # Strong parameters for promotion code form (accepts euros for display) + def promotion_code_params + params.require(:promotion_code).permit(:code, :discount_amount_euros, :expires_at, :active, :usage_limit) + end + + # Convert euros to cents for database storage + # The form displays euros for user convenience, but the database stores cents + def promotion_code_params_with_conversion + params = promotion_code_params + if params[:discount_amount_euros].present? + # Convert euros to cents (e.g., 20.50 -> 2050) + params[:discount_amount_cents] = (params[:discount_amount_euros].to_f * 100).to_i + params.delete(:discount_amount_euros) # Remove the temporary euro parameter + end + params + end +end diff --git a/app/models/event.rb b/app/models/event.rb index 2fa5daa..9dd32d5 100755 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -21,6 +21,7 @@ class Event < ApplicationRecord has_many :ticket_types has_many :tickets, through: :ticket_types has_many :orders + has_many :promotion_codes # === Callbacks === before_validation :geocode_address, if: :should_geocode_address? diff --git a/app/models/order.rb b/app/models/order.rb index bc7ff56..aea6182 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -90,10 +90,34 @@ class Order < ApplicationRecord end end - # Calculate total from ticket prices only (platform fee deducted from promoter payout) + # Calculate total from ticket prices minus promotion code discounts def calculate_total! ticket_total = tickets.sum(:price_cents) - update!(total_amount_cents: ticket_total) + discount_total = promotion_codes.sum(:discount_amount_cents) + + # Ensure total doesn't go below zero + final_total = [ticket_total - discount_total, 0].max + update!(total_amount_cents: final_total) + end + + # Subtotal amount before discounts + def subtotal_amount_cents + tickets.sum(:price_cents) + end + + # Subtotal amount in euros + def subtotal_amount_euros + subtotal_amount_cents / 100.0 + end + + # Total discount amount from all promotion codes + def discount_amount_cents + promotion_codes.sum(:discount_amount_cents) + end + + # Discount amount in euros + def discount_amount_euros + discount_amount_cents / 100.0 end # Platform fee: €0.50 fixed + 1.5% of ticket price, per ticket diff --git a/app/models/promotion_code.rb b/app/models/promotion_code.rb index 4eb56fc..a48604e 100644 --- a/app/models/promotion_code.rb +++ b/app/models/promotion_code.rb @@ -12,9 +12,28 @@ class PromotionCode < ApplicationRecord before_create :increment_uses_count # Associations + belongs_to :user + belongs_to :event has_many :order_promotion_codes has_many :orders, through: :order_promotion_codes + # Instance methods + def discount_amount_euros + discount_amount_cents / 100.0 + end + + def active? + active && (expires_at.nil? || expires_at > Time.current) + end + + def expired? + expires_at.present? && expires_at < Time.current + end + + def can_be_used? + active? && (usage_limit.nil? || uses_count < usage_limit) + end + private def increment_uses_count diff --git a/app/views/orders/checkout.html.erb b/app/views/orders/checkout.html.erb index bdedda7..20770df 100644 --- a/app/views/orders/checkout.html.erb +++ b/app/views/orders/checkout.html.erb @@ -1,30 +1,12 @@
-
+
- + <%= 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 } + ] %>
@@ -77,8 +59,8 @@
-
-

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"