artfully_ose 1.2.0.pre.27 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +4 -6
  3. data/app/assets/javascripts/application.js +39 -0
  4. data/app/assets/javascripts/boxoffice.js +558 -0
  5. data/app/assets/javascripts/custom/kits-config.js +33 -0
  6. data/app/assets/javascripts/sales-console.js +29 -24
  7. data/app/assets/javascripts/store/store.js +11 -0
  8. data/app/assets/stylesheets/application.sass +66 -52
  9. data/app/assets/stylesheets/bootstrap-overrides.css +1 -1
  10. data/app/assets/stylesheets/boxoffice.css.scss +258 -0
  11. data/app/assets/stylesheets/pages/bootstrap-responsive.css +1109 -0
  12. data/app/assets/stylesheets/sass/store.sass +52 -62
  13. data/app/assets/stylesheets/storefront.css +1 -1
  14. data/app/concerns/itemable.rb +1 -1
  15. data/app/concerns/pdf_generation.rb +1 -11
  16. data/app/concerns/search_by_dates.rb +20 -0
  17. data/app/controllers/events_controller.rb +1 -0
  18. data/app/controllers/export_controller.rb +11 -1
  19. data/app/controllers/imports_controller.rb +2 -3
  20. data/app/controllers/member_cards_controller.rb +2 -3
  21. data/app/controllers/orders_controller.rb +42 -0
  22. data/app/controllers/organizations_controller.rb +1 -0
  23. data/app/controllers/passes_reports_controller.rb +21 -1
  24. data/app/controllers/regular_donation_kits_controller.rb +32 -0
  25. data/app/controllers/store/donations_controller.rb +19 -1
  26. data/app/controllers/store/orders_controller.rb +15 -5
  27. data/app/helpers/artfully_ose_helper.rb +28 -18
  28. data/app/models/database_views/item_view.rb +41 -0
  29. data/app/models/event.rb +10 -2
  30. data/app/models/ext/integrations.rb +5 -0
  31. data/app/models/fee_strategy.rb +47 -1
  32. data/app/models/imports/events_import.rb +6 -7
  33. data/app/models/item.rb +4 -3
  34. data/app/models/job/order_processor.rb +4 -3
  35. data/app/models/kit.rb +18 -0
  36. data/app/models/kits/regular_donation_kit.rb +51 -9
  37. data/app/models/member.rb +4 -3
  38. data/app/models/membership.rb +1 -2
  39. data/app/models/membership_sale_search.rb +2 -20
  40. data/app/models/membership_type.rb +1 -2
  41. data/app/models/order.rb +29 -1
  42. data/app/models/order_handler.rb +4 -3
  43. data/app/models/organization.rb +17 -9
  44. data/app/models/pass.rb +18 -17
  45. data/app/models/pass_sale_search.rb +18 -0
  46. data/app/models/pass_type.rb +7 -2
  47. data/app/models/passes_report.rb +117 -0
  48. data/app/models/sale_search.rb +3 -21
  49. data/app/models/user.rb +1 -2
  50. data/app/serializers/show_serializer.rb +15 -0
  51. data/app/views/contributions/index.html.haml +2 -2
  52. data/app/views/events/_header.html.haml +1 -0
  53. data/app/views/events/_ticket_type_fields.html.haml +31 -15
  54. data/app/views/events/edit.html.haml +6 -1
  55. data/app/views/imports/_export_links.html.haml +3 -0
  56. data/app/views/imports/donations/_pending.html.haml +24 -6
  57. data/app/views/imports/events/_pending.html.haml +16 -5
  58. data/app/views/imports/index.html.haml +6 -4
  59. data/app/views/imports/people/_pending.html.haml +20 -25
  60. data/app/views/layouts/storefront.html.haml +9 -5
  61. data/app/views/order_mailer/confirmation_for.html.haml +11 -5
  62. data/app/views/order_mailer/confirmation_for_refund.html.haml +6 -2
  63. data/app/views/order_mailer/confirmation_for_refund.text.haml +4 -3
  64. data/app/views/orders/membership.html.haml +15 -19
  65. data/app/views/orders/passes.html.haml +97 -0
  66. data/app/views/orders/sales.html.haml +2 -2
  67. data/app/views/organizations/_form.html.haml +4 -37
  68. data/app/views/pass_types/index.html.haml +1 -1
  69. data/app/views/passes_reports/index.html.haml +79 -1
  70. data/app/views/people/show.html.haml +16 -15
  71. data/app/views/regular_donation_kits/edit.html.haml +140 -0
  72. data/app/views/store/checkouts/thanks.html.haml +14 -6
  73. data/app/views/store/donations/index.html.haml +19 -2
  74. data/app/views/store/events/calendar.html.haml +1 -0
  75. data/app/views/store/events/index.html.haml +1 -0
  76. data/app/views/store/events/show.html.haml +1 -0
  77. data/app/views/store/events/single_show.html.haml +2 -0
  78. data/app/views/store/orders/show.html.haml +10 -10
  79. data/app/views/store/passes/index.html.haml +2 -2
  80. data/app/views/store/shared/_donate_form.html.haml +31 -12
  81. data/app/views/store/shared/_small_donate_form.html.haml +22 -0
  82. data/app/views/users/invitations/edit.html.haml +3 -42
  83. data/config/locales/en.yml +3 -1
  84. data/config/routes.rb +4 -1
  85. data/db/migrate/20140603200735_add_subtitle_to_events.rb +5 -0
  86. data/lib/artfully_ose/version.rb +1 -1
  87. data/spec/factories/kit_factories.rb +5 -4
  88. metadata +25 -13
  89. data/app/assets/javascripts/box-office.js +0 -262
