effective_events 2.35.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 752b1ea45717c8cc9c6cef3c312ca7392186497fb0024c55c71ac63a8e0ac402
4
- data.tar.gz: e0dd03ae68b811e37b2ca5ee2237342ac4c1058bbf70a1136846fa81370dadaf
3
+ metadata.gz: 72f182aaf30b6c9d1d6d5813b8d8a9f027b5cb06908495ab7b4cd63515059774
4
+ data.tar.gz: 68d417df7dd7a5c24523b872a2b7dbcd6b9bcbf676cfd8362fe0e392b443ffe9
5
5
  SHA512:
6
- metadata.gz: 012ac6517e8998ddf0ede909ac774b7d18fcbede6170f5e4961a8db118252b0cd392cf0a0cb608ff7736c1d25a4bc4cf523fae38b12da271b4deae79734a1a2d
7
- data.tar.gz: d0a9ef6bb70fa6ef410cce8fccfd12d1bcf3be40d4d4eea8cc5e0803de03198b565287ad748d8f9195b257a2af056a37ba4d79e85b55b596b7868b1cd365e19b
6
+ metadata.gz: 16ada620e360116ce6550a46df6118bddd510551c16cab981d0dd6b3c04ef65ed282a5e3043f027a7d59d4d5a690a0b18b96bbff865370818849508dd960e304
7
+ data.tar.gz: 2cb548fabcd8ccdda8755a74fe1e0ecbabf111546b821f032f138ed0e79a7fe01e82487129b04392bb32905b3d202ae08ee19a32064bf2b0539b5ad5c8723b9f
@@ -10,35 +10,40 @@ module Admin
10
10
 
11
11
  col :event
12
12
  col :title
13
- col :category, visible: false
13
+ col :category, label: 'Purchasable by', visible: false
14
14
  col :waitlist, visible: false
15
+ col :guest_of_member, visible: false
15
16
 
16
17
  col :early_bird_price, as: :price, visible: false
17
- col :regular_price, as: :price, visible: false
18
+ col :non_member_price, as: :price, visible: false
18
19
  col :member_price, as: :price, visible: false
20
+ col :guest_of_member_price, as: :price, visible: false
19
21
 
20
- col :prices do |ticket|
21
- prices = ""
22
+ col :prices, label: 'Price' do |ticket|
23
+ prices = []
22
24
 
23
25
  if event&.early_bird_end_at.present?
24
- prices += "#{price_to_currency(ticket.early_bird_price || 0)} early<br />"
26
+ prices << "#{price_to_currency(ticket.early_bird_price || 0)} early"
25
27
  end
26
28
 
27
- if ticket.category == "Member Only"
28
- prices += "#{price_to_currency(ticket.member_price)} member"
29
- elsif ticket.category == "Regular"
30
- prices += "#{price_to_currency(ticket.regular_price)} regular"
31
- elsif ticket.category == ("Member or Non-Member" || "Regular")
32
- prices +=
33
- "
34
- #{price_to_currency(ticket.regular_price)} regular<br />
35
- #{price_to_currency(ticket.member_price)} member
36
- "
29
+ if [ticket.member_price, ticket.non_member_price, ticket.guest_of_member_price].compact.uniq.length == 1
30
+ prices << "#{price_to_currency(ticket.member_price)}"
37
31
  else
38
- "Invalid ticket category"
32
+ if ticket.anyone?
33
+ prices << "#{price_to_currency(ticket.non_member_price)} non-member"
34
+ prices << "#{price_to_currency(ticket.member_price)} member"
35
+ elsif ticket.members?
36
+ prices << "#{price_to_currency(ticket.member_price)} member"
37
+ else
38
+ raise("Invalid ticket category #{ticket.category}")
39
+ end
40
+
41
+ if ticket.guest_of_member?
42
+ prices << "#{price_to_currency(ticket.guest_of_member_price)} guest"
43
+ end
39
44
  end
40
45
 
41
- prices
46
+ prices.join('<br />')
42
47
  end
43
48
 
44
49
  col :capacity_available, visible: false
@@ -57,8 +62,6 @@ module Admin
57
62
  end
58
63
  end
59
64
 
60
- col :category, visible: false
61
-
62
65
  col :registered_event_registrants_count, label: 'Registered', visible: false, as: :integer do |event|
63
66
  event.event_registrants.registered.count
64
67
  end
@@ -35,8 +35,9 @@ class EffectiveEventsDatatable < Effective::Datatable
35
35
 
36
36
  actions_col show: false do |event|
37
37
  if event.registerable?
