effective_events 0.19.2 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/effective_events/base.js +32 -0
  3. data/app/controllers/effective/event_registrants_select2_ajax_controller.rb +61 -0
  4. data/app/controllers/effective/event_registrations_controller.rb +17 -1
  5. data/app/datatables/effective_event_registrants_datatable.rb +11 -11
  6. data/app/datatables/effective_event_registrations_datatable.rb +2 -1
  7. data/app/helpers/effective_events_helper.rb +2 -19
  8. data/app/mailers/effective/events_mailer.rb +1 -1
  9. data/app/models/concerns/effective_events_event_registration.rb +141 -51
  10. data/app/models/effective/event.rb +32 -12
  11. data/app/models/effective/event_notification.rb +1 -1
  12. data/app/models/effective/event_registrant.rb +171 -45
  13. data/app/models/effective/event_ticket.rb +20 -17
  14. data/app/models/effective/event_ticket_selection.rb +28 -0
  15. data/app/views/admin/event_registrants/_form.html.haml +16 -3
  16. data/app/views/admin/event_tickets/_form.html.haml +1 -1
  17. data/app/views/effective/event_registrants/_fields.html.haml +47 -28
  18. data/app/views/effective/event_registrations/_details.html.haml +1 -0
  19. data/app/views/effective/event_registrations/_fields_event_registrants.html.haml +26 -0
  20. data/app/views/effective/event_registrations/_fields_event_ticket_selections.html.haml +85 -0
  21. data/app/views/effective/event_registrations/_form_blank_registrants.html.haml +12 -14
  22. data/app/views/effective/event_registrations/_layout.html.haml +9 -1
  23. data/app/views/effective/event_registrations/billing.html.haml +1 -1
  24. data/app/views/effective/event_registrations/details.html.haml +10 -0
  25. data/app/views/effective/event_registrations/summary.html.haml +2 -2
  26. data/app/views/effective/event_registrations/tickets.html.haml +3 -13
  27. data/app/views/effective/events/show.html.haml +34 -34
  28. data/config/effective_events.rb +11 -4
  29. data/config/routes.rb +5 -0
  30. data/db/migrate/101_create_effective_events.rb +16 -1
  31. data/lib/effective_events/version.rb +1 -1
  32. data/lib/effective_events.rb +6 -4
  33. metadata +8 -7
  34. data/app/views/effective/event_registrants/_fields_member_only.html.haml +0 -10
  35. data/app/views/effective/event_registrants/_fields_member_or_non_member.html.haml +0 -34
  36. data/app/views/effective/event_registrants/_fields_questions.html.haml +0 -8
  37. data/app/views/effective/event_registrants/_fields_regular.html.haml +0 -8
  38. data/app/views/effective/event_registrations/_event_tickets.html.haml +0 -68
@@ -2,10 +2,13 @@
2
2
 
3
3
  module Effective
4
4
  class EventRegistrant < ActiveRecord::Base
5
+ include ActionView::Helpers::TagHelper
6
+
5
7
  self.table_name = (EffectiveEvents.event_registrants_table_name || :event_registrants).to_s
6
8
 
7
- PERMITTED_BLANK_REGISTRANT_CHANGES = ["first_name", "last_name", "email", "company", "user_id", "user_type", "blank_registrant", "member_or_non_member_choice", "response1", "response2", "response3"]
8
- MEMBER_OR_NON_MEMBER_CHOICES = ['Add a regular registration', 'Add a member registration']
9
+ PERMITTED_BLANK_REGISTRANT_CHANGES = ["first_name", "last_name", "email", "company", "user_id", "user_type", "organization_id", "organization_type", "blank_registrant", "response1", "response2", "response3"]
10
+
11
+ attr_accessor :building_user_and_organization
9
12
 
10
13
  acts_as_purchasable
11
14
  acts_as_archived
@@ -14,7 +17,7 @@ module Effective
14
17
 
15
18
  belongs_to :event, counter_cache: true
16
19
 
17
- # Basically a category containing all the pricing and unique info about htis registrant
20
+ # Basically a category containing all the pricing and unique info about this registrant
18
21
  belongs_to :event_ticket
19
22
 
20
23
  # Every event registrant is charged to a owner
