effective_events 0.10.1 → 0.11.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: cfe22059403401435f15bb3de7a04e64d5f6d66d67b5fa538e552f743bc80657
4
- data.tar.gz: 9dde412444e3898074f38c5b4c8cb845bb7b22afce81b2af11d46ec9fe9f22db
3
+ metadata.gz: 2c3cd1bb2313ea9a4be719350a54cb9f8bae0012040c26cd3661355a7590aba1
4
+ data.tar.gz: 82fa202806b65f47708ac748df70a44a3e2d5c253860049baad26925edf6e668
5
5
  SHA512:
6
- metadata.gz: 8a9b73d87d24d66c537427daf7a5f23d4be354eaaf24f34f35646bebd5527727d6236e2a7d8cd8728c9e00d96a061783ba7d772c5c4ab97662ab7bc8a96afdd2
7
- data.tar.gz: 6f84878e674939ad1843be2a35ee6d4946a1dc1a4a2dd05a6c477a9453d1ac04ada9903fe31e5c65e7c60cfd1d447f30c1ad3c4f5c0b2bc6ccd83b55c19c01e4
6
+ metadata.gz: af8087ebab4902bbce1ecb33310333f42943029f612477a2490d68d57c085ccaecded40fb10bcdbbd3cfbc28fb6506aeb1d146dafb22863560d35f2a46e6aa55
7
+ data.tar.gz: 90f1f61faed9c5991bdfc7289ca21071005f2b238cceea535e4648167102881f07b461021a9a6fc75bd117ab280bf3991d72b293485c5d090ad8503c1c38b389
@@ -1,29 +1,28 @@
1
1
  module Effective
2
2
  class EventRegistrationsController < ApplicationController
3
-
4
3
  if defined?(Devise)
5
4
  before_action :authenticate_user!, unless: -> { action_name == 'new' || (action_name == 'show' && params[:id] == 'start') }
6
5
  end
7
6
 
8
7
  include Effective::WizardController
9
8
 
9
+ before_action :redirect_unless_registerable, only: [:new, :show]
10
+
10
11
  resource_scope -> {
11
12
  event = Effective::Event.find(params[:event_id])
12
13
  EffectiveEvents.EventRegistration.deep.where(owner: current_user, event: event)
13
14
  }
14
15
 
15
- # Override ready_checkout to also check for any currently sold out tickets or addons
16
- # Prevents people from coming back and purchasing them
17
- def ready_checkout
18
- return unless step == :checkout
19
- return unless resource.class.try(:acts_as_purchasable_wizard?)
20
-
21
- if resource.sold_out_event_registrants.present? || resource.sold_out_event_addons.present?
22
- flash[:danger] = "Your selected event tickets are sold out. This event registration is no longer available."
23
- return redirect_to('/dashboard')
24
- end
16
+ # If the event is no longer registerable, do not let them continue
17
+ def redirect_unless_registerable
18
+ return if resource.blank?
19
+ return if resource.submitted?
20
+ return if resource.event.blank?
21
+ return if resource.event.registerable?
22
+ return if resource.submit_order&.deferred?
25
23
 
26
- resource.ready!
24
+ flash[:danger] = "Your selected event is no longer available for registration. This event registration is no longer available."
25
+ return redirect_to('/dashboard')
27
26
  end
28
27
 
29
28
  end
@@ -23,8 +23,8 @@ module Admin
23
23
  col :event_product, search: :string
24
24
  end
25
25
 
26
- col :purchased_order
27
- col :owner
26
+ col :purchased_order, visible: false
27
+ col :owner, visible: false
28
28
 
29
29
  col :first_name
30
30
  col :last_name
@@ -24,13 +24,21 @@ module Admin
24
24
  end
25
25
  end
26
26
 
27
- col :purchased_event_addons_count, label: 'Purchased'
27
+ col :registered_event_addons_count, label: 'Registered'
28
+ col :purchased_event_addons_count, label: 'Purchased', visible: false
29
+
28
30
  col :capacity, visible: false
29
31
  col :capacity_available, visible: false
30
32
 
31
- col :purchased_event_addons, label: 'Name' do |product|
32
- product.purchased_event_addons.reject(&:archived?).sort_by(&:to_s).map do |purchase|
33
- content_tag(:div, purchase.owner.to_s, class: 'col-resource_item')
33
+ col :registered_event_addons, label: 'Registered Names' do |product|
34
+ product.registered_event_addons.reject(&:archived?).sort_by(&:to_s).map do |addon|
35
+ content_tag(:div, addon.owner.to_s, class: 'col-resource_item')
36
+ end.join.html_safe
37
+ end
38
+
39
+ col :purchased_event_addons, label: 'Purchased Names', visible: false do |product|
40
+ product.purchased_event_addons.reject(&:archived?).sort_by(&:to_s).map do |addon|
41
+ content_tag(:div, addon.owner.to_s, class: 'col-resource_item')
34
42
  end.join.html_safe