38
+ label = (event.waitlist_only? ? 'Join Waitlist' : 'Register')
38
39
  url = event.external_registration_url.presence || effective_events.new_event_event_registration_path(event)
39
- dropdown_link_to('Register', url)
40
+ dropdown_link_to(label, url)
40
41
  end
41
42
  end
42
43
  end
@@ -41,21 +41,21 @@ module EffectiveEventsHelper
41
41
  end
42
42
  end
43
43
 
44
- def effective_events_ticket_price(event, ticket)
44
+ def effective_events_ticket_prices(event, ticket)
45
45
  raise('expected an Effective::Event') unless event.kind_of?(Effective::Event)
46
46
  raise('expected an Effective::EventTicket') unless ticket.kind_of?(Effective::EventTicket)
47
47
 
48
- prices = [
49
- (ticket.early_bird_price if event.early_bird?),
50
- (ticket.regular_price if ticket.regular? || ticket.member_or_non_member?),
51
- (ticket.member_price if ticket.member_only? || ticket.member_or_non_member?)
52
- ].compact.sort.uniq
48
+ guest_of_member = (ticket.guest_of_member? && (current_user.try(:membership_present?) || current_user.is_any?(:member)))
53
49
 
54
- if prices.length > 1
55
- "#{(prices.first == 0 ? '$0' : price_to_currency(prices.first))} or #{(prices.last == 0 ? '$0' : price_to_currency(prices.last))}"
56
- else
57
- (prices.first == 0 ? '$0' : price_to_currency(prices.first))
58
- end
50
+ prices = if event.early_bird? && ticket.early_bird_price.present?
51
+ [ticket.early_bird_price]
52
+ elsif ticket.members?
53
+ [ticket.member_price, (ticket.guest_of_member_price if guest_of_member)].compact
54
+ elsif ticket.anyone?
55
+ [ticket.member_price, (ticket.guest_of_member_price if guest_of_member), ticket.non_member_price].compact
56
+ end.uniq.sort
57
+
58
+ prices.map { |price| price == 0 ? '$0' : price_to_currency(price) }.to_sentence(last_word_connector: ' or ', two_words_connector: ' or ')
59
59
  end
60
60
 
61
61
  def effective_events_event_tickets_collection(event, namespace = nil)
@@ -210,8 +210,10 @@ module Effective
210
210
  end
211
211
 
212
212
  def registration_available?
213
- return false if registration_start_at.blank? || registration_end_at.blank?
214
- (registration_start_at..registration_end_at).cover?(Time.zone.now)
213
+ return false if closed?
214
+
215
+ return false if registration_start_at.blank?
216
+ registration_start_at <= Time.zone.now
215
217
  end
216
218
 
217
219
  def closed?
@@ -228,6 +230,10 @@ module Effective
228
230
  event_tickets.none? { |event_ticket| event_ticket_available?(event_ticket, except: except, quantity: 1) }
229
231
  end
230
232
 
233
+ def waitlist_only?
234
+ any_waitlist? && event_tickets.none? { |et| et.capacity_available > 0 }
235
+ end
236
+
231
237
  def upcoming?
232
238
  end_at > Time.zone.now
233
239
  end
@@ -297,7 +303,7 @@ module Effective
297
303
  end
298
304
 
299
305
  # Can I register/purchase this many new event tickets?
300
- def event_ticket_available?(event_ticket, except: nil, quantity: 0)
306
+ def event_ticket_available?(event_ticket, except: nil, quantity: 1)
301
307
  raise('expected an EventTicket') unless event_ticket.kind_of?(Effective::EventTicket)
302
308
  raise('expected except to be an EventRegistration') if except && !except.class.try(:effective_events_event_registration?)
303
309
  raise('expected quantity to be greater than 0') unless quantity.to_i > 0
@@ -311,7 +317,7 @@ module Effective
311
317
  end
312
318
 
313
319
  # Can I register/purchase this many new event products?
314
- def event_product_available?(event_product, quantity:)
320
+ def event_product_available?(event_product, quantity: 1)
315
321
  raise('expected an EventProduct') unless event_product.kind_of?(Effective::EventProduct)
316
322
  raise('expected quantity to be greater than 0') unless quantity.to_i > 0
317
323
 
@@ -119,7 +119,15 @@ module Effective
119
119
  errors.add(:waitlisted, 'is not permitted for a non-waitlist event ticket') if waitlisted? && !event_ticket.waitlist?
120
120
  end
121
121
 