@@ -23,20 +26,26 @@ module Effective
23
26
  # This fee when checked out through the event registration
24
27
  belongs_to :event_registration, polymorphic: true, optional: true
25
28
 
26
- # Required for member-only tickets. The user attending.
29
+ # The user for this registrant
27
30
  belongs_to :user, polymorphic: true, optional: true
31
+ accepts_nested_attributes_for :user
32
+
33
+ # The organization for this registrant
34
+ belongs_to :organization, polymorphic: true, optional: true
35
+ accepts_nested_attributes_for :organization
28
36
 
29
37
  effective_resource do
30
38
  first_name :string
31
39
  last_name :string
32
40
  email :string
33
- company :string
41
+ company :string # Organization name
34
42
 
35
- blank_registrant :boolean
36
- member_or_non_member_choice :string # Used by Member or Non-Member tickets to indicate a member or non-member
43
+ blank_registrant :boolean # Leave details and come back later
37
44
 
38
45
  waitlisted :boolean
39
46
  promoted :boolean # An admin marked this registrant as promoted from the waitlist
47
+
48
+ selected_at :datetime # When the event registration was selected by a user on the tickets! step
40
49
  registered_at :datetime # When the order is deferred or purchased
41
50
 
42
51
  # Question Responses
@@ -58,7 +67,7 @@ module Effective
58
67
  timestamps
59
68
  end
60
69
 
61
- scope :sorted, -> { order(:last_name) }
70
+ scope :sorted, -> { order(:event_ticket_id, :id) }
62
71
  scope :deep, -> { includes(:event, :event_ticket, :owner) }
63
72
  scope :registered, -> { where.not(registered_at: nil) }
64
73
 
@@ -67,12 +76,31 @@ module Effective
67
76
  self.owner ||= event_registration.owner
68
77
  end
69
78
 
70
- before_validation(if: -> { blank_registrant? }) do
71
- assign_attributes(user: nil, first_name: nil, last_name: nil, email: nil, company: nil)
72
- end
79
+ with_options(unless: -> { purchased? && !blank_registrant_was }) do
80
+ before_validation(if: -> { blank_registrant? }) do
81
+ assign_attributes(user: nil, organization: nil, first_name: nil, last_name: nil, email: nil, company: nil)
82
+ end
83
+
84
+ before_validation(if: -> { user.blank? }) do
85
+ assign_attributes(building_user_and_organization: true) # For member-only ticket validations
86
+ end
73
87
 
74
- before_validation(if: -> { user.present? }) do
75
- assign_attributes(first_name: user.first_name, last_name: user.last_name, email: user.email)
88
+ before_validation(if: -> { user.blank? && first_name.present? && last_name.present? && email.present? }) do
89
+ build_user() if EffectiveEvents.create_users
90
+ build_organization_and_representative() if EffectiveEvents.organization_enabled?
91
+ end
92
+
93
+ before_validation(if: -> { user.present? }) do
94
+ assign_attributes(first_name: user.first_name, last_name: user.last_name, email: (user.try(:public_email).presence || user.email))
95
+ end
96
+
97
+ before_validation(if: -> { organization.blank? && user.present? && user.class.try(:effective_memberships_organization_user?) }) do
98
+ assign_attributes(company: user.organizations.first.to_s.presence) if company.blank?
99
+ end
100
+
101
+ before_validation(if: -> { organization.present? }) do
102
+ assign_attributes(company: organization.to_s)
103
+ end
76
104
  end
77
105
 
78
106
  before_validation(if: -> { event_ticket.present? }, unless: -> { purchased? }) do
@@ -83,35 +111,44 @@ module Effective
83
111
  errors.add(:waitlisted, 'is not permitted for a non-waitlist event ticket') if waitlisted? && !event_ticket.waitlist?
84
112
  end
85
113
 
86
- validates :user_id, uniqueness: { scope: [:event_id], allow_blank: true, message: 'is already registered for this event' }
87
114
  validates :price, presence: true, numericality: { greater_than_or_equal_to: 0 }
88
115
  validates :email, email: true
89
116
 
