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
@@ -162,7 +162,7 @@ class EventsImport < Import
|
|
162
162
|
|
163
163
|
raise Import::RuntimeError, 'No section found for ticket' unless section
|
164
164
|
|
165
|
-
ticket = Ticket.build_one(show, section,
|
165
|
+
ticket = Ticket.build_one(show, section, true)
|
166
166
|
ticket.ticket_type = ticket_type
|
167
167
|
Rails.logger.info("Processing Import [#{id}] EVENT_IMPORT: Ticket built [#{ticket.inspect}]")
|
168
168
|
ticket.sell_to person
|
@@ -1,26 +1,19 @@
|
|
1
1
|
class ShowCreator < Struct.new(:datetimes, :show_params, :chart_params, :event, :organization, :publish)
|
2
2
|
|
3
|
-
#
|
4
|
-
# If datetime.length < 3, the shows will create right away. Otherwise, they'll be queued
|
5
|
-
#
|
6
3
|
def self.enqueue(datetimes, show_params, chart_params, event, organization, publish = false)
|
7
4
|
datetimes ||= []
|
8
5
|
creator = ShowCreator.new(datetimes, show_params, chart_params, event, organization, publish)
|
9
|
-
|
10
|
-
creator.perform
|
11
|
-
else
|
12
|
-
Delayed::Job.enqueue(creator)
|
13
|
-
end
|
6
|
+
Delayed::Job.enqueue(creator)
|
14
7
|
end
|
15
8
|
|
16
9
|
def perform
|
17
10
|
ActiveRecord::Base.transaction do
|
18
11
|
datetimes.each do |datetime_string|
|
19
|
-
@show = self.event.
|
12
|
+
@show = self.event.build_next_show
|
20
13
|
|
21
14
|
#clear the sections and replace them with whatever they entered
|
22
15
|
@show.chart.sections = []
|
23
|
-
@show.chart.update_attributes_from_params(chart_params)
|
16
|
+
@show.chart.update_attributes_from_params(chart_params, self.event.default_chart)
|
24
17
|
@show.update_attributes(show_params)
|
25
18
|
@show.organization = organization
|
26
19
|
@show.chart_id = @show.chart.id
|
data/app/models/kit.rb
CHANGED
@@ -83,7 +83,17 @@ class Kit < ActiveRecord::Base
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def self.subklasses
|
86
|
-
@subklasses ||= [ TicketingKit,
|
86
|
+
@subklasses ||= [ TicketingKit,
|
87
|
+
RegularDonationKit,
|
88
|
+
SponsoredDonationKit,
|
89
|
+
ResellerKit,
|
90
|
+
MailchimpKit,
|
91
|
+
MembershipKit,
|
92
|
+
PassesKit,
|
93
|
+
ScannableTicketsKit,
|
94
|
+
RelationshipsKit,
|
95
|
+
CampaignsKit,
|
96
|
+
AssignedSeatingKit ].freeze
|
87
97
|
end
|
88
98
|
|
89
99
|
def self.pad_with_new_kits(kits = [])
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class AssignedSeatingKit < Kit
|
2
|
+
|
3
|
+
acts_as_kit :admin_only => true do
|
4
|
+
self.configurable = false
|
5
|
+
|
6
|
+
state_machine do
|
7
|
+
state :cancelled, :enter => :kit_cancelled
|
8
|
+
event(:submit_for_approval) { transitions :from => :fresh, :to => :pending }
|
9
|
+
end
|
10
|
+
|
11
|
+
when_active do |organization|
|
12
|
+
organization.can :access, :assigned_seating
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def friendly_name
|
17
|
+
"Assigned Seating"
|
18
|
+
end
|
19
|
+
|
20
|
+
def pitch
|
21
|
+
"Assigned Seating"
|
22
|
+
end
|
23
|
+
end
|
data/app/models/member_walkup.rb
CHANGED
data/app/models/order_handler.rb
CHANGED
@@ -17,14 +17,20 @@ class OrderHandler
|
|
17
17
|
self.handle_discount_or_pass_code(params)
|
18
18
|
end
|
19
19
|
|
20
|
+
def add_tickets(tickets, ticket_type)
|
21
|
+
#check availability, obv
|
22
|
+
Ticket.lock(tickets, ticket_type, self.cart)
|
23
|
+
end
|
24
|
+
|
20
25
|
def handle_tickets(params)
|
21
26
|
if params[:ticket_type_id]
|
22
27
|
ticket_ids = []
|
23
28
|
over_limit = []
|
24
29
|
|
25
30
|
ticket_type = TicketType.find(params[:ticket_type_id])
|
31
|
+
seat = params[:seat_id].present? ? Seat.find(params[:seat_id]) : nil
|
26
32
|
Rails.logger.debug("QUANTITY #{params[:quantity].to_i}")
|
27
|
-
tickets = ticket_type.available_tickets(params[:quantity].to_i, member)
|
33
|
+
tickets, self.error = ticket_type.available_tickets(params[:quantity].to_i, member, seat, self.cart)
|
28
34
|
ids = tickets.collect(&:id)
|
29
35
|
Rails.logger.debug("TICKET IDS: #{ids}")
|
30
36
|
Ticket.lock(tickets, ticket_type, self.cart)
|
@@ -35,6 +41,7 @@ class OrderHandler
|
|
35
41
|
#TODO: return and display a sensible error message
|
36
42
|
end
|
37
43
|
|
44
|
+
|
38
45
|
params = params.merge(:tickets => ticket_ids) if ticket_ids.any?
|
39
46
|
end
|
40
47
|
params
|
@@ -124,16 +131,25 @@ class OrderHandler
|
|
124
131
|
def handle_discount(params)
|
125
132
|
begin
|
126
133
|
discount = nil
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
134
|
+
|
135
|
+
#
|
136
|
+
# If we have an event_id (discount was entered from specific event storefront)
|
137
|
+
# then find the discount with that. Otherwise, interrogate the cart to get
|
138
|
+
# events fro the tickets
|
139
|
+
#
|
140
|
+
if params[:event_id].present?
|
141
|
+
discount = Discount.find_by_code_and_event_id(params[:discount_or_pass_code].upcase, params[:event_id])
|
142
|
+
else
|
143
|
+
self.cart.tickets.each do |ticket|
|
144
|
+
discount = Discount.find_by_code_and_event_id(params[:discount_or_pass_code].upcase, ticket.show.event.id)
|
145
|
+
break if discount
|
132
146
|
end
|
133
147
|
end
|
134
148
|
|
135
149
|
if discount.nil?
|
136
150
|
self.error = "We could not find your discount. Please try again."
|
151
|
+
else
|
152
|
+
discount.apply_discount_to_cart(self.cart)
|
137
153
|
end
|
138
154
|
rescue RuntimeError => e
|
139
155
|
self.error = e.message
|
data/app/models/organization.rb
CHANGED
@@ -7,6 +7,7 @@ class Organization < ActiveRecord::Base
|
|
7
7
|
attr_accessible :name, :time_zone, :ein, :legal_organization_name, :email, :receive_daily_sales_report, :country, :state, :zip, :phone_number, :website, :discipline, :cached_slug, :fiscal_month, :fiscal_day, :budget_restrictions_attributes
|
8
8
|
|
9
9
|
has_many :events
|
10
|
+
has_many :venues
|
10
11
|
has_many :charts
|
11
12
|
has_many :shows
|
12
13
|
has_many :tickets
|
@@ -113,13 +114,11 @@ class Organization < ActiveRecord::Base
|
|
113
114
|
users.order('user_memberships.id asc').first
|
114
115
|
end
|
115
116
|
|
116
|
-
#
|
117
|
-
# A shorthand for "first org admin" basically meaning "Just get me someone at the org"
|
118
|
-
#
|
119
117
|
def owner
|
120
|
-
@owner ||= UserMembership.includes(:user).where(:organization_id => self.id).where(:organization_administrator => true).first.try(:user)
|
118
|
+
# @owner ||= UserMembership.includes(:user).where(:organization_id => self.id).where(:organization_administrator => true).first.try(:user)
|
119
|
+
@owner ||= user_memberships.select{|um| um.organization_administrator == true}.first.try(:user)
|
121
120
|
end
|
122
|
-
|
121
|
+
|
123
122
|
def daily_sales_report_recipients
|
124
123
|
@recipients ||= UserMembership.includes(:user).where(:organization_id => self.id).where(:receive_daily_sales_report => true).collect(&:user)
|
125
124
|
end
|
data/app/models/person.rb
CHANGED
@@ -41,6 +41,7 @@ class Person < ActiveRecord::Base
|
|
41
41
|
has_one :member
|
42
42
|
has_many :memberships, :through => :member
|
43
43
|
has_many :passes
|
44
|
+
has_many :holds, :class_name => "Seat", :foreign_key => :held_for_id
|
44
45
|
|
45
46
|
has_many :relationships, :foreign_key => :person_id, :class_name => 'Relationship', :dependent => :destroy
|
46
47
|
|
@@ -151,7 +152,7 @@ class Person < ActiveRecord::Base
|
|
151
152
|
# Tickets are a special case
|
152
153
|
#
|
153
154
|
def self.mergables
|
154
|
-
[:actions, :phones, :notes, :orders, :soft_credits, :scheduled_pledge_payments, :passes, :subscribed_lists]
|
155
|
+
[:actions, :phones, :notes, :orders, :soft_credits, :scheduled_pledge_payments, :passes, :subscribed_lists, :holds]
|
155
156
|
end
|
156
157
|
|
157
158
|
def self.loser_attributes_update_if_winner_not_present
|
@@ -807,6 +808,7 @@ class Person < ActiveRecord::Base
|
|
807
808
|
|
808
809
|
def subscribe_to_default_mailchimp_list!
|
809
810
|
return unless mailchimp_kit
|
811
|
+
return if subscribed_lists.where(:list_id => mailchimp_kit.default_list_id).exists?
|
810
812
|
subscribed_lists.create(:list_id => mailchimp_kit.default_list_id, :single_optin => true)
|
811
813
|
end
|
812
814
|
|
data/app/models/sale.rb
CHANGED
@@ -48,7 +48,7 @@ class Sale
|
|
48
48
|
amount_requested = @quantities[ticket_type_id].to_i
|
49
49
|
if amount_requested > 0
|
50
50
|
ticket_type = TicketType.find(ticket_type_id)
|
51
|
-
tickets_available_in_ticket_type = ticket_type.available_tickets(amount_requested)
|
51
|
+
tickets_available_in_ticket_type, error = ticket_type.available_tickets(amount_requested)
|
52
52
|
if tickets_available_in_ticket_type.length != amount_requested
|
53
53
|
errors.add(:base, "There aren't enough tickets available for that ticket type")
|
54
54
|
else
|
data/app/models/seat.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
class Seat < ActiveRecord::Base
|
2
|
+
# Even though we will eventually support multiple physical sections,
|
3
|
+
# Seat does not FK to Section. The reasons are:
|
4
|
+
#
|
5
|
+
# 1) section.rb has a ton of legacy junk in there.
|
6
|
+
# 2) section.rb is closely tied to ticket types, prices, etc...
|
7
|
+
#
|
8
|
+
# When we support multiple physical sections, we'll probably have Seat
|
9
|
+
# FK to a new object, like assigned_section or physical_section.
|
10
|
+
|
11
|
+
belongs_to :chart
|
12
|
+
belongs_to :held_for, :class_name => "Person", :foreign_key => :held_for_id
|
13
|
+
has_many :ticket_types_seats
|
14
|
+
has_many :ticket_types, :through => :ticket_types_seats, :dependent => :destroy
|
15
|
+
has_one :ticket
|
16
|
+
|
17
|
+
attr_accessible :row_index, # The 0-based row index of the seat irrespective of actual names
|
18
|
+
:col_index, # The 0-based column index of the seat irrespective of actual names
|
19
|
+
:row_label, # The actual name of the row "B" or "AAA"
|
20
|
+
:col_label, # The seat number. "17"
|
21
|
+
:label, # The physical label on the physical seat "4B", "B4", or "17".
|
22
|
+
:available # Is the seat available for purchase. Roughly analogous to "on_sale"
|
23
|
+
|
24
|
+
#
|
25
|
+
# "available" means that the seat isn't killed or held
|
26
|
+
# "available_for_purchase" means the underlying ticket can be purchased
|
27
|
+
#
|
28
|
+
def available_for_purchase
|
29
|
+
self.available && self.ticket && self.ticket.on_sale? && !self.ticket.locked?
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_hold?
|
33
|
+
self.house_hold? ||
|
34
|
+
self.development_hold? ||
|
35
|
+
self.tech_hold? ||
|
36
|
+
self.contractual_hold? ||
|
37
|
+
self.person_hold? ||
|
38
|
+
self.press_hold
|
39
|
+
end
|
40
|
+
|
41
|
+
def dup!
|
42
|
+
Seat.new(self.attributes.reject { |key, value| ["chart_id", "id"].include? key }, :without_protection => true)
|
43
|
+
end
|
44
|
+
|
45
|
+
def update_ticket
|
46
|
+
if self.ticket.present?
|
47
|
+
if self.on_hold?
|
48
|
+
self.ticket.off_sale! if ticket.on_sale?
|
49
|
+
else
|
50
|
+
self.ticket.on_sale! if self.ticket.off_sale?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def applies_to_pass?(pass)
|
56
|
+
self.ticket_types.each do |ticket_type|
|
57
|
+
return true if ticket_type.applies_to_pass? pass
|
58
|
+
end
|
59
|
+
false
|
60
|
+
end
|
61
|
+
|
62
|
+
def hold_type
|
63
|
+
return nil unless self.on_hold?
|
64
|
+
return "House" if self.house_hold?
|
65
|
+
return "Development" if self.development_hold?
|
66
|
+
return "Tech" if self.tech_hold?
|
67
|
+
return "Contractural" if self.contractual_hold?
|
68
|
+
return "Person" if self.person_hold?
|
69
|
+
return "Press" if self.press_hold
|
70
|
+
end
|
71
|
+
|
72
|
+
def member_ticket_for?(membership_types)
|
73
|
+
return false if membership_types.empty?
|
74
|
+
self.ticket_types.select{|tt| membership_types.collect(&:id).include? tt.membership_type_id }.present?
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# A human-readable qualifier to be displayed during ticket type selection
|
79
|
+
#
|
80
|
+
def qualifier
|
81
|
+
return "Wheelchair removable seat" if self.wheelchair
|
82
|
+
return "Wheelchair companion seat" if self.wheelchair_companion
|
83
|
+
return "Designated aisle seat" if self.aisle
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# Don't make this a callback! Charts and shows and everything else have a process
|
88
|
+
# about creating tickets when a producer creates a show. This method is for seats created *after* a show
|
89
|
+
# has been created and put on sale
|
90
|
+
#
|
91
|
+
def create_ticket
|
92
|
+
if self.chart.show.present? && self.ticket.nil?
|
93
|
+
Ticket.build_one(self.chart.show, self.chart.sections.first, !self.on_hold?, self).save
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/app/models/section.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
class Section < ActiveRecord::Base
|
2
|
-
include Ticket::Foundry
|
3
2
|
attr_accessor :skip_create_first_ticket_type
|
4
|
-
foundry :with => lambda { { :section_id => id, :count => capacity } }
|
5
3
|
|
6
4
|
attr_accessible :name, :capacity, :price, :chart_id, :description, :ticket_types_attributes, :members
|
7
5
|
delegate :show, :to => :chart
|
@@ -74,7 +72,7 @@ class Section < ActiveRecord::Base
|
|
74
72
|
end
|
75
73
|
|
76
74
|
def dup!
|
77
|
-
attrs = self.attributes.reject { |key, value|
|
75
|
+
attrs = self.attributes.reject { |key, value| ["chart_id", "id"].include? key }
|
78
76
|
self.class.new(attrs).tap do |copy|
|
79
77
|
copy.ticket_types = self.ticket_types.collect { |ticket_type| ticket_type.dup! }
|
80
78
|
end
|
data/app/models/show.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
class Show < ActiveRecord::Base
|
2
|
-
include Ticket::Foundry
|
3
2
|
include Ticket::Reporting
|
4
3
|
include ActiveRecord::Transitions
|
5
4
|
include Ext::Resellable::Show
|
@@ -41,8 +40,6 @@ class Show < ActiveRecord::Base
|
|
41
40
|
scope :played, lambda { where("shows.datetime < ?", Time.now) }
|
42
41
|
scope :unplayed, lambda { where("shows.datetime > ?", Time.now) }
|
43
42
|
|
44
|
-
foundry :using => :chart, :with => lambda {{:show_id => self.id, :organization_id => organization_id}}
|
45
|
-
|
46
43
|
delegate :free?, :to => :event
|
47
44
|
|
48
45
|
ANY_SHOW_ID = "-1"
|
@@ -51,7 +48,7 @@ class Show < ActiveRecord::Base
|
|
51
48
|
|
52
49
|
#pending and built are deprecated, left in only because we have shows in production which are built
|
53
50
|
state :pending
|
54
|
-
state :built, :exit => :
|
51
|
+
state :built, :exit => :create_tickets
|
55
52
|
state :published
|
56
53
|
state :unpublished
|
57
54
|
|
@@ -115,13 +112,19 @@ class Show < ActiveRecord::Base
|
|
115
112
|
self.cached_stats
|
116
113
|
end
|
117
114
|
|
115
|
+
#
|
116
|
+
# uses cached_stats instead of going to the DB
|
117
|
+
#
|
118
|
+
def sold_out?
|
119
|
+
self.on_sale < 1
|
120
|
+
end
|
121
|
+
|
118
122
|
def parsed_local_datetime
|
119
123
|
@parsed_local_datetime = (DateTime.parse(self.local_datetime.to_s) rescue self.datetime_local_to_event)
|
120
124
|
end
|
121
125
|
|
122
|
-
def
|
123
|
-
create_tickets
|
124
|
-
bulk_on_sale(:all)
|
126
|
+
def create_tickets
|
127
|
+
self.chart.create_tickets
|
125
128
|
end
|
126
129
|
|
127
130
|
def unscoped_event
|
@@ -206,16 +209,6 @@ class Show < ActiveRecord::Base
|
|
206
209
|
:chart => chart_for("storefront", options[:organization_id]).as_json(options))
|
207
210
|
end
|
208
211
|
|
209
|
-
def bulk_on_sale(ids)
|
210
|
-
targets = (ids == :all) ? tickets : tickets.where(:id => ids)
|
211
|
-
Ticket.put_on_sale(targets)
|
212
|
-
end
|
213
|
-
|
214
|
-
def bulk_off_sale(ids)
|
215
|
-
targets = (ids == :all) ? tickets : tickets.where(:id => ids)
|
216
|
-
Ticket.take_off_sale(targets)
|
217
|
-
end
|
218
|
-
|
219
212
|
def bulk_delete(ids)
|
220
213
|
tickets.where(:id => ids).collect{ |ticket| ticket.id if ticket.destroy }#.compact
|
221
214
|
end
|
data/app/models/ticket.rb
CHANGED
@@ -21,6 +21,7 @@ class Ticket < ActiveRecord::Base
|
|
21
21
|
belongs_to :pass
|
22
22
|
belongs_to :discount
|
23
23
|
belongs_to :action, :foreign_key => "validated_action_id", :class_name => "GoAction"
|
24
|
+
belongs_to :seat
|
24
25
|
|
25
26
|
#
|
26
27
|
# This refs the ticket_type that the ticket was sold under,
|
@@ -55,15 +56,34 @@ class Ticket < ActiveRecord::Base
|
|
55
56
|
scope :sold_or_comped, where(:state => [:sold, :comped])
|
56
57
|
|
57
58
|
state_machine :auto_scopes => true do
|
58
|
-
|
59
|
+
#
|
60
|
+
# :off_sale denotes that the tickets are not publicly available for purchase
|
61
|
+
# The tickets may still be sold by other means, such as the producer selling into a hold.
|
62
|
+
# Tickets may be off_Sale for a variety of reasons: seats are held, tickets explicitly
|
63
|
+
# set to off_sale, seats are killed, ticket refunded but not returned to inventory.
|
64
|
+
#
|
65
|
+
state :off_sale
|
66
|
+
|
67
|
+
#
|
68
|
+
# An :on_sale ticket is available for purchase through the storefront
|
69
|
+
#
|
59
70
|
state :on_sale
|
71
|
+
|
72
|
+
#
|
73
|
+
# A :sold ticket has been purchased by a buyer
|
74
|
+
#
|
60
75
|
state :sold
|
76
|
+
|
77
|
+
#
|
78
|
+
# A :comped ticket was given to a patron for no charge. It's similar to a $0 sold ticket
|
79
|
+
# but there are enough differences that it merited its own state
|
80
|
+
#
|
61
81
|
state :comped
|
62
82
|
|
63
83
|
event(:on_sale) { transitions :from => [ :on_sale, :off_sale ], :to => :on_sale }
|
64
84
|
event(:off_sale) { transitions :from => [ :on_sale, :off_sale ], :to => :off_sale }
|
65
85
|
event(:exchange, :success => :record_exchange) { transitions :from => [ :on_sale, :off_sale ], :to => :sold }
|
66
|
-
event(:sell, :success => :record_sale) { transitions :from => [ :on_sale ], :to => :sold }
|
86
|
+
event(:sell, :success => :record_sale) { transitions :from => [ :on_sale, :off_sale ], :to => :sold }
|
67
87
|
event(:comp, :success => :record_comp) { transitions :from => [ :on_sale, :off_sale ], :to => :comped }
|
68
88
|
event(:return_to_inventory) { transitions :from => [ :comped, :sold ], :to => :on_sale }
|
69
89
|
event(:return_off_sale) { transitions :from => [ :comped, :sold ], :to => :off_sale }
|
@@ -225,12 +245,15 @@ class Ticket < ActiveRecord::Base
|
|
225
245
|
not committed?
|
226
246
|
end
|
227
247
|
|
228
|
-
#
|
229
|
-
#
|
248
|
+
#
|
249
|
+
# Bulk creation of tickets should use this method to ensure all tickets are created the same
|
250
|
+
# Reminder that this returns a ActiveRecord::Import::Result, not an array of tickets
|
251
|
+
#
|
230
252
|
def self.create_many(show, section, quantity, on_sale = false)
|
231
253
|
new_tickets = []
|
254
|
+
|
232
255
|
quantity.times do
|
233
|
-
new_tickets << build_one(show, section,
|
256
|
+
new_tickets << build_one(show, section, on_sale)
|
234
257
|
end
|
235
258
|
|
236
259
|
result = Ticket.import(new_tickets)
|
@@ -242,11 +265,12 @@ class Ticket < ActiveRecord::Base
|
|
242
265
|
# This method does not refresh show stats
|
243
266
|
# Callers should do that manually with show.delay.refresh_stats
|
244
267
|
#
|
245
|
-
def self.build_one(show, section,
|
268
|
+
def self.build_one(show, section, on_sale = false, seat=nil)
|
246
269
|
t = Ticket.new({
|
247
270
|
:venue => show.event.venue.name,
|
248
271
|
:section => section,
|
249
272
|
})
|
273
|
+
t.seat = seat
|
250
274
|
t.show = show
|
251
275
|
t.organization = show.organization
|
252
276
|
t.set_uuid
|