artfully_ose 1.3.0.pre3 → 1.3.0.pre4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/images/loading-white.gif +0 -0
- data/app/assets/images/seating_temp/1.jpg +0 -0
- data/app/assets/images/seating_temp/10.jpg +0 -0
- data/app/assets/images/seating_temp/11.jpg +0 -0
- data/app/assets/images/seating_temp/2.jpg +0 -0
- data/app/assets/images/seating_temp/3.jpg +0 -0
- data/app/assets/images/seating_temp/4.jpg +0 -0
- data/app/assets/images/seating_temp/5.jpg +0 -0
- data/app/assets/images/seating_temp/6.jpg +0 -0
- data/app/assets/images/seating_temp/7.jpg +0 -0
- data/app/assets/images/seating_temp/8.jpg +0 -0
- data/app/assets/images/seating_temp/9.jpg +0 -0
- data/app/assets/images/seating_temp/icon_43405.png +0 -0
- data/app/assets/images/seating_temp/icon_43405.svg +3 -0
- data/app/assets/images/seating_temp/icon_43405_plus.png +0 -0
- data/app/assets/images/seating_temp/license.txt +8 -0
- data/app/assets/javascripts/application.js +1 -0
- data/app/assets/javascripts/custom/cookies.js +27 -0
- data/app/assets/javascripts/custom/inline-people-search.js +4 -0
- data/app/assets/javascripts/custom/job-monitor.js +0 -1
- data/app/assets/javascripts/exchange-seat-chart.js +5 -0
- data/app/assets/javascripts/seat-chart.js +606 -0
- data/app/assets/javascripts/show-seat-chart.js +17 -0
- data/app/assets/javascripts/store/store-seat-chart.js +76 -0
- data/app/assets/javascripts/store/store.js +14 -39
- data/app/assets/stylesheets/application.sass +49 -1
- data/app/assets/stylesheets/bootstrap-overrides.css +11 -3
- data/app/assets/stylesheets/sass/seat-chart.sass +311 -0
- data/app/assets/stylesheets/sass/store.sass +73 -19
- data/app/assets/stylesheets/storefront.css +2 -0
- data/app/concerns/pdf_generation.rb +1 -15
- data/app/controllers/advanced_searches_controller.rb +1 -3
- data/app/controllers/charts_controller.rb +14 -12
- data/app/controllers/console_sales_controller.rb +55 -0
- data/app/controllers/event_calendars_controller.rb +15 -0
- data/app/controllers/events_controller.rb +16 -5
- data/app/controllers/exchanges_controller.rb +32 -9
- data/app/controllers/export_controller.rb +8 -0
- data/app/controllers/members/sessions_controller.rb +0 -2
- data/app/controllers/membership_comps_controller.rb +2 -1
- data/app/controllers/prices_controller.rb +20 -0
- data/app/controllers/shows_controller.rb +3 -1
- data/app/controllers/store/events_controller.rb +6 -5
- data/app/controllers/store/orders_controller.rb +11 -13
- data/app/controllers/store/shows_controller.rb +1 -0
- data/app/controllers/store/store_controller.rb +11 -0
- data/app/controllers/tickets_controller.rb +0 -28
- data/app/controllers/user_memberships_controller.rb +7 -2
- data/app/controllers/venues_controller.rb +9 -0
- data/app/helpers/artfully_ose_helper.rb +18 -4
- data/app/helpers/seating_helper.rb +157 -0
- data/app/models/assigned_chart.rb +220 -0
- data/app/models/cart.rb +6 -1
- data/app/models/chart.rb +28 -17
- data/app/models/database_views/item_view.rb +76 -5
- data/app/models/discount.rb +4 -0
- data/app/models/discounts/buy_one_get_one_free_discount_type.rb +1 -1
- data/app/models/discounts/dollars_off_tickets_discount_type.rb +5 -1
- data/app/models/discounts/percentage_off_tickets_discount_type.rb +8 -4
- data/app/models/event.rb +86 -12
- data/app/models/general_admission_chart.rb +51 -0
- data/app/models/imports/events_import.rb +1 -1
- data/app/models/job/show_creator.rb +3 -10
- data/app/models/kit.rb +11 -1
- data/app/models/kits/assigned_seating_kit.rb +23 -0
- data/app/models/member_walkup.rb +1 -1
- data/app/models/order_handler.rb +22 -6
- data/app/models/organization.rb +4 -5
- data/app/models/person.rb +3 -1
- data/app/models/sale.rb +1 -1
- data/app/models/seat.rb +96 -0
- data/app/models/section.rb +1 -3
- data/app/models/show.rb +10 -17
- data/app/models/ticket.rb +30 -6
- data/app/models/ticket/locker.rb +3 -2
- data/app/models/ticket_type.rb +12 -6
- data/app/models/ticket_types_seat.rb +4 -0
- data/app/models/venue.rb +23 -0
- data/app/views/advanced_searches/filters/_birthday.html.haml +1 -0
- data/app/views/assigned_charts/_show.html.haml +12 -0
- data/app/views/console_sales/_aloha.html.haml +5 -4
- data/app/views/console_sales/new.html.haml +9 -0
- data/app/views/event_calendars/index.html.haml +34 -0
- data/app/views/events/_menu.html.haml +2 -1
- data/app/views/events/_section_fields.html.haml +13 -8
- data/app/views/events/new.html.haml +34 -4
- data/app/views/events/prices.html.haml +3 -4
- data/app/views/events/seating.html.haml +131 -0
- data/app/views/exchanges/_assigned_chart.html.haml +108 -0
- data/app/views/exchanges/_general_admission_chart.html.haml +55 -0
- data/app/views/exchanges/new.html.haml +1 -55
- data/app/views/general_admission_charts/_show.html.haml +2 -0
- data/app/views/layouts/_menu.html.haml +44 -31
- data/app/views/layouts/storefront.html.haml +72 -30
- data/app/views/membership_comps/new.html.haml +1 -0
- data/app/views/order_mailer/confirmation_for.html.haml +5 -3
- data/app/views/order_mailer/confirmation_for.text.haml +1 -2
- data/app/views/pdfs/order.html.haml +20 -6
- data/app/views/seating/_actions_menu.html.haml +10 -0
- data/app/views/seating/_chart.html.haml +15 -0
- data/app/views/seating/_chart_container.html.haml +2 -0
- data/app/views/seating/_chart_note_display.html.haml +7 -0
- data/app/views/seating/_hold_seats_modal.html.haml +39 -0
- data/app/views/seating/_layer_menu.html.haml +23 -0
- data/app/views/seating/_legend.html.haml +52 -0
- data/app/views/seating/_modify_seats_modal.html.haml +29 -0
- data/app/views/seating/_ticket_type_modals.html.haml +41 -0
- data/app/views/shows/_seat_chart.html.haml +122 -0
- data/app/views/shows/_sections_table.html.haml +3 -24
- data/app/views/shows/_ticket_table.html.haml +4 -2
- data/app/views/shows/_work_with.html.haml +4 -0
- data/app/views/shows/new.html.haml +2 -2
- data/app/views/shows/show.html.haml +93 -14
- data/app/views/store/assigned_charts/_show.html.haml +54 -0
- data/app/views/store/checkouts/shopping_cart_display/_tickets.haml +13 -0
- data/app/views/store/donations/index.html.haml +1 -1
- data/app/views/store/events/calendar.html.haml +94 -11
- data/app/views/store/events/index.html.haml +1 -1
- data/app/views/store/events/show.html.haml +36 -2
- data/app/views/store/events/single_show.html.haml +5 -4
- data/app/views/store/general_admission_charts/_show.html.haml +41 -0
- data/app/views/store/orders/show.html.haml +17 -4
- data/app/views/store/shared/_donate_form.html.haml +2 -1
- data/app/views/store/shared/_small_donate_form.html.haml +1 -1
- data/app/views/store/shows/_show.html.haml +1 -39
- data/app/views/ticket_types/edit.html.haml +1 -1
- data/app/views/user_memberships/_list.html.haml +1 -1
- data/app/views/venues/edit.html.haml +1 -1
- data/app/views/venues/show.html.haml +11 -0
- data/config/routes.rb +27 -10
- data/db/migrate/20140828174357_add_type_to_chart.rb +7 -0
- data/db/migrate/20140828195617_create_seats.rb +16 -0
- data/db/migrate/20140829135426_add_venue_to_chart.rb +5 -0
- data/db/migrate/20140829143520_add_assigned_to_event.rb +5 -0
- data/db/migrate/20140904164927_add_fields_to_seat.rb +14 -0
- data/db/migrate/20140912170010_add_note_to_seat.rb +6 -0
- data/db/migrate/20140919152307_add_seats_to_ticket.rb +5 -0
- data/db/migrate/20140930224543_add_public_note_to_chart.rb +5 -0
- data/db/migrate/20141001140737_add_seat_id_index_to_tickets.rb +5 -0
- data/db/migrate/20141001193242_associate_hold_with_person.rb +6 -0
- data/db/migrate/20141021175311_create_ticket_types_seats.rb +11 -0
- data/db/migrate/20150106161744_migrate_charts_back_to_venues.rb +18 -0
- data/db/migrate/20151105085424_add_creator_to_items_view.rb +40 -0
- data/lib/artfully_ose/version.rb +1 -1
- data/spec/factories/assigned_chart_factories.rb +18 -0
- data/spec/factories/chart_factories.rb +4 -8
- data/spec/factories/kit_factories.rb +4 -0
- data/spec/factories/seat_factories.rb +4 -0
- data/spec/factories/show_factories.rb +1 -1
- metadata +66 -5
- data/app/models/ticket/foundry.rb +0 -48
- data/app/models/ticket/template.rb +0 -40
- data/app/views/store/events/_calendar.html.haml +0 -13
data/app/models/cart.rb
CHANGED
@@ -2,7 +2,7 @@ class Cart < ActiveRecord::Base
|
|
2
2
|
include ActiveRecord::Transitions
|
3
3
|
|
4
4
|
has_many :donations, :dependent => :destroy
|
5
|
-
has_many :tickets, :after_add => :calculate_fees
|
5
|
+
has_many :tickets, :after_add => [:calculate_fees, :apply_discount_or_pass]
|
6
6
|
has_many :memberships, :after_add => :calculate_fees
|
7
7
|
has_many :passes, :after_add => :calculate_fees
|
8
8
|
after_destroy :clear!
|
@@ -123,6 +123,11 @@ class Cart < ActiveRecord::Base
|
|
123
123
|
FeeCalculator.apply(FeeStrategy.new).to(self)
|
124
124
|
end
|
125
125
|
|
126
|
+
def apply_discount_or_pass(obj)
|
127
|
+
self.discount.apply_discount_to_cart(self) if self.discount.present?
|
128
|
+
self.applied_pass.apply_pass_to_cart(self) if self.applied_pass.present?
|
129
|
+
end
|
130
|
+
|
126
131
|
def <<(tkts)
|
127
132
|
tkts = Array.wrap(tkts)
|
128
133
|
tkts.each do |t|
|
data/app/models/chart.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
class Chart < ActiveRecord::Base
|
2
|
-
include Ticket::Foundry
|
3
|
-
foundry :using => :sections, :with => lambda { { :venue => event.venue.name } }
|
4
2
|
attr_accessor :skip_create_first_section
|
5
|
-
attr_accessible :name, :is_template, :event_id, :organization_id,
|
3
|
+
attr_accessible :name, :is_template, :event_id, :organization_id,
|
4
|
+
:sections_attributes, :ticket_types_attributes, :organization,
|
5
|
+
:event, :skip_create_first_section, :venue_id, :public_note
|
6
6
|
|
7
7
|
belongs_to :event
|
8
|
+
belongs_to :venue
|
8
9
|
belongs_to :organization
|
9
10
|
has_one :show
|
10
11
|
has_many :sections, :order => 'name DESC'
|
@@ -17,7 +18,7 @@ class Chart < ActiveRecord::Base
|
|
17
18
|
scope :template, where(:is_template => true)
|
18
19
|
|
19
20
|
def as_json(options = {})
|
20
|
-
h = super(options)
|
21
|
+
h = super(options.merge({:except => :venue_id}))
|
21
22
|
h[:sections] = sections
|
22
23
|
h
|
23
24
|
end
|
@@ -33,8 +34,14 @@ class Chart < ActiveRecord::Base
|
|
33
34
|
duplicate(:without => "id", :with => { :name => "#{name} (Copy)" })
|
34
35
|
end
|
35
36
|
|
36
|
-
|
37
|
-
|
37
|
+
#
|
38
|
+
# Pass :save => true to persist the new chart
|
39
|
+
# The only way we can hook up ticket types to the dupe is if we save
|
40
|
+
#
|
41
|
+
# So unsaved charts will not have ticket types attached
|
42
|
+
#
|
43
|
+
def dup!(options = {})
|
44
|
+
duplicate(options.merge({:without => "id", :with => { :is_template => false }}))
|
38
45
|
end
|
39
46
|
|
40
47
|
def create_first_section
|
@@ -67,9 +74,16 @@ class Chart < ActiveRecord::Base
|
|
67
74
|
# params_hash is the params[:chart] with :section_attributes as a key.
|
68
75
|
# This is how they're submitted from the ticket types form
|
69
76
|
#
|
70
|
-
def update_attributes_from_params(params_hash = {})
|
71
|
-
upgrade_event
|
77
|
+
def update_attributes_from_params(params_hash = {}, parent_chart = nil)
|
72
78
|
update_attributes(params_hash)
|
79
|
+
upgrade_event
|
80
|
+
sync_with_venue(params_hash)
|
81
|
+
end
|
82
|
+
|
83
|
+
def sync_with_venue(params_hash)
|
84
|
+
if self.event
|
85
|
+
self.event.venue.update_default_chart_from(self.event.default_chart)
|
86
|
+
end
|
73
87
|
end
|
74
88
|
|
75
89
|
#If this is a free event, and they've specified prices on this chart, then upgrade to a paid event
|
@@ -91,22 +105,19 @@ class Chart < ActiveRecord::Base
|
|
91
105
|
prefix + ', default chart'
|
92
106
|
end
|
93
107
|
|
94
|
-
def self.default_chart_for(event)
|
95
|
-
raise TypeError, "Expecting an Event" unless event.kind_of? Event
|
96
|
-
@chart = self.new
|
97
|
-
@chart.name = self.get_default_name(event.name)
|
98
|
-
@chart.event_id = event.id
|
99
|
-
@chart
|
100
|
-
end
|
101
|
-
|
102
108
|
def has_paid_sections?
|
103
109
|
!self.ticket_types.drop_while{|s| s.price.to_i == 0}.empty?
|
104
110
|
end
|
105
111
|
|
106
|
-
|
112
|
+
protected
|
107
113
|
|
114
|
+
#
|
115
|
+
# Both AssignedChart and GeneralAdmissionChart implement this method in their subclasses
|
116
|
+
# Both implementations make use of this via super()
|
117
|
+
#
|
108
118
|
def duplicate(options = {})
|
109
119
|
rejections = Array.wrap(options[:without])
|
120
|
+
rejections << "type"
|
110
121
|
additions = options[:with] || {}
|
111
122
|
attrs = self.attributes.reject { |key, value| rejections.include?(key) }.merge(additions)
|
112
123
|
|
@@ -27,13 +27,36 @@ class ItemView < ActiveRecord::Base
|
|
27
27
|
default_scope order('created_at desc')
|
28
28
|
|
29
29
|
def self.sales_export_filename_for(organization)
|
30
|
-
"exports/Artfully-
|
30
|
+
"exports/Artfully-Sales-Export-#{organization.id}.csv"
|
31
31
|
end
|
32
32
|
|
33
33
|
def self.donations_export_filename_for(organization)
|
34
34
|
"exports/Artfully-Donations-Export-#{organization.id}.csv"
|
35
35
|
end
|
36
36
|
|
37
|
+
#load {item_id => product_type_name} once to avoid 3n query call for each item
|
38
|
+
def self.product_type_name(item_id, organization_id)
|
39
|
+
if @hash.nil?
|
40
|
+
sql = "SELECT items.id, " +
|
41
|
+
"CASE WHEN items.product_type = 'Ticket' THEN ticket_types.name " +
|
42
|
+
"WHEN items.product_type = 'Membership' THEN membership_types.name " +
|
43
|
+
"WHEN items.product_type = 'Pass' THEN pass_types.name " +
|
44
|
+
"END AS product_type_name " +
|
45
|
+
"FROM items " +
|
46
|
+
"LEFT OUTER JOIN orders ON orders.id = items.order_id " +
|
47
|
+
"LEFT OUTER JOIN tickets ON tickets.id = items.product_id AND items.product_type = 'Ticket' " +
|
48
|
+
"LEFT OUTER JOIN memberships ON memberships.id = items.product_id AND items.product_type = 'Membership' " +
|
49
|
+
"LEFT OUTER JOIN passes ON passes.id = items.product_id AND items.product_type = 'Pass' " +
|
50
|
+
"LEFT OUTER JOIN ticket_types ON ticket_types.id = tickets.ticket_type_id " +
|
51
|
+
"LEFT OUTER JOIN membership_types ON membership_types.id = memberships.membership_type_id " +
|
52
|
+
"LEFT OUTER JOIN pass_types ON pass_types.id = passes.pass_type_id " +
|
53
|
+
"WHERE product_type IN('Ticket', 'Pass', 'Membership') AND orders.organization_id = #{organization_id}"
|
54
|
+
@hash = Hash[ActiveRecord::Base.connection.select_all(sql).map(&:values)]
|
55
|
+
end
|
56
|
+
@hash[item_id]
|
57
|
+
end
|
58
|
+
|
59
|
+
|
37
60
|
comma :donation do
|
38
61
|
created_at_local_to_organization("Date")
|
39
62
|
|
@@ -42,8 +65,7 @@ class ItemView < ActiveRecord::Base
|
|
42
65
|
nongift_amount("Non-Deductible Amount") { |cents| ((cents || 0) / 100.00) }
|
43
66
|
special_instructions("Special Instructions")
|
44
67
|
notes("Notes")
|
45
|
-
|
46
|
-
order("Creator") { |order| order.creator && order.creator.email }
|
68
|
+
creator("Creator")
|
47
69
|
|
48
70
|
person("Email") { |person| person.email }
|
49
71
|
person("Salutation") { |person| person.salutation }
|
@@ -91,10 +113,10 @@ class ItemView < ActiveRecord::Base
|
|
91
113
|
datetime_local_to_organization("Performance Date-Time")
|
92
114
|
payment_method("Payment Method")
|
93
115
|
price("Ticket Price") { |cents| number_to_currency(cents.to_f/100) }
|
116
|
+
item("Ticket Type") { |item| item.product.ticket_type && item.product.ticket_type.name }
|
94
117
|
special_instructions("Special Instructions")
|
95
118
|
notes("Notes")
|
96
|
-
|
97
|
-
order("Creator") { |order| order.creator && order.creator.email }
|
119
|
+
creator("Creator")
|
98
120
|
|
99
121
|
person("Email") { |person| person.email }
|
100
122
|
person("Salutation") { |person| person.salutation }
|
@@ -228,4 +250,53 @@ class ItemView < ActiveRecord::Base
|
|
228
250
|
person("Do Not Email") { |person| person.do_not_email }
|
229
251
|
person("Do Not Call") { |person| person.do_not_call }
|
230
252
|
end
|
253
|
+
|
254
|
+
comma :all_sales do
|
255
|
+
created_at_local_to_organization("Date of Purchase")
|
256
|
+
order_id("Order Id")
|
257
|
+
product_type("Item")
|
258
|
+
item_id("Detail") { |item_id| ItemView.product_type_name(item_id, self.instance_variable_get("@instance").organization_id) }
|
259
|
+
payment_method("Payment Method")
|
260
|
+
price("Price") { |cents| number_to_currency(cents.to_f/100) }
|
261
|
+
special_instructions("Special Instructions")
|
262
|
+
notes("Notes")
|
263
|
+
creator("Creator")
|
264
|
+
|
265
|
+
person("Email") { |person| person.email }
|
266
|
+
person("Salutation") { |person| person.salutation }
|
267
|
+
person("First Name") { |person| person.first_name }
|
268
|
+
person("Middle Name") { |person| person.middle_name }
|
269
|
+
person("Last Name") { |person| person.last_name }
|
270
|
+
person("Suffix") { |person| person.suffix }
|
271
|
+
person("Nickname") { |person| person.nickname }
|
272
|
+
person("Listing Name") { |person| person.listing_name }
|
273
|
+
person("Title") { |person| person.title }
|
274
|
+
person("Type") { |person| person.type }
|
275
|
+
person("Subtype") { |person| person.subtype }
|
276
|
+
person("Company Name") { |person| person.company_name }
|
277
|
+
|
278
|
+
('A'..'C').each_with_index do |letter, i|
|
279
|
+
person("Address#{letter} Type") { |person| person.addresses[i] && person.addresses[i].kind }
|
280
|
+
person("Address#{letter} Address 1") { |person| person.addresses[i] && person.addresses[i].address1 }
|
281
|
+
person("Address#{letter} Address 2") { |person| person.addresses[i] && person.addresses[i].address2 }
|
282
|
+
person("Address#{letter} City") { |person| person.addresses[i] && person.addresses[i].city }
|
283
|
+
person("Address#{letter} State") { |person| person.addresses[i] && person.addresses[i].state }
|
284
|
+
person("Address#{letter} Zip") { |person| person.addresses[i] && person.addresses[i].zip }
|
285
|
+
person("Address#{letter} Country") { |person| person.addresses[i] && person.addresses[i].country }
|
286
|
+
end
|
287
|
+
|
288
|
+
(1..3).each do |i|
|
289
|
+
person("Phone#{i} type") { |person| person.phones[i-1] && person.phones[i-1].kind }
|
290
|
+
person("Phone#{i} number") { |person| person.phones[i-1] && person.phones[i-1].number }
|
291
|
+
end
|
292
|
+
|
293
|
+
person("Website") { |person| person.website }
|
294
|
+
person("Twitter Handle") { |person| person.twitter_handle }
|
295
|
+
person("Facebook URL") { |person| person.facebook_url }
|
296
|
+
person("Linked In Url") { |person| person.linked_in_url }
|
297
|
+
person("Tags") { |person| person.tags.join("|") }
|
298
|
+
person("Do Not Email") { |person| person.do_not_email }
|
299
|
+
person("Do Not Call") { |person| person.do_not_call }
|
300
|
+
person("Household Name") { |person| person.household && person.household.name }
|
301
|
+
end
|
231
302
|
end
|
data/app/models/discount.rb
CHANGED
@@ -57,6 +57,10 @@ class Discount < ActiveRecord::Base
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
+
def calculate_discount_for(ticket_type)
|
61
|
+
self.ticket_types.include?(ticket_type.name) ? type.calculate_discounted_price(ticket_type.price) : ticket_type.price
|
62
|
+
end
|
63
|
+
|
60
64
|
def ensure_properties_are_set
|
61
65
|
type.validate
|
62
66
|
end
|
@@ -8,7 +8,7 @@ class BuyOneGetOneFreeDiscountType < DiscountType
|
|
8
8
|
every_other_ticket.each do |ticket|
|
9
9
|
ticket.update_column(:cart_price, 0)
|
10
10
|
end
|
11
|
-
|
11
|
+
@discount.cart.calculate_fees(@discount.cart)
|
12
12
|
end
|
13
13
|
|
14
14
|
def every_other_ticket
|
@@ -13,7 +13,11 @@ class DollarsOffTicketsDiscountType < DiscountType
|
|
13
13
|
ticket.update_column(:cart_price, 0)
|
14
14
|
end
|
15
15
|
end
|
16
|
-
|
16
|
+
@discount.cart.calculate_fees(@discount.cart)
|
17
|
+
end
|
18
|
+
|
19
|
+
def calculate_discounted_price(price_in_cents)
|
20
|
+
price_in_cents - @properties[:amount]
|
17
21
|
end
|
18
22
|
|
19
23
|
def self.fee
|
@@ -17,9 +17,13 @@ class PercentageOffTicketsDiscountType < DiscountType
|
|
17
17
|
"#{@properties[:percentage] * 100.00}% off each ticket"
|
18
18
|
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
def ensure_percentage_exists
|
23
|
-
raise "Percentage missing!" if @properties[:percentage].blank?
|
20
|
+
def calculate_discounted_price(price_in_cents)
|
21
|
+
price_in_cents - (price_in_cents * @properties[:percentage])
|
24
22
|
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def ensure_percentage_exists
|
27
|
+
raise "Percentage missing!" if @properties[:percentage].blank?
|
28
|
+
end
|
25
29
|
end
|
data/app/models/event.rb
CHANGED
@@ -5,13 +5,17 @@ class Event < ActiveRecord::Base
|
|
5
5
|
include Ticket::Reporting
|
6
6
|
include EventPresenter
|
7
7
|
include OhNoes::Destroy
|
8
|
+
include ActionView::Helpers::TextHelper
|
8
9
|
require 'email_validator'
|
9
10
|
|
10
11
|
CATEGORIES = ["Dance", "Film & Electronic Media", "Literary Arts", "Music", "Theater", "Visual Arts", "Other"]
|
11
12
|
|
12
13
|
attr_accessible :name, :producer, :description, :contact_email, :contact_phone, :image, :venue_attributes,
|
13
14
|
:show_special_instructions, :special_instructions_caption, :public, :primary_category,
|
14
|
-
:secondary_categories, :primary_category_other, :secondary_category_other, :members_only,
|
15
|
+
:secondary_categories, :primary_category_other, :secondary_category_other, :members_only,
|
16
|
+
:subtitle, :assigned
|
17
|
+
|
18
|
+
attr_accessor :reserved_seating
|
15
19
|
|
16
20
|
store :cached_stats, :accessors => [ :on_sale, :off_sale, :sold, :sales_total ]
|
17
21
|
|
@@ -49,6 +53,7 @@ class Event < ActiveRecord::Base
|
|
49
53
|
before_create :set_primary_category
|
50
54
|
before_create { self.public = true }
|
51
55
|
after_create :create_default_chart
|
56
|
+
after_create :create_venue_chart
|
52
57
|
|
53
58
|
serialize :secondary_categories, Array
|
54
59
|
|
@@ -143,23 +148,38 @@ class Event < ActiveRecord::Base
|
|
143
148
|
Item.where(:show_id => self.shows)
|
144
149
|
end
|
145
150
|
|
146
|
-
def filter_charts(charts)
|
147
|
-
charts.reject { |chart| already_has_chart(chart) }
|
148
|
-
end
|
149
|
-
|
150
151
|
def set_primary_category
|
151
152
|
self.primary_category ||= "Other"
|
152
153
|
end
|
153
154
|
|
154
155
|
def create_default_chart
|
155
|
-
|
156
|
-
|
157
|
-
|
156
|
+
unless default_chart
|
157
|
+
chart = chart_class.default_chart_for(self)
|
158
|
+
self.charts << chart
|
159
|
+
chart.save
|
160
|
+
end
|
161
|
+
chart
|
162
|
+
end
|
163
|
+
|
164
|
+
#
|
165
|
+
# In the case where producer is re-using chart from a venue
|
166
|
+
# This will return false if a default_chart has been set
|
167
|
+
# No changes will be made if a default chart has been set
|
168
|
+
#
|
169
|
+
def set_default_chart(chart)
|
170
|
+
return false unless default_chart.nil?
|
171
|
+
self.charts << chart
|
172
|
+
chart.event = self
|
158
173
|
chart.save
|
159
174
|
end
|
160
175
|
|
176
|
+
def chart_class
|
177
|
+
self.assigned? ? AssignedChart : GeneralAdmissionChart
|
178
|
+
end
|
179
|
+
|
161
180
|
def default_chart
|
162
|
-
|
181
|
+
return nil unless self.persisted?
|
182
|
+
self.charts.includes(chart_class.included_models).first
|
163
183
|
end
|
164
184
|
|
165
185
|
def upcoming_shows_rel
|
@@ -200,17 +220,56 @@ class Event < ActiveRecord::Base
|
|
200
220
|
upcoming_shows(:all, true).select(&:published?)
|
201
221
|
end
|
202
222
|
|
203
|
-
|
223
|
+
#
|
224
|
+
# Used to build a flimsy show for use by the Rails form on shows/new
|
225
|
+
#
|
226
|
+
def build_next_show
|
204
227
|
shows.build(:datetime => Show.next_datetime(shows.last))
|
205
228
|
show = shows.pop
|
206
|
-
show.chart = default_chart.dup!
|
229
|
+
show.chart = default_chart.dup!({:save => false})
|
207
230
|
show
|
208
231
|
end
|
209
232
|
|
210
233
|
def as_widget_json(options = {})
|
211
|
-
as_json(options.merge({:methods => ['venue', 'uuid'], :except => [:members_only, :cached_stats]})).merge('performances' => upcoming_public_shows.as_json)
|
234
|
+
as_json(options.merge({:methods => ['venue', 'uuid'], :except => [:members_only, :cached_stats, :assigned]})).merge('performances' => upcoming_public_shows.as_json)
|
212
235
|
end
|
213
236
|
|
237
|
+
EVENT_CALENDAR_COLORS = ["#3a87ad", "#16a085", "#27ae60", "#8e44ad", "#2c3e50", "#d35400", "#c0392b"]
|
238
|
+
#
|
239
|
+
# This drives the all events calendar for producers
|
240
|
+
#
|
241
|
+
def self.as_full_calendar_json(organization, starts_at=nil, ends_at=nil)
|
242
|
+
shows_rel = organization.shows.includes(:event => :venue)
|
243
|
+
shows_rel = shows_rel.where('datetime > ?', starts_at) unless starts_at.nil?
|
244
|
+
shows_rel = shows_rel.where('datetime < ?', ends_at) unless ends_at.nil?
|
245
|
+
|
246
|
+
shows=shows_rel.all
|
247
|
+
|
248
|
+
#
|
249
|
+
# Reject shows which have had their events deleted
|
250
|
+
#
|
251
|
+
shows.reject! {|s| s.event.nil?}
|
252
|
+
|
253
|
+
event_ids = shows.collect(&:event_id).uniq
|
254
|
+
event_ids.sort!
|
255
|
+
colors = EVENT_CALENDAR_COLORS
|
256
|
+
|
257
|
+
shows.collect do |show|
|
258
|
+
{ :title => show.event.name.truncate(30),
|
259
|
+
:start => show.datetime_local_to_event,
|
260
|
+
:allDay => false,
|
261
|
+
:id => show.id,
|
262
|
+
:state => show.state,
|
263
|
+
:event_id => show.event_id,
|
264
|
+
:backgroundColor => show.published? ? colors[(event_ids.index(show.event_id) % colors.length)] : "#adadad",
|
265
|
+
:borderColor => colors[(event_ids.index(show.event_id) % colors.length)]
|
266
|
+
}
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
#
|
271
|
+
# This drivers the per-event show calendar for producers
|
272
|
+
#
|
214
273
|
def as_full_calendar_json
|
215
274
|
shows.includes(:event).collect do |p|
|
216
275
|
{ :title => '',
|
@@ -223,6 +282,17 @@ class Event < ActiveRecord::Base
|
|
223
282
|
end
|
224
283
|
end
|
225
284
|
|
285
|
+
def as_storefront_calendar_json
|
286
|
+
upcoming_public_shows.collect do |p|
|
287
|
+
{ :title => '',
|
288
|
+
:start => p.datetime_local_to_event,
|
289
|
+
:allDay => false,
|
290
|
+
:uuid => p.uuid,
|
291
|
+
:color => p.sold_out? ? "#ADADAD" : "#33AADD"
|
292
|
+
}
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
226
296
|
def as_json(options = {})
|
227
297
|
super(options)
|
228
298
|
end
|
@@ -264,4 +334,8 @@ class Event < ActiveRecord::Base
|
|
264
334
|
def already_has_chart(chart)
|
265
335
|
!self.charts.select{|c| c.name == chart.name }.empty?
|
266
336
|
end
|
337
|
+
|
338
|
+
def create_venue_chart
|
339
|
+
self.venue.update_default_chart_from(self.default_chart)
|
340
|
+
end
|
267
341
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class GeneralAdmissionChart < Chart
|
2
|
+
def self.default_chart_for(chartable)
|
3
|
+
chart = GeneralAdmissionChart.where(chartable.class.name.foreign_key.to_sym => chartable.id)
|
4
|
+
.where(:is_template => true)
|
5
|
+
.first
|
6
|
+
return chart unless chart.nil?
|
7
|
+
|
8
|
+
chart = GeneralAdmissionChart.new
|
9
|
+
chart.name = chartable.name
|
10
|
+
chart.organization = chartable.organization
|
11
|
+
chart.send("#{chartable.class.name.downcase}=", chartable)
|
12
|
+
chart.is_template = true
|
13
|
+
chart
|
14
|
+
end
|
15
|
+
|
16
|
+
def duplicate(options = {})
|
17
|
+
new_chart = super(options)
|
18
|
+
|
19
|
+
if (!!options[:save])
|
20
|
+
new_chart.save
|
21
|
+
end
|
22
|
+
|
23
|
+
new_chart
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Suitable for chaining includes
|
28
|
+
# :chart => chart.class.included_models
|
29
|
+
#
|
30
|
+
def self.included_models
|
31
|
+
[:sections => :ticket_types]
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_tickets
|
35
|
+
raise "Only charts that have been assigned to shows can create tickets" if self.show.nil?
|
36
|
+
Ticket.create_many(self.show, self.sections.first, self.sections.first.capacity)
|
37
|
+
self.sections.first.put_on_sale(self.sections.first.capacity)
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Returns an array of available tickets as well as an error
|
42
|
+
# [[ ticket array ], "error message suitable for end-user display"]
|
43
|
+
#
|
44
|
+
def get_available_tickets(ticket_type, ticket_limit = 4, member = nil, seat = nil, cart = nil)
|
45
|
+
available_tickets = Ticket.available({:section_id => ticket_type.section.id,
|
46
|
+
:ticket_type_id => nil },
|
47
|
+
[ticket_limit, ticket_type.available(member)].min)
|
48
|
+
|
49
|
+
[available_tickets, ""]
|
50
|
+
end
|
51
|
+
end
|