90
- # Member Only Ticket
91
- with_options(if: -> { event_ticket&.member_only? && present_registrant? }) do
92
- validates :user_id, presence: { message: 'Please select a member' }
93
- end
117
+ # This works for persisted and adding a new one. But not adding two at same time in a registration
118
+ validates :user_id, uniqueness: { scope: [:event_id], allow_blank: true, message: 'is already registered for this event' }
119
+
120
+ # First name, last name and email are always required fields on details
121
+ validates :first_name, presence: true, if: -> { registrant_validations_enabled? }
122
+ validates :last_name, presence: true, if: -> { registrant_validations_enabled? }
123
+ validates :email, presence: true, if: -> { registrant_validations_enabled? }
124
+
125
+ # User, company and organization conditionall required
126
+ validates :user, presence: true, if: -> { registrant_validations_enabled? && EffectiveEvents.create_users }
127
+ validates :company, presence: true, if: -> { registrant_validations_enabled? && EffectiveEvents.company_or_organization_required }
128
+ validates :organization, presence: true, if: -> { registrant_validations_enabled? && EffectiveEvents.company_or_organization_required && EffectiveEvents.organization_enabled? }
94
129
 
95
- # Regular Ticket
96
- with_options(if: -> { event_ticket&.regular? && present_registrant? }) do
97
- validates :first_name, presence: true, unless: -> { EffectiveEvents.event_registrant_required_fields.exclude?(:first_name) }
98
- validates :last_name, presence: true, unless: -> { EffectiveEvents.event_registrant_required_fields.exclude?(:last_name) }
99
- validates :email, presence: true, unless: -> { EffectiveEvents.event_registrant_required_fields.exclude?(:email) }
100
- validates :company, presence: true, unless: -> { EffectiveEvents.event_registrant_required_fields.exclude?(:company) }
130
+ # Member ticket: company name is locked in. you can only add to your own company
131
+ validate(if: -> { registrant_validations_enabled? && event_ticket&.member_only? }) do
132
+ if building_user_and_organization && owner.present? && Array(owner.try(:organizations)).exclude?(organization)
133
+ errors.add(:organization_id, "must be your own for member-only tickets")
134
+ end
135
+
136
+ errors.add(:user_id, 'must be a member to register for member-only tickets') unless member_present?
101
137
  end
102
138
 
103
- # Member or Non-Member Ticket
104
- validates :member_or_non_member_choice, presence: true, if: -> { event_ticket&.member_or_non_member? && present_registrant? }
139
+ # Copy any user errors from build_user_and_organization() into the registrant
140
+ after_validation(if: -> { user && user.new_record? && user.errors.present? }) do
141
+ errors.add(:first_name, user.errors[:first_name].join(', ')) if user.errors[:first_name].present?
142
+ errors.add(:last_name, user.errors[:last_name].join(', ')) if user.errors[:last_name].present?
143
+ errors.add(:email, user.errors[:email].join(', ')) if user.errors[:email].present?
105
144
 
106
- with_options(if: -> { event_ticket&.member_or_non_member? && present_registrant? && member_or_non_member_choice == 'Add a regular registration' }) do
107
- validates :first_name, presence: true, unless: -> { EffectiveEvents.event_registrant_required_fields.exclude?(:first_name) }
108
- validates :last_name, presence: true, unless: -> { EffectiveEvents.event_registrant_required_fields.exclude?(:last_name) }
109
- validates :email, presence: true, unless: -> { EffectiveEvents.event_registrant_required_fields.exclude?(:email) }
110
- validates :company, presence: true, unless: -> { EffectiveEvents.event_registrant_required_fields.exclude?(:company) }
145
+ others = user.errors.reject { |error| [:first_name, :last_name, :email].include?(error.attribute) }
146
+ errors.add(:base, others.map(&:full_message).join(', ')) if others.present?
111
147
  end
112
148
 
113
- with_options(if: -> { event_ticket&.member_or_non_member? && present_registrant? && member_or_non_member_choice == 'Add a member registration' }) do
114
- validates :user_id, presence: { message: 'Please select a member' }
149
+ # Copy any organization errors from build_user_and_organization() into the registrant
150
+ after_validation(if: -> { organization && organization.new_record? && organization.errors.present? }) do
151
+ errors.add(:company, organization.errors.full_messages.join(', '))
115
152
  end
116
153
 
117
154
  after_defer do
