artfully_ose 1.2.0.pre.19 → 1.2.0.pre.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +28 -0
  3. data/app/assets/javascripts/change-membership.js +66 -16
  4. data/app/assets/javascripts/store/store.js +4 -0
  5. data/app/assets/stylesheets/sass/store.sass +2 -0
  6. data/app/{models/carts → concerns}/cart_finder.rb +0 -0
  7. data/app/{models/actions → concerns}/immutable_action.rb +0 -0
  8. data/app/concerns/pdf_generation.rb +71 -0
  9. data/app/{models/orders → concerns}/unrefundable.rb +0 -0
  10. data/app/controllers/export_controller.rb +1 -5
  11. data/app/controllers/imports_controller.rb +12 -0
  12. data/app/controllers/members/index_controller.rb +1 -1
  13. data/app/controllers/members/members_controller.rb +6 -1
  14. data/app/controllers/members/passwords_controller.rb +10 -0
  15. data/app/controllers/members/people_controller.rb +17 -0
  16. data/app/controllers/membership_cancellations_controller.rb +46 -0
  17. data/app/controllers/membership_comps_controller.rb +97 -0
  18. data/app/controllers/membership_types_controller.rb +6 -2
  19. data/app/controllers/people_controller.rb +15 -3
  20. data/app/controllers/sales_controller.rb +4 -0
  21. data/app/controllers/searches_controller.rb +2 -2
  22. data/app/controllers/sections_controller.rb +1 -1
  23. data/app/controllers/shows_controller.rb +52 -3
  24. data/app/controllers/store/checkouts_controller.rb +2 -7
  25. data/app/controllers/store/memberships_controller.rb +2 -1
  26. data/app/helpers/artfully_ose_helper.rb +4 -3
  27. data/app/mailers/order_mailer.rb +3 -3
  28. data/app/models/actions/comp_action.rb +15 -0
  29. data/app/models/address.rb +7 -0
  30. data/app/models/{carts/cart.rb → cart.rb} +0 -19
  31. data/app/models/checkout.rb +53 -15
  32. data/app/models/comp.rb +21 -11
  33. data/app/models/database_views/item_view.rb +4 -0
  34. data/app/models/event.rb +1 -0
  35. data/app/models/{ext/ext.rb → ext.rb} +14 -1
  36. data/app/models/ext/preprocessor.rb +6 -0
  37. data/app/models/job/order_processor.rb +6 -3
  38. data/app/models/job/show_creator.rb +6 -2
  39. data/app/models/kit.rb +1 -1
  40. data/app/models/kits/membership_kit.rb +8 -1
  41. data/app/models/kits/scannable_tickets_kit.rb +24 -0
  42. data/app/models/member.rb +59 -13
  43. data/app/models/membership.rb +2 -14
  44. data/app/models/membership_cancellation.rb +80 -0
  45. data/app/models/membership_comp.rb +103 -0
  46. data/app/models/membership_comp_job.rb +32 -0
  47. data/app/models/membership_type.rb +3 -3
  48. data/app/models/{orders/order.rb → order.rb} +8 -2
  49. data/app/models/orders/comp_order.rb +4 -0
  50. data/app/models/organization.rb +5 -1
  51. data/app/models/{payments/payment.rb → payment.rb} +12 -1
  52. data/app/models/payments/credit_card_payment.rb +36 -5
  53. data/app/models/person.rb +11 -1
  54. data/app/models/rolling_membership_type.rb +3 -1
  55. data/app/models/sale.rb +1 -1
  56. data/app/models/search.rb +1 -6
  57. data/app/models/seasonal_membership_type.rb +1 -0
  58. data/app/models/ticket.rb +2 -0
  59. data/app/models/ticket/qr_code.rb +1 -1
  60. data/app/models/ticket/transfers.rb +6 -3
  61. data/app/models/ticket_type.rb +6 -0
  62. data/app/models/user.rb +2 -1
  63. data/app/views/addresses/_address.html.haml +7 -6
  64. data/app/views/events/_ticket_type_fields.html.haml +2 -2
  65. data/app/views/imports/index.html.haml +2 -1
  66. data/app/views/layouts/_menu.html.haml +3 -2
  67. data/app/views/layouts/storefront.html.haml +17 -13
  68. data/app/views/members/index/index.html.haml +5 -11
  69. data/app/views/members/invitations/edit.html.haml +17 -0
  70. data/app/views/members/mailer/_invitation_body.html.haml +18 -0
  71. data/app/views/members/mailer/invitation_instructions.html.haml +6 -12
  72. data/app/views/members/mailer/reset_password_instructions.html.erb +8 -0
  73. data/app/views/members/passwords/edit.html.haml +18 -0
  74. data/app/views/members/sessions/new.html.haml +19 -0
  75. data/app/views/membership_cancellations/_form.html.haml +39 -0
  76. data/app/views/membership_cancellations/_modal.html.haml +2 -0
  77. data/app/views/membership_cancellations/_processing.html.haml +14 -0
  78. data/app/views/membership_cancellations/create.js.erb +3 -0
  79. data/app/views/membership_cancellations/new.js.erb +3 -0
  80. data/app/views/membership_comps/confirm.html.haml +85 -0
  81. data/app/views/membership_comps/create.html.haml +18 -0
  82. data/app/views/membership_comps/new.html.haml +82 -0
  83. data/app/views/membership_mailer/cancellation_confirmation.html.haml +9 -0
  84. data/app/views/membership_mailer/cancellation_confirmation.text.haml +6 -0
  85. data/app/views/membership_mailer/refund_problem.html.haml +18 -0
  86. data/app/views/membership_mailer/refund_problem.text.haml +14 -0
  87. data/app/views/membership_types/_form.html.haml +18 -53
  88. data/app/views/membership_types/_membership_type_fees.html.haml +0 -0
  89. data/app/views/membership_types/index.html.haml +1 -5
  90. data/app/views/memberships/_membership_scripts.js.erb +15 -0
  91. data/app/views/memberships/index.html.haml +18 -17
  92. data/app/views/order_mailer/confirmation_for.html.haml +8 -0
  93. data/app/views/orders/_order_sidebar.html.haml +1 -3
  94. data/app/views/organizations/_form.html.haml +6 -0
  95. data/app/views/pdfs/member.html.haml +66 -0
  96. data/app/views/pdfs/order.html.haml +84 -0
  97. data/app/views/people/_comp_membership.html.haml +23 -0
  98. data/app/views/people/_edit_modal.html.haml +6 -3
  99. data/app/views/people/show.html.haml +1 -2
  100. data/app/views/searches/_form.html.haml +34 -33
  101. data/app/views/searches/show.html.haml +4 -1
  102. data/app/views/segments/show.html.haml +4 -1
  103. data/app/views/shows/_ticket_table.html.haml +1 -1
  104. data/app/views/shows/index.html.haml +8 -2
  105. data/app/views/store/checkouts/_membership_info.html.haml +1 -0
  106. data/app/views/store/checkouts/thanks.html.haml +7 -3
  107. data/app/views/store/events/index.html.haml +9 -3
  108. data/app/views/store/events/single_show.html.haml +4 -1
  109. data/app/views/store/memberships/index.html.haml +2 -1
  110. data/app/views/store/orders/show.html.haml +2 -2
  111. data/config/initializers/devise.rb +1 -1
  112. data/config/initializers/paperclip.rb +39 -0
  113. data/config/locales/devise_invitable.en.yml +1 -1
  114. data/config/locales/en.yml +9 -0
  115. data/config/routes.rb +14 -7
  116. data/db/migrate/20131223215615_goodbye_order_view.rb +6 -0
  117. data/db/migrate/20140114011856_add_welcome_message_to_memberships.rb +5 -0
  118. data/db/migrate/20140114212127_add_send_email_to_memberships.rb +5 -0
  119. data/db/migrate/20140125183606_index_memberships_and_types.rb +6 -0
  120. data/db/migrate/20140128213101_add_pdf_to_members.rb +5 -0
  121. data/db/migrate/20140128223140_add_uuid_to_member.rb +6 -0
  122. data/db/migrate/20140128223948_add_qr_code_to_member.rb +9 -0
  123. data/lib/artfully_ose/common_abilities.rb +1 -1
  124. data/lib/artfully_ose/engine.rb +23 -2
  125. data/lib/artfully_ose/version.rb +1 -1
  126. data/spec/factories/action_factories.rb +19 -0
  127. data/spec/factories/address_factories.rb +11 -0
  128. data/spec/factories/cart_factories.rb +26 -0
  129. data/spec/factories/chart_factories.rb +52 -0
  130. data/spec/factories/discount_factories.rb +11 -0
  131. data/spec/factories/donation_factories.rb +14 -0
  132. data/spec/factories/event_factories.rb +29 -0
  133. data/spec/factories/import_factories.rb +61 -0
  134. data/spec/factories/item_factories.rb +51 -0
  135. data/spec/factories/kit_factories.rb +27 -0
  136. data/spec/factories/member_factories.rb +19 -0
  137. data/spec/factories/membership_factories.rb +8 -0
  138. data/spec/factories/membership_type_factories.rb +18 -0
  139. data/spec/factories/order_factories.rb +40 -0
  140. data/spec/factories/organization_factories.rb +44 -0
  141. data/spec/factories/payments_factories.rb +97 -0
  142. data/spec/factories/person_factories.rb +44 -0
  143. data/spec/factories/phone_factories.rb +6 -0
  144. data/spec/factories/section_factories.rb +21 -0
  145. data/spec/factories/segment_factories.rb +6 -0
  146. data/spec/factories/show_factories.rb +33 -0
  147. data/spec/factories/ticket_factories.rb +57 -0
  148. data/spec/factories/ticket_offer_factories.rb +16 -0
  149. data/spec/factories/ticket_type_factories.rb +8 -0
  150. data/spec/factories/user_factories.rb +24 -0
  151. metadata +75 -17
  152. data/app/controllers/membership_awards_controller.rb +0 -60
  153. data/app/models/database_views/order_view.rb +0 -34
  154. data/app/models/membership_award.rb +0 -24
  155. data/app/models/orders/pdf_generation.rb +0 -75
  156. data/app/views/members/invitations/edit.html.erb +0 -14
  157. data/app/views/membership_awards/confirm.html.haml +0 -105
  158. data/app/views/membership_awards/create.html.haml +0 -1
  159. data/app/views/membership_awards/new.html.haml +0 -79
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- M2E4OTBlNDU5Zjc0NGJmODQyY2ZmNzQ2ODI1OGEzYjQ2N2Q1ODAyZQ==
4
+ NzIwYmNmYWQyNWJhNWY3OGVlMGYxYjYzMzFlYzlhMTA5MzMyZWUzNw==
5
5
  data.tar.gz: !binary |-