35
43
  end
36
44
 
@@ -25,7 +25,11 @@ module Admin
25
25
  end
26
26
  end
27
27
 
28
- col :purchased_event_registrants_count, label: 'Registered' do |event|
28
+ col :registered_event_registrants_count, label: 'Registered' do |event|
29
+ event.event_registrants.registered.unarchived.count
30
+ end
31
+
32
+ col :purchased_event_registrants_count, label: 'Purchased', visible: false do |event|
29
33
  event.event_registrants.purchased.unarchived.count
30
34
  end
31
35
 
@@ -20,7 +20,7 @@ module EffectiveEventsHelper
20
20
  remaining = (ticket.capacity.present? ? "#{ticket.capacity_available} remaining" : nil)
21
21
 
22
22
  label = [title, price, remaining].compact.join(' - ')
23
- disabled = { disabled: :disabled } unless (authorized || ticket.available?)
23
+ disabled = { disabled: :disabled } unless (authorized || event.event_ticket_available?(ticket, quantity: 1))
24
24
 
25
25
  [label, ticket.to_param, disabled].compact
26
26
  end
@@ -39,7 +39,7 @@ module EffectiveEventsHelper
39
39
  remaining = (product.capacity.present? ? "#{product.capacity_available} remaining" : nil)
40
40
 
41
41
  label = [title, price, remaining].compact.join(' - ')
42
- disabled = { disabled: :disabled } unless (authorized || product.available?)
42
+ disabled = { disabled: :disabled } unless (authorized || event.event_product_available?(product, quantity: 1))
43
43
 
44
44
  [label, product.to_param, disabled].compact
45
45
  end
@@ -77,7 +77,13 @@ module EffectiveEventsEventRegistration
77
77
  timestamps
78
78
  end
79
79
 
80
- scope :deep, -> { includes(:owner, :event_registrants, :event_addons, event: [:event_products, :event_tickets]) }
80
+ scope :deep, -> {
81
+ includes(:owner)
82
+ .includes(event: [:rich_texts, event_products: :purchased_event_addons, event_tickets: :purchased_event_registrants])
83
+ .includes(event_registrants: [event_ticket: :purchased_event_registrants])
84
+ .includes(event_addons: [event_product: :purchased_event_addons])
85
+ }
86
+
81
87
  scope :sorted, -> { order(:id) }
82
88
 
83
89
  scope :in_progress, -> { where.not(status: [:submitted]) }
@@ -99,16 +105,17 @@ module EffectiveEventsEventRegistration
99
105
  self.errors.add(:event_registrants, "can't be blank") unless present_event_registrants.present?
100
106
  end
101
107
 
102
- # Validate all items are available
103
- validate(unless: -> { current_step == :checkout || done? }) do
104
- sold_out_event_registrants.each do |item|
105
- errors.add(:base, "The #{item.event_ticket} ticket is sold out and no longer available for purchase")
106
- item.errors.add(:event_ticket_id, "#{item.event_ticket} is unavailable for purchase")
108
+ # Validate all tickets are available for registration
109
+ validate(if: -> { current_step == :tickets }) do
110
+ unavailable_event_tickets.each do |event_ticket|
111
+ errors.add(:base, "The requested number of #{event_ticket} tickets are not available")
107
112
  end
113
+ end
108
114
 
109
- sold_out_event_addons.each do |item|
110
- errors.add(:base, "The #{item.event_product} product is sold out and no longer available for purchase")
111
- item.errors.add(:event_product_id, "#{item.event_product} is unavailable for purchase")
115
+ # Validate all products are available for registration
116
+ validate(if: -> { current_step == :addons }) do
117
+ unavailable_event_products.each do |event_product|
118
+ errors.add(:base, "The requested number of #{event_product} add-ons are not available")
112
119
  end
113
120
  end
114
121
 
@@ -132,15 +139,6 @@ module EffectiveEventsEventRegistration
132
139
  notifications = event.event_notifications.select(&:registrant_purchased?)
133
140
  notifications.each { |notification| notification.notify!(event_registrants: event_registrants) }
134
141
  end
135
-
136
- def sold_out_event_registrants
137
- event_registrants.reject { |er| er.purchased? || er.event_ticket&.available? }
138
- end
139
-
140
- def sold_out_event_addons
141
- event_addons.reject { |ep| ep.purchased? || ep.event_product&.available? }
142
- end
143
-
144
142
  end
145
143
 
146
144
  # Instance Methods
@@ -200,10 +198,34 @@ module EffectiveEventsEventRegistration
200
198
  event_addons
201
199
  end
202
200
 