122
- validates :price, presence: true, numericality: { greater_than_or_equal_to: 0 }
122
+ validate(if: -> { event_ticket&.members? }, unless: -> { purchased? }) do
123
+ errors.add(:base, "must be a member") unless owner.try(:membership_present?)
124
+ end
125
+
126
+ validate(if: -> { event_ticket&.members? && registrant_validations_enabled? }, unless: -> { purchased? }) do
127
+ errors.add(:user_id, "registrant must be a member") unless event_ticket.guest_of_member? || member?
128
+ end
129
+
130
+ validates :price, numericality: { greater_than_or_equal_to: 0 }
123
131
  validates :email, email: true
124
132
 
125
133
  # First name, last name and email are always required fields on details
@@ -132,15 +140,6 @@ module Effective
132
140
  validates :company, presence: true, if: -> { registrant_validations_enabled? && EffectiveEvents.company_or_organization_required }
133
141
  validates :organization, presence: true, if: -> { registrant_validations_enabled? && EffectiveEvents.company_or_organization_required && EffectiveEvents.organization_enabled? }
134
142
 
135
- # Member ticket: company name is locked in. you can only add to your own company
136
- validate(if: -> { registrant_validations_enabled? && event_ticket&.member_only? }) do
137
- if building_user_and_organization && owner.present? && Array(owner.try(:organizations)).exclude?(organization)
138
- errors.add(:organization_id, "must be your own for member-only tickets")
139
- end
140
-
141
- errors.add(:user_id, 'must be a member to register for member-only tickets') unless member_present?
142
- end
143
-
144
143
  # Copy any user errors from build_user_and_organization() into the registrant
145
144
  after_validation(if: -> { user && user.new_record? && user.errors.present? }) do
146
145
  errors.add(:first_name, user.errors[:first_name].join(', ')) if user.errors[:first_name].present?
@@ -214,7 +213,8 @@ module Effective
214
213
 
215
214
  def details
216
215
  [
217
- (content_tag(:span, 'Member', class: 'badge badge-warning') if member_ticket?),
216
+ (content_tag(:span, 'Member', class: 'badge badge-warning') if member?),
217
+ (content_tag(:span, 'Guest of Member', class: 'badge badge-warning') if guest_of_member?),
218
218
  (content_tag(:span, 'Waitlist', class: 'badge badge-warning') if waitlisted_not_promoted?),
219
219
  (content_tag(:span, 'Archived', class: 'badge badge-warning') if archived?)
220
220
  ].compact.join(' ').html_safe
@@ -232,26 +232,49 @@ module Effective
232
232
  (first_name.present? && last_name.present?) ? "#{last_name}, #{first_name}" : "GUEST"
233
233
  end
234
234
 
235
- # We create registrants on the tickets step. But don't enforce validations until the details step.
236
- def registrant_validations_enabled?
237
- return false if blank_registrant? # They want to come back later
238
-
239
- return true if event_registration.blank? # If we're creating in an Admin area
240
- return false if event_ticket.blank? # Invalid anyway
235
+ # Anyone or Members tickets
236
+ def early_bird?
237
+ return false if event.blank?
238
+ return false if event_ticket.blank?
239
+ return false if event_ticket.early_bird_price.blank?
241
240
 
242
- event_registration.current_step == :details
241
+ event.early_bird?
243
242
  end
244
243
 
245
- def member_present?
244
+ # Anyone or Members tickets
245
+ def member?
246
+ return false if event.blank?
247
+ return false if event_ticket.blank?
248
+
246
249
  user.try(:membership_present?) || organization.try(:membership_present?)
247
250
  end
248
251
 
249
- def member_ticket?
252
+ # Anyone or Members tickets
253
+ def guest_of_member?
254
+ return false if event.blank?
255
+ return false if event_ticket.blank?
256
+ return false unless event_ticket.guest_of_member?
257
+
258
+ !member? && owner.try(:membership_present?)
259
+ end
260
+
261
+ # Anyone tickets only
262
+ def non_member?
263
+ return false if event.blank?
250
264
  return false if event_ticket.blank?
251
- return true if event_ticket.member_only?
252
- return true if event_ticket.member_or_non_member? && member_present?
265
+ return false unless event_ticket.anyone?
266
+
267
+ !member? && !guest_of_member?
268
+ end
253
269
 
254
- false
270
+ # We create registrants on the tickets step. But don't enforce validations until the details step.
271
+ def registrant_validations_enabled?
272
+ return false if blank_registrant? # They want to come back later
273
+
274
+ return true if event_registration.blank? # If we're creating in an Admin area
275
+ return false if event_ticket.blank? # Invalid anyway
276
+
277
+ event_registration.current_step == :details
255
278
  end
256
279
 
257
280
  def present_registrant?