6
- ZGI1ZmRhMjY3MjhlZjc0YjJhYmNhZDQ0Yjc5ZDZhNGE4NGQ3NTlmNQ==
6
+ ZGNiZTkwODAyZjJkOGM3OGYxM2ZkMzg2YzI2N2VkNWRkMjBjYzZjNQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- ODhhZDk0ZWFjOWMwNGU2NmQxMGI1NzkzNjI2NGFjZjQ2MDYwYjQzNjE0YWY0
10
- MTUxZmFjMzdlMTI1MjA3YzYyZDBmNWRhOTgyYWVjODcyYWFjNThlMzJhYzA0
11
- MzJjY2I0MmQ4MmJiNjJmMGMyYWU3YThhZDFjNzc2ZGE5MjgwOWY=
9
+ YjNmNmM0MWU4ODJiMDBjYTg2MWQzNTk5M2RjOGE3MzE2NGMxNDQ1MDg3MzZl
10
+ Yzk2YmNjMTNlMWZhYzM5OTdjZGUyNjk1YzFmY2VlNjc3YmVmNWYwNzdhNzA5
11
+ OWJkZDg2Zjg4NzI0YmMxYzhjZmZiNWVlNWUyMDIxM2U0YWE2MTI=
12
12
  data.tar.gz: !binary |-