@@ -127,7 +164,7 @@ module Effective
127
164
  end
128
165
 
129
166
  def title
130
- [event_ticket.to_s, name, ('WAITLIST' if waitlisted_not_promoted?)].compact.join(' - ')
167
+ ["#{event_ticket} - #{name}", details.presence].compact.join(' ').html_safe
131
168
  end
132
169
 
133
170
  def name
@@ -140,20 +177,42 @@ module Effective
140
177
  end
141
178
  end
142
179
 
180
+ def details
181
+ [
182
+ (content_tag(:span, 'Member', class: 'badge badge-warning') if member_ticket?),
183
+ (content_tag(:span, 'Waitlist', class: 'badge badge-warning') if waitlisted_not_promoted?),
184
+ (content_tag(:span, 'Archived', class: 'badge badge-warning') if event_ticket&.archived?)
185
+ ].compact.join(' ').html_safe
186
+ end
187
+
188
+ def purchasable_name
189
+ ["#{event_ticket} - #{name}", details.presence].compact.join('<br>').html_safe
190
+ end
191
+
143
192
  def last_first_name
144
- first_name.present? ? "#{last_name}, #{first_name}" : "GUEST"
193
+ (first_name.present? && last_name.present?) ? "#{last_name}, #{first_name}" : "GUEST"
145
194
  end
146
195
 
147
- def member_present?
148
- user&.is?(:member)
196
+ # We create registrants on the tickets step. But don't enforce validations until the details step.
197
+ def registrant_validations_enabled?
198
+ return false if blank_registrant? # They want to come back later
199
+
200
+ return true if event_registration.blank? # If we're creating in an Admin area
201
+ return false if event_ticket.blank? # Invalid anyway
202
+
203
+ event_registration.current_step == :details
149
204
  end
150
205
 
151
- def member_or_non_member_choice
152
- self[:member_or_non_member_choice] || 'Add a regular registration'
206
+ def member_present?
207
+ user.try(:is?, :member) || organization.try(:is?, :member)
153
208
  end
154
209
 
155
- def member_email
156
- email.presence || user&.email
210
+ def member_ticket?
211
+ return false if event_ticket.blank?
212
+ return true if event_ticket.member_only?
213
+ return true if event_ticket.member_or_non_member? && member_present?
214
+
215
+ false
157
216
  end
158
217
 
159
218
  def present_registrant?
@@ -168,10 +227,19 @@ module Effective
168
227
  event_ticket&.qb_item_name
169
228
  end
170
229
 
230
+ def selected?
231
+ selected_at.present?
232
+ end
233
+
171
234
  def registered?
172
235
  registered_at.present?
173
236
  end
174
237
 
238
+ def selected_not_expired?
239
+ return false unless EffectiveEvents.EventRegistration.selection_window.present?
240
+ selected_at.present? && (selected_at + EffectiveEvents.EventRegistration.selection_window > Time.zone.now)
241
+ end
242
+
175
243
  # Called by an event_registration after_defer and after_purchase
176
244
  def registered!
177
245
  self.registered_at ||= Time.zone.now
@@ -219,10 +287,6 @@ module Effective
219
287
  true
220
288
  end
221
289
 
222
- def registered?
223
- registered_at.present?
224
- end
225
-
226
290
  def event_ticket_price
227
291
  raise('expected an event') if event.blank?
228
292
  raise('expected an event ticket') if event_ticket.blank?
@@ -246,6 +310,68 @@ module Effective
246
310
 
247
311
  private
248
312
 
