artfully_ose 1.2.0.alpha.2 → 1.2.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/app/assets/stylesheets/application.sass +7 -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/member_cards_controller.rb +2 -3
- data/app/controllers/orders_controller.rb +42 -0
- data/app/controllers/passes_reports_controller.rb +21 -1
- data/app/helpers/artfully_ose_helper.rb +10 -0
- data/app/models/database_views/item_view.rb +41 -0
- data/app/models/ext/integrations.rb +4 -0
- data/app/models/fee_strategy.rb +47 -1
- data/app/models/item.rb +4 -3
- data/app/models/job/order_processor.rb +4 -3
- data/app/models/member.rb +4 -3
- data/app/models/membership_sale_search.rb +2 -20
- data/app/models/membership_type.rb +1 -2
- data/app/models/order.rb +29 -0
- data/app/models/pass.rb +2 -1
- data/app/models/pass_sale_search.rb +18 -0
- data/app/models/pass_type.rb +6 -1
- data/app/models/passes_report.rb +117 -0
- data/app/models/sale_search.rb +3 -21
- data/app/views/contributions/index.html.haml +2 -2
- 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/pass_types/index.html.haml +1 -1
- data/app/views/passes_reports/index.html.haml +79 -1
- data/app/views/store/passes/index.html.haml +2 -2
- data/config/routes.rb +1 -0
- data/lib/artfully_ose/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NzdkN2Y3NDg3MDVhMDY5NjQ4OWM1MzlhYjlmNGFkMTI1YThlM2EzYQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NzhhODQxYjMzYTFjMDI5M2RkNzZiMzg3YzYyYTVmYTc1NjcyMjgzOQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZThmZDFjY2RlMWQ2MGExYzlkODYyYWE2MmQ3OWY1NDYyNjk5MDIzOTQ1MDhl
|
10
|
+
NTkzN2Q0NGJhOGJiNDE4ODBhODJkODczNzZmMWE5OTVmMGUzYzVlZDhiMzI3
|
11
|
+
ZGQ3NGI4NmJiZWUzODFiM2IzYzUzNzU5NGQ3OGE2OGNmN2YyMTg=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MzU1N2U3MzgzODQ2MzZmOTc2MjU4YjBjYzc2MzBjMzQ0YWU2NDExMjcxZTNk
|
14
|
+
ZmJjNzBjM2JiMzVkMDUxNzM5MzZlZjBjZGI2NTZjZmVhYjEyNDdiMDkzNWVm
|
15
|
+
NWUzNTE4MWUxZTk0NzgwMGFhYzRjNGE2OGFmODRkMjU1ZGNkNGI=
|
@@ -119,8 +119,14 @@ ul#memberships
|
|
119
119
|
#text
|
120
120
|
padding-top: 50px
|
121
121
|
|
122
|
-
#
|
122
|
+
#no-pass-sales
|
123
123
|
text-align: center
|
124
|
+
width: 100%
|
125
|
+
height: 100px
|
126
|
+
#text
|
127
|
+
padding-top: 25px
|
128
|
+
|
129
|
+
#add-a-pass-type
|
124
130
|
width: 75%
|
125
131
|
height: 150px
|
126
132
|
#text
|
data/app/concerns/itemable.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Include this method on objects that can be used to create items using Item.for
|
3
|
-
# Ticket class doesn't
|
3
|
+
# Ticket class doesn't need it because it defines its own sold_price method
|
4
4
|
#
|
5
5
|
module Itemable
|
6
6
|
extend ActiveSupport::Concern
|
@@ -17,17 +17,7 @@ class PdfGeneration
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def generate
|
20
|
-
|
21
|
-
json = JSON.parse(response.body)
|
22
|
-
|
23
|
-
while !json["complete"]
|
24
|
-
response = http_party.get(status_url(json))
|
25
|
-
json = JSON.parse(response.body)
|
26
|
-
|
27
|
-
sleeper.sleep 1 unless json["complete"]
|
28
|
-
end
|
29
|
-
|
30
|
-
download_url(json)
|
20
|
+
Wisepdf::Writer.new.to_pdf(content)
|
31
21
|
end
|
32
22
|
|
33
23
|
def content
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module SearchByDates
|
2
|
+
attr_reader :start, :stop
|
3
|
+
attr_reader :organization
|
4
|
+
|
5
|
+
def start_with(start)
|
6
|
+
start.present? ? DateTime.parse(start) : default_start
|
7
|
+
end
|
8
|
+
|
9
|
+
def stop_with(stop)
|
10
|
+
stop.present? ? Sundial.midnightish(@organization, stop) : default_stop
|
11
|
+
end
|
12
|
+
|
13
|
+
def default_start
|
14
|
+
DateTime.now.in_time_zone(@organization.time_zone).beginning_of_month
|
15
|
+
end
|
16
|
+
|
17
|
+
def default_stop
|
18
|
+
DateTime.now.in_time_zone(@organization.time_zone).end_of_day
|
19
|
+
end
|
20
|
+
end
|
@@ -4,9 +4,8 @@ class MemberCardsController < ArtfullyOseController
|
|
4
4
|
before_filter :find_members
|
5
5
|
|
6
6
|
def new
|
7
|
-
|
8
|
-
|
9
|
-
redirect_to generator.download_url
|
7
|
+
pdf = MemberCardGenerator::BlanksUsaIdc6.new(@members).generate
|
8
|
+
send_data pdf, :filename => "member_cards.pdf", :type => "application/pdf", :disposition => "attachment"
|
10
9
|
end
|
11
10
|
|
12
11
|
private
|
@@ -89,6 +89,48 @@ class OrdersController < ArtfullyOseController
|
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
|
+
def passes
|
93
|
+
authorize! :view, Order
|
94
|
+
|
95
|
+
@organization = current_organization
|
96
|
+
@pass_type = PassType.find_by_id(params[:pass_type_id]) if params[:pass_type_id].present?
|
97
|
+
@pass_types = @organization.pass_types
|
98
|
+
|
99
|
+
request.format = :csv if params[:commit] == "Download"
|
100
|
+
|
101
|
+
search_terms = {
|
102
|
+
:start => params[:start],
|
103
|
+
:stop => params[:stop],
|
104
|
+
:organization => @organization,
|
105
|
+
:pass_type => @pass_type
|
106
|
+
}
|
107
|
+
|
108
|
+
@search = PassSaleSearch.new(search_terms) do |results|
|
109
|
+
results.paginate(:page => params[:page], :per_page => 25)
|
110
|
+
end
|
111
|
+
|
112
|
+
respond_to do |format|
|
113
|
+
format.html
|
114
|
+
format.csv do
|
115
|
+
filename = "Artfully-Pass-Sales-Export-#{DateTime.now.strftime("%m-%d-%y")}.csv"
|
116
|
+
items = ItemView.where(:product_type => "Pass")
|
117
|
+
.where('items_view.created_at > ? ', @search.start)
|
118
|
+
.where('items_view.created_at < ?', @search.stop)
|
119
|
+
.where('items_view.organization_id = ?', current_organization)
|
120
|
+
.order('items_view.created_at desc')
|
121
|
+
if @pass_type
|
122
|
+
items = items.joins(:item).
|
123
|
+
joins("INNER JOIN passes ON (items.product_type = #{::Item.sanitize('Pass')} AND items.product_id = passes.id)").
|
124
|
+
joins("INNER JOIN pass_types ON (pass_types.id = passes.pass_type_id)").
|
125
|
+
where(:pass_types => {:id => @pass_type}).
|
126
|
+
group('items_view.order_id')
|
127
|
+
end
|
128
|
+
csv_string = items.all.to_comma(:pass_sale)
|
129
|
+
send_data csv_string, :filename => filename, :type => "text/csv", :disposition => "attachment"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
92
134
|
def sales
|
93
135
|
authorize! :view, Order
|
94
136
|
|
@@ -1,5 +1,25 @@
|
|
1
1
|
class PassesReportsController < ArtfullyOseController
|
2
2
|
def index
|
3
|
-
@
|
3
|
+
@start_date = params[:start_date]
|
4
|
+
@end_date = params[:end_date]
|
5
|
+
@organization = current_user.current_organization
|
6
|
+
@pass_types = @organization.pass_types
|
7
|
+
@pass_type = PassType.find(params[:pass_type]) if params[:pass_type].present?
|
8
|
+
@report = nil
|
9
|
+
@report = PassesReport.new(@organization, @pass_type, @start_date, @end_date)
|
10
|
+
@rows = @report.rows.paginate(:page => params[:page], :per_page => 100) unless @report.nil?
|
11
|
+
|
12
|
+
@options_for_select = @pass_types.collect{ |p| [p.name, p.id] }
|
13
|
+
@options_for_select.unshift [PassType::ALL_PASSES_STRING, nil]
|
14
|
+
|
15
|
+
respond_to do |format|
|
16
|
+
format.html
|
17
|
+
|
18
|
+
format.csv do
|
19
|
+
@filename = [ @report.header, ".csv" ].join
|
20
|
+
@csv_string = @report.rows.to_comma
|
21
|
+
send_data @csv_string, :filename => @filename, :type => "text/csv", :disposition => "attachment"
|
22
|
+
end
|
23
|
+
end
|
4
24
|
end
|
5
25
|
end
|
@@ -252,6 +252,16 @@ module ArtfullyOseHelper
|
|
252
252
|
select_tag membership_type_id, raw(options), :class => "span3"
|
253
253
|
end
|
254
254
|
|
255
|
+
def select_pass_type_for_sales_search(pass_types, pass_type_id, default)
|
256
|
+
options =
|
257
|
+
[
|
258
|
+
content_tag(:option, " --- All Pass Types --- ", :value => ""),
|
259
|
+
options_from_collection_for_select(pass_types, :id, :name, default)
|
260
|
+
].join
|
261
|
+
|
262
|
+
select_tag pass_type_id, raw(options), :class => "span3"
|
263
|
+
end
|
264
|
+
|
255
265
|
def nav_dropdown(text, link='#')
|
256
266
|
link_to ERB::Util.html_escape(text) + ' <b class="caret"></b>'.html_safe, link, :class => 'dropdown-toggle', 'data-toggle' => 'dropdown'
|
257
267
|
end
|
@@ -145,4 +145,45 @@ class ItemView < ActiveRecord::Base
|
|
145
145
|
person("Do Not Email") { |person| person.do_not_email }
|
146
146
|
person("Do Not Call") { |person| person.do_not_call }
|
147
147
|
end
|
148
|
+
|
149
|
+
comma :pass_sale do
|
150
|
+
created_at_local_to_organization("Date of Purchase")
|
151
|
+
|
152
|
+
item('Pass Type') { |item| item.product.pass_type.name }
|
153
|
+
payment_method("Payment Method")
|
154
|
+
price("Price") { |cents| number_to_currency(cents.to_f/100) }
|
155
|
+
special_instructions("Special Instructions")
|
156
|
+
notes("Notes")
|
157
|
+
|
158
|
+
person("Email") { |person| person.email }
|
159
|
+
person("Salutation") { |person| person.salutation }
|
160
|
+
person("First Name") { |person| person.first_name }
|
161
|
+
person("Middle Name") { |person| person.middle_name }
|
162
|
+
person("Last Name") { |person| person.last_name }
|
163
|
+
person("Suffix") { |person| person.suffix }
|
164
|
+
person("Title") { |person| person.title }
|
165
|
+
person("Type") { |person| person.type }
|
166
|
+
person("Subtype") { |person| person.subtype }
|
167
|
+
person("Company Name") { |person| person.company_name }
|
168
|
+
|
169
|
+
person("Address 1") { |person| person.address && person.address.address1 }
|
170
|
+
person("Address 2") { |person| person.address && person.address.address2 }
|
171
|
+
person("City") { |person| person.address && person.address.city }
|
172
|
+
person("State") { |person| person.address && person.address.state }
|
173
|
+
person("Zip") { |person| person.address && person.address.zip }
|
174
|
+
person("Country") { |person| person.address && person.address.country }
|
175
|
+
person("Phone1 type") { |person| person.phones[0] && person.phones[0].kind }
|
176
|
+
person("Phone1 number") { |person| person.phones[0] && person.phones[0].number }
|
177
|
+
person("Phone2 type") { |person| person.phones[1] && person.phones[1].kind }
|
178
|
+
person("Phone2 number") { |person| person.phones[1] && person.phones[1].number }
|
179
|
+
person("Phone3 type") { |person| person.phones[2] && person.phones[2].kind }
|
180
|
+
person("Phone3 number") { |person| person.phones[2] && person.phones[2].number }
|
181
|
+
person("Website") { |person| person.website }
|
182
|
+
person("Twitter Handle") { |person| person.twitter_handle }
|
183
|
+
person("Facebook URL") { |person| person.facebook_url }
|
184
|
+
person("Linked In Url") { |person| person.linked_in_url }
|
185
|
+
person("Tags") { |person| person.tags.join("|") }
|
186
|
+
person("Do Not Email") { |person| person.do_not_email }
|
187
|
+
person("Do Not Call") { |person| person.do_not_call }
|
188
|
+
end
|
148
189
|
end
|
data/app/models/fee_strategy.rb
CHANGED
@@ -1,5 +1,51 @@
|
|
1
1
|
class FeeStrategy
|
2
|
+
def ticket_fee
|
3
|
+
ARTFULLY_CONFIG[:ticket_fee] || 0
|
4
|
+
end
|
5
|
+
|
2
6
|
def apply_to_cart(cart)
|
3
|
-
|
7
|
+
return if cart.is_a? BoxOffice::Cart
|
8
|
+
|
9
|
+
handle_tickets(cart)
|
10
|
+
handle_memberships(cart)
|
11
|
+
handle_passes(cart)
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle_tickets(cart)
|
15
|
+
cart.tickets.each do |ticket|
|
16
|
+
if ticket.price > 0
|
17
|
+
ticket.service_fee = ticket_fee
|
18
|
+
elsif ticket.price == 0
|
19
|
+
ticket.service_fee = 0
|
20
|
+
end
|
21
|
+
|
22
|
+
if ticket.cart_price == 0 && waive_fee_for?(ticket)
|
23
|
+
ticket.service_fee = 0
|
24
|
+
end
|
25
|
+
|
26
|
+
ticket.save
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def handle_memberships(cart)
|
31
|
+
cart.memberships.each do |membership|
|
32
|
+
membership.service_fee = membership.membership_type.hide_fee? ? 0 : (membership.cart_price || membership.price) * MembershipType::SERVICE_FEE
|
33
|
+
membership.save
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def handle_passes(cart)
|
38
|
+
cart.passes.each do |pass|
|
39
|
+
pass.service_fee = pass.pass_type.hide_fee? ? 0 : pass.price * PassType::SERVICE_FEE
|
40
|
+
pass.save
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def waive_fee_for?(ticket)
|
45
|
+
#
|
46
|
+
# This match is too tightly coupled to discount. Also, horrible.
|
47
|
+
# Check needs to be made because cart_price == 0 && BOGO means fee is applied
|
48
|
+
#
|
49
|
+
(ticket.discount.try(:promotion_type) == "DollarsOffTickets") || ticket.pass.present?
|
4
50
|
end
|
5
51
|
end
|
data/app/models/item.rb
CHANGED
@@ -22,9 +22,10 @@ class Item < ActiveRecord::Base
|
|
22
22
|
validates_presence_of :product_type, :price, :realized_price, :net
|
23
23
|
validates_inclusion_of :product_type, :in => %( Ticket Donation Membership Pass)
|
24
24
|
|
25
|
-
scope :donation,
|
26
|
-
scope :membership,
|
27
|
-
scope :ticket,
|
25
|
+
scope :donation, where(:product_type => 'Donation')
|
26
|
+
scope :membership, where(:product_type => 'Membership')
|
27
|
+
scope :ticket, where(:product_type => 'Ticket')
|
28
|
+
scope :sold_or_comped, where("state in ('purchased','comped','settled')")
|
28
29
|
|
29
30
|
scope :imported, joins(:order).merge(Order.imported)
|
30
31
|
scope :not_imported, joins(:order).merge(Order.not_imported)
|
@@ -85,9 +85,10 @@ class OrderProcessor < Struct.new(:order, :options)
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def generate_pdf
|
88
|
-
|
89
|
-
|
90
|
-
|
88
|
+
pdf = PdfGeneration.new(order).generate
|
89
|
+
file = Tempfile.new(["#{order.id}", '.pdf'])
|
90
|
+
file << pdf.force_encoding("UTF-8")
|
91
|
+
order.pdf = file
|
91
92
|
order.save
|
92
93
|
end
|
93
94
|
end
|
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
|
|
@@ -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?
|
@@ -269,6 +273,23 @@ class Order < ActiveRecord::Base
|
|
269
273
|
standard = standard.where("membership_types.id = ?", search.membership_type.id) if search.membership_type if search.membership_type
|
270
274
|
standard.all
|
271
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
|
272
293
|
|
273
294
|
def has_single_donation?
|
274
295
|
(donations.size == 1) && tickets.empty?
|
@@ -307,6 +328,14 @@ class Order < ActiveRecord::Base
|
|
307
328
|
items.select(&:membership?).present?
|
308
329
|
end
|
309
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
|
+
|
310
339
|
def sum_donations
|
311
340
|
all_donations.collect{|item| item.total_price.to_i}.sum
|
312
341
|
end
|
data/app/models/pass.rb
CHANGED
@@ -18,6 +18,7 @@ class Pass < ActiveRecord::Base
|
|
18
18
|
|
19
19
|
scope :not_expired, lambda { |time = DateTime.now| where("#{Pass.table_name}.ends_at > ?", time) }
|
20
20
|
scope :expired, lambda { |time = DateTime.now| where("#{Pass.table_name}.ends_at < ?", time) }
|
21
|
+
scope :owned, where('person_id is not null')
|
21
22
|
|
22
23
|
def self.for(pass_type)
|
23
24
|
new.tap do |pass|
|
@@ -30,7 +31,7 @@ class Pass < ActiveRecord::Base
|
|
30
31
|
pass.starts_at = pass_type.starts_at
|
31
32
|
pass.ends_at = pass_type.ends_at
|
32
33
|
end
|
33
|
-
end
|
34
|
+
end
|
34
35
|
|
35
36
|
def adjust_ends_at
|
36
37
|
self.ends_at = self.ends_at.end_of_day unless self.ends_at.blank?
|
@@ -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
|
|
@@ -14,7 +15,7 @@ class PassType < ActiveRecord::Base
|
|
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
|
data/app/models/sale_search.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class SaleSearch
|
2
|
-
|
3
|
-
|
4
|
-
attr_reader :
|
2
|
+
include SearchByDates
|
3
|
+
|
4
|
+
attr_reader :event, :show
|
5
5
|
|
6
6
|
def initialize(terms)
|
7
7
|
@organization = terms[:organization]
|
@@ -16,22 +16,4 @@ class SaleSearch
|
|
16
16
|
def results
|
17
17
|
@results ||= Order.sale_search(self).select(&:has_ticket?)
|
18
18
|
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def start_with(start)
|
23
|
-
start.present? ? DateTime.parse(start) : default_start
|
24
|
-
end
|
25
|
-
|
26
|
-
def stop_with(stop)
|
27
|
-
stop.present? ? Sundial.midnightish(@organization, stop) : default_stop
|
28
|
-
end
|
29
|
-
|
30
|
-
def default_start
|
31
|
-
DateTime.now.in_time_zone(@organization.time_zone).beginning_of_month
|
32
|
-
end
|
33
|
-
|
34
|
-
def default_stop
|
35
|
-
DateTime.now.in_time_zone(@organization.time_zone).end_of_day
|
36
|
-
end
|
37
19
|
end
|
@@ -6,9 +6,9 @@
|
|
6
6
|
= form_tag contributions_path, :method => :get, :class => 'well form-inline' do
|
7
7
|
.pull-left
|
8
8
|
= label_tag :start, "From", :class => "control-label"
|
9
|
-
= text_field_tag :start,"#{l @search.start, :format => :date_for_input}", :
|
9
|
+
= text_field_tag :start,"#{l @search.start, :format => :date_for_input}", :class => 'datepicker input-small'
|
10
10
|
= label_tag :stop, "To", :class => "control-label"
|
11
|
-
= text_field_tag :stop, "#{l @search.stop, :format => :date_for_input}", :
|
11
|
+
= text_field_tag :stop, "#{l @search.stop, :format => :date_for_input}", :class => 'datepicker input-small'
|
12
12
|
.pull-right
|
13
13
|
= submit_tag "Search", :class => "btn"
|
14
14
|
= submit_tag "Download", :class => "btn"
|
@@ -2,26 +2,16 @@
|
|
2
2
|
- content_for :header do
|
3
3
|
%h1 Membership Orders
|
4
4
|
|
5
|
-
#print-cards.modal.hide.fade
|
6
|
-
.modal-header
|
7
|
-
.close{'data-dismiss'=>'modal'} x
|
8
|
-
%h3 Generating Member Cards
|
9
|
-
.modal-body
|
10
|
-
%p
|
11
|
-
A PDF is being generated and will automatically begin downloading when ready...
|
12
|
-
.progress.progress-success.progress-striped.active
|
13
|
-
.bar{:style => 'width: 90%'}
|
14
|
-
|
15
5
|
#donations-search
|
16
6
|
|
17
7
|
.control-group.well
|
18
|
-
= form_tag membership_orders_path, :method => :get, :class => 'form-inline' do
|
8
|
+
= form_tag membership_orders_path, :method => :get, :id => 'memberships-date-search-form', :class => 'form-inline' do
|
19
9
|
.pull-left
|
20
10
|
= label_tag :start, "From", :class => "control-label"
|
21
|
-
= text_field_tag :start,"#{l @search.start, :format => :date_for_input}", :
|
11
|
+
= text_field_tag :start,"#{l @search.start, :format => :date_for_input}", :class => 'datepicker input-small'
|
22
12
|
|
23
13
|
= label_tag :stop, "To", :class => "control-label"
|
24
|
-
= text_field_tag :stop, "#{l @search.stop, :format => :date_for_input}", :
|
14
|
+
= text_field_tag :stop, "#{l @search.stop, :format => :date_for_input}", :class => 'datepicker input-small'
|
25
15
|
|
26
16
|
- if @membership_types.present?
|
27
17
|
= label_tag :membership_type_id, nil, :class => "control-label"
|
@@ -41,7 +31,7 @@
|
|
41
31
|
= link_to 'Export to CSV', params.merge(:format => 'csv').delete_if {|k,v| :commit == k.to_sym }
|
42
32
|
- with_kit(:membership) do
|
43
33
|
%li
|
44
|
-
=link_to 'Print Member Cards', new_member_card_path({:start => @search.start, :stop => @search.stop, :membership_type_id => @search.membership_type.try(:id)})
|
34
|
+
=link_to 'Print Member Cards', new_member_card_path({:start => @search.start, :stop => @search.stop, :membership_type_id => @search.membership_type.try(:id)})
|
45
35
|
|
46
36
|
|
47
37
|
- if @search.results.present?
|
@@ -59,16 +49,22 @@
|
|
59
49
|
%tbody
|
60
50
|
- @search.results.each do |order|
|
61
51
|
- order.items.select(&:membership?).each_with_index do |item, index|
|
62
|
-
|
63
|
-
|
52
|
+
- if index == 0
|
53
|
+
%tr{:id => "order_#{order.id}"}
|
64
54
|
- rowspan = order.items.select(&:membership?).size
|
65
55
|
%td{:rowspan => rowspan}= link_to order.id, order_path(order.id)
|
66
56
|
%td{:rowspan => rowspan}= l(order.created_at_local_to_organization, :format => :short)
|
67
57
|
%td{:rowspan => rowspan}= link_to_person(order.person)
|
68
58
|
%td{:rowspan => rowspan}= (order.payment_method || "")
|
69
|
-
|
70
|
-
|
71
|
-
|
59
|
+
%td
|
60
|
+
="#{item.product.membership_type.name}"
|
61
|
+
%td= number_as_cents item.price
|
62
|
+
- else
|
63
|
+
%tr
|
64
|
+
%td
|
65
|
+
="#{item.product.membership_type.name}"
|
66
|
+
%td= number_as_cents item.price
|
67
|
+
|
72
68
|
= will_paginate(@search.results)
|
73
69
|
|
74
70
|
- else
|
@@ -0,0 +1,97 @@
|
|
1
|
+
- in_section :transactions
|
2
|
+
- content_for :header do
|
3
|
+
%h1 Pass Orders
|
4
|
+
|
5
|
+
#donations-search
|
6
|
+
|
7
|
+
.control-group.well
|
8
|
+
= form_tag passes_orders_path, :method => :get, :id => 'passes-date-search-form', :class => 'form-inline' do
|
9
|
+
.pull-left
|
10
|
+
= label_tag :start, "From", :class => "control-label"
|
11
|
+
= text_field_tag :start,"#{l @search.start, :format => :date_for_input}", :class => 'datepicker input-small'
|
12
|
+
|
13
|
+
= label_tag :stop, "To", :class => "control-label"
|
14
|
+
= text_field_tag :stop, "#{l @search.stop, :format => :date_for_input}", :class => 'datepicker input-small'
|
15
|
+
|
16
|
+
- if @pass_types.present?
|
17
|
+
= label_tag :pass_type_id, nil, :class => "control-label"
|
18
|
+
= raw select_pass_type_for_sales_search @pass_types, :pass_type_id, params[:pass_type_id]
|
19
|
+
|
20
|
+
= submit_tag "Search", :class => "btn"
|
21
|
+
|
22
|
+
|
23
|
+
- if @search.results.present?
|
24
|
+
.pull-right
|
25
|
+
|
26
|
+
%ul.in-table
|
27
|
+
%li.dropdown#bulkactions
|
28
|
+
=icon_link_to('Work with...', "#menu#bulkactions", 'fa-asterisk', 'dropdown-toggle dropdown btn', '')
|
29
|
+
%ul.dropdown-menu
|
30
|
+
%li
|
31
|
+
= link_to 'Export to CSV', params.merge(:format => 'csv').delete_if {|k,v| :commit == k.to_sym }
|
32
|
+
|
33
|
+
|
34
|
+
- if @search.results.present?
|
35
|
+
|
36
|
+
#tickets
|
37
|
+
%table.standalone.zebra.table
|
38
|
+
%thead
|
39
|
+
%tr
|
40
|
+
%th Order
|
41
|
+
%th Time
|
42
|
+
%th Person
|
43
|
+
%th Method
|
44
|
+
%th Membership Type
|
45
|
+
%th Amount
|
46
|
+
%tbody
|
47
|
+
- @search.results.each do |order|
|
48
|
+
- order.items.select(&:pass?).each_with_index do |item, index|
|
49
|
+
- if index == 0
|
50
|
+
%tr{:id => "order_#{order.id}"}
|
51
|
+
- rowspan = order.items.select(&:pass?).size
|
52
|
+
%td{:rowspan => rowspan}= link_to order.id, order_path(order.id)
|
53
|
+
%td{:rowspan => rowspan}= l(order.created_at_local_to_organization, :format => :short)
|
54
|
+
%td{:rowspan => rowspan}= link_to_person(order.person)
|
55
|
+
%td{:rowspan => rowspan}= (order.payment_method || "")
|
56
|
+
%td
|
57
|
+
="#{item.product.pass_type.name}"
|
58
|
+
%td= number_as_cents item.price
|
59
|
+
- else
|
60
|
+
%tr
|
61
|
+
%td
|
62
|
+
="#{item.product.pass_type.name}"
|
63
|
+
%td= number_as_cents item.price
|
64
|
+
|
65
|
+
= will_paginate(@search.results)
|
66
|
+
|
67
|
+
- else
|
68
|
+
|
69
|
+
%h4= "No sales found."
|
70
|
+
|
71
|
+
- content_for :custom_js do
|
72
|
+
:javascript
|
73
|
+
var printCardInterval;
|
74
|
+
|
75
|
+
$('#print-cards').on('show', function (show) {
|
76
|
+
// Remove any existing intervals
|
77
|
+
clearInterval(printCardInterval);
|
78
|
+
|
79
|
+
// Initial hurry to 90%
|
80
|
+
var bar = $('#print-cards .bar');
|
81
|
+
$(bar).css('width', '1%').animate({width: '90%'}, 1500, function() {
|
82
|
+
|
83
|
+
// Progress to 100% from there
|
84
|
+
var times = 0;
|
85
|
+
printCardInterval = setInterval(function() {
|
86
|
+
// Count this run
|
87
|
+
times = times + 1;
|
88
|
+
|
89
|
+
// Update the progress bar
|
90
|
+
$(bar).css('width', (90 + times) + '%');
|
91
|
+
|
92
|
+
// Clear the interval on the last run
|
93
|
+
if (times > 9) { clearInterval(printCardInterval); }
|
94
|
+
}, 1000);
|
95
|
+
|
96
|
+
});
|
97
|
+
});
|
@@ -7,10 +7,10 @@
|
|
7
7
|
.control-group.well
|
8
8
|
.pull-left
|
9
9
|
= label_tag :start, "From", :class => "control-label"
|
10
|
-
= text_field_tag :start,"#{l @search.start, :format => :date_for_input}", :
|
10
|
+
= text_field_tag :start,"#{l @search.start, :format => :date_for_input}", :class => 'datepicker input-small'
|
11
11
|
|
12
12
|
= label_tag :stop, "To", :class => "control-label"
|
13
|
-
= text_field_tag :stop, "#{l @search.stop, :format => :date_for_input}", :
|
13
|
+
= text_field_tag :stop, "#{l @search.stop, :format => :date_for_input}", :class => 'datepicker input-small'
|
14
14
|
|
15
15
|
- if @events.present?
|
16
16
|
= label_tag :event_id, nil, :class => "control-label"
|
@@ -21,7 +21,7 @@
|
|
21
21
|
%td=link_to pass_type.name, edit_pass_type_path(pass_type)
|
22
22
|
%td=l pass_type.starts_at, :format => :slashed_date
|
23
23
|
%td=l pass_type.ends_at, :format => :slashed_date
|
24
|
-
%td.right=pass_type.
|
24
|
+
%td.right=pass_type.sold.count
|
25
25
|
%td.right=pass_type.tickets_allowed
|
26
26
|
%td.right=number_as_cents pass_type.price
|
27
27
|
%td.right
|
@@ -1,2 +1,80 @@
|
|
1
1
|
-content_for :header do
|
2
|
-
%h1
|
2
|
+
%h1 Pass Usage
|
3
|
+
|
4
|
+
= form_tag passes_reports_path, :method => :get, :class => 'well form-inline' do
|
5
|
+
= label_tag :pass_type, "Pass", :class => "control-label"
|
6
|
+
= select_tag :pass_type, options_for_select(@options_for_select, @report.pass_type.try(:id))
|
7
|
+
|
8
|
+
|
9
|
+
= label_tag :start_date, "From", :class => "control-label"
|
10
|
+
= text_field_tag :start_date, @start_date, :readonly => true, :class => 'datepicker input-small'
|
11
|
+
|
12
|
+
= label_tag :end_date, "To", :class => "control-label"
|
13
|
+
= text_field_tag :end_date, @end_date, :readonly => true, :class => 'datepicker input-small'
|
14
|
+
|
15
|
+
.pull-right
|
16
|
+
= submit_tag "Search", :class => "btn"
|
17
|
+
|
18
|
+
- unless @report.nil?
|
19
|
+
|
20
|
+
.row-fluid.botton-room
|
21
|
+
.span9
|
22
|
+
%h3=@report.header
|
23
|
+
.span3
|
24
|
+
.pull-right
|
25
|
+
=link_to "Download CSV", passes_reports_path(code: @report.pass_type, start_date: @report.start_date, end_date: @report.end_date, format: "csv"), :class => "btn"
|
26
|
+
|
27
|
+
#statement-summary.bottom-room.well
|
28
|
+
.row-fluid
|
29
|
+
.span4
|
30
|
+
.center.headline-stat#passes-sold-stat
|
31
|
+
=@report.passes_sold
|
32
|
+
.center.headline-caption
|
33
|
+
%h6 PASSES SOLD
|
34
|
+
.span4
|
35
|
+
.center.headline-stat#tickets-sold-stat
|
36
|
+
=@report.tickets_sold
|
37
|
+
.center.headline-caption
|
38
|
+
%h6 TICKETS SOLD
|
39
|
+
.span4
|
40
|
+
.center.headline-stat#tickets-remaining-stat
|
41
|
+
=@report.tickets_remaining
|
42
|
+
.center.headline-caption
|
43
|
+
%h6 TICKETS REMAINING
|
44
|
+
|
45
|
+
.row
|
46
|
+
.span12
|
47
|
+
%table.table.zebra#order-table
|
48
|
+
%thead
|
49
|
+
%tr
|
50
|
+
%th{:style=>'width:200px'} Pass
|
51
|
+
%th Order/Date
|
52
|
+
%th{:style=>'width:200px'} Person
|
53
|
+
%th Event
|
54
|
+
%th.right Tickets
|
55
|
+
%th.right Orig. Price
|
56
|
+
%th.right Gross
|
57
|
+
%tbody
|
58
|
+
-if @rows.empty?
|
59
|
+
%tr
|
60
|
+
%td{:colspan => 7}
|
61
|
+
.no-image#no-pass-sales
|
62
|
+
#text
|
63
|
+
=icon_tag '299-ticket'
|
64
|
+
%br
|
65
|
+
This pass hasn't been used to buy any tickets.
|
66
|
+
-@rows.each do |row|
|
67
|
+
%tr
|
68
|
+
%td=row.pass_type
|
69
|
+
%td
|
70
|
+
=link_to row.order.id, order_path(row.order)
|
71
|
+
%br
|
72
|
+
=l row.order.created_at, :format => :slashed_date
|
73
|
+
%td
|
74
|
+
=link_to row.order.person, person_path(row.order.person)
|
75
|
+
%td=link_to row.show.event.name, event_path(row.show.event)
|
76
|
+
%td.right=row.ticket_count
|
77
|
+
%td.right=number_as_cents row.original_price
|
78
|
+
%td.right=number_as_cents row.gross
|
79
|
+
|
80
|
+
= will_paginate(@rows)
|
@@ -17,7 +17,7 @@
|
|
17
17
|
.title.active
|
18
18
|
.price
|
19
19
|
=number_as_cents pass_type.price
|
20
|
-
.
|
20
|
+
.pass_type_name
|
21
21
|
=pass_type.name
|
22
22
|
=pass_type.description
|
23
23
|
%br
|
@@ -26,7 +26,7 @@
|
|
26
26
|
= form_for pass_type, :as => :pass_type, :url => store_order_path(@store_organization.cached_slug), :html => {:id => "edit_pass_type_#{pass_type.id}"}, :method => :post do |f|
|
27
27
|
= f.hidden_field :id
|
28
28
|
= select_tag :quantity, options_for_select((1..6).to_a.map {|i| [pluralize(i, "#{pass_type.passerize}"), i]})
|
29
|
-
= f.submit 'Add to cart', :class => 'btn btn-primary', :style => 'margin-top: -10px'
|
29
|
+
= f.submit 'Add to cart', :class => 'add-to-cart btn btn-primary', :style => 'margin-top: -10px'
|
30
30
|
|
31
31
|
.span4
|
32
32
|
.side-section
|
data/config/routes.rb
CHANGED
data/lib/artfully_ose/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: artfully_ose
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.0.
|
4
|
+
version: 1.2.0.beta.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Artful.ly
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -1916,6 +1916,7 @@ files:
|
|
1916
1916
|
- app/concerns/itemable.rb
|
1917
1917
|
- app/concerns/oh_noes.rb
|
1918
1918
|
- app/concerns/pdf_generation.rb
|
1919
|
+
- app/concerns/search_by_dates.rb
|
1919
1920
|
- app/concerns/unrefundable.rb
|
1920
1921
|
- app/controllers/actions_controller.rb
|
1921
1922
|
- app/controllers/addresses_controller.rb
|
@@ -2122,8 +2123,10 @@ files:
|
|
2122
2123
|
- app/models/organization_ability.rb
|
2123
2124
|
- app/models/parsed_row.rb
|
2124
2125
|
- app/models/pass.rb
|
2126
|
+
- app/models/pass_sale_search.rb
|
2125
2127
|
- app/models/pass_summary.rb
|
2126
2128
|
- app/models/pass_type.rb
|
2129
|
+
- app/models/passes_report.rb
|
2127
2130
|
- app/models/payment.rb
|
2128
2131
|
- app/models/payments/cash_payment.rb
|
2129
2132
|
- app/models/payments/check_payment.rb
|
@@ -2354,6 +2357,7 @@ files:
|
|
2354
2357
|
- app/views/orders/_search_form.haml
|
2355
2358
|
- app/views/orders/index.html.haml
|
2356
2359
|
- app/views/orders/membership.html.haml
|
2360
|
+
- app/views/orders/passes.html.haml
|
2357
2361
|
- app/views/orders/sales.html.haml
|
2358
2362
|
- app/views/orders/show.html.haml
|
2359
2363
|
- app/views/organizations/_connection_form.html.haml
|