13
- ZjUyNWY5ODY4ZDA3NGY2MjU3YWU3OWM5NmNlYzA4MmM0Mzc3MjM4MGVkN2Jm
14
- YjI4NmM2Njk5MzAzMTgzZTEzZWJjOTVmOTk1YzVhYTRhN2Y0MmRjZTZkMjM1
15
- ZjI2YmFlZTFmOWRhYjJhYTQwNTAzYzI1MGFjM2UwMDg4MmJlN2Y=
13
+ Y2E4ZTI2NjIyYjcwNmU0ZTQzOTdlNTZmZWJhZGQ0ZDkxYjI4MzY0OTgyOTVj
14
+ MTUwNTA4MDA4ODIwZmJhYWUwMDNjYjIxYjI0MmE2MmNkODQzNWMyZWM0ZjBl
15
+ NzJiZTRmMjAzZjM2Yjk4MmUxNTFiODhjYzc0MmE4NDAyOGFmOWE=
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # Artful.ly OSE
2
+
3
+ Welcome to Artful.ly OSE
4
+
5
+ ## About
6
+
7
+ Artful.ly Open Source Edition is the core code of the Artful.ly app downloadable for free and ready for you to roll up your sleeves and build a custom management system for your arts business. The Artful.ly OSE framework gives software developers a base from which they can add features, integrate with other apps, and much more!
8
+
9
+ ## Before You Begin
10
+
11
+ You'll want the following running on your machine:
12
+
13
+ - Ruby 1.9.3
14
+ - MySQL
15
+
16
+ ## Usage
17
+
18
+ Artful.ly Open Source Engine is a Rails Engine. **It is not intended to be mounted into an existing project** but rather to be used with the reference implementation [here](http://www.github.com/fracturedatlas/artfully_app)
19
+
20
+ ## Branch strategy
21
+
22
+ Master is the current development branch. Every effort is made to make master tidy and working at all times but it is the edge and problems do happen. For any stable production applications, you'll *absolutely* want to be pointing to a published, stable gem. A list can be found [on Rubygems](https://rubygems.org/gems/artfully_ose)
23
+
24
+ ## Contributors
25
+
26
+ Gary Moore - Lead Developer at Fractured Atlas
27
+
28
+ Clinton Judy - Open Source Lead at Fractured Atlas
@@ -1,6 +1,7 @@
1
1
  //
2
2
  // Service for keeping track of which memberships are selected
3
3
  //
4
+
4
5
  angular.module('artfully').factory('membershipSelections', function() {
5
6
  // Map of selected membership ids
6
7
  var map = {};
@@ -10,14 +11,15 @@ angular.module('artfully').factory('membershipSelections', function() {
10
11
 
11
12
  // Watch for changes
12
13
  $('body').on('change', 'input[name=membership_ids\\[\\]]', function(change) {
13
- var e = $(change.target);
14
- var row = e.closest('tr');
15
- var type = $(row.find('.item-description')[0]);
16
- var price = $(row.find('.price')[0]);
14
+ var e = $(change.target);
17
15
  var membership_id = e.val();
18
16
 
19
17
  if ($(e).prop( "checked" )) {
20
18
  // Add the membership id if it's not already in the list
19
+ var row = e.closest('tr');
20
+ var type = $(row.find('.item-description')[0]);
21
+ var price = $(row.find('.price')[0]);
22
+
21
23
  if (map[membership_id] === undefined) {
22
24
  map[membership_id] = {
23
25
  id: membership_id,
@@ -38,27 +40,28 @@ angular.module('artfully').factory('membershipSelections', function() {
38
40
  //
39
41
  // Controller
40
42
  //
41
- angular.module('artfully').controller('ChangeMembershipController', ['$scope', 'membershipSelections', function($scope, membershipSelections) {
42
43
 
43
- // Template variables
44
- $scope.payment_method = 'cash';
45
- $scope.price = 0;
46
- $scope.total = 0;
47
- $scope.selected = {};
44
+ angular.module('artfully').controller('MembershipActionsCtrl', ['$scope', 'membershipSelections', function($scope, membershipSelections) {
45
+ $scope.loading = false;
46
+ $scope.error = false;
47
+ $scope.errorMessage = '';
48
+
49
+ $scope.checkSelected = function() {
50
+ $scope.error = false;
51
+ $scope.errorMessage = '';
48
52
 
49
- // Helpers
50
- $scope.anySelected = function() {
51
53
  if (Object.keys(membershipSelections).length == 0 ) {
54
+ $scope.error = true;
55
+ $scope.errorMessage = "Select one or more memberships.";
52
56
  return false;
53
57
  }
54
58
  return true;
55
59
  }
56
60
 
57
- $scope.changeSelected = function(click) {
61
+ $scope.change = function(click) {
58
62
  click.preventDefault();
59
63
 
60
- if (!$scope.anySelected()) {
61
- alert("Select one or more memberships to change.");
64
+ if (!$scope.checkSelected()) {
62
65
  return false;
63
66
  }
64
67
 
@@ -67,11 +70,58 @@ angular.module('artfully').controller('ChangeMembershipController', ['$scope', '
67
70
  return false;
68
71
  }
69
72
 
73
+ $scope.cancel = function(click) {
74
+ click.preventDefault();
75
+
76
+ if (!$scope.checkSelected()) {
77
+ return false;
78
+ }
79
+
80
+ $scope.loading = true;
81
+
82
+ // Get membership_cancellations/new (fetches and displays the modal)
83
+ $.ajax({
84
+ url: 'membership_cancellations/new.js',
85
+ data: {membership_ids: Object.keys(membershipSelections)},
86
+ dataType: 'script',
87
+ success: function (script, status, xhr) {
88
+ $scope.$apply(function() {
89
+ $scope.loading = false;
90
+ });
91
+ },
92
+ error: function (xhr, text, error) {
93
+ $scope.$apply(function() {
94
+ $scope.loading = false;
95
+ $scope.error = true;
96
+
97
+ var message = error;
98
+ if (xhr &&
99
+ xhr.responseText !== undefined &&
100
+ xhr.responseText != '' &&
101
+ xhr.responseText != ' ') {
102
+ message = xhr.responseText;
103
+ }
104
+ $scope.errorMessage = message;
105
+ });
106
+ }
107
+ });
108
+ }
109
+
110
+ }]);
111
+
112
+ angular.module('artfully').controller('ChangeMembershipController', ['$scope', 'membershipSelections', function($scope, membershipSelections) {
113
+
114
+ // Template variables
115
+ $scope.payment_method = 'cash';
116
+ $scope.price = 0;
117
+ $scope.total = 0;
118
+ $scope.selected = {};
119
+
120
+ // Helpers
70
121
  $scope.updateTotal = function() {
71
122
  var price = parseFloat($scope.price.substr(1).replace(/,/, ""));
72
123
  var total = (Object.keys($scope.selected).length * price);
73
124
 
74
-
75
125
  $scope.total = '$'+total.toFixed(2);
76
126
  }
77
127
 
@@ -12,6 +12,10 @@ $(document).ready(function(){
12
12
  'regionField' : '#payment_customer_address_state'
13
13
  });
14
14
 
15
+ $(document).locationSelector({
16
+ 'countryField' : '#individual_address_attributes_country',
17
+ 'regionField' : '#individual_address_attributes_state'
18
+ });
15
19
 
16
20
  // toggle a showing's sections
17
21
  $('#multi-show-container .title').click(function() {
@@ -429,6 +429,8 @@ table.calendar
429
429
 
430
430
  .store-event-display
431
431
  margin-bottom: 20px
432
+ h1
433
+ margin-top: 0px
432
434
 
433
435
  #shopping-cart-display
434
436
  table
File without changes
@@ -0,0 +1,71 @@
1
+ require 'json'
2
+ require 'digest/md5'
3
+
4
+ class PdfGeneration
5
+ PDF_POST_URL = "http://quick-pdf.geminisbs.net/pdfs.json"
6
+ PDF_GET_URL = "http://quick-pdf.geminisbs.net/pdfs/:id.json?api_key=:key"
7
+ PDF_DOWNLOAD_URL = "http://quick-pdf.geminisbs.net/pdfs/:id/download?api_key=:key"
8
+
9
+ def initialize(pdfable, pdf_api_key = PDF_API_KEY, http_party = HTTParty, sleeper = Kernel)
10
+ @pdfable = pdfable
11
+ @pdf_api_key = pdf_api_key
12
+ @http_party = http_party
13
+ @sleeper = sleeper
14
+ end
15
+
16
+ def generate
17
+ response = http_party.post(PDF_POST_URL, pdf_attributes)
18
+ json = JSON.parse(response.body)
19
+
20
+ while !json["complete"]
21
+ response = http_party.get(status_url(json))
22
+ json = JSON.parse(response.body)
23
+
24
+ sleeper.sleep 1 unless json["complete"]
25
+ end
26
+
27
+ download_url(json)
28
+ end
29
+
30
+ def content
31
+ file_name = pdfable.class.name.underscore
32
+ file_name = 'order' if file_name.ends_with?('order')
33
+ template = File.read("#{ArtfullyOse::Engine.root}/app/views/pdfs/#{file_name}.html.haml")
34
+ haml_engine = Haml::Engine.new(template)
35
+ scope = Object.new.extend(ArtfullyOseHelper)
36
+ output = haml_engine.render(scope, {:pdfable => pdfable})
37
+ output.gsub("'","\'") # necessary to escape single '
38
+ end
39
+
40
+ private
41
+ attr_reader :pdfable, :pdf_api_key, :http_party, :sleeper
42
+ def pdf_attributes
43
+ {
44
+ :body => {
45
+ :api_key => pdf_api_key,
46
+ :pdf => {
47
+ :html_doc => content,
48
+ :filename => filename,
49
+ :pdf_options => {
50
+ :margin_top => "0.5in",
51
+ :margin_bottom => "0.5in",
52
+ :margin_left => "0.5in",
53
+ :margin_right => "0.5in"
54
+ }
55
+ }
56
+ }
57
+ }
58
+ end
59
+
60
+ def filename
61
+ "#{Digest::MD5.hexdigest pdfable.id.to_s}.pdf"
62
+ end
63
+
64
+ def status_url(json)
65
+ PDF_GET_URL.gsub(":id", json["id"].to_s).gsub(":key", pdf_api_key)
66
+ end
67
+
68
+ def download_url(json)
69
+ PDF_DOWNLOAD_URL.gsub(":id", json["id"].to_s).gsub(":key", pdf_api_key)
70
+ end
71
+ end
File without changes
@@ -16,11 +16,7 @@ class ExportController < ArtfullyOseController
16
16
  end
17
17
 
18
18
  def ticket_sales
19
- @organization = current_user.current_organization
20
- @filename = "Artfully-Ticket-Sales-Export-#{DateTime.now.strftime("%m-%d-%y")}.csv"
21
- @items = ItemView.where(:organization_id => current_organization).where(:product_type => "Ticket").all
22
- @csv_string = @items.to_comma(:ticket_sale)
23
- send_data @csv_string, :filename => @filename, :type => "text/csv", :disposition => "attachment"
19
+ # Moved to s3. Generated nightly with rake csv:sales
24
20
  end
25
21
 
26
22
  end
@@ -5,6 +5,7 @@ class ImportsController < ArtfullyOseController
5
5
 
6
6
  def index
7
7
  @imports = organization.imports.includes(:user, :organization).order('created_at desc').all
8
+ @sales_csv_download_link = sales_csv_download_link
8
9
  end
9
10
 
10
11
  def approve
@@ -103,4 +104,15 @@ class ImportsController < ArtfullyOseController
103
104
  @type = (params[:type] || session[:type])
104
105
  end
105
106
 
107
+ def sales_csv_download_link
108
+ s3 = AWS::S3.new(
109
+ :access_key_id => ENV['S3_ACCESS_KEY_ID'],
110
+ :secret_access_key => ENV['S3_SECRET_ACCESS_KEY']
111
+ )
112
+ bucket = s3.buckets[ENV['S3_BUCKET']]
113
+ object = bucket.objects[ItemView.sales_export_filename_for(current_organization)]
114
+ url = object.url_for(:read, :expires => 10*60)
115
+ url.to_s
116
+ end
117
+
106
118
  end
@@ -1,4 +1,4 @@
1
1
  class Members::IndexController < Members::MembersController
2
- def index
2
+ def index
3
3
  end
4
4
  end
@@ -1,4 +1,9 @@
1
1
  class Members::MembersController < Store::StoreController
2
- skip_before_filter :authenticate_user!
3
2
  before_filter :authenticate_member!
3
+ skip_before_filter :authenticate_user!
4
+ skip_filter :require_more_info
5
+
6
+ def update
7
+ address = Address.unhash(person_params.delete("address_attributes"))
8
+ end
4
9
  end
@@ -0,0 +1,10 @@
1
+ class Members::PasswordsController < Devise::PasswordsController
2
+ layout 'devise_layout'
3
+
4
+ protected
5
+
6
+ #This method changed from devise 2.0 and 3.0
7
+ def after_sign_in_path_for(resource)
8
+ members_root_path
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ class Members::PeopleController < Members::MembersController
2
+ def update
3
+ address = Address.unhash(person_params.delete("address_attributes"))
4
+ @person = current_member.person
5
+ results = @person.update_attributes(person_params)
6
+ @person.delay.new_note("Member made the following changes from their dashboard: #{@person.previous_changes_sentence}", Time.now, nil, current_member.organization.id)
7
+ @person.address.update_with_note(@person, nil, address, current_member.organization.time_zone, "member dashboard")
8
+
9
+ flash[:notice] = "Your changes have been saved."
10
+ redirect_to members_root_path
11
+ end
12
+
13
+ private
14
+ def person_params
15
+ @person_params ||= params.fetch((:person),{}).merge(params.fetch(:company, {})).merge(params.fetch(:individual,{}))
16
+ end
17
+ end
@@ -0,0 +1,46 @@
1
+ class MembershipCancellationsController < ApplicationController
2
+ before_filter :set_person
3
+ before_filter :require_membership_ids
4
+ before_filter :require_memberships_for_person
5
+
6
+ respond_to :js
7
+
8
+ def new
9
+ @cancellation = MembershipCancellation.new(params[:membership_ids])
10
+ respond_with
11
+ end
12
+
13
+ def create
14
+ @membership_count = params[:membership_ids].count
15
+ MembershipCancellation.enqueue(params[:membership_ids])
16
+ end
17
+
18
+ private
19
+
20
+ def require_membership_ids
21
+ if params[:membership_ids].present?
22
+ true
23
+ else
24
+ render :text => ' ', :status => :bad_request
25
+ false
26
+ end
27
+ end
28
+
29
+ def require_memberships_for_person
30
+ # Count memberships for this person that match the given membership ids
31
+ query = Membership.where(id: params[:membership_ids], member_id: @person.member.id)
32
+
33
+ # This is true if the person owns ALL of the given membership ids
34
+ if query.count == params[:membership_ids].count
35
+ true
36
+ else
37
+ render :text => 'This person does not own the memberships.', :status => :unauthorized
38
+ false
39
+ end
40
+ end
41
+
42
+ def set_person
43
+ @person = Person.find(params[:person_id])
44
+ true
45
+ end
46
+ end
@@ -0,0 +1,97 @@
1
+ class MembershipCompsController < ArtfullyOseController
2
+ requires_kit :membership
3
+
4
+ def new
5
+ @membership_types = current_organization.membership_types.all
6
+ @membership_types_hash = {}
7
+ @membership_types.each {|mt| @membership_types_hash[mt.id] = I18n.l(mt.ends_at, :format => :date_for_input)}
8
+
9
+ @membership_comp = MembershipComp.new
10
+ @membership_comp.membership_type ||= @membership_types.first
11
+ @membership_comp.ends_at ||= I18n.l(@membership_types.first.ends_at, :format => :date_for_input)
12
+ @membership_comp.send_email ||= true
13
+ @membership_comp.number_of_memberships ||= 1
14
+ @membership_comp.person_id = params[:person_id]
15
+ @membership_comp.segment_id = params[:segment_id]
16
+ @membership_comp.search_id = params[:search_id]
17
+ @membership_comp.people = find_people
18
+ end
19
+
20
+ def index
21
+ @membership_comp = MembershipComp.new
22
+ @membership_comp.membership_type = current_user.current_organization.membership_types.first
23
+ render "create" and return
24
+ end
25
+
26
+ def create
27
+ @membership_comp = from_params(params)
28
+ if params[:membership_comp][:confirm].present?
29
+ @membership_comp.benefactor = current_user
30
+ @membership_comp.award
31
+ render 'create' and return
32
+ else
33
+ @number_without_emails = @membership_comp.people.select{ |person| person.email.blank? }.length
34
+ @number_of_companies = @membership_comp.people.select{ |person| person.company? }.length
35
+ @email_preview = generate_invitation_preview_for(@membership_comp)
36
+ if !@membership_comp.valid?
37
+ flash[:error] = @membership_comp.errors.full_messages.to_sentence
38
+ redirect_to :back and return
39
+ end
40
+ render "confirm" and return
41
+ end
42
+ end
43
+
44
+ private
45
+ def generate_invitation_preview_for(membership_comp)
46
+ @resource = Member.new
47
+ render_to_string( :partial => 'members/mailer/invitation_body',
48
+ :layout => false,
49
+ :locals => {:resource => @resource,
50
+ :person => membership_comp.people.first,
51
+ :welcome_message => membership_comp.welcome_message,
52
+ :membership_types => [membership_comp.membership_type],
53
+ :invitation_token => "",
54
+ :organization => current_user.current_organization})
55
+
56
+ end
57
+
58
+ def from_params(params)
59
+ membership_comp = MembershipComp.new
60
+ membership_comp_params = params[:membership_comp]
61
+ membership_comp.membership_type = MembershipType.find(membership_comp_params[:membership_type])
62
+ membership_comp.ends_at = membership_comp_params[:ends_at]
63
+ membership_comp.send_email = membership_comp_params[:send_email] == "true"
64
+ membership_comp.number_of_memberships = membership_comp_params[:number_of_memberships]
65
+ membership_comp.welcome_message = membership_comp_params[:welcome_message]
66
+ membership_comp.notes = membership_comp_params[:notes]
67
+ membership_comp.person_id = membership_comp_params[:person_id]
68
+ membership_comp.search_id = membership_comp_params[:search_id]
69
+ membership_comp.segment_id = membership_comp_params[:segment_id]
70
+
71
+ membership_comp.organization = current_user.current_organization
72
+ membership_comp.people = find_people(membership_comp_params)
73
+ membership_comp
74
+ end
75
+
76
+ def cache_key
77
+ current_user.id.to_s + "membership_comp_person_ids"
78
+ end
79
+
80
+ def find_people(p = params)
81
+
82
+ return @people unless @people.nil?
83
+
84
+ if p[:person_id].present?
85
+ @ids = Array.wrap(p[:person_id])
86
+ elsif p[:segment_id].present?
87
+ @ids = current_user.current_organization.segments.where(:id => p[:segment_id]).first.people.collect(&:id)
88
+ elsif p[:search_id].present?
89
+ @ids = current_user.current_organization.searches.where(:id => p[:search_id]).first.people.collect(&:id)
90
+ else
91
+ []
92
+ end
93
+
94
+ @people = Array.wrap(Person.find(@ids))
95
+ @people
96
+ end
97
+ end