@@ -417,16 +440,18 @@ module Effective
417
440
  raise('expected an event') if event.blank?
418
441
  raise('expected an event ticket') if event_ticket.blank?
419
442
 
420
- if event.early_bird?
421
- event_ticket.early_bird_price # Early Bird Pricing
422
- elsif event_ticket.regular?
423
- event_ticket.regular_price
424
- elsif event_ticket.member_only?
443
+ if early_bird?
444
+ event_ticket.early_bird_price
445
+ elsif blank_registrant?
446
+ event_ticket.maximum_price
447
+ elsif member?
425
448
  event_ticket.member_price
426
- elsif event_ticket.member_or_non_member?
427
- (member_present? ? event_ticket.member_price : event_ticket.regular_price)
449
+ elsif guest_of_member?
450
+ event_ticket.guest_of_member_price
451
+ elsif non_member?
452
+ event_ticket.non_member_price
428
453
  else
429
- raise("Unexpected event ticket price calculation")
454
+ event_ticket.maximum_price
430
455
  end
431
456
  end
432
457
 
@@ -18,7 +18,7 @@ module Effective
18
18
 
19
19
  has_rich_text :body
20
20
 
21
- CATEGORIES = ['Regular', 'Member Only', 'Member or Non-Member']
21
+ CATEGORIES = ['Anyone', 'Members'] # Purchasable by
22
22
 
23
23
  effective_resource do
24
24
  title :string
@@ -27,7 +27,8 @@ module Effective
27
27
  display_capacity :boolean
28
28
  waitlist :boolean
29
29
 
30
- category :string
30
+ category :string # Purchasable by
31
+ guest_of_member :boolean # Allow members to purchase a guest ticket
31
32
 
32
33
  # Questions
33
34
  question1 :text
@@ -36,8 +37,10 @@ module Effective
36
37
 
37
38
  # Pricing
38
39
  early_bird_price :integer
40
+
41
+ non_member_price :integer # Used to be regular_price
39
42
  member_price :integer
40
- regular_price :integer
43
+ guest_of_member_price :integer
41
44
 
42
45
  qb_item_name :string
43
46
  tax_exempt :boolean
@@ -57,16 +60,18 @@ module Effective
57
60
  end
58
61
 
59
62
  validates :title, presence: true, uniqueness: { scope: [:event_id] }
60
- validates :category, presence: true
61
-
62
- validates :regular_price, presence: true, if: -> { member_or_non_member? || regular? }
63
- validates :regular_price, numericality: { greater_than_or_equal_to: 0, allow_blank: true }
63
+ validates :category, presence: true, inclusion: { in: CATEGORIES }
64
64
 
65
- validates :member_price, presence: true, if: -> { member_or_non_member? || member_only? }
65
+ # Price validations
66
+ validates :early_bird_price, numericality: { greater_than_or_equal_to: 0, allow_blank: true }
67
+ validates :non_member_price, numericality: { greater_than_or_equal_to: 0, allow_blank: true }
66
68
  validates :member_price, numericality: { greater_than_or_equal_to: 0, allow_blank: true }
69
+ validates :guest_of_member_price, numericality: { greater_than_or_equal_to: 0, allow_blank: true }
67
70
 
68
- validates :early_bird_price, presence: true, if: -> { event&.early_bird_end_at.present? }
69
- validates :early_bird_price, numericality: { greater_than_or_equal_to: 0, allow_blank: true }
71
+ validates :early_bird_price, presence: true, if: -> { early_bird? }
72
+ validates :non_member_price, presence: true, if: -> { anyone? }
73
+ validates :member_price, presence: true, if: -> { anyone? || members? }
74
+ validates :guest_of_member_price, presence: true, if: -> { guest_of_member? }
70
75
 
71
76
  validates :capacity, numericality: { greater_than_or_equal_to: 0, allow_blank: true }
72
77
  validates :capacity, presence: { message: 'must be present when using the waitlist'}, if: -> { waitlist? }
@@ -133,16 +138,23 @@ module Effective
133
138
  [question1.presence, question2.presence, question3.presence].compact
134
139
  end
135
140
 
136
- def regular?
137
- category == 'Regular'
141
+ def early_bird?
142
+ event&.early_bird_end_at.present?
138
143
  end
139
144
 
140
- def member_only?
141
- category == 'Member Only'
145
+ def maximum_price
146
+ [non_member_price, member_price, (guest_of_member_price if guest_of_member?)].compact.max
142
147
  end
143
148
 