313
+ def build_user
314
+ raise('is already purchased') if purchased?
315
+ raise('expected no user') unless user.blank?
316
+ raise('expected a first_name') unless first_name.present?
317
+ raise('expected a last_name') unless last_name.present?
318
+ raise('expected a email') unless email.present?
319
+
320
+ return if user_type.blank?
321
+
322
+ # Add User
323
+ user_klass = user_type.constantize
324
+
325
+ # First we lookup the user by email. If they actually exist we ignore all other fields
326
+ existing_user = user_klass.find_by_any_email(email.strip.downcase)
327
+
328
+ if existing_user.present?
329
+ assign_attributes(user: existing_user)
330
+
331
+ if EffectiveEvents.organization_enabled? && user_klass.try(:effective_memberships_organization_user?)
332
+ assign_attributes(organization: existing_user.organizations.first) if existing_user.organizations.present?
333
+ end
334
+ else
335
+ # Otherwise create a new user
336
+ new_user = user_klass.create(
337
+ first_name: first_name.strip,
338
+ last_name: last_name.strip,
339
+ email: email.strip.downcase,
340
+ password: SecureRandom.base64(12) + '!@#123abcABC-'
341
+ )
342
+
343
+ assign_attributes(user: new_user)
344
+ end
345
+
346
+ user.valid?
347
+ end
348
+
349
+ # The organization might already be set here
350
+ def build_organization_and_representative
351
+ raise('is already purchased') if purchased?
352
+
353
+ return if organization_type.blank?
354
+
355
+ # We previously created an invalid user
356
+ return if user.present? && user.errors.present?
357
+
358
+ # Add Organization and representative
359
+ organization_klass = organization_type.constantize
360
+
361
+ # Find or create the organization
362
+ if organization.present?
363
+ user.build_representative(organization: organization) if user.present?
364
+ elsif company.present?
365
+ new_organization = organization_klass.where(title: company.strip).first
366
+ new_organization ||= organization_klass.create(title: company.strip, email: email.strip.downcase)
367
+ assign_attributes(organization: new_organization)
368
+
369
+ user.build_representative(organization: new_organization) if user.present?
370
+ end
371
+
372
+ true
373
+ end
374
+
249
375
  def assign_price
250
376
  raise('is already purchased') if purchased?
251
377
 
@@ -69,35 +69,38 @@ module Effective
69
69
  validates :early_bird_price, numericality: { greater_than_or_equal_to: 0, allow_blank: true }
70
70
 
71
71
  validates :capacity, numericality: { greater_than_or_equal_to: 0, allow_blank: true }
72
+ validates :capacity, presence: { message: 'must be present when using the waitlist'}, if: -> { waitlist? }
72
73
 
73
74
  def to_s
74
75
  title.presence || 'New Event Ticket'
75
76
  end
76
77
 
77
- # This is supposed to be an indempotent big update the world thing
78
- def update_waitlist!
79
- return false unless waitlist?
78
+ def capacity_selectable(except: nil)
79
+ return nil if capacity.blank?
80
+ return nil if waitlist?
80
81
 
81
- changed_event_registrants = registered_event_registrants.each_with_index.map do |event_registrant, index|
82
- next if event_registrant.purchased?
82
+ capacity_available(except: except)
83
+ end
83
84
 
84
- waitlisted_was = event_registrant.waitlisted?
85
- waitlisted = (waitlist? && index >= capacity)
86
- next if waitlisted == waitlisted_was
85
+ def capacity_available(except: nil)
86
+ return nil if capacity.blank?
87
+ [(capacity - capacity_taken(except: except)), 0].max
88
+ end
87
89
 
88
- event_registrant.update!(waitlisted: waitlisted) # Updates price
89
- event_registrant
90
- end.compact
90
+ def capacity_taken(except: nil)
91
+ registered_or_selected_event_registrants(except: except).reject(&:waitlisted?).length
92
+ end
91
93
 
92
- orders = changed_event_registrants.flat_map { |event_registrant| event_registrant.deferred_orders }.compact.uniq
93
- orders.each { |order| order.update_purchasable_attributes! }
94
+ def registered_or_selected_event_registrants(except: nil)
95
+ raise('expected except to be an EventRegistration') if except && !except.class.try(:effective_events_event_registration?)
94
96
 
95
- true
97
+ event_registrants.select do |er|
98
+ (er.registered? || er.selected_not_expired?) && (except.blank? || er.event_registration_id != except.id)
99
+ end
96
100
  end
97
101
 
98
- def capacity_available
99
- return nil if capacity.blank?
100
- [(capacity - registered_event_registrants_count), 0].max
102
+ def registered_or_selected_event_registrants_count
103
+ registered_or_selected_event_registrants.count
101
104
  end
102
105
 
