artfully_ose 1.2.0.pre.27 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/README.md +4 -6
- data/app/assets/javascripts/application.js +39 -0
- data/app/assets/javascripts/boxoffice.js +558 -0
- data/app/assets/javascripts/custom/kits-config.js +33 -0
- data/app/assets/javascripts/sales-console.js +29 -24
- data/app/assets/javascripts/store/store.js +11 -0
- data/app/assets/stylesheets/application.sass +66 -52
- data/app/assets/stylesheets/bootstrap-overrides.css +1 -1
- data/app/assets/stylesheets/boxoffice.css.scss +258 -0
- data/app/assets/stylesheets/pages/bootstrap-responsive.css +1109 -0
- data/app/assets/stylesheets/sass/store.sass +52 -62
- data/app/assets/stylesheets/storefront.css +1 -1
- data/app/concerns/itemable.rb +1 -1
- data/app/concerns/pdf_generation.rb +1 -11
- data/app/concerns/search_by_dates.rb +20 -0
- data/app/controllers/events_controller.rb +1 -0
- data/app/controllers/export_controller.rb +11 -1
- data/app/controllers/imports_controller.rb +2 -3
- data/app/controllers/member_cards_controller.rb +2 -3
- data/app/controllers/orders_controller.rb +42 -0
- data/app/controllers/organizations_controller.rb +1 -0
- data/app/controllers/passes_reports_controller.rb +21 -1
- data/app/controllers/regular_donation_kits_controller.rb +32 -0
- data/app/controllers/store/donations_controller.rb +19 -1
- data/app/controllers/store/orders_controller.rb +15 -5
- data/app/helpers/artfully_ose_helper.rb +28 -18
- data/app/models/database_views/item_view.rb +41 -0
- data/app/models/event.rb +10 -2
- data/app/models/ext/integrations.rb +5 -0
- data/app/models/fee_strategy.rb +47 -1
- data/app/models/imports/events_import.rb +6 -7
- data/app/models/item.rb +4 -3
- data/app/models/job/order_processor.rb +4 -3
- data/app/models/kit.rb +18 -0
- data/app/models/kits/regular_donation_kit.rb +51 -9
- data/app/models/member.rb +4 -3
- data/app/models/membership.rb +1 -2
- data/app/models/membership_sale_search.rb +2 -20
- data/app/models/membership_type.rb +1 -2
- data/app/models/order.rb +29 -1
- data/app/models/order_handler.rb +4 -3
- data/app/models/organization.rb +17 -9
- data/app/models/pass.rb +18 -17
- data/app/models/pass_sale_search.rb +18 -0
- data/app/models/pass_type.rb +7 -2
- data/app/models/passes_report.rb +117 -0
- data/app/models/sale_search.rb +3 -21
- data/app/models/user.rb +1 -2
- data/app/serializers/show_serializer.rb +15 -0
- data/app/views/contributions/index.html.haml +2 -2
- data/app/views/events/_header.html.haml +1 -0
- data/app/views/events/_ticket_type_fields.html.haml +31 -15
- data/app/views/events/edit.html.haml +6 -1
- data/app/views/imports/_export_links.html.haml +3 -0
- data/app/views/imports/donations/_pending.html.haml +24 -6
- data/app/views/imports/events/_pending.html.haml +16 -5
- data/app/views/imports/index.html.haml +6 -4
- data/app/views/imports/people/_pending.html.haml +20 -25
- data/app/views/layouts/storefront.html.haml +9 -5
- data/app/views/order_mailer/confirmation_for.html.haml +11 -5
- data/app/views/order_mailer/confirmation_for_refund.html.haml +6 -2
- data/app/views/order_mailer/confirmation_for_refund.text.haml +4 -3
- data/app/views/orders/membership.html.haml +15 -19
- data/app/views/orders/passes.html.haml +97 -0
- data/app/views/orders/sales.html.haml +2 -2
- data/app/views/organizations/_form.html.haml +4 -37
- data/app/views/pass_types/index.html.haml +1 -1
- data/app/views/passes_reports/index.html.haml +79 -1
- data/app/views/people/show.html.haml +16 -15
- data/app/views/regular_donation_kits/edit.html.haml +140 -0
- data/app/views/store/checkouts/thanks.html.haml +14 -6
- data/app/views/store/donations/index.html.haml +19 -2
- data/app/views/store/events/calendar.html.haml +1 -0
- data/app/views/store/events/index.html.haml +1 -0
- data/app/views/store/events/show.html.haml +1 -0
- data/app/views/store/events/single_show.html.haml +2 -0
- data/app/views/store/orders/show.html.haml +10 -10
- data/app/views/store/passes/index.html.haml +2 -2
- data/app/views/store/shared/_donate_form.html.haml +31 -12
- data/app/views/store/shared/_small_donate_form.html.haml +22 -0
- data/app/views/users/invitations/edit.html.haml +3 -42
- data/config/locales/en.yml +3 -1
- data/config/routes.rb +4 -1
- data/db/migrate/20140603200735_add_subtitle_to_events.rb +5 -0
- data/lib/artfully_ose/version.rb +1 -1
- data/spec/factories/kit_factories.rb +5 -4
- metadata +25 -13
- data/app/assets/javascripts/box-office.js +0 -262
|
@@ -13,8 +13,8 @@ module ArtfullyOseHelper
|
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def with_kit(kit)
|
|
17
|
-
organization = current_user.try(:current_organization) || @store_organization
|
|
16
|
+
def with_kit(kit, organization = nil)
|
|
17
|
+
organization = organization || current_user.try(:current_organization) || @store_organization
|
|
18
18
|
if organization.has_kit? kit
|
|
19
19
|
yield
|
|
20
20
|
end
|
|
@@ -29,11 +29,11 @@ module ArtfullyOseHelper
|
|
|
29
29
|
def build_order_location(order)
|
|
30
30
|
order.location
|
|
31
31
|
end
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
def channel_checkbox(channel)
|
|
34
34
|
channel.to_s.eql?("storefront") ? "Storefront & Widgets" : channel.to_s.humanize
|
|
35
35
|
end
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
def channel_text(channel)
|
|
38
38
|
case channel.to_s
|
|
39
39
|
when "members"
|
|
@@ -44,7 +44,7 @@ module ArtfullyOseHelper
|
|
|
44
44
|
channel.to_s.humanize
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
def build_action_path(target, action)
|
|
49
49
|
action_path_name = action.new_record? ? "actions" : "actions"
|
|
50
50
|
"#{target.class.name.downcase}_#{action_path_name}_path"
|
|
@@ -71,17 +71,17 @@ module ArtfullyOseHelper
|
|
|
71
71
|
def get_selected_class(selected_object, menu_object)
|
|
72
72
|
selected_object.try(:id) == menu_object.id ? "active" : "unselected"
|
|
73
73
|
end
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
#For use with Font Awesome icon %i classes
|
|
76
76
|
def icon_link_to(text, href, icon, class_names, id, html_attributes={})
|
|
77
77
|
s = "<a href='#{href}' class='#{class_names}' id='#{id}' "
|
|
78
78
|
html_attributes.each do |k,v|
|
|
79
|
-
s = s + " #{k}=#{v} "
|
|
79
|
+
s = s + " #{k}=#{v} "
|
|
80
80
|
end
|
|
81
81
|
s = s + "><i class='fa #{icon}'></i> #{text}</a>"
|
|
82
82
|
s.html_safe
|
|
83
83
|
end
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
#
|
|
86
86
|
# just name the image, this method will prepend the path and append the .png
|
|
87
87
|
# icon_tag('111-logo')
|
|
@@ -93,12 +93,12 @@ module ArtfullyOseHelper
|
|
|
93
93
|
def time_zone_description(tz)
|
|
94
94
|
ActiveSupport::TimeZone.create(tz)
|
|
95
95
|
end
|
|
96
|
-
|
|
96
|
+
|
|
97
97
|
#This is for the widget generator, DO NOT use anywhere else
|
|
98
98
|
def fully_qualified_asset_path(asset)
|
|
99
99
|
"#{asset_path(asset, :digest => false)}"
|
|
100
100
|
end
|
|
101
|
-
|
|
101
|
+
|
|
102
102
|
def events_to_options(selected_event_id = nil)
|
|
103
103
|
@events = current_user.current_organization.events
|
|
104
104
|
@events_array = @events.map { |event| [event.name, event.id] }
|
|
@@ -132,7 +132,7 @@ module ArtfullyOseHelper
|
|
|
132
132
|
str += " (#{number_as_cents item.nongift_amount} Non-deductible)" unless item.nongift_amount.nil? || item.nongift_amount == 0
|
|
133
133
|
str
|
|
134
134
|
end
|
|
135
|
-
|
|
135
|
+
|
|
136
136
|
#This method will not prepend the $
|
|
137
137
|
def number_to_dollars(cents)
|
|
138
138
|
cents.to_i / 100.00
|
|
@@ -241,7 +241,7 @@ module ArtfullyOseHelper
|
|
|
241
241
|
|
|
242
242
|
select_tag show_id, raw(options), :class => "span3"
|
|
243
243
|
end
|
|
244
|
-
|
|
244
|
+
|
|
245
245
|
def select_membership_type_for_sales_search(membership_types, membership_type_id, default)
|
|
246
246
|
options =
|
|
247
247
|
[
|
|
@@ -252,10 +252,20 @@ 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
|
|
258
|
-
|
|
268
|
+
|
|
259
269
|
def bootstrapped_type(type)
|
|
260
270
|
case type
|
|
261
271
|
when :notice then "alert alert-info"
|
|
@@ -268,7 +278,7 @@ module ArtfullyOseHelper
|
|
|
268
278
|
def link_to_remove_fields(name, f)
|
|
269
279
|
f.hidden_field(:_destroy) + link_to(name, "#", :onclick => "remove_fields(this); return false;")
|
|
270
280
|
end
|
|
271
|
-
|
|
281
|
+
|
|
272
282
|
def link_to_add_fields(name, f, association, view_path = '', additional_javascript=nil)
|
|
273
283
|
new_object = f.object.class.reflect_on_association(association).klass.new
|
|
274
284
|
fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
|
|
@@ -278,17 +288,17 @@ module ArtfullyOseHelper
|
|
|
278
288
|
end
|
|
279
289
|
link_to name, "#", :onclick => "add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\"); #{additional_javascript} return false;"
|
|
280
290
|
end
|
|
281
|
-
|
|
291
|
+
|
|
282
292
|
def ticket_seller_name(ticket)
|
|
283
293
|
end
|
|
284
|
-
|
|
294
|
+
|
|
285
295
|
def credit_card_message
|
|
286
296
|
end
|
|
287
|
-
|
|
297
|
+
|
|
288
298
|
def date_field_tag(name, value = nil, options = {})
|
|
289
299
|
text_field_tag(name, value, options.stringify_keys.update("type" => "date"))
|
|
290
300
|
end
|
|
291
|
-
|
|
301
|
+
|
|
292
302
|
def datetime_field_tag(name, value = nil, options = {})
|
|
293
303
|
text_field_tag(name, value, options.stringify_keys.update("type" => "datetime"))
|
|
294
304
|
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/event.rb
CHANGED
|
@@ -10,8 +10,9 @@ class Event < ActiveRecord::Base
|
|
|
10
10
|
|
|
11
11
|
attr_accessible :name, :producer, :description, :contact_email, :contact_phone, :image, :venue_attributes,
|
|
12
12
|
:show_special_instructions, :special_instructions_caption, :public, :primary_category,
|
|
13
|
-
:secondary_categories, :primary_category_other, :secondary_category_other, :members_only
|
|
14
|
-
|
|
13
|
+
:secondary_categories, :primary_category_other, :secondary_category_other, :members_only,
|
|
14
|
+
:subtitle
|
|
15
|
+
|
|
15
16
|
store :cached_stats, :accessors => [ :on_sale, :off_sale, :sold, :sales_total ]
|
|
16
17
|
|
|
17
18
|
belongs_to :organization
|
|
@@ -28,6 +29,7 @@ class Event < ActiveRecord::Base
|
|
|
28
29
|
validates :contact_email, :presence => true, :email => true
|
|
29
30
|
validates :name, :presence => true
|
|
30
31
|
validates :organization_id, :presence => true
|
|
32
|
+
validate :subtitle, length: { maximum: 255 }
|
|
31
33
|
|
|
32
34
|
has_attached_file :image,
|
|
33
35
|
:storage => :s3,
|
|
@@ -59,9 +61,15 @@ class Event < ActiveRecord::Base
|
|
|
59
61
|
ANY_EVENT_TEXT = "(Any Event)"
|
|
60
62
|
ANY_EVENT_ID = "-1"
|
|
61
63
|
|
|
64
|
+
searchable do
|
|
65
|
+
text :name
|
|
66
|
+
end
|
|
67
|
+
include Ext::DelayedIndexing
|
|
68
|
+
|
|
62
69
|
#
|
|
63
70
|
# Run synchronously only with great care.
|
|
64
71
|
#
|
|
72
|
+
|
|
65
73
|
def refresh_stats
|
|
66
74
|
self.on_sale = self.glance.available.on_sale
|
|
67
75
|
self.off_sale = self.glance.available.off_sale
|
|
@@ -3,6 +3,10 @@ module Ext
|
|
|
3
3
|
module Member
|
|
4
4
|
end
|
|
5
5
|
|
|
6
|
+
module ServiceFee
|
|
7
|
+
SERVICE_FEE = 0
|
|
8
|
+
end
|
|
9
|
+
|
|
6
10
|
module User
|
|
7
11
|
def need_more_info?
|
|
8
12
|
false
|
|
@@ -46,6 +50,7 @@ module Ext
|
|
|
46
50
|
kit.save
|
|
47
51
|
end
|
|
48
52
|
end
|
|
53
|
+
validates_presence_of :name, :email, :time_zone
|
|
49
54
|
end
|
|
50
55
|
end
|
|
51
56
|
|
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
|
|
@@ -193,14 +193,13 @@ class EventsImport < Import
|
|
|
193
193
|
order
|
|
194
194
|
end
|
|
195
195
|
|
|
196
|
-
def
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
parsed_rows.each do |row|
|
|
196
|
+
def parse_and_hash(rows)
|
|
197
|
+
rows.reduce({}) do | all,imported_row|
|
|
198
|
+
row = ParsedRow.new(headers, imported_row.content)
|
|
200
199
|
key = (row.event_name || "") + (row.venue_name || "") + (row.show_date.to_s || "")
|
|
201
|
-
|
|
202
|
-
|
|
200
|
+
all[key] ||= []
|
|
201
|
+
all[key] << row
|
|
202
|
+
all
|
|
203
203
|
end
|
|
204
|
-
@events
|
|
205
204
|
end
|
|
206
205
|
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/kit.rb
CHANGED
|
@@ -23,6 +23,7 @@ class Kit < ActiveRecord::Base
|
|
|
23
23
|
|
|
24
24
|
event(:activate, :success => :record_activation) { transitions :from => [:fresh, :pending], :to => :activated, :guard => :activatable? }
|
|
25
25
|
event(:approve, :success => :record_approval) { transitions :from => :pending, :to => :activated, :guard => :approvable? }
|
|
26
|
+
event(:admin_approve, :success => :record_approval) { transitions :from => :pending, :to => :activated, :guard => :admin_approvable? }
|
|
26
27
|
event(:cancel) { transitions :from => [:activated, :pending, :rejected ], :to => :cancelled }
|
|
27
28
|
event(:reactivate) { transitions :from => :cancelled, :to => :activated, :guard => :activatable? }
|
|
28
29
|
event(:activate_without_pending) { transitions :from => [:fresh, :pending, :cancelled], :to => :activated }
|
|
@@ -48,6 +49,11 @@ class Kit < ActiveRecord::Base
|
|
|
48
49
|
approval_requirements[:if] << options.delete(:if) if options.has_key?(:if)
|
|
49
50
|
end
|
|
50
51
|
|
|
52
|
+
def self.admin_approve(options)
|
|
53
|
+
admin_approval_requirements[:unless] << options.delete(:unless) if options.has_key?(:unless)
|
|
54
|
+
admin_approval_requirements[:if] << options.delete(:if) if options.has_key?(:if)
|
|
55
|
+
end
|
|
56
|
+
|
|
51
57
|
def self.activation_requirements
|
|
52
58
|
@requirements ||= Hash.new { |h,k| h[k] = [] }
|
|
53
59
|
end
|
|
@@ -56,6 +62,10 @@ class Kit < ActiveRecord::Base
|
|
|
56
62
|
@approval_requirements ||= Hash.new { |h,k| h[k] = [] }
|
|
57
63
|
end
|
|
58
64
|
|
|
65
|
+
def self.admin_approval_requirements
|
|
66
|
+
@admin_approval_requirements ||= Hash.new { |h,k| h[k] = [] }
|
|
67
|
+
end
|
|
68
|
+
|
|
59
69
|
def self.when_active(&block)
|
|
60
70
|
self.ability_proc = Proc.new(&block)
|
|
61
71
|
end
|
|
@@ -108,6 +118,10 @@ class Kit < ActiveRecord::Base
|
|
|
108
118
|
check_approval
|
|
109
119
|
end
|
|
110
120
|
|
|
121
|
+
def admin_approvable?
|
|
122
|
+
check_admin_approval
|
|
123
|
+
end
|
|
124
|
+
|
|
111
125
|
class DuplicateError < StandardError
|
|
112
126
|
end
|
|
113
127
|
|
|
@@ -124,6 +138,10 @@ class Kit < ActiveRecord::Base
|
|
|
124
138
|
check_unlesses(self.class.approval_requirements[:unless]) and check_ifs(self.class.approval_requirements[:if])
|
|
125
139
|
end
|
|
126
140
|
|
|
141
|
+
def check_admin_approval
|
|
142
|
+
check_unlesses(self.class.admin_approval_requirements[:unless]) and check_ifs(self.class.admin_approval_requirements[:if])
|
|
143
|
+
end
|
|
144
|
+
|
|
127
145
|
def check_unlesses(unlesses)
|
|
128
146
|
return true if unlesses.empty?
|
|
129
147
|
unlesses.all? { |req| !self.send(req) }
|
|
@@ -1,35 +1,58 @@
|
|
|
1
1
|
class RegularDonationKit < Kit
|
|
2
2
|
acts_as_kit :with_approval => true do
|
|
3
|
+
self.configurable = true
|
|
4
|
+
|
|
3
5
|
activate :if => :has_tax_info?
|
|
4
6
|
activate :if => :exclusive?
|
|
5
|
-
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# So, this is horrible. Sorry.
|
|
10
|
+
# Leaving "approve" out of this list sets the kit to auto-approve which is the
|
|
11
|
+
# opposite of what we want. So, this kludge is here to force the kit to
|
|
12
|
+
# never approve until you call kit.admin_approve
|
|
13
|
+
#
|
|
14
|
+
approve :if => :dont_approve
|
|
15
|
+
admin_approve :unless => :no_bank_account?
|
|
6
16
|
|
|
7
17
|
when_active do |organization|
|
|
8
18
|
organization.can :receive, Donation
|
|
9
19
|
end
|
|
10
20
|
end
|
|
11
21
|
|
|
22
|
+
ACCESSORS = [
|
|
23
|
+
:about_organization_text, :donation_ask_text, :donate_now_text, :donation_nudge_text,
|
|
24
|
+
:suggested_gifts, :open_gift_field, :thanks_msg_text, :email_msg_text, :donation_only_storefront,
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
attr_accessible *ACCESSORS
|
|
28
|
+
|
|
29
|
+
store :settings, :accessors => ACCESSORS
|
|
30
|
+
|
|
31
|
+
def dont_approve
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
|
|
12
35
|
def has_tax_info?
|
|
13
|
-
errors.add(:requirements,
|
|
36
|
+
errors.add(:requirements, 'Your organization\'s tax information is missing or incomplete. Please complete it in order to active this kit.') unless organization.has_tax_info?
|
|
14
37
|
organization.has_tax_info?
|
|
15
38
|
end
|
|
16
|
-
|
|
39
|
+
|
|
17
40
|
def friendly_name
|
|
18
|
-
|
|
41
|
+
'501(c)(3) Donations'
|
|
19
42
|
end
|
|
20
|
-
|
|
43
|
+
|
|
21
44
|
def pitch
|
|
22
|
-
|
|
45
|
+
'Receive donations for a 501(c)(3)'
|
|
23
46
|
end
|
|
24
47
|
|
|
25
48
|
def exclusive?
|
|
26
49
|
exclusive = !organization.kits.where(:type => alternatives.collect(&:to_s)).any?
|
|
27
|
-
errors.add(:requirements,
|
|
50
|
+
errors.add(:requirements, 'You have already activated a mutually exclusive kit.') unless exclusive
|
|
28
51
|
exclusive
|
|
29
52
|
end
|
|
30
53
|
|
|
31
54
|
def no_bank_account?
|
|
32
|
-
errors.add(:requirements,
|
|
55
|
+
errors.add(:requirements, 'Your organization needs bank account information first.') if organization.bank_account.nil?
|
|
33
56
|
organization.bank_account.nil?
|
|
34
57
|
end
|
|
35
58
|
|
|
@@ -41,4 +64,23 @@ class RegularDonationKit < Kit
|
|
|
41
64
|
AdminMailer.donation_kit_notification(self).deliver
|
|
42
65
|
ProducerMailer.donation_kit_notification(self, organization.owner).deliver
|
|
43
66
|
end
|
|
44
|
-
|
|
67
|
+
|
|
68
|
+
def suggested_gifts=(value)
|
|
69
|
+
value = value.values if value.is_a?(Hash)
|
|
70
|
+
|
|
71
|
+
value = value.map do |suggested_gift|
|
|
72
|
+
suggested_gift = { :amount => suggested_gift } if [String, Fixnum, Bignum, Float, BigDecimal].any? { |klass| suggested_gift.is_a?(klass) }
|
|
73
|
+
suggested_gift[:amount] = suggested_gift[:amount].to_i
|
|
74
|
+
suggested_gift.delete :level_name if suggested_gift[:level_name].blank?
|
|
75
|
+
suggested_gift.with_indifferent_access
|
|
76
|
+
end.reject do |suggested_gift|
|
|
77
|
+
suggested_gift[:amount].to_i <= 0
|
|
78
|
+
end.sort do |l, r|
|
|
79
|
+
l[:amount] <=> r[:amount]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
self.settings = {} unless self.settings.is_a?(Hash)
|
|
83
|
+
self.settings[:suggested_gifts] = value
|
|
84
|
+
self.settings_will_change!
|
|
85
|
+
end
|
|
86
|
+
end
|