144
- def member_or_non_member?
145
- category == 'Member or Non-Member'
149
+ # “Anyone” can buy tickets have: Member, Non-member, and Guest of Member pricing. Member and Non-member are always required.
150
+ def anyone?
151
+ category == 'Anyone'
146
152
  end
153
+
154
+ # “Members” can buy tickets have: Member and Guest of Member pricing. Member pricing is always required.
155
+ def members?
156
+ category == 'Members'
157
+ end
158
+
147
159
  end
148
160
  end
@@ -6,56 +6,43 @@
6
6
 
7
7
  .row
8
8
  .col
9
- = f.select :category, Effective::EventTicket::CATEGORIES, hint: "Determines who can purchase this ticket at which price. Also determines if the dropdown of related members is displayed to the purchaser."
9
+ = f.select :category, Effective::EventTicket::CATEGORIES, label: 'Purchasable by', hint: "Determines who can purchase this ticket."
10
10
 
11
- = f.show_if(:category, 'Regular') do
12
- .alert.alert-info.mb-4
13
- %strong Regular Ticket:
14
- Anyone will be able to purchase this ticket. Only the regular price applies.
11
+ = f.price_field :early_bird_price,
12
+ hint: 'The price charged when registering before the early bird date. This price will be charged instead of any of the prices below. Leave blank for no early bird price.',
13
+ disabled: !f.object.event&.early_bird_end_at.present?
14
+
15
+ = f.show_if(:category, 'Anyone') do
16
+ = f.price_field :non_member_price, label: 'Non-member price', hint: 'The price charged when registering a non-member.'
17
+ = f.price_field :member_price, hint: 'The price charged when registering a member.'
18
+
19
+ = f.show_if(:category, 'Members') do
20
+ = f.price_field :member_price, hint: 'The price charged when registering a member.'
15
21
 
16
- = f.show_if(:category, 'Member Only') do
17
- .alert.alert-info.mb-4
18
- %strong Member Only Ticket:
19
- Only members will be able to purchase this ticket. They must select a member from the dropdown list of all members. Only the member price applies.
22
+ = f.check_box :guest_of_member, label: 'Allow members to purchase a guest ticket'
20
23
 
21
- = f.show_if(:category, 'Member or Non-Member') do
22
- .alert.alert-info.mb-4
23
- %strong Member or Non-Member Ticket:
24
- Anyone will be able to purchase this ticket. They can select a member from the dropdown list of all members to receive the member pricing or they can enter a first name and last name to receive the regular pricing.
24
+ = f.show_if(:guest_of_member, true) do
25
+ = f.price_field :guest_of_member_price, hint: 'The price charged to members when registering a non-member guest.'
26
+
27
+ - if EffectiveOrders.use_item_names?
28
+ = qb_item_name_field(f)
29
+
30
+ = f.check_box :tax_exempt, label: "This #{etd(f.object)} is tax exempt"
25
31
 
26
32
  .col
27
33
  = f.number_field :capacity, hint: "The number of registrations will be limited to capacity. Leave blank for unlimited capacity."
28
- = f.check_box :display_capacity, label: "Yes, display the remaining ticket capacity to users during registration", hint: "Leave blank to hide the capacity."
34
+ = f.check_box :display_capacity, label: "Display the remaining ticket capacity to users during registration", hint: "Leave blank to hide the capacity."
29
35
 
30
36
  - if EffectiveEvents.delayed?
31
37
  - event_delayed = f.object.event&.delayed?
32
38
  - f.object.waitlist = false if !event_delayed
33
39
 
34
40
  = f.check_box :waitlist,
35
- label: "Yes, add to waitlist once capacity is reached",
36
- hint: "requires a event with delayed payment. Once capacity is reached, new registrations will be added to the waitlist. Payment information is collected but not charged for waitlisted registrants. To waitlist everyone and promote later, set the capacity to zero.",
41
+ label: "Add to waitlist once capacity is reached",
42
+ hint: "Once capacity is reached, new registrations will be added to the waitlist. Payment information is collected but not charged for waitlisted registrants. To waitlist everyone and promote later, set the capacity to zero. Requires an event with delayed payment.",
37
43
  disabled: !event_delayed
38
- .row
39
- .col-md-6
40
- = f.price_field :early_bird_price,
41
- hint: 'requires an event with early bird date. A price of $0 will allow a checkout for free. Leave blank for no early bird price.',
42
- disabled: !f.object.event&.early_bird_end_at.present?
43
-
44
- = f.show_if_any(:category, ['Regular', 'Member or Non-Member']) do
45
- = f.price_field :regular_price, hint: 'A price of $0 will allow a checkout for free.'
46
-
47
- = f.show_if_any(:category, ['Member Only']) do
48
- = f.static_field :regular_price, value: 'None'
49
-
50
- = f.show_if_any(:category, ['Member Only', 'Member or Non-Member']) do
51
- = f.price_field :member_price, hint: 'A price of $0 will allow a checkout for free when selecting a member.'
52
-
53
- - if EffectiveOrders.use_item_names?
54
- .row
55
- .col-md-6= qb_item_name_field(f)
56
44
 