103
106
  def registered_event_registrants_count
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Form object to select a # of tickets on the EventRegistration form
4
+
5
+ module Effective
6
+ class EventTicketSelection < ActiveRecord::Base
7
+ self.table_name = (EffectiveEvents.event_ticket_selections_table_name || :event_ticket_selections).to_s
8
+
9
+ belongs_to :event_registration, polymorphic: true
10
+ belongs_to :event_ticket
11
+
12
+ effective_resource do
13
+ quantity :integer
14
+
15
+ timestamps
16
+ end
17
+
18
+ scope :sorted, -> { order(:id) }
19
+ scope :deep, -> { includes(:event_registration, :event_ticket) }
20
+
21
+ validates :quantity, numericality: { greater_than_or_equal_to: 0 }
22
+
23
+ def to_s
24
+ persisted? ? "#{quantity}x #{event_ticket}": model_name.human
25
+ end
26
+
27
+ end
28
+ end
@@ -9,10 +9,10 @@
9
9
  - if f.object.new_record?
10
10
  -# User
11
11
  - klass = (f.object.owner || current_user).class
12
- - ajax_url = (@select2_users_ajax_path || effective_resources.users_admin_select2_ajax_index_path) unless Rails.env.test?
12
+ - ajax_url = (effective_resources.users_admin_select2_ajax_index_path unless Rails.env.test?)
13
13
 
14
14
  = f.hidden_field :owner_type, value: klass.name
15
- = f.select :owner_id, klass.all, ajax_url: ajax_url, label: 'User'
15
+ = f.select :owner_id, klass.all, ajax_url: ajax_url, label: 'Registration User'
16
16
  - else
17
17
  = f.static_field :owner
18
18
 
@@ -20,7 +20,20 @@
20
20
 
21
21
  #effective-events-event-registrant-ajax
22
22
  - if f.object.event.present?
23
- = render 'effective/event_registrants/fields', f: f, event: event_registrant.event, namespace: :admin
23
+ .card
24
+ .card-body
25
+ - if f.object.purchased?
26
+ = f.static_field :event_ticket, label: 'Purchased ticket'
27
+
28
+ = f.select :event_ticket_id, effective_events_event_tickets_collection(f.object.event, namespace), required: true
29
+
30
+ - if f.object.event.allow_blank_registrants? && (f.object.new_record? || f.object.blank_registrant?)
31
+ = f.check_box :blank_registrant, label: "I will return and add this ticket's information later"
32
+ - else
33
+ = f.hidden_field :blank_registrant, value: false
34
+
35
+ = f.show_if(:blank_registrant, false) do
36
+ = render('effective/event_registrants/fields', f: f)
24
37
 
25
38
  = f.check_box :archived, label: "Archive this registrant. It will be displayed as archived on the owner's event registration"
26
39
 
@@ -11,7 +11,7 @@
11
11
  = f.show_if(:category, 'Regular') do
12
12
  .alert.alert-info.mb-4
13
13
  %strong Regular Ticket:
14
- Anyone will be able to purchase this ticket. They will be asked for a first and last name. Will not display the dropdown list of all members. Only the regular price applies.
14
+ Anyone will be able to purchase this ticket. Only the regular price applies.
15
15
 
16
16
  = f.show_if(:category, 'Member Only') do
17
17
  .alert.alert-info.mb-4
