diff --git a/app/controllers/events/public_registrations_controller.rb b/app/controllers/events/public_registrations_controller.rb index 4a433d82bb..8773eb7ec4 100644 --- a/app/controllers/events/public_registrations_controller.rb +++ b/app/controllers/events/public_registrations_controller.rb @@ -15,6 +15,7 @@ def new return end + @discount_code = params[:discount_code] if @event.discount_code? && params[:discount_code].present? @form_fields = visible_form_fields @scholarship = scholarship_mode? @scholarship_form = @event.scholarship_form if @scholarship @@ -76,6 +77,8 @@ def create # events (flushed after this action) so every record it wrote is traceable. Current.form_submission_id = result.form_submission&.id + apply_discount_code(registration) + if !registration.scholarship_requested? && @event.cost_cents.to_i > 0 && credit_card_payment?(registration_params) checkout_session = create_stripe_checkout_session(registration, result.form_submission) redirect_to checkout_session.url, allow_other_host: true, status: :see_other @@ -145,6 +148,14 @@ def show private + def apply_discount_code(registration) + code = params[:discount_code].to_s.strip + return unless @event.discount_code? && code.casecmp?(@event.discount_code) + + discount = Discount.create!(amount_cents: @event.discount_amount_cents) + Allocation.create!(source: discount, allocatable: registration, amount: @event.discount_amount_cents) + end + # A file input can't be repopulated, so a form re-rendered after a validation # error carries the already-uploaded blob's signed id in retained_uploads. # An untouched file input still posts a blank value, so fall back to the @@ -170,7 +181,7 @@ def credit_card_payment?(form_params) def create_stripe_checkout_session(registration, submission = nil) person = registration.registrant - amount = @event.cost_cents + amount = registration.remaining_cost metadata = { event_registration_id: registration.id, event_id: @event.id } metadata[:form_submission_id] = submission.id if submission diff --git a/app/models/event.rb b/app/models/event.rb index 3635ffdf84..704de50eea 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -88,6 +88,7 @@ class Event < ApplicationRecord validates :hint_dates, length: { maximum: 255 } validates :hint_times, length: { maximum: 255 } validates :hint_registration_cost, length: { maximum: 255 } + validates :discount_code, format: { with: /\A[A-Za-z0-9_-]+\z/, message: "can only contain letters, numbers, hyphens, and underscores" }, allow_blank: true validate :end_date_not_before_start_date validate :registration_form_required_when_publicly_registerable, on: :update validate :staff_members_are_unique, on: :update @@ -478,6 +479,23 @@ def ce_hours_cost=(dollar_amount) end end + def discount_amount + return nil if discount_amount_cents.nil? + discount_amount_cents / 100.0 + end + + def discount_amount=(dollar_amount) + if dollar_amount.blank? + self.discount_amount_cents = nil + else + self.discount_amount_cents = (dollar_amount.to_s.gsub(/[^\d.]/, "").to_f * 100).round + end + end + + def discount_code? + discount_code.present? && discount_amount_cents.to_i > 0 + end + # An event grants CE credit when it offers a positive number of hours. Derived # from ce_hours_offered rather than a separate stored flag, so there's a single # source of truth. diff --git a/app/policies/event_policy.rb b/app/policies/event_policy.rb index 4195d502c5..c666bd8610 100644 --- a/app/policies/event_policy.rb +++ b/app/policies/event_policy.rb @@ -169,6 +169,8 @@ def google_analytics? params_filter do |params| permitted = [ :cost, + :discount_code, + :discount_amount, :created_by_id, :location_id, :title, diff --git a/app/views/events/_form.html.erb b/app/views/events/_form.html.erb index edd9b39ba9..87a6e229fe 100644 --- a/app/views/events/_form.html.erb +++ b/app/views/events/_form.html.erb @@ -137,29 +137,61 @@ +
Cost <%= f.object.errors[:cost].join(", ") %>
+ <% end %> +Cost <%= f.object.errors[:cost].join(", ") %>
- <% end %>+ Discount link: + <%= link_to new_event_public_registration_url(f.object, discount_code: f.object.discount_code), + new_event_public_registration_url(f.object, discount_code: f.object.discount_code), + class: "text-blue-600 hover:underline", target: "_blank" %> +
+(Must click save after changing the code for the link to update)
+ <% end %> +