57
- = f.check_box :tax_exempt, label: "Yes, this #{etd(f.object)} is tax exempt"
58
- = f.check_box :archived, label: 'Archive this ticket. While archived, it cannot be purchased by users but registrants can only be added by an admin.'
45
+ = f.check_box :archived, label: 'Archive this ticket', hint: "While archived, it cannot be purchased by users but registrants can still be added by an admin."
59
46
 
60
47
  = card('Questions') do
61
48
  %p
@@ -1,5 +1,5 @@
1
1
  = effective_form_with(model: [:admin, event], engine: true) do |f|
2
- = f.check_box :authenticate_user, label: 'Yes, the user must be be signed in to view this event', hint: 'Sign up is required to register for any event'
2
+ = f.check_box :authenticate_user, label: 'The user must be be signed in to view this event', hint: 'Sign up is required to register for any event'
3
3
 
4
4
  - if EffectiveEvents.use_effective_roles
5
5
  = f.checks :roles, EffectiveRoles.roles_collection(f.object)
@@ -28,9 +28,9 @@
28
28
  = f.datetime_field :early_bird_end_at, label: "Early bird end",
29
29
  hint: 'Event tickets are purchased at early bird pricing before this date. After this date, regular pricing applies.'
30
30
 
31
- = f.check_box :allow_blank_registrants, label: "Yes, allow blank ticket registrations", hint: "Allow event tickets to be purchased without adding a name. The purchaser may return to add names later."
31
+ = f.check_box :allow_blank_registrants, label: "Allow blank ticket registrations", hint: "Allow event tickets to be purchased without adding a name. The purchaser may return to add names later."
32
32
 
33
- = f.check_box :external_registration, label: "Yes, the registration for this event is handled by another website"
33
+ = f.check_box :external_registration, label: "The registration for this event is handled by another website"
34
34
 
35
35
  = f.show_if(:external_registration, true) do
36
36
  = f.url_field :external_registration_url, hint: "The url for external event registration. Must start with http(s)://"
@@ -40,13 +40,13 @@
40
40
  %h2 Delayed Payments
41
41
  %p The online payment for this event will be charged as follows:
42
42
 
43
- = f.check_box :delayed_payment, label: "Yes, this is a delayed payment event", hint: "Allow registrations for this event without paying immediately.<br>A secure token representing their credit card will be saved and charged automatically on the following payment date."
43
+ = f.check_box :delayed_payment, label: "This is a delayed payment event", hint: "Allow registrations for this event without paying immediately.<br>A secure token representing their credit card will be saved and charged automatically on the following payment date."
44
44
 
45
45
  = f.hide_if(:delayed_payment, true) do
46
46
  = f.hidden_field :delayed_payment_date, value: ''
47
47
 
48
48
  = f.show_if(:delayed_payment, true) do
49
- = f.date_field :delayed_payment_date, label: "Delayed Payment Charge Date", hint: "The date that the credit card will be charged. Expects a date in the future, after the registration end date.<br>Changing this will update the charge date for all existing delayed payment orders."
49
+ = f.date_field :delayed_payment_date, label: "Delayed payment charge date", hint: "The date that the credit card will be charged. Expects a date in the future, after the registration end date.<br>Changing this will update the charge date for all existing delayed payment orders."
50
50
 
51
51
  = f.submit do
52
52
  = f.save 'Save'
@@ -27,18 +27,17 @@
27
27
 
28
28
  - organizations = EffectiveMemberships.Organization.sorted.all
29
29
 
30
- - if event_ticket&.member_only?
30
+ - if event_ticket && event_ticket.members? && !event_ticket.guest_of_member?
31
31
  - organization_id = (f.object.event_registration&.owner || current_user).try(:organizations).try(:first).try(:id)
32
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}",
33
+ - # Must select any existing member organization
34
+ = f.select :organization_id, organizations.members, label: organization_label, placeholder: 'Search by name', input_html: { disabled: disabled },
36
35
  value: (organization_id if organization_id && f.object.organization_id.blank?)
37
36
  - else
38
37
  - # This creates a select field organization_id and a text field company