@@ -1,33 +1,52 @@
1
- .card.mb-4
2
- .card-body
3
- - if f.object.purchased?
4
- = f.static_field :event_ticket, label: 'Purchased ticket'
5
- - else
6
- = f.select :event_ticket_id, effective_events_event_tickets_collection(event, namespace), label: 'Ticket'
7
-
8
- - if f.object.purchased? && namespace == :admin
9
- = f.select :event_ticket_id, effective_events_event_tickets_collection(event, namespace), label: 'Change Ticket', hint: 'Admin only. Change the purchased ticket. This will not create charges, alter the original order, or consider ticket capacity.'
10
-
11
- - event.event_tickets.each do |ticket|
12
- - next if ticket.member_only? && !current_user&.is?(:member)
13
-
14
- = f.show_if(:event_ticket_id, ticket.id) do
15
- - if event.allow_blank_registrants? && (f.object.new_record? || f.object.blank_registrant?)
16
- = f.check_box :blank_registrant, label: "I will return and add this ticket's information later"
1
+ .event-registrant-user-fields
2
+ - user_klass = (f.object.user || current_user).class
3
+ - ajax_url = (effective_events.users_event_registrants_select2_ajax_index_path unless Rails.env.test?)
4
+ - disabled = (f.object.user.present? && f.object.user.persisted? && f.object.user.errors.blank?)
5
+ - event_ticket = f.object.event_ticket
6
+
7
+ = f.hidden_field :user_type, value: user_klass.name
8
+
9
+ = f.select :user_id, user_klass.all, ajax_url: ajax_url, label: "Quick add", placeholder: "Search by name, email, or company",
10
+ hint: "Can't find someone? Add their details below.", input_js: { minimumInputLength: 1 }, 'data-event-registrant-user-search': true
11
+
12
+ .row
13
+ .col-md= f.text_field :first_name, input_html: { disabled: disabled }
14
+ .col-md= f.text_field :last_name, input_html: { disabled: disabled }
15
+
16
+ .row
17
+ .col-md= f.email_field :email, input_html: { disabled: disabled }
18
+ .col-md
19
+ = f.hidden_field :organization_type
20
+ = f.hidden_field :organization_id
21
+
22
+ - if EffectiveEvents.organization_enabled? == false
23
+ = f.text_field :company, input_html: { disabled: disabled }
24
+
25
+ - if EffectiveEvents.organization_enabled?
26
+ = f.hidden_field :organization_type, value: EffectiveMemberships.Organization.name
27
+
28
+ - organizations = EffectiveMemberships.Organization.sorted.all
29
+
30
+ - if event_ticket&.member_only?
31
+ - organization_id = (f.object.event_registration&.owner || current_user).try(:organizations).try(:first).try(:id)
32
+
33
+ = f.select :organization_id, organizations, label: organization_label, placeholder: 'Search by name', input_html: { disabled: disabled },
34
+ input_js: { minimumInputLength: 1 },
35
+ hint: "You can only add new members to your own #{organization_label.downcase}",
36
+ value: (organization_id if organization_id && f.object.organization_id.blank?)
17
37
  - else
18
- = f.hidden_field :blank_registrant, value: false
38
+ - # This creates a select field organization_id and a text field company
39
+ = f.select_or_text :organization_id, :company, organizations, name: organization_label.downcase, input_html: { disabled: disabled },
40
+ text: { label: "#{organization_label} name", placeholder: "New #{organization_label.downcase} name" },
41
+ select: { label: organization_label, placeholder: 'Search by name', input_js: { minimumInputLength: 1 } }
19
42
 
20
- = f.show_if(:blank_registrant, false, nested: true) do
21
- %hr
43
+ - if event_ticket.present?
44
+ - if event_ticket.question1.present?
45
+ = f.text_field :response1, label: event_ticket.question1
22
46
 
23
- - if ticket.regular?
24
- = render('effective/event_registrants/fields_regular', f: f)
25
- - elsif ticket.member_only?
26
- = render('effective/event_registrants/fields_member_only', f: f)
27
- - elsif ticket.member_or_non_member?
28
- = render('effective/event_registrants/fields_member_or_non_member', f: f)
29
- - else
30
- - raise("Unexpected ticket category: #{ticket.category || 'nil'}")
47
+ - if event_ticket.question2.present?
48
+ = f.text_field :response2, label: event_ticket.question2
31
49
 
32
- = render('effective/event_registrants/fields_questions', f: f, ticket: ticket)
50
+ - if event_ticket.question3.present?
51
+ = f.text_field :response3, label: event_ticket.question3
33
52
 
