artfully_ose 1.2.0.pre.27 → 1.2.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 +8 -8
- data/README.md +4 -6
- data/app/assets/javascripts/application.js +39 -0
- data/app/assets/javascripts/boxoffice.js +558 -0
- data/app/assets/javascripts/custom/kits-config.js +33 -0
- data/app/assets/javascripts/sales-console.js +29 -24
- data/app/assets/javascripts/store/store.js +11 -0
- data/app/assets/stylesheets/application.sass +66 -52
- data/app/assets/stylesheets/bootstrap-overrides.css +1 -1
- data/app/assets/stylesheets/boxoffice.css.scss +258 -0
- data/app/assets/stylesheets/pages/bootstrap-responsive.css +1109 -0
- data/app/assets/stylesheets/sass/store.sass +52 -62
- data/app/assets/stylesheets/storefront.css +1 -1
- data/app/concerns/itemable.rb +1 -1
- data/app/concerns/pdf_generation.rb +1 -11
- data/app/concerns/search_by_dates.rb +20 -0
- data/app/controllers/events_controller.rb +1 -0
- data/app/controllers/export_controller.rb +11 -1
- data/app/controllers/imports_controller.rb +2 -3
- data/app/controllers/member_cards_controller.rb +2 -3
- data/app/controllers/orders_controller.rb +42 -0
- data/app/controllers/organizations_controller.rb +1 -0
- data/app/controllers/passes_reports_controller.rb +21 -1
- data/app/controllers/regular_donation_kits_controller.rb +32 -0
- data/app/controllers/store/donations_controller.rb +19 -1
- data/app/controllers/store/orders_controller.rb +15 -5
- data/app/helpers/artfully_ose_helper.rb +28 -18
- data/app/models/database_views/item_view.rb +41 -0
- data/app/models/event.rb +10 -2
- data/app/models/ext/integrations.rb +5 -0
- data/app/models/fee_strategy.rb +47 -1
- data/app/models/imports/events_import.rb +6 -7
- data/app/models/item.rb +4 -3
- data/app/models/job/order_processor.rb +4 -3
- data/app/models/kit.rb +18 -0
- data/app/models/kits/regular_donation_kit.rb +51 -9
- data/app/models/member.rb +4 -3
- data/app/models/membership.rb +1 -2
- data/app/models/membership_sale_search.rb +2 -20
- data/app/models/membership_type.rb +1 -2
- data/app/models/order.rb +29 -1
- data/app/models/order_handler.rb +4 -3
- data/app/models/organization.rb +17 -9
- data/app/models/pass.rb +18 -17
- data/app/models/pass_sale_search.rb +18 -0
- data/app/models/pass_type.rb +7 -2
- data/app/models/passes_report.rb +117 -0
- data/app/models/sale_search.rb +3 -21
- data/app/models/user.rb +1 -2
- data/app/serializers/show_serializer.rb +15 -0
- data/app/views/contributions/index.html.haml +2 -2
- data/app/views/events/_header.html.haml +1 -0
- data/app/views/events/_ticket_type_fields.html.haml +31 -15
- data/app/views/events/edit.html.haml +6 -1
- data/app/views/imports/_export_links.html.haml +3 -0
- data/app/views/imports/donations/_pending.html.haml +24 -6
- data/app/views/imports/events/_pending.html.haml +16 -5
- data/app/views/imports/index.html.haml +6 -4
- data/app/views/imports/people/_pending.html.haml +20 -25
- data/app/views/layouts/storefront.html.haml +9 -5
- data/app/views/order_mailer/confirmation_for.html.haml +11 -5
- data/app/views/order_mailer/confirmation_for_refund.html.haml +6 -2
- data/app/views/order_mailer/confirmation_for_refund.text.haml +4 -3
- data/app/views/orders/membership.html.haml +15 -19
- data/app/views/orders/passes.html.haml +97 -0
- data/app/views/orders/sales.html.haml +2 -2
- data/app/views/organizations/_form.html.haml +4 -37
- data/app/views/pass_types/index.html.haml +1 -1
- data/app/views/passes_reports/index.html.haml +79 -1
- data/app/views/people/show.html.haml +16 -15
- data/app/views/regular_donation_kits/edit.html.haml +140 -0
- data/app/views/store/checkouts/thanks.html.haml +14 -6
- data/app/views/store/donations/index.html.haml +19 -2
- data/app/views/store/events/calendar.html.haml +1 -0
- data/app/views/store/events/index.html.haml +1 -0
- data/app/views/store/events/show.html.haml +1 -0
- data/app/views/store/events/single_show.html.haml +2 -0
- data/app/views/store/orders/show.html.haml +10 -10
- data/app/views/store/passes/index.html.haml +2 -2
- data/app/views/store/shared/_donate_form.html.haml +31 -12
- data/app/views/store/shared/_small_donate_form.html.haml +22 -0
- data/app/views/users/invitations/edit.html.haml +3 -42
- data/config/locales/en.yml +3 -1
- data/config/routes.rb +4 -1
- data/db/migrate/20140603200735_add_subtitle_to_events.rb +5 -0
- data/lib/artfully_ose/version.rb +1 -1
- data/spec/factories/kit_factories.rb +5 -4
- metadata +25 -13
- data/app/assets/javascripts/box-office.js +0 -262
data/app/models/member.rb
CHANGED
|
@@ -169,9 +169,10 @@ class Member < ActiveRecord::Base
|
|
|
169
169
|
end
|
|
170
170
|
|
|
171
171
|
def generate_pdf
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
pdf = PdfGeneration.new(self).generate
|
|
173
|
+
file = Tempfile.new(["#{self.id}", '.pdf'])
|
|
174
|
+
file << pdf.force_encoding("UTF-8")
|
|
175
|
+
self.pdf = file
|
|
175
176
|
self.save
|
|
176
177
|
end
|
|
177
178
|
|
data/app/models/membership.rb
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
#
|
|
5
5
|
class Membership < ActiveRecord::Base
|
|
6
6
|
include Extendable
|
|
7
|
-
extend ActionView::Helpers::TextHelper
|
|
8
7
|
|
|
9
8
|
belongs_to :organization
|
|
10
9
|
belongs_to :member
|
|
@@ -72,7 +71,7 @@ class Membership < ActiveRecord::Base
|
|
|
72
71
|
if membership_types.length > 1
|
|
73
72
|
"multiple memberships"
|
|
74
73
|
else
|
|
75
|
-
pluralize(memberships.length, "#{memberships.first.membership_type.membershipize}")
|
|
74
|
+
ActionController::Base.helpers.pluralize(memberships.length, "#{memberships.first.membership_type.membershipize}")
|
|
76
75
|
end
|
|
77
76
|
else
|
|
78
77
|
"No memberships"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
class MembershipSaleSearch
|
|
2
|
+
include SearchByDates
|
|
2
3
|
|
|
3
|
-
attr_reader :
|
|
4
|
-
attr_reader :organization, :membership_type
|
|
4
|
+
attr_reader :membership_type
|
|
5
5
|
|
|
6
6
|
def initialize(terms)
|
|
7
7
|
@organization = terms[:organization]
|
|
@@ -15,22 +15,4 @@ class MembershipSaleSearch
|
|
|
15
15
|
def results
|
|
16
16
|
@results ||= Order.membership_sale_search(self).select(&:has_membership?)
|
|
17
17
|
end
|
|
18
|
-
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
def start_with(start)
|
|
22
|
-
start.present? ? DateTime.parse(start) : default_start
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def stop_with(stop)
|
|
26
|
-
stop.present? ? Sundial.midnightish(@organization, stop) : default_stop
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def default_start
|
|
30
|
-
DateTime.now.in_time_zone(@organization.time_zone).beginning_of_month
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def default_stop
|
|
34
|
-
DateTime.now.in_time_zone(@organization.time_zone).end_of_day
|
|
35
|
-
end
|
|
36
18
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
class MembershipType < ActiveRecord::Base
|
|
2
|
+
include Ext::Integrations::ServiceFee
|
|
2
3
|
extend ::ArtfullyOseHelper
|
|
3
4
|
attr_accessible :name, :price, :fee, :number_of_shows,
|
|
4
5
|
:plan, :on_sale, :description, :ends_at,
|
|
@@ -20,8 +21,6 @@ class MembershipType < ActiveRecord::Base
|
|
|
20
21
|
scope :sales_valid, where("sales_start_at < ? or sales_start_at is null", DateTime.now).where("sales_end_at > ? or sales_end_at is null", DateTime.now)
|
|
21
22
|
scope :not_ended, where('ends_at > ?', DateTime.now)
|
|
22
23
|
|
|
23
|
-
SERVICE_FEE = 0.05
|
|
24
|
-
|
|
25
24
|
comma do
|
|
26
25
|
name
|
|
27
26
|
description
|
data/app/models/order.rb
CHANGED
|
@@ -121,6 +121,10 @@ class Order < ActiveRecord::Base
|
|
|
121
121
|
def discount_codes
|
|
122
122
|
tickets.collect(&:discount).uniq.compact
|
|
123
123
|
end
|
|
124
|
+
|
|
125
|
+
def pass_codes
|
|
126
|
+
tickets.collect(&:pass).uniq.compact
|
|
127
|
+
end
|
|
124
128
|
|
|
125
129
|
def imported?
|
|
126
130
|
!self.import_id.nil?
|
|
@@ -256,7 +260,6 @@ class Order < ActiveRecord::Base
|
|
|
256
260
|
|
|
257
261
|
def self.membership_sale_search(search)
|
|
258
262
|
standard = ::Order.
|
|
259
|
-
where("orders.type != ?", ::Reseller::Order.name).
|
|
260
263
|
joins(:items).
|
|
261
264
|
joins("INNER JOIN memberships ON (items.product_type = #{::Item.sanitize('Membership')} AND items.product_id = memberships.id)").
|
|
262
265
|
joins("INNER JOIN membership_types ON (membership_types.id = memberships.membership_type_id)").
|
|
@@ -270,6 +273,23 @@ class Order < ActiveRecord::Base
|
|
|
270
273
|
standard = standard.where("membership_types.id = ?", search.membership_type.id) if search.membership_type if search.membership_type
|
|
271
274
|
standard.all
|
|
272
275
|
end
|
|
276
|
+
|
|
277
|
+
def self.pass_sale_search(search)
|
|
278
|
+
standard = ::Order.
|
|
279
|
+
where("orders.type != ?", ::Reseller::Order.name).
|
|
280
|
+
joins(:items).
|
|
281
|
+
joins("INNER JOIN passes ON (items.product_type = #{::Item.sanitize('Pass')} AND items.product_id = passes.id)").
|
|
282
|
+
joins("INNER JOIN pass_types ON (pass_types.id = passes.pass_type_id)").
|
|
283
|
+
includes([:organization, :person]).
|
|
284
|
+
group('orders.id')
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
standard = standard.after(search.start) if search.start
|
|
288
|
+
standard = standard.before(search.stop) if search.stop
|
|
289
|
+
standard = standard.where('orders.organization_id = ?', search.organization.id) if search.organization
|
|
290
|
+
standard = standard.where("pass_types.id = ?", search.pass_type.id) if search.pass_type if search.pass_type
|
|
291
|
+
standard.all
|
|
292
|
+
end
|
|
273
293
|
|
|
274
294
|
def has_single_donation?
|
|
275
295
|
(donations.size == 1) && tickets.empty?
|
|
@@ -308,6 +328,14 @@ class Order < ActiveRecord::Base
|
|
|
308
328
|
items.select(&:membership?).present?
|
|
309
329
|
end
|
|
310
330
|
|
|
331
|
+
def has_pass?
|
|
332
|
+
items.select(&:pass?).present?
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
def items_that_used_pass
|
|
336
|
+
items.select{ |i| i.pass_id.present? }
|
|
337
|
+
end
|
|
338
|
+
|
|
311
339
|
def sum_donations
|
|
312
340
|
all_donations.collect{|item| item.total_price.to_i}.sum
|
|
313
341
|
end
|
data/app/models/order_handler.rb
CHANGED
|
@@ -41,15 +41,16 @@ class OrderHandler
|
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def handle_donation(params, organization)
|
|
44
|
-
|
|
44
|
+
donation_amount = params[:donation_amount].present? ? params[:donation_amount] : params[:donation_amount_fixed]
|
|
45
|
+
if donation_amount
|
|
45
46
|
self.cart.clear_donations
|
|
46
|
-
if
|
|
47
|
+
if donation_amount.to_i == 0
|
|
47
48
|
self.error = "Please enter a donation amount."
|
|
48
49
|
return
|
|
49
50
|
end
|
|
50
51
|
|
|
51
52
|
donation = Donation.new
|
|
52
|
-
donation.amount =
|
|
53
|
+
donation.amount = donation_amount.to_i * 100
|
|
53
54
|
donation.organization = organization
|
|
54
55
|
self.cart.donations << donation
|
|
55
56
|
end
|
data/app/models/organization.rb
CHANGED
|
@@ -34,14 +34,10 @@ class Organization < ActiveRecord::Base
|
|
|
34
34
|
|
|
35
35
|
has_many :imports
|
|
36
36
|
|
|
37
|
-
validates_presence_of :name, :email, :time_zone, :country, :state, :zip, :phone_number, :discipline
|
|
38
|
-
validates :ein, :presence => true, :if => :updating_tax_info
|
|
39
|
-
validates :legal_organization_name, :presence => true, :if => :updating_tax_info
|
|
40
|
-
|
|
41
37
|
scope :receiving_sales_email, where(:receive_daily_sales_report => true)
|
|
42
38
|
|
|
43
39
|
is_sluggable :name, :editable => true
|
|
44
|
-
validates :cached_slug,
|
|
40
|
+
validates :cached_slug,
|
|
45
41
|
:exclusion => { :in => %w(orders tickets admin artfully statements settlements search searches store event events show shows reseller members mobile member resellers merges people phones refunds exchanges),
|
|
46
42
|
:message => "we can't set your Storefront URL to \"%{value}\"" },
|
|
47
43
|
:uniqueness => { :message => "\"%{value}\" has already been taken"}
|
|
@@ -142,9 +138,11 @@ class Organization < ActiveRecord::Base
|
|
|
142
138
|
end
|
|
143
139
|
|
|
144
140
|
def authorization_hash
|
|
145
|
-
{
|
|
141
|
+
{
|
|
142
|
+
:authorized => can?(:receive, Donation),
|
|
146
143
|
:type => donation_type,
|
|
147
|
-
:fsp_name => name_for_donations
|
|
144
|
+
:fsp_name => name_for_donations
|
|
145
|
+
}
|
|
148
146
|
end
|
|
149
147
|
|
|
150
148
|
def donations
|
|
@@ -155,14 +153,24 @@ class Organization < ActiveRecord::Base
|
|
|
155
153
|
Item.includes(:show => [:event => :venue], :order => [:person => :address]).where(:product_type => "Ticket", :orders => { :organization_id => id })
|
|
156
154
|
end
|
|
157
155
|
|
|
156
|
+
def kit(name)
|
|
157
|
+
name = "#{name.to_s.camelize.gsub(/Kit$/, '')}Kit"
|
|
158
|
+
kits.select { |k| k.class.name == name }.first
|
|
159
|
+
end
|
|
160
|
+
|
|
158
161
|
def has_kit?(name)
|
|
159
|
-
|
|
162
|
+
name = "#{name.to_s.camelize.gsub(/Kit$/, '')}Kit"
|
|
163
|
+
kits.select { |k| k.class.name == name && k.activated? }.any?
|
|
160
164
|
end
|
|
161
165
|
|
|
162
166
|
def individuals
|
|
163
167
|
people.where(:type => 'Individual')
|
|
164
168
|
end
|
|
165
169
|
|
|
170
|
+
def has_active_donation_only_storefront?
|
|
171
|
+
self.has_kit?(:regular_donation) && self.kit(:regular_donation).donation_only_storefront == '1'
|
|
172
|
+
end
|
|
173
|
+
|
|
166
174
|
private
|
|
167
175
|
|
|
168
176
|
def check_for_duplicates(kit)
|
|
@@ -170,7 +178,7 @@ class Organization < ActiveRecord::Base
|
|
|
170
178
|
end
|
|
171
179
|
|
|
172
180
|
def donation_type
|
|
173
|
-
return :sponsored if kits.where(:type => "SponsoredDonationKit").any? && kits.where(:type => "SponsoredDonationKit").first.activated?
|
|
174
181
|
return :regular if kits.where(:type => "RegularDonationKit").any? && kits.where(:type => "RegularDonationKit").first.activated?
|
|
182
|
+
return :sponsored if kits.where(:type => "SponsoredDonationKit").any? && kits.where(:type => "SponsoredDonationKit").first.activated?
|
|
175
183
|
end
|
|
176
184
|
end
|
data/app/models/pass.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
class Pass < ActiveRecord::Base
|
|
2
2
|
include Extendable
|
|
3
|
-
include ActionView::Helpers::TextHelper
|
|
4
3
|
|
|
5
4
|
belongs_to :pass_type
|
|
6
5
|
belongs_to :person
|
|
@@ -19,6 +18,7 @@ class Pass < ActiveRecord::Base
|
|
|
19
18
|
|
|
20
19
|
scope :not_expired, lambda { |time = DateTime.now| where("#{Pass.table_name}.ends_at > ?", time) }
|
|
21
20
|
scope :expired, lambda { |time = DateTime.now| where("#{Pass.table_name}.ends_at < ?", time) }
|
|
21
|
+
scope :owned, where('person_id is not null')
|
|
22
22
|
|
|
23
23
|
def self.for(pass_type)
|
|
24
24
|
new.tap do |pass|
|
|
@@ -31,7 +31,7 @@ class Pass < ActiveRecord::Base
|
|
|
31
31
|
pass.starts_at = pass_type.starts_at
|
|
32
32
|
pass.ends_at = pass_type.ends_at
|
|
33
33
|
end
|
|
34
|
-
end
|
|
34
|
+
end
|
|
35
35
|
|
|
36
36
|
def adjust_ends_at
|
|
37
37
|
self.ends_at = self.ends_at.end_of_day unless self.ends_at.blank?
|
|
@@ -96,7 +96,7 @@ class Pass < ActiveRecord::Base
|
|
|
96
96
|
if pass_types.length > 1
|
|
97
97
|
"multiple passes"
|
|
98
98
|
else
|
|
99
|
-
pluralize(passes.length, "#{passes.first.pass_type.passerize}")
|
|
99
|
+
ActionController::Base.helpers.pluralize(passes.length, "#{passes.first.pass_type.passerize}")
|
|
100
100
|
end
|
|
101
101
|
else
|
|
102
102
|
"No passes"
|
|
@@ -109,25 +109,22 @@ class Pass < ActiveRecord::Base
|
|
|
109
109
|
.where(:event_id => event.id)
|
|
110
110
|
.where(:pass_type_id => self.pass_type_id).first
|
|
111
111
|
|
|
112
|
-
Rails.logger.debug ("PASSES the ept is [#{@ept.inspect}]")
|
|
113
|
-
|
|
114
112
|
return 0 if @ept.nil?
|
|
115
113
|
return self.tickets_allowed if @ept.limit_per_pass.nil?
|
|
116
|
-
|
|
117
|
-
Rails.logger.debug ("PASSES tickets remaining to this event [#{@ept.limit_per_pass - event.tickets.where(:pass_id => self.id).count}]")
|
|
118
|
-
|
|
119
114
|
return @ept.limit_per_pass - event.tickets.where(:pass_id => self.id).count
|
|
120
115
|
end
|
|
121
116
|
|
|
122
117
|
def apply_pass_to_cart(cart)
|
|
118
|
+
Rails.logger.debug ("PASSES Applying pass [#{self.id}] to cart [#{cart.id}]")
|
|
123
119
|
cart.prepare_for_pass!
|
|
124
120
|
|
|
125
121
|
#the number of tickets remining for this pass. We go straight to the DB here
|
|
126
122
|
#to avoid a race condition on pass.tickets_remaining
|
|
127
|
-
|
|
123
|
+
tickets_remaining_on_pass = self.tickets_allowed - tickets_purchased
|
|
124
|
+
Rails.logger.debug ("PASSES [#{tickets_remaining_on_pass}] tickets remaining on this pass")
|
|
128
125
|
|
|
129
126
|
self.errors.add(:base, EXPIRED_ERROR) and return if self.expired?
|
|
130
|
-
self.errors.add(:base, OUT_OF_TICKETS) and return if
|
|
127
|
+
self.errors.add(:base, OUT_OF_TICKETS) and return if tickets_remaining_on_pass < 1
|
|
131
128
|
|
|
132
129
|
#The list of tickets w'eve applied this pass too
|
|
133
130
|
tickets_applied = []
|
|
@@ -148,20 +145,24 @@ class Pass < ActiveRecord::Base
|
|
|
148
145
|
(pass_errors << TICKET_TYPE_NOT_ELIGIBLE and next) unless self.applies_to? (ticket.ticket_type)
|
|
149
146
|
(pass_errors << ORG_ERROR and next) unless (self.organization == ticket.organization)
|
|
150
147
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
tickets_remaining_for_this_event
|
|
148
|
+
event = ticket.show.event
|
|
149
|
+
tickets_remaining_for_this_event = tickets_remaining_for(event)
|
|
150
|
+
Rails.logger.debug ("PASSES [#{tickets_remaining_for_this_event}] tickets remaining to event [#{event.id}]")
|
|
154
151
|
over_event_limit = true if tickets_remaining_for_this_event == 0
|
|
155
152
|
|
|
156
|
-
tickets_remaining = [
|
|
153
|
+
tickets_remaining = [tickets_remaining_on_pass, tickets_remaining_for_this_event].min
|
|
154
|
+
Rails.logger.debug ("PASSES [#{tickets_remaining}] tickets remaining after considering pass and event")
|
|
157
155
|
|
|
158
156
|
if tickets_remaining > 0
|
|
157
|
+
Rails.logger.debug ("PASSES adding pass [#{self.id}] to ticket [#{ticket.id}]")
|
|
159
158
|
ticket.pass = self
|
|
160
159
|
ticket.cart_price = 0
|
|
161
160
|
ticket.save
|
|
162
161
|
tickets_applied << ticket
|
|
163
|
-
|
|
162
|
+
tickets_remaining_on_pass = tickets_remaining_on_pass - 1
|
|
163
|
+
Rails.logger.debug ("PASSES Now only [#{tickets_remaining_on_pass}] tickets remaining on this pass")
|
|
164
164
|
else
|
|
165
|
+
Rails.logger.debug ("PASSES rejecting ticket [#{ticket.id}]")
|
|
165
166
|
tickets_rejected << tickets
|
|
166
167
|
end
|
|
167
168
|
end
|
|
@@ -171,7 +172,7 @@ class Pass < ActiveRecord::Base
|
|
|
171
172
|
if tickets_applied.length == 0
|
|
172
173
|
str += "There are no tickets"
|
|
173
174
|
else
|
|
174
|
-
str += "Only #{pluralize(tickets_applied.length, 'ticket')}"
|
|
175
|
+
str += "Only #{ActionController::Base.helpers.pluralize(tickets_applied.length, 'ticket')}"
|
|
175
176
|
str += tickets_applied.length > 1 ? " were" : " was"
|
|
176
177
|
end
|
|
177
178
|
|
|
@@ -179,7 +180,7 @@ class Pass < ActiveRecord::Base
|
|
|
179
180
|
str += " for this event" if over_event_limit
|
|
180
181
|
|
|
181
182
|
if tickets_applied.length > 0
|
|
182
|
-
str += ". We've applied your pass to #{pluralize(tickets_applied.length, 'ticket')} and left the others in your cart."
|
|
183
|
+
str += ". We've applied your pass to #{ActionController::Base.helpers.pluralize(tickets_applied.length, 'ticket')} and left the others in your cart."
|
|
183
184
|
end
|
|
184
185
|
|
|
185
186
|
pass_errors << str
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class PassSaleSearch
|
|
2
|
+
include SearchByDates
|
|
3
|
+
|
|
4
|
+
attr_reader :pass_type
|
|
5
|
+
|
|
6
|
+
def initialize(terms)
|
|
7
|
+
@organization = terms[:organization]
|
|
8
|
+
@pass_type = terms[:pass_type]
|
|
9
|
+
@start = start_with(terms[:start])
|
|
10
|
+
@stop = stop_with(terms[:stop])
|
|
11
|
+
|
|
12
|
+
@results = yield(results) if block_given?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def results
|
|
16
|
+
@results ||= Order.pass_sale_search(self).select(&:has_pass?)
|
|
17
|
+
end
|
|
18
|
+
end
|
data/app/models/pass_type.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
class PassType < ActiveRecord::Base
|
|
2
|
+
include Ext::Integrations::ServiceFee
|
|
2
3
|
include OhNoes::Destroy
|
|
3
4
|
extend ::ArtfullyOseHelper
|
|
4
5
|
|
|
@@ -8,13 +9,13 @@ class PassType < ActiveRecord::Base
|
|
|
8
9
|
attr_accessible :name, :description, :hide_fee, :thanks_copy, :email_copy, :sales_start_at, :sales_end_at,
|
|
9
10
|
:on_sale, :price, :tickets_allowed, :starts_at, :ends_at
|
|
10
11
|
|
|
11
|
-
validates :name, :description, :price, :tickets_allowed, :presence => true
|
|
12
|
+
validates :name, :description, :price, :tickets_allowed, :starts_at, :ends_at, :presence => true
|
|
12
13
|
|
|
13
14
|
scope :storefront, where(:on_sale => true).where("sales_start_at < ? or sales_start_at is null", DateTime.now).where("sales_end_at > ? or sales_end_at is null", DateTime.now)
|
|
14
15
|
scope :on_sale, where(:on_sale => true)
|
|
15
16
|
scope :not_ended, where('ends_at > ?', DateTime.now)
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
ALL_PASSES_STRING = "ALL PASSES"
|
|
18
19
|
|
|
19
20
|
comma do
|
|
20
21
|
name
|
|
@@ -30,6 +31,10 @@ class PassType < ActiveRecord::Base
|
|
|
30
31
|
sales_start_at
|
|
31
32
|
sales_end_at
|
|
32
33
|
end
|
|
34
|
+
|
|
35
|
+
def sold
|
|
36
|
+
self.passes.select{ |p| p.person_id.present? }
|
|
37
|
+
end
|
|
33
38
|
|
|
34
39
|
def passerize
|
|
35
40
|
self.name.end_with?("Pass") ? self.name : self.name + " Pass"
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
class PassesReport
|
|
2
|
+
attr_accessor :pass_type, :header, :start_date, :end_date, :rows, :counts
|
|
3
|
+
attr_accessor :tickets_sold, :passes_sold, :total_tickets, :tickets_remaining, :original_price, :discounted
|
|
4
|
+
extend ::ArtfullyOseHelper
|
|
5
|
+
|
|
6
|
+
def pass_type_name
|
|
7
|
+
pass_type.try(:name) || PassType::ALL_PASSES_STRING
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def initialize(organization, pass_type, start_date, end_date)
|
|
11
|
+
self.pass_type = pass_type
|
|
12
|
+
self.start_date = start_date
|
|
13
|
+
self.end_date = end_date
|
|
14
|
+
|
|
15
|
+
@orders = find_orders
|
|
16
|
+
|
|
17
|
+
self.rows = []
|
|
18
|
+
@orders.each do |order|
|
|
19
|
+
self.rows << Row.new(order)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
build_header
|
|
23
|
+
|
|
24
|
+
self.passes_sold = count_passes_sold
|
|
25
|
+
self.total_tickets = calculate_total_tickets
|
|
26
|
+
self.tickets_sold = self.rows.inject(0) { |total, row| total + row.ticket_count}
|
|
27
|
+
self.tickets_remaining= self.total_tickets - self.tickets_sold
|
|
28
|
+
self.original_price = self.rows.inject(0) { |total, row| total + row.original_price }
|
|
29
|
+
self.discounted = self.rows.inject(0) { |total, row| total + row.discounted }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def calculate_total_tickets
|
|
33
|
+
@passes = Pass.owned
|
|
34
|
+
if self.pass_type.present?
|
|
35
|
+
@passes = @passes.where(:pass_type_id => self.pass_type.id)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
@passes.sum(:tickets_allowed)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def count_passes_sold
|
|
42
|
+
@items = Item.sold_or_comped.where(:product_type => "Pass")
|
|
43
|
+
@items = @items.joins("INNER join passes ON items.product_id = passes.id")
|
|
44
|
+
@items = @items.joins("INNER join pass_types ON passes.pass_type_id = pass_types.id")
|
|
45
|
+
|
|
46
|
+
if self.pass_type.present?
|
|
47
|
+
@items = @items.where("pass_types.id" => self.pass_type)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
@items = @items.joins(:order)
|
|
51
|
+
@items = @items.where('orders.created_at > ?',self.start_date) unless start_date.blank?
|
|
52
|
+
@items = @items.where('orders.created_at < ?',self.end_date) unless end_date.blank?
|
|
53
|
+
@items.count
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def find_orders
|
|
57
|
+
@orders = Order.includes(:person, :items => [:show => :event])
|
|
58
|
+
.joins(:items)
|
|
59
|
+
.joins("INNER join passes ON items.pass_id = passes.id")
|
|
60
|
+
.joins("INNER join pass_types ON passes.pass_type_id = pass_types.id")
|
|
61
|
+
.group('orders.id')
|
|
62
|
+
.order('orders.created_at desc')
|
|
63
|
+
|
|
64
|
+
if pass_type.nil?
|
|
65
|
+
@orders = @orders.where("pass_types.id is not null")
|
|
66
|
+
else
|
|
67
|
+
@orders = @orders.where("pass_types.id" => self.pass_type.id)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
@orders = @orders.where('orders.created_at > ?',self.start_date) unless start_date.blank?
|
|
71
|
+
@orders = @orders.where('orders.created_at < ?',self.end_date) unless end_date.blank?
|
|
72
|
+
@orders
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def build_header
|
|
76
|
+
self.header = pass_type_name
|
|
77
|
+
if self.start_date.blank? && self.end_date.blank?
|
|
78
|
+
return
|
|
79
|
+
elsif self.start_date.blank?
|
|
80
|
+
self.header = self.header + " through #{I18n.localize(DateTime.parse(self.end_date), :format => :slashed_date)}"
|
|
81
|
+
elsif self.end_date.blank?
|
|
82
|
+
self.header = self.header + " since #{I18n.localize(DateTime.parse(self.start_date), :format => :slashed_date)}"
|
|
83
|
+
else
|
|
84
|
+
self.header = self.header + " from #{I18n.localize(DateTime.parse(self.start_date), :format => :slashed_date)} through #{I18n.localize(DateTime.parse(self.end_date), :format => :slashed_date)}"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
class Row
|
|
89
|
+
attr_accessor :order, :show, :pass_type, :ticket_count, :original_price, :gross, :discounted
|
|
90
|
+
|
|
91
|
+
def initialize(order)
|
|
92
|
+
self.order = order
|
|
93
|
+
self.pass_type = order.pass_codes.first.pass_type.name
|
|
94
|
+
self.show = order.items_that_used_pass.first.show
|
|
95
|
+
self.original_price = order.items_that_used_pass.inject(0) { |total, item| total + item.original_price }
|
|
96
|
+
self.gross = order.items_that_used_pass.inject(0) { |total, item| total + item.price }
|
|
97
|
+
self.discounted = self.original_price - self.gross
|
|
98
|
+
self.ticket_count = order.items_that_used_pass.length
|
|
99
|
+
self.ticket_count = self.ticket_count * -1 if !order.items_that_used_pass.select(&:refund?).empty?
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
comma do
|
|
103
|
+
pass_type("Pass")
|
|
104
|
+
order("Order") { |order| order.id }
|
|
105
|
+
order("Order Date") { |order| order.created_at }
|
|
106
|
+
order("First Name") { |order| order.person.first_name }
|
|
107
|
+
order("Last Name") { |order| order.person.last_name }
|
|
108
|
+
order("Email") { |order| order.person.email }
|
|
109
|
+
show("Event") { |show| show.event.name }
|
|
110
|
+
ticket_count
|
|
111
|
+
original_price { |original_price| DiscountsReport.number_as_cents original_price }
|
|
112
|
+
discounted { |discounted| DiscountsReport.number_as_cents discounted }
|
|
113
|
+
gross { |gross| DiscountsReport.number_as_cents gross }
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
end
|
|
117
|
+
end
|