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.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/loading-white.gif +0 -0
  3. data/app/assets/images/seating_temp/1.jpg +0 -0
  4. data/app/assets/images/seating_temp/10.jpg +0 -0
  5. data/app/assets/images/seating_temp/11.jpg +0 -0
  6. data/app/assets/images/seating_temp/2.jpg +0 -0
  7. data/app/assets/images/seating_temp/3.jpg +0 -0
  8. data/app/assets/images/seating_temp/4.jpg +0 -0
  9. data/app/assets/images/seating_temp/5.jpg +0 -0
  10. data/app/assets/images/seating_temp/6.jpg +0 -0
  11. data/app/assets/images/seating_temp/7.jpg +0 -0
  12. data/app/assets/images/seating_temp/8.jpg +0 -0
  13. data/app/assets/images/seating_temp/9.jpg +0 -0
  14. data/app/assets/images/seating_temp/icon_43405.png +0 -0
  15. data/app/assets/images/seating_temp/icon_43405.svg +3 -0
  16. data/app/assets/images/seating_temp/icon_43405_plus.png +0 -0
  17. data/app/assets/images/seating_temp/license.txt +8 -0
  18. data/app/assets/javascripts/application.js +1 -0
  19. data/app/assets/javascripts/custom/cookies.js +27 -0
  20. data/app/assets/javascripts/custom/inline-people-search.js +4 -0
  21. data/app/assets/javascripts/custom/job-monitor.js +0 -1
  22. data/app/assets/javascripts/exchange-seat-chart.js +5 -0
  23. data/app/assets/javascripts/seat-chart.js +606 -0
  24. data/app/assets/javascripts/show-seat-chart.js +17 -0
  25. data/app/assets/javascripts/store/store-seat-chart.js +76 -0
  26. data/app/assets/javascripts/store/store.js +14 -39
  27. data/app/assets/stylesheets/application.sass +49 -1
  28. data/app/assets/stylesheets/bootstrap-overrides.css +11 -3
  29. data/app/assets/stylesheets/sass/seat-chart.sass +311 -0
  30. data/app/assets/stylesheets/sass/store.sass +73 -19
  31. data/app/assets/stylesheets/storefront.css +2 -0
  32. data/app/concerns/pdf_generation.rb +1 -15
  33. data/app/controllers/advanced_searches_controller.rb +1 -3
  34. data/app/controllers/charts_controller.rb +14 -12
  35. data/app/controllers/console_sales_controller.rb +55 -0
  36. data/app/controllers/event_calendars_controller.rb +15 -0
  37. data/app/controllers/events_controller.rb +16 -5
  38. data/app/controllers/exchanges_controller.rb +32 -9
  39. data/app/controllers/export_controller.rb +8 -0
  40. data/app/controllers/members/sessions_controller.rb +0 -2
  41. data/app/controllers/membership_comps_controller.rb +2 -1
  42. data/app/controllers/prices_controller.rb +20 -0
  43. data/app/controllers/shows_controller.rb +3 -1
  44. data/app/controllers/store/events_controller.rb +6 -5
  45. data/app/controllers/store/orders_controller.rb +11 -13
  46. data/app/controllers/store/shows_controller.rb +1 -0
  47. data/app/controllers/store/store_controller.rb +11 -0
  48. data/app/controllers/tickets_controller.rb +0 -28
  49. data/app/controllers/user_memberships_controller.rb +7 -2
  50. data/app/controllers/venues_controller.rb +9 -0
  51. data/app/helpers/artfully_ose_helper.rb +18 -4
  52. data/app/helpers/seating_helper.rb +157 -0
  53. data/app/models/assigned_chart.rb +220 -0
  54. data/app/models/cart.rb +6 -1
  55. data/app/models/chart.rb +28 -17
  56. data/app/models/database_views/item_view.rb +76 -5
  57. data/app/models/discount.rb +4 -0
  58. data/app/models/discounts/buy_one_get_one_free_discount_type.rb +1 -1
  59. data/app/models/discounts/dollars_off_tickets_discount_type.rb +5 -1
  60. data/app/models/discounts/percentage_off_tickets_discount_type.rb +8 -4
  61. data/app/models/event.rb +86 -12
  62. data/app/models/general_admission_chart.rb +51 -0
  63. data/app/models/imports/events_import.rb +1 -1
  64. data/app/models/job/show_creator.rb +3 -10
  65. data/app/models/kit.rb +11 -1
  66. data/app/models/kits/assigned_seating_kit.rb +23 -0
  67. data/app/models/member_walkup.rb +1 -1
  68. data/app/models/order_handler.rb +22 -6
  69. data/app/models/organization.rb +4 -5
  70. data/app/models/person.rb +3 -1
  71. data/app/models/sale.rb +1 -1
  72. data/app/models/seat.rb +96 -0
  73. data/app/models/section.rb +1 -3
  74. data/app/models/show.rb +10 -17
  75. data/app/models/ticket.rb +30 -6
  76. data/app/models/ticket/locker.rb +3 -2
  77. data/app/models/ticket_type.rb +12 -6
  78. data/app/models/ticket_types_seat.rb +4 -0
  79. data/app/models/venue.rb +23 -0
  80. data/app/views/advanced_searches/filters/_birthday.html.haml +1 -0
  81. data/app/views/assigned_charts/_show.html.haml +12 -0
  82. data/app/views/console_sales/_aloha.html.haml +5 -4
  83. data/app/views/console_sales/new.html.haml +9 -0
  84. data/app/views/event_calendars/index.html.haml +34 -0
  85. data/app/views/events/_menu.html.haml +2 -1
  86. data/app/views/events/_section_fields.html.haml +13 -8
  87. data/app/views/events/new.html.haml +34 -4
  88. data/app/views/events/prices.html.haml +3 -4
  89. data/app/views/events/seating.html.haml +131 -0
  90. data/app/views/exchanges/_assigned_chart.html.haml +108 -0
  91. data/app/views/exchanges/_general_admission_chart.html.haml +55 -0
  92. data/app/views/exchanges/new.html.haml +1 -55
  93. data/app/views/general_admission_charts/_show.html.haml +2 -0
  94. data/app/views/layouts/_menu.html.haml +44 -31
  95. data/app/views/layouts/storefront.html.haml +72 -30
  96. data/app/views/membership_comps/new.html.haml +1 -0
  97. data/app/views/order_mailer/confirmation_for.html.haml +5 -3
  98. data/app/views/order_mailer/confirmation_for.text.haml +1 -2
  99. data/app/views/pdfs/order.html.haml +20 -6
  100. data/app/views/seating/_actions_menu.html.haml +10 -0
  101. data/app/views/seating/_chart.html.haml +15 -0
  102. data/app/views/seating/_chart_container.html.haml +2 -0
  103. data/app/views/seating/_chart_note_display.html.haml +7 -0
  104. data/app/views/seating/_hold_seats_modal.html.haml +39 -0
  105. data/app/views/seating/_layer_menu.html.haml +23 -0
  106. data/app/views/seating/_legend.html.haml +52 -0
  107. data/app/views/seating/_modify_seats_modal.html.haml +29 -0
  108. data/app/views/seating/_ticket_type_modals.html.haml +41 -0
  109. data/app/views/shows/_seat_chart.html.haml +122 -0
  110. data/app/views/shows/_sections_table.html.haml +3 -24
  111. data/app/views/shows/_ticket_table.html.haml +4 -2
  112. data/app/views/shows/_work_with.html.haml +4 -0
  113. data/app/views/shows/new.html.haml +2 -2
  114. data/app/views/shows/show.html.haml +93 -14
  115. data/app/views/store/assigned_charts/_show.html.haml +54 -0
  116. data/app/views/store/checkouts/shopping_cart_display/_tickets.haml +13 -0
  117. data/app/views/store/donations/index.html.haml +1 -1
  118. data/app/views/store/events/calendar.html.haml +94 -11
  119. data/app/views/store/events/index.html.haml +1 -1
  120. data/app/views/store/events/show.html.haml +36 -2
  121. data/app/views/store/events/single_show.html.haml +5 -4
  122. data/app/views/store/general_admission_charts/_show.html.haml +41 -0
  123. data/app/views/store/orders/show.html.haml +17 -4
  124. data/app/views/store/shared/_donate_form.html.haml +2 -1
  125. data/app/views/store/shared/_small_donate_form.html.haml +1 -1
  126. data/app/views/store/shows/_show.html.haml +1 -39
  127. data/app/views/ticket_types/edit.html.haml +1 -1
  128. data/app/views/user_memberships/_list.html.haml +1 -1
  129. data/app/views/venues/edit.html.haml +1 -1
  130. data/app/views/venues/show.html.haml +11 -0
  131. data/config/routes.rb +27 -10
  132. data/db/migrate/20140828174357_add_type_to_chart.rb +7 -0
  133. data/db/migrate/20140828195617_create_seats.rb +16 -0
  134. data/db/migrate/20140829135426_add_venue_to_chart.rb +5 -0
  135. data/db/migrate/20140829143520_add_assigned_to_event.rb +5 -0
  136. data/db/migrate/20140904164927_add_fields_to_seat.rb +14 -0
  137. data/db/migrate/20140912170010_add_note_to_seat.rb +6 -0
  138. data/db/migrate/20140919152307_add_seats_to_ticket.rb +5 -0
  139. data/db/migrate/20140930224543_add_public_note_to_chart.rb +5 -0
  140. data/db/migrate/20141001140737_add_seat_id_index_to_tickets.rb +5 -0
  141. data/db/migrate/20141001193242_associate_hold_with_person.rb +6 -0
  142. data/db/migrate/20141021175311_create_ticket_types_seats.rb +11 -0
  143. data/db/migrate/20150106161744_migrate_charts_back_to_venues.rb +18 -0
  144. data/db/migrate/20151105085424_add_creator_to_items_view.rb +40 -0
  145. data/lib/artfully_ose/version.rb +1 -1
  146. data/spec/factories/assigned_chart_factories.rb +18 -0
  147. data/spec/factories/chart_factories.rb +4 -8
  148. data/spec/factories/kit_factories.rb +4 -0
  149. data/spec/factories/seat_factories.rb +4 -0
  150. data/spec/factories/show_factories.rb +1 -1
  151. metadata +66 -5
  152. data/app/models/ticket/foundry.rb +0 -48
  153. data/app/models/ticket/template.rb +0 -40
  154. data/app/views/store/events/_calendar.html.haml +0 -13
@@ -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|
@@ -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, :sections_attributes, :ticket_types_attributes, :organization, :event, :skip_create_first_section
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
- def dup!
37
- duplicate(:without => "id", :with => { :is_template => false })
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
- private
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-Ticket-Sales-Export-#{organization.id}.csv"
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
@@ -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
- FeeCalculator.apply(FeeStrategy.new).to(@discount.cart)
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
- FeeCalculator.apply(FeeStrategy.new).to(@discount.cart)
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
- private
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
@@ -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, :subtitle
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
- chart = self.charts.build({ :name => self.name,
156
- :is_template => false })
157
- chart.organization = self.organization
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
- charts.first
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
- def next_show
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