201
+ def unavailable_event_tickets
202
+ unavailable = []
203
+
204
+ present_event_registrants.map(&:event_ticket).group_by { |t| t }.each do |event_ticket, event_tickets|
205
+ unavailable << event_ticket unless event.event_ticket_available?(event_ticket, quantity: event_tickets.length)
206
+ end
207
+
208
+ unavailable
209
+ end
210
+
211
+ def unavailable_event_products
212
+ unavailable = []
213
+
214
+ present_event_addons.map(&:event_product).group_by { |p| p }.each do |event_product, event_products|
215
+ unavailable << event_product unless event.event_product_available?(event_product, quantity: event_products.length)
216
+ end
217
+
218
+ unavailable
219
+ end
220
+
203
221
  private
204
222
 
205
223
  def present_event_registrants
206
- event_registrants.reject(&:marked_for_destruction?)
224
+ event_registrants.reject(&:marked_for_destruction?).reject(&:archived?)
225
+ end
226
+
227
+ def present_event_addons
228
+ event_addons.reject(&:marked_for_destruction?).reject(&:archived?)
207
229
  end
208
230
 
209
231
  end
@@ -24,6 +24,10 @@ module Effective
24
24
  has_many :event_notifications, -> { order(:id) }, inverse_of: :event, dependent: :destroy
25
25
  accepts_nested_attributes_for :event_notifications, allow_destroy: true
26
26
 
27
+ # Used by the registration_available checks
28
+ has_many :registered_event_registrants, -> { EventRegistrant.registered }, class_name: 'Effective::EventRegistrant', inverse_of: :event
29
+ has_many :registered_event_addons, -> { EventAddon.registered }, class_name: 'Effective::EventAddon', inverse_of: :event
30
+
27
31
  # rich_text_body - Used by the select step
28
32
  has_many_rich_texts
29
33
 
@@ -186,7 +190,8 @@ module Effective
186
190
  end
187
191
 
188
192
  def sold_out?
189
- false
193
+ return false unless event_tickets.present?
194
+ event_tickets.none? { |event_ticket| event_ticket_available?(event_ticket, quantity: 1) }
190
195
  end
191
196
 
192
197
  def early_bird?
@@ -229,5 +234,35 @@ module Effective
229
234
  start_at
230
235
  end
231
236
 
237
+ # Can I register/purchase this many new event tickets?
238
+ def event_ticket_available?(event_ticket, quantity:)
239
+ raise('expected an EventTicket') unless event_ticket.kind_of?(Effective::EventTicket)
240
+ raise('expected quantity to be greater than 0') unless quantity.to_i > 0
241
+
242
+ return false if event_ticket.archived?
243
+ return true if event_ticket.capacity.blank? # No capacity enforced for this ticket
244
+
245
+ # Total number already sold
246
+ registered = registered_event_registrants.count { |r| r.event_ticket_id == event_ticket.id }
247
+
248
+ # If there's capacity for this many more
249
+ (registered + quantity) <= event_ticket.capacity
250
+ end
251
+
252
+ # Can I register/purchase this many new event products?
253
+ def event_product_available?(event_product, quantity:)
254
+ raise('expected an EventProduct') unless event_product.kind_of?(Effective::EventProduct)
255
+ raise('expected quantity to be greater than 0') unless quantity.to_i > 0
256
+
257
+ return false if event_product.archived?
258
+ return true if event_product.capacity.blank? # No capacity enforced for this product
259
+
260
+ # Total number already sold
261
+ registered = registered_event_addons.count { |r| r.event_product_id == event_product.id }
262
+
263
+ # If there's capacity for this many more
264
+ (registered + quantity) <= event_product.capacity
265
+ end
266
+
232
267
  end
233
268
  end
@@ -42,6 +42,7 @@ module Effective
42
42
 
43
43
  scope :sorted, -> { order(:id) }
44
44
  scope :deep, -> { includes(:event, :event_product) }
45
+ scope :registered, -> { purchased_or_deferred.unarchived }
45
46
 
46
47
  before_validation(if: -> { event_registration.present? }) do
47
48
  self.event ||= event_registration.event
@@ -9,7 +9,8 @@ module Effective
9
9
  belongs_to :event
10
10
 
11
11
  has_many :event_addons
12
- has_many :purchased_event_addons, -> { EventAddon.purchased }, class_name: 'Effective::EventAddon'
12
+ has_many :purchased_event_addons, -> { EventAddon.purchased.unarchived }, class_name: 'Effective::EventAddon'
13
+ has_many :registered_event_addons, -> { EventAddon.registered.unarchived }, class_name: 'Effective::EventAddon'
13
14
 
14
15
  log_changes(to: :event) if respond_to?(:log_changes)
15
16
 
@@ -45,23 +46,17 @@ module Effective
45
46
  title.presence || 'New Event Product'