@@ -0,0 +1 @@
1
+ -# Intentionally blank
@@ -0,0 +1,26 @@
1
+ - # Displayed on the details step
2
+ - event = form.object.event
3
+
4
+ - form.object.event_registrants.each_with_index do |event_registrant, index|
5
+ = card("Ticket ##{index+1}") do
6
+ - event_ticket = event_registrant.event_ticket
7
+
8
+ %p
9
+ = event_ticket
10
+ = ' - '
11
+
12
+ - if event_ticket.member_or_non_member? && event_registrant.first_name.blank? && !event.early_bird?
13
+ = effective_events_ticket_price(event, event_ticket)
14
+ - else
15
+ = price_to_currency(event_registrant.price)
16
+
17
+ = event_registrant.details
18
+
19
+ = form.fields_for :event_registrants, event_registrant do |fr|
20
+ - if event.allow_blank_registrants? && (fr.object.user.blank? || fr.object.blank_registrant?)
21
+ = fr.check_box :blank_registrant, label: "I will return and add this ticket's information later"
22
+ - else
23
+ = fr.hidden_field :blank_registrant, value: false
24
+
25
+ = fr.show_if(:blank_registrant, false) do
26
+ = render('effective/event_registrants/fields', f: fr)
@@ -0,0 +1,85 @@
1
+ -# Displayed on the tickets step
2
+ - event = form.object.event
3
+ - tickets = event.event_tickets.reject(&:archived?)
4
+ - waitlist = tickets.any? { |ticket| ticket.waitlist? }
5
+
6
+ - all_member_only_tickets = tickets.all? { |ticket| ticket.member_only? }
7
+ - any_member_only_tickets = tickets.any? { |ticket| ticket.member_only? }
8
+ - is_member = current_user.try(:is?, :member)
9
+
10
+ - if event.early_bird?
11
+ .alert.alert-warning.mb-3
12
+ Early Bird rates end on
13
+ = event.early_bird_end_at.strftime("%A, %B %d, %Y at %l:%M%P.")
14
+
15
+ %table.table.table-sm.table-striped
16
+ %thead
17
+ %tr
18
+ %th Ticket
19
+ %th Price
20
+ %th Quantity
21
+
22
+ %tbody
23
+ - tickets.each do |ticket|
24
+ %tr
25
+ %td
26
+ = ticket.to_s
27
+ - if ticket.capacity.present? && ticket.display_capacity?
28
+ %br
29
+ %small
30
+ #{event.capacity_available(event_ticket: ticket, event_registration: form.object)} remaining
31
+ - if ticket.waitlist?
32
+ before waitlist
33
+ %td
34
+ %ul.list-unstyled.mb-0
35
+ - # Early Bird
36
+ - if event.early_bird? && ticket.early_bird_price.to_i > 0 && [ticket.member_price, ticket.regular_price].exclude?(ticket.early_bird_price)
37
+ %li
38
+ - if ticket.regular_price.to_i > 0
39
+ %div
40
+ %s.text-muted
41
+ = price_to_currency(ticket.regular_price)
42
+
43
+ - if ticket.member_price.to_i > 0
44
+ %div
45
+ %s.text-muted
46
+ = price_to_currency(ticket.member_price)
47
+ .badge.badge-secondary.mr-2 Members
48
+
49
+ %div
50
+ = price_to_currency(ticket.early_bird_price)
51
+ .badge.badge-warning Early Bird
52
+ - else
53
+ - if ticket.regular_price.present?
54
+ %li
55
+ = price_to_currency(ticket.regular_price)
56
+
57
+ - if ticket.member_price.present?
58
+ %li
59
+ = price_to_currency(ticket.member_price)
60
+ .badge.badge-secondary Members
61
+
62
+ %td
63
+ - event_ticket_selection = form.object.event_ticket_selection(event_ticket: ticket)
64
+
65
+ = form.fields_for :event_ticket_selections, event_ticket_selection do |f|
66
+ = f.hidden_field :event_ticket_id
67
+ = f.hidden_field :quantity, value: 0
68
+
69
+ - capacity = event.capacity_selectable(event_ticket: ticket, event_registration: form.object)
70
+ - disabled = (ticket.member_only? && !is_member)
71
+
72
+ - if form.object.selected_expired? && !f.object.errors.present?
73
+ - f.object.assign_attributes(quantity: 0)
74
+
75
+ = f.select :quantity, (0..capacity), label: false, disabled: disabled,
76
+ include_blank: false, input_js: { minimumResultsForSearch: 'Infinity' }
77
+
78
+ - if waitlist
79
+ %p If the ticket capacity has been reached you will be added to the waitlist.
80
+
81
+ - unless is_member
82
+ - if all_member_only_tickets
83
+ .alert.alert-info.mb-4 You must be a member to purchase tickets.
84
+ - elsif any_member_only_tickets
85
+ .alert.alert-info.mb-4 You must be a member to purchase some of these tickets.