@@ -123,8 +123,6 @@ h4
123
123
  img#logo
124
124
  float: left
125
125
  margin-right: 10px
126
-
127
- h1#logo
128
126
 
129
127
  ul#shows, ul#memberships
130
128
  clear: both
@@ -230,56 +228,6 @@ table.calendar
230
228
  #shopping-cart
231
229
  width: auto
232
230
  background-color: #e6e6e6 !important
233
- #steps
234
- display: none
235
- position: static
236
- background: #fff
237
- position: static
238
- width: 650px
239
- margin: 0px auto
240
- padding: 50px
241
- padding-top: 10px
242
- padding-bottom: 0
243
- height: 380px
244
- overflow: auto
245
- ul#nav
246
- width: 650px
247
- margin: 0 auto
248
- overflow: hidden
249
- margin-bottom: 20px
250
- li
251
- float: left
252
- list-style: none
253
- letter-spacing: 0
254
- font-family: "Helvetica", Arial, arial, sans-serif
255
- word-spacing: normal
256
- &.active a
257
- background-color: $compliment_highlight
258
- color: #fff
259
- font-weight: normal
260
- &.disabled a
261
- color: #BBB
262
- cursor: default
263
- a
264
- @include rounded-corners(15px, 15px, 15px, 15px)
265
- font-size: 12px
266
- padding-top: 8px
267
- padding-bottom: 8px
268
- margin-top: 4px
269
- padding-right: 12px
270
- padding-left: 12px
271
- margin-right: 2px
272
- line-height: 14px
273
- display: block
274
- color: #333
275
- &:hover
276
- text-decoration: none
277
- lable.error
278
- color: red
279
- .tab-pane
280
- display: none
281
- &.active
282
- display: block
283
231
 
284
232
  #cart
285
233
  width: 100%
@@ -412,15 +360,7 @@ table.calendar
412
360
  text-shadow: none
413
361
  color: #fff
414
362
  background-color: #a85300