46
47
  end
47
48
 
48
- # Available for purchase
49
- def available?
50
- return false if archived?
51
- capacity_available?
52
- end
53
-
54
- def capacity_available?
55
- capacity.blank? || (capacity_available > 0)
56
- end
57
-
58
49
  def capacity_available
59
50
  return nil if capacity.blank?
60
- [(capacity - purchased_event_addons_count), 0].max
51
+ [(capacity - registered_event_addons_count), 0].max
52
+ end
53
+
54
+ def registered_event_addons_count
55
+ registered_event_addons.length
61
56
  end
62
57
 
63
58
  def purchased_event_addons_count
64
- purchased_event_addons.reject(&:archived?).length
59
+ purchased_event_addons.length
65
60
  end
66
61
 
67
62
  end
@@ -41,6 +41,7 @@ module Effective
41
41
 
42
42
  scope :sorted, -> { order(:last_name) }
43
43
  scope :deep, -> { includes(:event, :event_ticket) }
44
+ scope :registered, -> { purchased_or_deferred.unarchived }
44
45
 
45
46
  validates :first_name, presence: true
46
47
  validates :last_name, presence: true
@@ -9,7 +9,8 @@ module Effective
9
9
  belongs_to :event
10
10
 
11
11
  has_many :event_registrants
12
- has_many :purchased_event_registrants, -> { EventRegistrant.purchased }, class_name: 'Effective::EventRegistrant'
12
+ has_many :purchased_event_registrants, -> { EventRegistrant.purchased.unarchived }, class_name: 'Effective::EventRegistrant'
13
+ has_many :registered_event_registrants, -> { EventRegistrant.registered.unarchived }, class_name: 'Effective::EventRegistrant'
13
14
 
14
15
  log_changes(to: :event) if respond_to?(:log_changes)
15
16
 
@@ -51,23 +52,17 @@ module Effective
51
52
  event.early_bird? ? early_bird_price : regular_price
52
53
  end
53
54
 
54
- # Available for purchase
55
- def available?
56
- return false if archived?
57
- capacity_available?
58
- end
59
-
60
- def capacity_available?
61
- capacity.blank? || (capacity_available > 0)
62
- end
63
-
64
55
  def capacity_available
65
56
  return nil if capacity.blank?
66
- [(capacity - purchased_event_registrants_count), 0].max
57
+ [(capacity - registered_event_registrants_count), 0].max
58
+ end
59
+
60
+ def registered_event_registrants_count
61
+ registered_event_registrants.length
67
62
  end
68
63
 
69
64
  def purchased_event_registrants_count
70
- purchased_event_registrants.reject(&:archived?).length
65
+ purchased_event_registrants.length
71
66
  end
72
67
 
73
68
  end
@@ -1,5 +1,5 @@
1
1
  -# In progress registration
2
- - registration = EffectiveEvents.EventRegistration.in_progress.for(current_user).first
2
+ - registration = EffectiveEvents.EventRegistration.in_progress.includes(event: :event_products).for(current_user).first
3
3
 
4
4
  - datatable = EffectiveResources.best('EffectiveEventRegistrationsDatatable').new(self, namespace: :effective)
5
5
 
@@ -1,6 +1,18 @@
1
1
  = render 'layout' do
2
2
  = render 'effective/event_registrations/content', resource: resource
3
3
 
4
- .card
5
- .card-body
6
- = render_checkout_step2(resource.submit_order, purchased_url: wizard_path(:submitted), deferred_url: wizard_path(:checkout), declined_url: wizard_path(:checkout))
4
+ - if resource.submit_order.deferred?
5
+ .card
6
+ .card-body
7
+ = render_checkout_step2(resource.submit_order, purchased_url: wizard_path(:submitted), deferred_url: wizard_path(:checkout), declined_url: wizard_path(:checkout))
8
+ - elsif resource.event.registerable? == false
9
+ .alert.alert-danger Your selected event is no longer available for registration.
10
+ - elsif resource.unavailable_event_tickets.present?
11
+ .alert.alert-danger Your selected number of event tickets are no longer available.
12
+ - elsif resource.unavailable_event_products.present?
13
+ .alert.alert-danger Your selected number of event add-ons are no longer available.
14
+ - else
15
+ .card
16
+ .card-body
17
+ = render_checkout_step2(resource.submit_order, purchased_url: wizard_path(:submitted), deferred_url: wizard_path(:checkout), declined_url: wizard_path(:checkout))
18
+
@@ -1,3 +1,3 @@
1
1
  module EffectiveEvents
2
- VERSION = '0.10.1'.freeze
2
+ VERSION = '0.11.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: 0.10.1
4
+ version: 0.11.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: 2023-12-01 00:00:00.000000000 Z
11
+ date: 2024-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails