effective_events 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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