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