diff --git a/BACKLOG.md b/BACKLOG.md index abe8eab..1cf6e4e 100755 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -8,6 +8,7 @@ ### 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 @@ -53,6 +54,7 @@ ## 🚧 Doing +- [ ] feat: Promotion code on ticket - [ ] feat: Page to display all tickets for an event - [ ] feat: Add a link into notification email to order page that display all tickets diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index 9456dd9..f6a6e29 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -126,6 +126,20 @@ class OrdersController < ApplicationController @total_amount = @order.total_amount_cents @expiring_soon = @order.expiring_soon? + # Handle promotion code application + if params[:promotion_code].present? + promotion_code = PromotionCode.valid.find_by(code: params[:promotion_code].upcase) + if promotion_code + # Apply the promotion code to the order + @order.promotion_codes << promotion_code + @order.calculate_total! + @total_amount = @order.total_amount_cents + flash.now[:notice] = "Code promotionnel appliqué: #{promotion_code.code}" + else + flash.now[:alert] = "Code promotionnel invalide" + end + end + # For free orders, automatically mark as paid and redirect to success if @order.free? @order.mark_as_paid! diff --git a/app/models/order.rb b/app/models/order.rb index 3c84bc7..bc7ff56 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -7,6 +7,8 @@ class Order < ApplicationRecord belongs_to :user belongs_to :event has_many :tickets, dependent: :destroy + has_many :order_promotion_codes, dependent: :destroy + has_many :promotion_codes, through: :order_promotion_codes # === Validations === validates :user_id, presence: true diff --git a/app/models/order_promotion_code.rb b/app/models/order_promotion_code.rb new file mode 100644 index 0000000..9effdee --- /dev/null +++ b/app/models/order_promotion_code.rb @@ -0,0 +1,26 @@ +class OrderPromotionCode < ApplicationRecord + # Associations + belongs_to :order + belongs_to :promotion_code + + # Validations + validates :order, presence: true + validates :promotion_code, presence: true + + # Callbacks + after_create :apply_discount + after_create :increment_promotion_code_uses + + private + + def apply_discount + # Apply the discount to the order + discount_amount = promotion_code.discount_amount_cents + order.update!(total_amount_cents: [ order.total_amount_cents - discount_amount, 0 ].max) + end + + def increment_promotion_code_uses + # Increment the uses count on the promotion code + promotion_code.increment!(:uses_count) + end +end diff --git a/app/models/promotion_code.rb b/app/models/promotion_code.rb new file mode 100644 index 0000000..4eb56fc --- /dev/null +++ b/app/models/promotion_code.rb @@ -0,0 +1,23 @@ +class PromotionCode < ApplicationRecord + # Validations + validates :code, presence: true, uniqueness: true + validates :discount_amount_cents, numericality: { greater_than_or_equal_to: 0 } + + # Scopes + scope :active, -> { where(active: true) } + scope :expired, -> { where("expires_at < ? OR active = ?", Time.current, false) } + scope :valid, -> { active.where("expires_at > ? OR expires_at IS NULL", Time.current) } + + # Callbacks + before_create :increment_uses_count + + # Associations + has_many :order_promotion_codes + has_many :orders, through: :order_promotion_codes + + private + + def increment_uses_count + self.uses_count ||= 0 + end +end diff --git a/app/views/orders/checkout.html.erb b/app/views/orders/checkout.html.erb index 73fd9c8..bdedda7 100644 --- a/app/views/orders/checkout.html.erb +++ b/app/views/orders/checkout.html.erb @@ -118,6 +118,16 @@

Procédez au paiement pour finaliser votre commande

+ + <%= form_tag checkout_order_path(@order), method: :get, class: "mb-6" do %> +
+ <%= text_field_tag :promotion_code, params[:promotion_code], class: "flex-1 border-none bg-transparent focus:ring-0 text-sm", placeholder: "Code promotionnel (optionnel)" %> + <%= button_tag type: "submit", class: "ml-2 btn btn-secondary py-2 px-4 text-sm" do %> + Appliquer + <% end %> +
+ <% end %> + <% if @checkout_session.present? %>
@@ -131,13 +141,13 @@
-