effective_events 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +97 -0
- data/Rakefile +18 -0
- data/app/assets/config/effective_events_manifest.js +3 -0
- data/app/assets/javascripts/effective_events/base.js +0 -0
- data/app/assets/javascripts/effective_events.js +1 -0
- data/app/assets/stylesheets/effective_events/base.scss +0 -0
- data/app/assets/stylesheets/effective_events.scss +1 -0
- data/app/controllers/admin/event_registrants_controller.rb +11 -0
- data/app/controllers/admin/event_registrations_controller.rb +19 -0
- data/app/controllers/admin/event_tickets_controller.rb +8 -0
- data/app/controllers/admin/events_controller.rb +18 -0
- data/app/controllers/effective/event_registrations_controller.rb +53 -0
- data/app/controllers/effective/events_controller.rb +47 -0
- data/app/datatables/admin/effective_event_registrants_datatable.rb +47 -0
- data/app/datatables/admin/effective_event_registrations_datatable.rb +25 -0
- data/app/datatables/admin/effective_event_tickets_datatable.rb +42 -0
- data/app/datatables/admin/effective_events_datatable.rb +51 -0
- data/app/datatables/effective_event_registrants_datatable.rb +50 -0
- data/app/datatables/effective_event_registrations_datatable.rb +35 -0
- data/app/datatables/effective_events_datatable.rb +42 -0
- data/app/helpers/effective_events_helper.rb +18 -0
- data/app/models/concerns/effective_events_event_registration.rb +231 -0
- data/app/models/effective/event.rb +181 -0
- data/app/models/effective/event_registrant.rb +85 -0
- data/app/models/effective/event_registration.rb +7 -0
- data/app/models/effective/event_ticket.rb +59 -0
- data/app/views/admin/event_registrants/_form.html.haml +14 -0
- data/app/views/admin/event_tickets/_form.html.haml +7 -0
- data/app/views/admin/events/_form.html.haml +27 -0
- data/app/views/admin/events/_form_access.html.haml +10 -0
- data/app/views/admin/events/_form_content.html.haml +5 -0
- data/app/views/admin/events/_form_event.html.haml +24 -0
- data/app/views/admin/events/_form_event_registration_content.html.haml +19 -0
- data/app/views/effective/event_registrants/_fields.html.haml +19 -0
- data/app/views/effective/event_registrations/_content.html.haml +10 -0
- data/app/views/effective/event_registrations/_dashboard.html.haml +30 -0
- data/app/views/effective/event_registrations/_event_registration.html.haml +8 -0
- data/app/views/effective/event_registrations/_layout.html.haml +3 -0
- data/app/views/effective/event_registrations/_orders.html.haml +4 -0
- data/app/views/effective/event_registrations/_registrants.html.haml +10 -0
- data/app/views/effective/event_registrations/_summary.html.haml +29 -0
- data/app/views/effective/event_registrations/billing.html.haml +14 -0
- data/app/views/effective/event_registrations/checkout.html.haml +6 -0
- data/app/views/effective/event_registrations/registrants.html.haml +14 -0
- data/app/views/effective/event_registrations/start.html.haml +18 -0
- data/app/views/effective/event_registrations/submitted.html.haml +15 -0
- data/app/views/effective/event_registrations/summary.html.haml +8 -0
- data/app/views/effective/event_tickets/_fields.html.haml +4 -0
- data/app/views/effective/events/_dashboard.html.haml +14 -0
- data/app/views/effective/events/_event.html.haml +23 -0
- data/app/views/effective/events/_layout.html.haml +1 -0
- data/app/views/effective/events/_spacer.html.haml +1 -0
- data/app/views/effective/events/index.html.haml +8 -0
- data/app/views/effective/events/show.html.haml +16 -0
- data/config/effective_events.rb +17 -0
- data/config/routes.rb +24 -0
- data/db/migrate/01_create_effective_events.rb.erb +98 -0
- data/db/seeds.rb +45 -0
- data/lib/effective_events/engine.rb +18 -0
- data/lib/effective_events/version.rb +3 -0
- data/lib/effective_events.rb +21 -0
- data/lib/generators/effective_events/install_generator.rb +30 -0
- data/lib/generators/templates/effective_events_mailer_preview.rb +4 -0
- data/lib/tasks/effective_events_tasks.rake +8 -0
- metadata +262 -0
@@ -0,0 +1,231 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# EffectiveEventsEventRegistration
|
4
|
+
#
|
5
|
+
# Mark your owner model with effective_events_event_registration to get all the includes
|
6
|
+
|
7
|
+
module EffectiveEventsEventRegistration
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
module Base
|
11
|
+
def effective_events_event_registration
|
12
|
+
include ::EffectiveEventsEventRegistration
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def effective_events_event_registration?; true; end
|
18
|
+
|
19
|
+
def all_wizard_steps
|
20
|
+
const_get(:WIZARD_STEPS).keys
|
21
|
+
end
|
22
|
+
|
23
|
+
def required_wizard_steps
|
24
|
+
[:start, :summary, :billing, :checkout, :submitted]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
included do
|
29
|
+
acts_as_purchasable_parent
|
30
|
+
acts_as_tokened
|
31
|
+
|
32
|
+
acts_as_statused(
|
33
|
+
:draft, # Just Started
|
34
|
+
:submitted # All done
|
35
|
+
)
|
36
|
+
|
37
|
+
acts_as_wizard(
|
38
|
+
start: 'Start',
|
39
|
+
registrants: 'Registrants',
|
40
|
+
summary: 'Review',
|
41
|
+
billing: 'Billing Address',
|
42
|
+
checkout: 'Checkout',
|
43
|
+
submitted: 'Submitted'
|
44
|
+
)
|
45
|
+
|
46
|
+
log_changes(except: :wizard_steps) if respond_to?(:log_changes)
|
47
|
+
|
48
|
+
# Application Namespace
|
49
|
+
belongs_to :owner, polymorphic: true
|
50
|
+
accepts_nested_attributes_for :owner
|
51
|
+
|
52
|
+
# Effective Namespace
|
53
|
+
belongs_to :event
|
54
|
+
|
55
|
+
has_many :event_registrants, -> { order(:id) }, inverse_of: :event_registration, dependent: :destroy
|
56
|
+
accepts_nested_attributes_for :event_registrants, reject_if: :all_blank, allow_destroy: true
|
57
|
+
|
58
|
+
has_many :orders, -> { order(:id) }, as: :parent, class_name: 'Effective::Order', dependent: :nullify
|
59
|
+
accepts_nested_attributes_for :orders
|
60
|
+
|
61
|
+
effective_resource do
|
62
|
+
# Acts as Statused
|
63
|
+
status :string, permitted: false
|
64
|
+
status_steps :text, permitted: false
|
65
|
+
|
66
|
+
# Dates
|
67
|
+
submitted_at :datetime
|
68
|
+
|
69
|
+
# Acts as Wizard
|
70
|
+
wizard_steps :text, permitted: false
|
71
|
+
|
72
|
+
timestamps
|
73
|
+
end
|
74
|
+
|
75
|
+
scope :deep, -> { includes(:owner, :event, :event_registrants) }
|
76
|
+
scope :sorted, -> { order(:id) }
|
77
|
+
|
78
|
+
scope :in_progress, -> { where.not(status: [:submitted]) }
|
79
|
+
scope :done, -> { where(status: [:submitted]) }
|
80
|
+
|
81
|
+
scope :for, -> (user) {
|
82
|
+
owner = (user.respond_to?(:effective_memberships_owners) ? user.effective_memberships_owners : user)
|
83
|
+
where(owner: owner)
|
84
|
+
}
|
85
|
+
|
86
|
+
# All Steps validations
|
87
|
+
validates :owner, presence: true
|
88
|
+
validates :event, presence: true
|
89
|
+
|
90
|
+
# Registrants Step
|
91
|
+
validate(if: -> { current_step == :registrants }) do
|
92
|
+
self.errors.add(:event_registrants, "can't be blank") unless present_event_registrants.present?
|
93
|
+
end
|
94
|
+
|
95
|
+
# Billing Step
|
96
|
+
validate(if: -> { current_step == :billing && owner.present? }) do
|
97
|
+
self.errors.add(:base, "must have a billing address") unless owner.billing_address.present?
|
98
|
+
self.errors.add(:base, "must have an email") unless owner.email.present?
|
99
|
+
end
|
100
|
+
|
101
|
+
after_purchase do |_|
|
102
|
+
raise('expected submit_order to be purchased') unless submit_order&.purchased?
|
103
|
+
submit_purchased!
|
104
|
+
after_submit_purchased!
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Instance Methods
|
109
|
+
def to_s
|
110
|
+
persisted? ? "Registration ##{id}" : 'Event Registration'
|
111
|
+
end
|
112
|
+
|
113
|
+
def in_progress?
|
114
|
+
draft?
|
115
|
+
end
|
116
|
+
|
117
|
+
def done?
|
118
|
+
submitted?
|
119
|
+
end
|
120
|
+
|
121
|
+
def can_visit_step?(step)
|
122
|
+
can_revisit_completed_steps(step)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Find or build
|
126
|
+
def event_registrant(first_name:, last_name:, email:)
|
127
|
+
registrant = event_registrants.find { |er| er.first_name == first_name && er.last_name == last_name && er.email == email }
|
128
|
+
registrant || event_registrants.build(event: event, owner: owner, first_name: first_name, last_name: last_name, email: email)
|
129
|
+
end
|
130
|
+
|
131
|
+
# This builds the default event registrants used by the wizard form
|
132
|
+
def build_event_registrants
|
133
|
+
if event_registrants.blank?
|
134
|
+
raise('expected owner and event to be present') unless owner && event
|
135
|
+
event_registrants.build(first_name: owner.first_name, last_name: owner.last_name, email: owner.email)
|
136
|
+
end
|
137
|
+
|
138
|
+
event_registrants
|
139
|
+
end
|
140
|
+
|
141
|
+
# All Fees and Orders
|
142
|
+
def submit_fees
|
143
|
+
event_registrants
|
144
|
+
end
|
145
|
+
|
146
|
+
def submit_order
|
147
|
+
orders.first
|
148
|
+
end
|
149
|
+
|
150
|
+
def find_or_build_submit_order
|
151
|
+
order = submit_order || orders.build(user: owner)
|
152
|
+
fees = submit_fees()
|
153
|
+
|
154
|
+
# Adds fees, but does not overwrite any existing price.
|
155
|
+
fees.each do |fee|
|
156
|
+
order.add(fee) unless order.purchasables.include?(fee)
|
157
|
+
end
|
158
|
+
|
159
|
+
order.purchasables.each do |purchasable|
|
160
|
+
order.remove(purchasable) unless fees.include?(purchasable)
|
161
|
+
end
|
162
|
+
|
163
|
+
# From Billing Step
|
164
|
+
order.billing_address = owner.billing_address if owner.billing_address.present?
|
165
|
+
|
166
|
+
# Important to add/remove anything
|
167
|
+
order.save
|
168
|
+
|
169
|
+
order
|
170
|
+
end
|
171
|
+
|
172
|
+
# Should be indempotent.
|
173
|
+
def build_submit_fees_and_order
|
174
|
+
return false if was_submitted?
|
175
|
+
|
176
|
+
fees = submit_fees()
|
177
|
+
raise('already has purchased submit fees') if fees.any?(&:purchased?)
|
178
|
+
|
179
|
+
order = find_or_build_submit_order()
|
180
|
+
raise('already has purchased submit order') if order.purchased?
|
181
|
+
|
182
|
+
true
|
183
|
+
end
|
184
|
+
|
185
|
+
# If they go back and change registrants. Update the order right away.
|
186
|
+
def registrants!
|
187
|
+
save!
|
188
|
+
build_submit_fees_and_order if submit_order.present?
|
189
|
+
true
|
190
|
+
end
|
191
|
+
|
192
|
+
# Owner clicks on the Billing step. Next step is Checkout
|
193
|
+
def billing!
|
194
|
+
ready!
|
195
|
+
end
|
196
|
+
|
197
|
+
# Ready to check out
|
198
|
+
def ready!
|
199
|
+
build_submit_fees_and_order
|
200
|
+
save!
|
201
|
+
end
|
202
|
+
|
203
|
+
# Called automatically via after_purchase hook above
|
204
|
+
def submit_purchased!
|
205
|
+
return false if was_submitted?
|
206
|
+
|
207
|
+
wizard_steps[:checkout] = Time.zone.now
|
208
|
+
submit!
|
209
|
+
end
|
210
|
+
|
211
|
+
# A hook to extend
|
212
|
+
def after_submit_purchased!
|
213
|
+
end
|
214
|
+
|
215
|
+
# Draft -> Submitted requirements
|
216
|
+
def submit!
|
217
|
+
raise('already submitted') if was_submitted?
|
218
|
+
raise('expected a purchased order') unless submit_order&.purchased?
|
219
|
+
|
220
|
+
wizard_steps[:checkout] ||= Time.zone.now
|
221
|
+
wizard_steps[:submitted] = Time.zone.now
|
222
|
+
submitted!
|
223
|
+
end
|
224
|
+
|
225
|
+
private
|
226
|
+
|
227
|
+
def present_event_registrants
|
228
|
+
event_registrants.reject(&:marked_for_destruction?)
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Effective
|
4
|
+
class Event < ActiveRecord::Base
|
5
|
+
has_many :event_registrants, -> { order(:event_ticket_id, :created_at) }, inverse_of: :event
|
6
|
+
accepts_nested_attributes_for :event_registrants, allow_destroy: true
|
7
|
+
|
8
|
+
has_many :event_tickets, -> { order(:id) }, inverse_of: :event
|
9
|
+
accepts_nested_attributes_for :event_tickets, allow_destroy: true
|
10
|
+
|
11
|
+
# rich_text_body - Used by the select step
|
12
|
+
has_many_rich_texts
|
13
|
+
|
14
|
+
# rich_text_body
|
15
|
+
# rich_text_excerpt
|
16
|
+
|
17
|
+
# rich_text_all_steps_content
|
18
|
+
# rich_text_start_content
|
19
|
+
# rich_text_select_content
|
20
|
+
# rich_text_select_content
|
21
|
+
|
22
|
+
acts_as_slugged
|
23
|
+
log_changes if respond_to?(:log_changes)
|
24
|
+
acts_as_role_restricted if respond_to?(:acts_as_role_restricted)
|
25
|
+
|
26
|
+
self.table_name = EffectiveEvents.events_table_name.to_s
|
27
|
+
|
28
|
+
effective_resource do
|
29
|
+
title :string
|
30
|
+
|
31
|
+
slug :string
|
32
|
+
draft :boolean
|
33
|
+
|
34
|
+
start_at :datetime
|
35
|
+
end_at :datetime
|
36
|
+
|
37
|
+
registration_start_at :datetime
|
38
|
+
registration_end_at :datetime
|
39
|
+
|
40
|
+
early_bird_end_at :datetime # Optional
|
41
|
+
|
42
|
+
# Access
|
43
|
+
roles_mask :integer
|
44
|
+
authenticate_user :boolean
|
45
|
+
|
46
|
+
timestamps
|
47
|
+
end
|
48
|
+
|
49
|
+
scope :sorted, -> { order(:end_at) }
|
50
|
+
scope :deep, -> { includes(:event_registrants, :event_tickets) }
|
51
|
+
|
52
|
+
scope :drafts, -> { where(draft: true) }
|
53
|
+
scope :published, -> { where(draft: false) }
|
54
|
+
|
55
|
+
scope :upcoming, -> { where(arel_table[:end_at].gt(Time.zone.now)) }
|
56
|
+
scope :past, -> { where(arel_table[:end_at].lteq(Time.zone.now)) }
|
57
|
+
|
58
|
+
scope :closed, -> { where(arel_table[:registration_end_at].lt(Time.zone.now)) }
|
59
|
+
scope :not_closed, -> { where(arel_table[:registration_end_at].gteq(Time.zone.now)) }
|
60
|
+
|
61
|
+
scope :with_tickets, -> { where(id: Effective::EventTicket.select('event_id')) }
|
62
|
+
|
63
|
+
# Doesnt consider sold out yet
|
64
|
+
scope :registerable, -> { published.not_closed.with_tickets }
|
65
|
+
|
66
|
+
scope :paginate, -> (page: nil, per_page: nil) {
|
67
|
+
page = (page || 1).to_i
|
68
|
+
offset = [(page - 1), 0].max * (per_page || EffectiveEvents.per_page)
|
69
|
+
|
70
|
+
limit(per_page).offset(offset)
|
71
|
+
}
|
72
|
+
|
73
|
+
scope :events, -> (user: nil, unpublished: false) {
|
74
|
+
scope = all.deep.sorted
|
75
|
+
|
76
|
+
if defined?(EffectiveRoles) && EffectivePosts.use_effective_roles
|
77
|
+
scope = scope.for_role(user&.roles)
|
78
|
+
end
|
79
|
+
|
80
|
+
if user.blank?
|
81
|
+
scope = scope.where(authenticate_user: false)
|
82
|
+
end
|
83
|
+
|
84
|
+
unless unpublished
|
85
|
+
scope = scope.published
|
86
|
+
end
|
87
|
+
|
88
|
+
scope
|
89
|
+
}
|
90
|
+
|
91
|
+
validates :title, presence: true, length: { maximum: 255 }
|
92
|
+
|
93
|
+
validates :start_at, presence: true
|
94
|
+
validates :end_at, presence: true
|
95
|
+
validates :registration_start_at, presence: true
|
96
|
+
validates :registration_end_at, presence: true
|
97
|
+
|
98
|
+
validate(if: -> { start_at && end_at }) do
|
99
|
+
self.errors.add(:end_at, 'must be after start date') unless start_at < end_at
|
100
|
+
end
|
101
|
+
|
102
|
+
validate(if: -> { start_at && registration_start_at }) do
|
103
|
+
self.errors.add(:registration_start_at, 'must be before start date') unless registration_start_at < start_at
|
104
|
+
end
|
105
|
+
|
106
|
+
validate(if: -> { registration_start_at && registration_end_at }) do
|
107
|
+
self.errors.add(:registration_end_at, 'must be after start registration date') unless registration_start_at < registration_end_at
|
108
|
+
end
|
109
|
+
|
110
|
+
validate(if: -> { start_at && early_bird_end_at }) do
|
111
|
+
self.errors.add(:early_bird_end_at, 'must be before start date') unless early_bird_end_at < start_at
|
112
|
+
end
|
113
|
+
|
114
|
+
def to_s
|
115
|
+
title.presence || 'New Event'
|
116
|
+
end
|
117
|
+
|
118
|
+
def body
|
119
|
+
rich_text_body
|
120
|
+
end
|
121
|
+
|
122
|
+
def excerpt
|
123
|
+
rich_text_excerpt
|
124
|
+
end
|
125
|
+
|
126
|
+
def registerable?
|
127
|
+
return false if draft?
|
128
|
+
return false if closed?
|
129
|
+
return false if sold_out?
|
130
|
+
return false if event_tickets.blank?
|
131
|
+
|
132
|
+
true
|
133
|
+
end
|
134
|
+
|
135
|
+
def closed?
|
136
|
+
return false if registration_end_at.blank?
|
137
|
+
registration_end_at < Time.zone.now
|
138
|
+
end
|
139
|
+
|
140
|
+
def sold_out?
|
141
|
+
false
|
142
|
+
end
|
143
|
+
|
144
|
+
def early_bird?
|
145
|
+
return false if early_bird_end_at.blank?
|
146
|
+
early_bird_end_at < Time.zone.now
|
147
|
+
end
|
148
|
+
|
149
|
+
def early_bird_past?
|
150
|
+
return false if early_bird_end_at.blank?
|
151
|
+
early_bird_end_at >= Time.zone.now
|
152
|
+
end
|
153
|
+
|
154
|
+
def early_bird_status
|
155
|
+
if early_bird?
|
156
|
+
'Early Bird Pricing'
|
157
|
+
elsif early_bird_past?
|
158
|
+
'Expired'
|
159
|
+
else
|
160
|
+
'None'
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Returns a duplicated event object, or throws an exception
|
165
|
+
def duplicate
|
166
|
+
Event.new(attributes.except('id', 'updated_at', 'created_at')).tap do |event|
|
167
|
+
event.title = event.title + ' (Copy)'
|
168
|
+
event.slug = event.slug + '-copy'
|
169
|
+
event.draft = true
|
170
|
+
|
171
|
+
event.body = body
|
172
|
+
event.excerpt = excerpt
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def duplicate!
|
177
|
+
duplicate.tap { |event| event.save! }
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Effective
|
4
|
+
class EventRegistrant < ActiveRecord::Base
|
5
|
+
acts_as_purchasable
|
6
|
+
log_changes(to: :event) if respond_to?(:log_changes)
|
7
|
+
|
8
|
+
belongs_to :event, counter_cache: true
|
9
|
+
|
10
|
+
# Basically a category containing all the pricing and unique info about htis registrant
|
11
|
+
belongs_to :event_ticket
|
12
|
+
|
13
|
+
# Every event registrant is charged to a owner
|
14
|
+
belongs_to :owner, polymorphic: true
|
15
|
+
|
16
|
+
# This fee when checked out through the event registration
|
17
|
+
belongs_to :event_registration, polymorphic: true, optional: true
|
18
|
+
|
19
|
+
effective_resource do
|
20
|
+
first_name :string
|
21
|
+
last_name :string
|
22
|
+
email :string
|
23
|
+
|
24
|
+
company :string
|
25
|
+
number :string
|
26
|
+
notes :text
|
27
|
+
|
28
|
+
# Acts as Purchasable
|
29
|
+
price :integer
|
30
|
+
qb_item_name :string
|
31
|
+
tax_exempt :boolean
|
32
|
+
|
33
|
+
timestamps
|
34
|
+
end
|
35
|
+
|
36
|
+
scope :sorted, -> { order(:last_name) }
|
37
|
+
scope :deep, -> { all }
|
38
|
+
|
39
|
+
validates :first_name, presence: true
|
40
|
+
validates :last_name, presence: true
|
41
|
+
validates :email, presence: true, email: true
|
42
|
+
|
43
|
+
before_validation(if: -> { event_registration.present? }) do
|
44
|
+
self.event ||= event_registration.event
|
45
|
+
self.owner ||= event_registration.owner
|
46
|
+
end
|
47
|
+
|
48
|
+
before_validation(if: -> { event_ticket.present? }) do
|
49
|
+
self.price ||= event_ticket.price
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_s
|
53
|
+
persisted? ? title : 'registrant'
|
54
|
+
end
|
55
|
+
|
56
|
+
def title
|
57
|
+
"#{event_ticket} - #{last_first_name}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def last_first_name
|
61
|
+
"#{last_name}, #{first_name}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def tax_exempt
|
65
|
+
event_ticket.tax_exempt
|
66
|
+
end
|
67
|
+
|
68
|
+
def qb_item_name
|
69
|
+
event_ticket.qb_item_name
|
70
|
+
end
|
71
|
+
|
72
|
+
# This is the Admin Save and Mark Paid action
|
73
|
+
def mark_paid!
|
74
|
+
raise('expected a blank event registration') if event_registration.present?
|
75
|
+
|
76
|
+
save!
|
77
|
+
|
78
|
+
order = Effective::Order.new(items: self, user: owner)
|
79
|
+
order.purchase!(skip_buyer_validations: true, email: false)
|
80
|
+
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Effective
|
4
|
+
class EventTicket < ActiveRecord::Base
|
5
|
+
belongs_to :event
|
6
|
+
|
7
|
+
has_many :event_registrants
|
8
|
+
has_many :purchased_event_registrants, -> { EventRegistrant.purchased }, class_name: 'Effective::EventRegistrant'
|
9
|
+
|
10
|
+
log_changes(to: :event) if respond_to?(:log_changes)
|
11
|
+
|
12
|
+
has_rich_text :body
|
13
|
+
|
14
|
+
effective_resource do
|
15
|
+
title :string
|
16
|
+
capacity :integer
|
17
|
+
|
18
|
+
# Pricing
|
19
|
+
regular_price :integer
|
20
|
+
early_bird_price :integer
|
21
|
+
|
22
|
+
qb_item_name :string
|
23
|
+
tax_exempt :boolean
|
24
|
+
|
25
|
+
position :integer
|
26
|
+
|
27
|
+
timestamps
|
28
|
+
end
|
29
|
+
|
30
|
+
scope :sorted, -> { order(:position) }
|
31
|
+
scope :deep, -> { with_rich_text_body.includes(:purchased_event_registrants) }
|
32
|
+
|
33
|
+
before_validation(if: -> { event.present? }) do
|
34
|
+
self.position ||= (event.event_tickets.map(&:position).compact.max || -1) + 1
|
35
|
+
end
|
36
|
+
|
37
|
+
validates :title, presence: true
|
38
|
+
validates :regular_price, presence: true
|
39
|
+
validates :early_bird_price, presence: true, if: -> { event&.early_bird_end_at.present? }
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
title.presence || 'New Event Ticket'
|
43
|
+
end
|
44
|
+
|
45
|
+
def price
|
46
|
+
event.early_bird? ? early_bird_price : regular_price
|
47
|
+
end
|
48
|
+
|
49
|
+
def capacity_available?
|
50
|
+
return true if capacity.blank?
|
51
|
+
capacity <= purchased_event_registrants.count
|
52
|
+
end
|
53
|
+
|
54
|
+
def purchased_event_registrants_count
|
55
|
+
purchased_event_registrants.count
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
= effective_form_with(model: [:admin, event_registrant], engine: true) do |f|
|
2
|
+
= f.hidden_field :event_id
|
3
|
+
|
4
|
+
- if f.object.new_record?
|
5
|
+
= f.select :owner, { 'Users' => current_user.class.all }, polymorphic: true
|
6
|
+
- else
|
7
|
+
= f.static_field :owner
|
8
|
+
|
9
|
+
= render 'effective/event_registrants/fields', f: f, event: event_registrant.event
|
10
|
+
|
11
|
+
- if f.object.new_record?
|
12
|
+
= f.submit 'Save and Mark Paid'
|
13
|
+
- else
|
14
|
+
= f.submit 'Save'
|
@@ -0,0 +1,7 @@
|
|
1
|
+
= effective_form_with(model: [:admin, event_ticket], engine: true) do |f|
|
2
|
+
= f.hidden_field :event_id
|
3
|
+
|
4
|
+
/= f.number_field :capacity, hint: 'The number of online purchases will be loosely limited to capacity.'
|
5
|
+
= render 'effective/event_tickets/fields', f: f
|
6
|
+
|
7
|
+
= effective_submit(f)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
= tabs do
|
2
|
+
= tab "Event" do
|
3
|
+
= render 'admin/events/form_event', event: event
|
4
|
+
|
5
|
+
- if event.persisted?
|
6
|
+
= tab 'Registrants' do
|
7
|
+
- datatable = Admin::EffectiveEventRegistrantsDatatable.new(event_id: event.id)
|
8
|
+
= render_inline_datatable(datatable)
|
9
|
+
|
10
|
+
= tab 'Content' do
|
11
|
+
= render '/admin/events/form_content', event: event
|
12
|
+
|
13
|
+
= tab 'Tickets' do
|
14
|
+
%p An event must have tickets before registration can begin
|
15
|
+
|
16
|
+
- datatable = Admin::EffectiveEventTicketsDatatable.new(event_id: event.id)
|
17
|
+
= render_inline_datatable(datatable)
|
18
|
+
|
19
|
+
= tab 'Registration' do
|
20
|
+
= render '/admin/events/form_event_registration_content', event: event
|
21
|
+
|
22
|
+
= tab 'Access' do
|
23
|
+
= render '/admin/events/form_access', event: event
|
24
|
+
|
25
|
+
- if event.respond_to?(:log_changes_datatable)
|
26
|
+
= tab "Logs" do
|
27
|
+
= render_inline_datatable(event.log_changes_datatable)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
= effective_form_with(model: event, url: event.persisted? ? effective_events.admin_event_path(event.id) : effective_events.admin_events_path) 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'
|
3
|
+
|
4
|
+
- if EffectiveEvents.use_effective_roles
|
5
|
+
= f.checks :roles, EffectiveRoles.roles_collection(f.object)
|
6
|
+
|
7
|
+
%p.text-hint
|
8
|
+
* leave blank for a regular public event that anyone can view
|
9
|
+
|
10
|
+
= f.submit
|
@@ -0,0 +1,24 @@
|
|
1
|
+
= effective_form_with(model: [:admin, event], engine: true) do |f|
|
2
|
+
= f.text_field :title, label: "Title"
|
3
|
+
= f.check_box :draft, hint: 'Save this event as a draft. It will not be accessible on the website.'
|
4
|
+
|
5
|
+
- if f.object.persisted? || f.object.errors.include?(:slug)
|
6
|
+
- current_url = (effective_events.event_url(f.object) rescue nil)
|
7
|
+
= f.text_field :slug, hint: "The slug controls this event's internet address. Be careful, changing the slug will break links that other websites may have to the old address.<br>#{('This event is currently reachable via ' + link_to(current_url.gsub(f.object.slug, '<strong>' + f.object.slug + '</strong>').html_safe, current_url)) if current_url }".html_safe
|
8
|
+
|
9
|
+
= f.datetime_field :start_at, label: "Event Start"
|
10
|
+
= f.datetime_field :end_at, label: "Event End"
|
11
|
+
|
12
|
+
%h2 Registration Opens
|
13
|
+
%p The online registration and purchase for this event will be available between:
|
14
|
+
= f.datetime_field :registration_start_at, label: "Registration Start"
|
15
|
+
= f.datetime_field :registration_end_at, label: "Registration End"
|
16
|
+
|
17
|
+
= f.datetime_field :early_bird_end_at, label: "Early Bird End",
|
18
|
+
hint: 'Event tickets can be purchased for early bird pricing before this date. Afterwards regular pricing applies.'
|
19
|
+
|
20
|
+
= f.submit do
|
21
|
+
= f.save 'Save'
|
22
|
+
= f.save 'Save and View', class: 'btn btn-secondary'
|
23
|
+
- if f.object.persisted?
|
24
|
+
= f.save 'Duplicate', class: 'btn btn-info'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
%p Each of the following content areas will be displayed on the event registration wizard.
|
2
|
+
|
3
|
+
= effective_form_with(model: [:admin, event], engine: true) do |f|
|
4
|
+
= card("All Steps") do
|
5
|
+
= f.rich_text_area "rich_text_all_steps_content", label: false,
|
6
|
+
hint: "displayed on all steps"
|
7
|
+
|
8
|
+
%hr
|
9
|
+
|
10
|
+
- enabled = EffectiveEvents.EventRegistration.all_wizard_steps
|
11
|
+
|
12
|
+
- EffectiveEvents.EventRegistration::WIZARD_STEPS.each do |step, title|
|
13
|
+
- next unless enabled.include?(step)
|
14
|
+
|
15
|
+
= card("#{title}") do
|
16
|
+
= f.rich_text_area "rich_text_#{step}_content", label: false,
|
17
|
+
hint: "displayed on the event registration #{step} wizard step only"
|
18
|
+
|
19
|
+
= f.submit
|
@@ -0,0 +1,19 @@
|
|
1
|
+
.card
|
2
|
+
.card-body
|
3
|
+
%h5.card-title Event Registrant
|
4
|
+
|
5
|
+
- if f.object.purchased?
|
6
|
+
= f.static_field :event_ticket, label: 'Purchased event ticket'
|
7
|
+
- else
|
8
|
+
= f.select :event_ticket_id, effective_events_event_tickets_collection(event)
|
9
|
+
|
10
|
+
.row
|
11
|
+
.col-lg= f.text_field :first_name
|
12
|
+
.col-lg= f.text_field :last_name
|
13
|
+
.col-lg= f.text_field :number
|
14
|
+
|
15
|
+
.row
|
16
|
+
.col-lg= f.email_field :email
|
17
|
+
.col-lg= f.text_field :company
|
18
|
+
|
19
|
+
= f.text_area :notes, label: 'Dietary restrictions or other notes'
|