39
38
  = f.select_or_text :organization_id, :company, organizations, name: organization_label.downcase, input_html: { disabled: disabled },
40
39
  text: { label: "#{organization_label} name", placeholder: "New #{organization_label.downcase} name" },
41
- select: { label: organization_label, placeholder: 'Search by name', input_js: { minimumInputLength: 1 } }
40
+ select: { label: organization_label, placeholder: 'Search by name' }
42
41
 
43
42
  - if event_ticket.present?
44
43
  - if event_ticket.question1.present?
@@ -8,13 +8,12 @@
8
8
  %p
9
9
  = event_ticket
10
10
  = ' - '
11
+ = effective_events_ticket_prices(event, event_ticket)
11
12
 
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
13
+ -# - if event_ticket.member_or_non_member? && event_registrant.first_name.blank? && !event.early_bird?
14
+ -# = effective_events_ticket_price(event, event_ticket)
15
+ -# - else
16
+ -# = price_to_currency(event_registrant.price)
18
17
 
19
18
  = form.fields_for :event_registrants, event_registrant do |fr|
20
19
  - if event.allow_blank_registrants? && (fr.object.user.blank? || fr.object.blank_registrant?)
@@ -3,8 +3,8 @@
3
3
  - tickets = event.event_tickets.reject(&:archived?)
4
4
  - waitlist = tickets.any? { |ticket| ticket.waitlist? }
5
5
 
6
- - all_member_only_tickets = tickets.all? { |ticket| ticket.member_only? }
7
- - any_member_only_tickets = tickets.any? { |ticket| ticket.member_only? }
6
+ - all_members_tickets = tickets.all? { |ticket| ticket.members? }
7
+ - any_members_tickets = tickets.any? { |ticket| ticket.members? }
8
8
  - is_member = current_user.try(:membership_present?)
9
9
 
10
10
  - if event.early_bird?
@@ -32,33 +32,40 @@
32
32
  before waitlist
33
33
  %td
34
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)
35
+
36
+ - if event.early_bird? && ticket.early_bird_price.present?
37
+ %li
38
+ = price_to_currency(ticket.early_bird_price)
39
+ .badge.badge-warning Early Bird
40
+ - elsif ticket.members?
37
41
  %li
38
- - if ticket.regular_price.to_i > 0 && (ticket.member_or_non_member? || ticket.regular?)
39
- %div
40
- %s.text-muted
41
- = price_to_currency(ticket.regular_price)
42
-
43
- - if ticket.member_price.to_i > 0 && (ticket.member_or_non_member? || ticket.member_only?)
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.to_i > 0 && (ticket.member_or_non_member? || ticket.regular?)
42
+ = price_to_currency(ticket.member_price)
43
+ .badge.badge-secondary Member
44
+
45
+ - if ticket.guest_of_member? && (current_user.try(:membership_present?) || current_user.is_any?(:member))
54
46
  %li
55
- = price_to_currency(ticket.regular_price)
47
+ = price_to_currency(ticket.guest_of_member_price)
48
+ .badge.badge-secondary Guest of Member
49
+
50
+ - elsif ticket.anyone?
51
+ - all_same_price = [ticket.member_price, (ticket.guest_of_member_price if ticket.guest_of_member?), ticket.non_member_price].compact.uniq.length == 1
56
52
 
57
- - if ticket.member_price.to_i > 0 && (ticket.member_or_non_member? || ticket.member_only?)
53
+ - if all_same_price
58
54
  %li
59
55
  = price_to_currency(ticket.member_price)
60
- .badge.badge-secondary Members
56
+ - else
57
+ %li
58
+ = price_to_currency(ticket.member_price)
59
+ .badge.badge-secondary Member
61
60
 
61
+ - if ticket.guest_of_member? && (current_user.try(:membership_present?) || current_user.is_any?(:member))
62
+ %li
63
+ = price_to_currency(ticket.guest_of_member_price)
64
+ .badge.badge-secondary Guest of Member
65
+
66
+ %li
67
+ = price_to_currency(ticket.non_member_price)
68
+ .badge.badge-secondary Non-Member
62
69
  %td
63
70
  - event_ticket_selection = form.object.event_ticket_selection(event_ticket: ticket)
64
71
 
@@ -67,7 +74,7 @@
67
74
  = f.hidden_field :quantity, value: 0
68
75
 
69
76
  - capacity = event.capacity_selectable(event_ticket: ticket, event_registration: form.object)
70
- - disabled = (ticket.member_only? && !is_member)
77
+ - disabled = (ticket.members? && !is_member)
71
78
 
72
79
  - if form.object.selected_expired? && !f.object.errors.present?