415
- background-image: -khtml-gradient(linear, left top, left bottom, from(#f8930a), to(#a85300))
416
- background-image: -moz-linear-gradient(top, #f8930a, #a85300)
417
- background-image: -ms-linear-gradient(top, #f8930a, #a85300)
418
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8930a), color-stop(100%, #a85300))
419
- background-image: -webkit-linear-gradient(top, #f8930a, #a85300)
420
- background-image: -o-linear-gradient(top, #f8930a, #a85300)
421
- background-image: linear-gradient(top, #f8930a, #a85300)
422
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8930a', endColorstr='#a85300', GradientType=0)
423
- border-color: #a85300 #a85300 #003f81
363
+ background-image: none
424
364
 
425
365
  .navbar .btn.primary
426
366
  margin-top: 3px
@@ -502,7 +442,7 @@ tr.no-border
502
442
  padding: 3px
503
443
  border: 1px solid #eee
504
444
 
505
- #event-header
445
+ #event-header, #donate-now-header
506
446
  h1
507
447
  font-family: 'Roboto', sans-serif
508
448
  font-weight: 300
@@ -511,6 +451,19 @@ tr.no-border
511
451
  font-weight: 100
512
452
  margin: 0px 0px 2px 0px
513
453
 
454
+ #donate-now-header
455
+ text-align: center
456
+ margin-bottom: 30px
457
+
458
+ #donate-now-container
459
+ margin-top: -30px
460
+ padding: 50px 20px 60px 20px
461
+ box-shadow: 6px 5px 5px -5px #999, -6px 5px 5px -5px #999
462
+
463
+ #donate-now
464
+ text-align: center
465
+ margin-top: 20px
466
+
514
467
  .available-ticket-type-table
515
468
  form
516
469
  margin: 0px
@@ -538,3 +491,40 @@ tr.no-border
538
491
  #poster-modal
539
492
  .modal-body
540
493
  text-align: center
494
+
495
+ .add-donation-to-cart
496
+ .preset-amount
497
+ float: left
498
+ width: 227px
499
+ // height: 28px
500
+ margin-bottom: 10px
501
+ text-align: left
502
+
503
+ .add-donation-to-cart
504
+ .preset-amount.last
505
+ width: 455px
506
+
507
+ .add-donation-to-cart
508
+ .preset-amount
509
+ label
510
+ margin: 0
511
+ padding: 0
512
+ // height: 28px
513
+ line-height: 28px
514
+
515
+ .add-donation-to-cart
516
+ .preset-amount
517
+ label
518
+ input[type='radio']
519
+ float: none
520
+ vertical-align: baseline
521
+ margin-top: 0
522
+
523
+ #event-header.side-section
524
+ h4
525
+ padding-bottom: 8px
526
+ #subtitle
527
+ padding-bottom: 8px
528
+ font-weight: bold
529
+ line-height: 1.4em
530
+ font-size: 1em
@@ -1,4 +1,4 @@
1
- /*
1
+ /*
2
2
  *= require bootstrap
3
3
  *= require sass/cart
4
4
  *= require sass/store
@@ -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 meed it because it defines its own sold_price method
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
- response = http_party.post(PDF_POST_URL, pdf_attributes)
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
@@ -95,6 +95,7 @@ class EventsController < ArtfullyOseController
95
95
  end
96
96
 
97
97
  def widget
98
+ @donation_kit = current_user.current_organization.kit(:regular_donation)
98
99
  end
99
100
 
100
101
  def storefront_link
@@ -7,6 +7,9 @@ class ExportController < ArtfullyOseController
7
7
  send_data @csv_string, :filename => @filename, :type => "text/csv", :disposition => "attachment"
8
8
  end
9
9
 
10
+ #
11
+ # Artful.ly generates these nightly and provides links directly to s3
12
+ #
10
13
  def donations
11
14
  @organization = current_user.current_organization
12
15
  @filename = "Artfully-Donations-Export-#{DateTime.now.strftime("%m-%d-%y")}.csv"
@@ -15,8 +18,15 @@ class ExportController < ArtfullyOseController
15
18
  send_data @csv_string, :filename => @filename, :type => "text/csv", :disposition => "attachment"
16
19
  end
17
20
 
21
+ #
22
+ # Artful.ly generates these nightly and provides links directly to s3
23
+ #
18
24
  def ticket_sales
19
- # Moved to s3. Generated nightly with rake csv:sales
25
+ @organization = current_user.current_organization
26
+ @filename = "Artfully-Ticket-Sales-Export-#{DateTime.now.strftime("%m-%d-%y")}.csv"
27
+ @items = ItemView.where(:organization_id => current_organization).where(:product_type => "Ticket").all
28
+ @csv_string = @items.to_comma(:ticket_sale)
29
+ send_data @csv_string, :filename => @filename, :type => "text/csv", :disposition => "attachment"
20
30
  end
21
31
 
22
32
  end
@@ -23,9 +23,8 @@ class ImportsController < ArtfullyOseController
23
23
  # Building an import preview was just murdering us. The problem is way down in Array.index in parsed_row.load_value.
24
24
  # Temporarily shutting it off for > 1000
25
25
  #
26
- @under_limit = @import.import_rows.count < 1000
27
- if @import.status == "pending" && @under_limit
28
- @parsed_rows = @import.parsed_rows.paginate(:page => params[:page], :per_page => 50)
26
+ if @import.status == "pending"
27
+ @imported_rows = @import.import_rows.paginate(:page => params[:page], :per_page => 50)
29
28
  end
30
29
 
31
30
  @people = Person.where(:import_id => @import.id).paginate(:page => params[:page], :per_page => 50) unless @import.id.nil?
@@ -4,9 +4,8 @@ class MemberCardsController < ArtfullyOseController
4
4
  before_filter :find_members
5
5
 
6
6
  def new
7
- generator = MemberCardGenerator::BlanksUsaIdc6.new(@members)
8
- generator.generate
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
 
@@ -40,6 +40,7 @@ class OrganizationsController < ArtfullyOseController
40
40
 
41
41
  if @organization.save
42
42
  @organization.users << current_user
43
+ @organization.make_owner(current_user)
43
44
  redirect_to organizations_url, :notice => "#{@organization.name} has been created"
44
45
  else
45
46
  render :new
@@ -1,5 +1,25 @@
1
1
  class PassesReportsController < ArtfullyOseController
2
2
  def index
3
- @pass_types = current_organization.pass_types.all
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
@@ -0,0 +1,32 @@
1
+ class RegularDonationKitsController < ApplicationController
2
+ rescue_from CanCan::AccessDenied do |exception|
3
+ flash[:alert] = exception.message
4
+ redirect_to root_path, :alert => exception.message
5
+ end
6
+
7
+ before_filter do
8
+ authorize! :edit, current_user.current_organization
9
+ end
10
+
11
+ def edit
12
+ @kit = Kit.find(params[:id])
13
+ end
14
+
15
+ def update
16
+ @kit = Kit.find(params[:id])
17
+
18
+ if @kit.update_attributes(kit_params)
19
+ flash[:notice] = 'Your changes have been saved.'
20
+ redirect_to organization_path(@kit.organization)
21
+ else
22
+ flash[:error] = 'We had a problem configuring your kit. Please try again.'
23
+ render :edit
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def kit_params
30
+ params[:regular_donation_kit]
31
+ end
32
+ end
@@ -1,4 +1,22 @@
1
1
  class Store::DonationsController < Store::StoreController
2
+ rescue_from ActiveRecord::RecordNotFound do
3
+ render :text => File.read("#{Rails.root}/public/404.html"),
4
+ :content_type => Mime::HTML,
5
+ :status => :not_found
6
+ end
7
+
2
8
  def index
9
+ # If there is no kit at all, NotFound
10
+ raise ActionController::RoutingError.new('Not Found') unless @store_organization.has_kit?(:regular_donation)
11
+
12
+ # If there's a kit, and they're logged in, show them a preview if the kit is off
13
+ if current_user && current_user.current_organization == @store_organization
14
+ if !@store_organization.has_active_donation_only_storefront?
15
+ flash[:notice] = "You are seeing a preview of your donation-only storefront. To make this page visible to the general public, go to your 501(c)(3) kit configuration and check \"Display Donation-Only Storefront\""
16
+ end
17
+ else
18
+ # show everyone else NotFound
19
+ raise ActionController::RoutingError.new('Not Found') unless @store_organization.has_active_donation_only_storefront?
20
+ end
3
21
  end
4
- end
22
+ end
@@ -1,18 +1,29 @@
1
1
  class Store::OrdersController < Store::StoreController
2
2
  include ActionView::Helpers::TextHelper
3
3
  include ArtfullyOseHelper
4
-
4
+
5
5
  def update
6
6
  handler = OrderHandler.new(current_cart, current_member)
7
- handler.handle_tickets(params)
7
+ handler.handle_tickets(params)
8
8
  handler.handle_donation(params, @store_organization)
9
9
  handler.handle_memberships(params, current_member)
10
10
  handler.handle_passes(params)
11
11
  handler.handle_discount_or_pass_code(params)
12
12
 
13
- flash[:alert] = handler.error unless handler.error.blank?
13
+ if handler.error.present?
14
+ flash[:alert] = handler.error unless handler.error.blank?
15
+
16
+ redirect_url = case params[:_source]
17
+ when 'storefront'
18
+ store_donate_path
19
+ else
20
+ store_order_path
21
+ end
14
22
 
15
- redirect_to store_order_path
23
+ redirect_to redirect_url
24
+ else
25
+ redirect_to store_order_path
26
+ end
16
27
  end
17
28
 
18
29
  def show
@@ -50,7 +61,6 @@ class Store::OrdersController < Store::StoreController
50
61
  end
51
62
 
52
63
  private
53
-
54
64
  def event
55
65
  current_cart.tickets.first.event
56
66
  end