73
80
  - f.object.assign_attributes(quantity: 0)
@@ -79,7 +86,7 @@
79
86
  %p If the ticket capacity has been reached you will be added to the waitlist.
80
87
 
81
88
  - unless is_member
82
- - if all_member_only_tickets
89
+ - if all_members_tickets
83
90
  .alert.alert-info.mb-4 You must be a member to purchase tickets.
84
- - elsif any_member_only_tickets
91
+ - elsif any_members_tickets
85
92
  .alert.alert-info.mb-4 You must be a member to purchase some of these tickets.
@@ -16,8 +16,9 @@
16
16
 
17
17
  - if @event.registerable? || (impersonating? && @event.registerable_when_impersonating?)
18
18
  .register.mb-4
19
+ - label = (@event.waitlist_only? ? 'Join Waitlist' : 'Register')
19
20
  - url = @event.external_registration_url.presence || effective_events.new_event_event_registration_path(@event)
20
- = link_to 'Register', url, class: 'btn btn-lg btn-primary'
21
+ = link_to label, url, class: 'btn btn-lg btn-primary'
21
22
 
22
23
  - if @event.file.attached?
23
24
  = image_tag url_for(@event.file), class: "effective-events-image d-none d-lg-block float-right", alt: @event.title, width: "350", height: "220"
@@ -67,7 +68,8 @@
67
68
 
68
69
  - if @event.registerable?
69
70
  .register.mb-4
71
+ - label = (@event.waitlist_only? ? 'Join Waitlist' : 'Register')
70
72
  - url = @event.external_registration_url.presence || effective_events.new_event_event_registration_path(@event)
71
- = link_to 'Register', url, class: 'btn btn-lg btn-primary'
73
+ = link_to label, url, class: 'btn btn-lg btn-primary'
72
74
 
73
75
  = link_to("&larr; #{events_name_label}".html_safe, effective_events.events_path, class: "btn btn-secondary my-4")
@@ -45,10 +45,13 @@ class CreateEffectiveEvents < ActiveRecord::Migration[6.0]
45
45
  t.boolean :display_capacity, default: false
46
46
 
47
47
  t.boolean :waitlist, default: false
48
+
48
49
  t.string :category
50
+ t.boolean :guest_of_member, default: false
49
51
 
50
- t.integer :regular_price
52
+ t.integer :non_member_price
51
53
  t.integer :member_price
54
+ t.integer :guest_of_member_price
52
55
  t.integer :early_bird_price
53
56
 
54
57
  t.text :question1
@@ -113,7 +116,6 @@ class CreateEffectiveEvents < ActiveRecord::Migration[6.0]
113
116
  t.timestamps
114
117
  end
115
118
 
116
- add_index :event_registrants, [:user_type, :user_id, :owner_type, :owner_id], if_not_exists: true
117
119
  add_index :event_registrants, :event_registration_id, if_not_exists: true
118
120
  add_index :event_registrants, :event_ticket_id, if_not_exists: true
119
121
  add_index :event_registrants, :archived, if_not_exists: true
data/db/seeds.rb CHANGED
@@ -25,7 +25,7 @@ event = Effective::Event.create!(
25
25
  event.event_tickets.create!(
26
26
  title: 'Ticket A 10 Seats',
27
27
  capacity: 10,
28
- regular_price: 100_00,
28
+ non_member_price: 100_00,
29
29
  early_bird_price: 50_00,
30
30
  member_price: 75_00,
31
31
  qb_item_name: 'Tickets'
@@ -34,7 +34,7 @@ event.event_tickets.create!(
34
34
  event.event_tickets.create!(
35
35
  title: 'Ticket B 20 Seats',
36
36
  capacity: 20,
37
- regular_price: 200_00,
37
+ non_member_price: 200_00,
38
38
  early_bird_price: 150_00,
39
39
  member_price: 75_00,
40
40
  qb_item_name: 'Tickets'
@@ -43,7 +43,7 @@ event.event_tickets.create!(
43
43
  event.event_tickets.create!(
44
44
  title: 'Ticket C Unlimited Seats',
45
45
  capacity: nil,
46
- regular_price: 200_00,
46
+ non_member_price: 200_00,
47
47
  early_bird_price: 150_00,
48
48
  member_price: 75_00,
49
49
  qb_item_name: 'Tickets'
@@ -1,3 +1,3 @@
1
1
  module EffectiveEvents
2
- VERSION = '2.35.0'.freeze
2
+ VERSION = '3.0.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_events
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.35.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-07-23 00:00:00.000000000 Z
11
+ date: 2025-07-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails