caboose-cms 0.8.67 → 0.8.68

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 650fd50d2cc40e1d916e15ed23930f3cff2427d6
4
- data.tar.gz: 0cb4538479b27adf6d72fd3dcf640afdac72d071
3
+ metadata.gz: f3be7648fb20dea0f63181aa3fc29816743639b3
4
+ data.tar.gz: 378b44904c3a735619e44c5a150ed12ff50e4c4b
5
5
  SHA512:
6
- metadata.gz: 5f745259efc0b4cfd3e37cce5ccfcf73903497a0f5c2c0f8ddc1798072425f41f34bd71684f94d7e2d32c2473d06e4f3e2324a9b03b19a5507f578788db9c91b
7
- data.tar.gz: f0c6a9d6ef387930ea19b0dc393de4da1246fc386ca666a2d9d204d52dea90ffa1309b85c0cf11f39a6fabdf2edfc736bbcef9c919352a5cc847bf59a6679245
6
+ metadata.gz: f7e3584b65a103265aeeee1d52353053dd3d5277d552b3bc9e16a63be3e5ec03c4be2338c6d2db8787a71d246b8c8f9555784b4cb1e8390ec522518dd02b6933
7
+ data.tar.gz: 03a0db1c20df423d62d674fd7c3d16f49ecff43d14b55f9267850be35c2dd91ee3f067ff1447eef5f5c99616b7438b13c7dabb3627ed264ab4d1e35ba2bf51af
@@ -296,9 +296,12 @@ InvoiceController.prototype = {
296
296
  requires_shipping ? that.noneditable_shipping_address() : "This invoice doesn't require shipping."
297
297
  ));
298
298
  }
299
- //.append($('<td/>').attr('valign', 'top').attr('id', 'billing_address' ).append(that.noneditable_billing_address()))
299
+ //.append($('<td/>').attr('valign', 'top').attr('id', 'billing_address' ).append(that.noneditable_billing_address()))
300
+
301
+ var c = that.invoice.customer;
300
302
  tr.append($('<td/>').attr('valign', 'top').append($('<div/>').attr('id', 'invoice_' + that.invoice.id + '_status')))
301
303
  .append($('<td/>').attr('valign', 'top')
304
+ .append($('<div/>').append(c && c.card_last4 ? "Card on file: " + c.card_brand + " ending in " + c.card_last4 : "No card on file."))
302
305
  .append($('<div/>').attr('id', 'invoice_' + that.invoice.id + '_payment_terms'))
303
306
  .append($('<div/>').attr('id', 'invoice_' + that.invoice.id + '_payment_terms'))
304
307
  .append($('<div/>').attr('id', 'invoice_' + that.invoice.id + '_financial_status'))
@@ -764,7 +767,12 @@ InvoiceController.prototype = {
764
767
  var p = $('<p/>');
765
768
  p.append($('<input/>').attr('type', 'button').val('< Back').click(function() { window.location = '/admin/invoices'; })).append(' ');
766
769
  if (that.invoice.total > 0 && that.invoice.financial_status == 'pending')
767
- p.append($('<input/>').attr('type', 'button').val('Send for Payment').click(function() { that.send_for_authorization(); })).append(' ');
770
+ {
771
+ if (that.invoice.customer.card_last4)
772
+ p.append($('<input/>').attr('type', 'button').val('Charge Card on File').click(function() { that.authorize_and_capture(); })).append(' ');
773
+ else
774
+ p.append($('<input/>').attr('type', 'button').val('Send for Payment').click(function() { that.send_for_authorization(); })).append(' ');
775
+ }
768
776
  if (that.invoice.total > 0 && (that.invoice.financial_status == 'captured' || that.invoice.financial_status == 'paid by check' || that.invoice.financial_status == 'paid by other means'))
769
777
  p.append($('<input/>').attr('type', 'button').val('Send Receipt to Customer' ).click(function() { that.send_receipt(); })).append(' ');
770
778
  p.append($('<input/>').attr('type', 'button').val('Add Item' ).click(function() { that.add_variant(); })).append(' ');
@@ -1032,6 +1040,30 @@ InvoiceController.prototype = {
1032
1040
  });
1033
1041
  },
1034
1042
 
1043
+ authorize_and_capture: function(confirm)
1044
+ {
1045
+ var that = this;
1046
+ if (!confirm)
1047
+ {
1048
+ var c = that.invoice.customer;
1049
+ var p = $('<p/>').addClass('note confirm')
1050
+ .append("Are you sure you want to authorize and capture $" + curr(that.invoice.total) + " to customer's " + c.card_brand + " ending in " + c.card_last4 + "?<br/><br/>")
1051
+ .append($('<input/>').attr('type','button').val('Yes').click(function() { that.authorize_and_capture(true); }))
1052
+ .append(' ')
1053
+ .append($('<input/>').attr('type','button').val('No').click(function() { $('#message').empty(); }));
1054
+ $('#message').empty().append(p);
1055
+ return;
1056
+ }
1057
+ $('#message').html("<p class='loading'>Charging card on file...</p>");
1058
+ $.ajax({
1059
+ url: '/admin/invoices/' + that.invoice.id + '/authorize-and-capture',
1060
+ success: function(resp) {
1061
+ if (resp.error) { that.flash_error(resp.error); }
1062
+ if (resp.success) { that.refresh(function() { that.flash_success("The customer's card on file has been charged successfuly."); }); }
1063
+ }
1064
+ });
1065
+ },
1066
+
1035
1067
  send_receipt: function(confirm)
1036
1068
  {
1037
1069
  var that = this;
@@ -10,6 +10,8 @@ StripePaymentMethodController.prototype = {
10
10
  card_last4: false,
11
11
  card_name: false,
12
12
  card_zip: false,
13
+ refresh_url: '/checkout/stripe/json',
14
+ after_update_url: '/checkout/stripe-details',
13
15
 
14
16
  init: function(params)
15
17
  {
@@ -22,7 +24,7 @@ StripePaymentMethodController.prototype = {
22
24
  {
23
25
  var that = this;
24
26
  $.ajax({
25
- url: '/checkout/stripe/json',
27
+ url: that.refresh_url,
26
28
  type: 'get',
27
29
  success: function(resp) {
28
30
  that.stripe_key = resp.stripe_key;
@@ -143,7 +145,7 @@ StripePaymentMethodController.prototype = {
143
145
  that.card_brand = resp.card.brand;
144
146
  that.card_last4 = resp.card.last4;
145
147
  $.ajax({
146
- url: '/checkout/stripe-details',
148
+ url: that.after_update_url,
147
149
  type: 'put',
148
150
  data: { token: resp.id, card: resp.card },
149
151
  success: function(resp2) {
@@ -140,18 +140,11 @@ module Caboose
140
140
  end
141
141
 
142
142
  if c.nil?
143
- begin
144
- c = Stripe::Customer.create(
145
- :source => params[:token],
146
- :email => u.email,
147
- :metadata => { :user_id => u.id }
148
- )
149
- rescue Stripe::CardError => e
150
- render :json => {
151
- :error => e.message
152
- }
153
- return
154
- end
143
+ c = Stripe::Customer.create(
144
+ :source => params[:token],
145
+ :email => u.email,
146
+ :metadata => { :user_id => u.id }
147
+ )
155
148
  end
156
149
 
157
150
  u.stripe_customer_id = c.id
@@ -217,7 +210,7 @@ module Caboose
217
210
  :amount => c.amount/100.0,
218
211
  :date_processed => DateTime.now.utc,
219
212
  :success => c.status == 'succeeded'
220
- )
213
+ )
221
214
  end
222
215
 
223
216
  if !ot.success
@@ -113,6 +113,26 @@ module Caboose
113
113
  render :json => resp
114
114
  end
115
115
 
116
+ # @route GET /admin/invoices/:id/authorize-and-capture
117
+ def admin_authorize_and_capture
118
+ return if !user_is_allowed('invoices', 'edit')
119
+
120
+ invoice = Invoice.find(params[:id])
121
+ resp = invoice.authorize_and_capture
122
+
123
+ # Send out emails
124
+ #begin
125
+ # InvoicesMailer.configure_for_site(@site.id).customer_new_invoice(@invoice).deliver
126
+ # InvoicesMailer.configure_for_site(@site.id).fulfillment_new_invoice(@invoice).deliver
127
+ #rescue
128
+ # puts "=================================================================="
129
+ # puts "Error sending out invoice confirmation emails for invoice ID #{@invoice.id}"
130
+ # puts "=================================================================="
131
+ #end
132
+
133
+ render :json => resp
134
+ end
135
+
116
136
  # @route GET /admin/invoices/:id/void
117
137
  def admin_void
118
138
  return if !user_is_allowed('invoices', 'edit')
@@ -54,6 +54,21 @@ module Caboose
54
54
  render :json => u.as_json(:include => :roles)
55
55
  end
56
56
 
57
+ # @route GET /admin/users/:id/stripe/json
58
+ def admin_stripe_json_single
59
+ return if !user_is_allowed('users', 'view')
60
+ sc = @site.store_config
61
+ u = User.find(params[:id])
62
+ render :json => {
63
+ :stripe_key => sc.stripe_publishable_key.strip,
64
+ :customer_id => u.stripe_customer_id,
65
+ :card_last4 => u.card_last4,
66
+ :card_brand => u.card_brand,
67
+ :card_exp_month => u.card_exp_month,
68
+ :card_exp_year => u.card_exp_year
69
+ }
70
+ end
71
+
57
72
  # @route GET /admin/users/new
58
73
  def admin_new
59
74
  return if !user_is_allowed('users', 'add')
@@ -73,7 +88,21 @@ module Caboose
73
88
  @roles = Role.roles_with_user(@edituser.id)
74
89
  end
75
90
 
76
- # @route GET /admin/users/:id/edit-password
91
+ # @route GET /admin/users/:id/roles
92
+ def admin_edit_roles
93
+ return if !user_is_allowed('users', 'edit')
94
+ @edituser = User.find(params[:id])
95
+ @all_roles = Role.tree(@site.id)
96
+ @roles = Role.roles_with_user(@edituser.id)
97
+ end
98
+
99
+ # @route GET /admin/users/:id/payment-method
100
+ def admin_edit_payment_method
101
+ return if !user_is_allowed('users', 'edit')
102
+ @edituser = User.find(params[:id])
103
+ end
104
+
105
+ # @route GET /admin/users/:id/password
77
106
  def admin_edit_password
78
107
  return if !user_is_allowed('users', 'edit')
79
108
  @edituser = User.find(params[:id])
@@ -83,6 +112,12 @@ module Caboose
83
112
  o = [('a'..'z'),('A'..'Z'),('0'..'9')].map { |i| i.to_a }.flatten
84
113
  return (0...length).map { o[rand(o.length)] }.join
85
114
  end
115
+
116
+ # @route GET /admin/users/:id/delete
117
+ def admin_delete_form
118
+ return if !user_is_allowed('users', 'edit')
119
+ @edituser = User.find(params[:id])
120
+ end
86
121
 
87
122
  # @route POST /admin/users/import
88
123
  def admin_import
@@ -212,7 +247,31 @@ module Caboose
212
247
  when "roles"
213
248
  user.roles = [];
214
249
  value.each { |rid| user.roles << Role.find(rid) } unless value.nil?
215
- resp.attribute = { 'text' => user.roles.collect{ |r| r.name }.join(', ') }
250
+ resp.attribute = { 'text' => user.roles.collect{ |r| r.name }.join(', ') }
251
+
252
+ when 'card'
253
+
254
+ sc = @site.store_config
255
+ Stripe.api_key = sc.stripe_secret_key.strip
256
+
257
+ c = nil
258
+ if user.stripe_customer_id
259
+ c = Stripe::Customer.retrieve(user.stripe_customer_id)
260
+ begin
261
+ c.source = params[:token]
262
+ c.save
263
+ rescue
264
+ c = nil
265
+ end
266
+ end
267
+ c = Stripe::Customer.create(:source => params[:token], :email => user.email, :metadata => { :user_id => user.id }) if c.nil?
268
+ user.stripe_customer_id = c.id
269
+ user.card_last4 = params[:card][:last4]
270
+ user.card_brand = params[:card][:brand]
271
+ user.card_exp_month = params[:card][:exp_month]
272
+ user.card_exp_year = params[:card][:exp_year]
273
+ user.save
274
+
216
275
  end
217
276
  end
218
277
 
@@ -71,5 +71,9 @@ class Caboose::CorePlugin < Caboose::CaboosePlugin
71
71
  def self.request_protocol(current_value, request)
72
72
  return current_value
73
73
  end
74
+
75
+ def self.admin_user_tabs(tabs, user, site)
76
+ return tabs
77
+ end
74
78
 
75
79
  end
@@ -289,7 +289,58 @@ module Caboose
289
289
  return true if li.variant.taxable && li.variant.taxable == true
290
290
  end
291
291
  return false
292
- end
292
+ end
293
+
294
+ # Authorize and capture funds
295
+ def authorize_and_capture
296
+
297
+ resp = StdClass.new
298
+ if self.financial_status == Invoice::FINANCIAL_STATUS_CAPTURED
299
+ resp.error = "Funds for this invoice have already been captured."
300
+ else
301
+
302
+ sc = self.site.store_config
303
+ case sc.pp_name
304
+ when StoreConfig::PAYMENT_PROCESSOR_STRIPE
305
+
306
+ Stripe.api_key = sc.stripe_secret_key.strip
307
+ bt = nil
308
+ begin
309
+ c = Stripe::Charge.create(
310
+ :amount => (self.total * 100).to_i,
311
+ :currency => 'usd',
312
+ :customer => self.customer.stripe_customer_id,
313
+ :capture => true,
314
+ :metadata => { :invoice_id => self.id },
315
+ :statement_descriptor => "Invoice ##{self.id}"
316
+ )
317
+ rescue Exception => ex
318
+ resp.error = "Error during capture process\n#{ex.message}"
319
+ end
320
+ if resp.error.nil?
321
+ InvoiceTransaction.create(
322
+ :invoice_id => self.id,
323
+ :transaction_id => c.id,
324
+ :transaction_type => InvoiceTransaction::TYPE_AUTHCAP,
325
+ :payment_processor => sc.pp_name,
326
+ :amount => c.amount / 100.0,
327
+ :captured => true,
328
+ :date_processed => DateTime.now.utc,
329
+ :success => c.status == 'succeeded'
330
+ )
331
+ if c.status == 'succeeded'
332
+ self.financial_status = Invoice::FINANCIAL_STATUS_CAPTURED
333
+ self.save
334
+ resp.success = true
335
+ else
336
+ resp.error = "Error capturing funds."
337
+ end
338
+ end
339
+
340
+ end
341
+ end
342
+ return resp
343
+ end
293
344
 
294
345
  # Capture funds from a previously authorized transaction
295
346
  def capture_funds
@@ -4,22 +4,23 @@
4
4
  <%= javascript_include_tag "caboose/model/all" %>
5
5
  <% end %>
6
6
 
7
- <h1>Edit Advertiser</h1>
7
+ <h1>Edit User - <%= @edituser.first_name %> <%= @edituser.last_name %></h1>
8
8
  <ul id='tabs'>
9
9
  <%
10
10
  tabs = {
11
- 'General' => "/admin/advertisers/#{@advertiser.id}",
12
- 'Authorize.net Info' => "/admin/advertisers/#{@advertiser.id}/authnet",
13
- 'Users' => "/admin/advertisers/#{@advertiser.id}/users",
14
- 'Campaigns' => "/admin/advertisers/#{@advertiser.id}/campaigns",
15
- 'Invoices' => "/admin/advertisers/#{@advertiser.id}/invoices",
16
- 'Delete' => "/admin/advertisers/#{@advertiser.id}/delete"
11
+ 'General' => "/admin/users/#{@edituser.id}",
12
+ 'Payment Method' => "/admin/users/#{@edituser.id}/payment-method",
13
+ 'Login Logs' => "/admin/login-logs?user_id=#{@edituser.id}",
14
+ 'Password' => "/admin/users/#{@edituser.id}/password",
15
+ 'Roles' => "/admin/users/#{@edituser.id}/roles",
16
+ 'Delete' => "/admin/users/#{@edituser.id}/delete"
17
17
  }
18
+ tabs = Caboose.plugin_hook('admin_user_tabs', tabs, @edituser, @site)
18
19
  %>
19
20
  <% tabs.each do |text, href| %>
20
21
  <% selected = true if request.fullpath == href || (text != 'General' && request.fullpath.starts_with?(href)) %>
21
22
  <li<% if selected %> class='selected'<% end %>><a href='<%= href %>'><%= raw text %></a></li>
22
23
  <% end %>
23
- <li class='back'><input type='button' value='< Back' onclick="window.location='/admin/advertisers';" /></li>
24
+ <li class='back'><input type='button' value='< Back' onclick="window.location='/admin/users';" /></li>
24
25
  </ul>
25
26
  <div id='content2'>
@@ -0,0 +1,59 @@
1
+
2
+ <%= render :partial => 'caboose/users/admin_header' %>
3
+
4
+ <h1>Delete User</h1>
5
+
6
+ <div id='message'>
7
+ <input type='button' value='Delete User' onclick="delete_user(<%= @edituser.id %>);" />
8
+ </div>
9
+
10
+ <%= render :partial => 'caboose/users/admin_footer' %>
11
+
12
+ <% content_for :caboose_css do %>
13
+ <style type='text/css'>
14
+ </style>
15
+ <% end %>
16
+ <% content_for :caboose_js do %>
17
+ <%= javascript_include_tag "caboose/model/all" %>
18
+ <script type="text/javascript">
19
+
20
+ $(document).ready(function() {
21
+ new ModelBinder({
22
+ name: 'User',
23
+ id: <%= @edituser.id %>,
24
+ update_url: '/admin/users/<%= @edituser.id %>',
25
+ authenticity_token: '<%= form_authenticity_token %>',
26
+ attributes: [
27
+ { name: 'first_name' , nice_name: 'First name', type: 'text' , value: <%= raw Caboose.json(@edituser.first_name) %>, width: 280 },
28
+ { name: 'last_name' , nice_name: 'Last name' , type: 'text' , value: <%= raw Caboose.json(@edituser.last_name) %>, width: 280 },
29
+ { name: 'username' , nice_name: 'Username' , type: 'text' , value: <%= raw Caboose.json(@edituser.username) %>, width: 280 },
30
+ { name: 'email' , nice_name: 'Email' , type: 'text' , value: <%= raw Caboose.json(@edituser.email) %>, width: 280 },
31
+ { name: 'locked' , nice_name: 'Locked' , type: 'checkbox' , value: <%= @edituser.locked ? 1 : 0 %>, width: 280 }
32
+ ]
33
+ });
34
+ });
35
+
36
+ function delete_user(user_id, confirm)
37
+ {
38
+ if (!confirm)
39
+ {
40
+ var p = $('<p/>').addClass('note confirm')
41
+ .append('Are you sure you want to delete the user? ')
42
+ .append($('<input/>').attr('type','button').val('Yes').click(function() { delete_user(user_id, true); })).append(' ')
43
+ .append($('<input/>').attr('type','button').val('No').click(function() { $('#message').empty(); }));
44
+ $('#message').empty().append(p);
45
+ return;
46
+ }
47
+ $('#message').html("<p class='loading'>Deleting user...</p>");
48
+ $.ajax({
49
+ url: '/admin/users/' + user_id,
50
+ type: 'delete',
51
+ success: function(resp) {
52
+ if (resp.error) $('#message').html("<p class='note error'>" + resp.error + "</p>");
53
+ if (resp.redirect) window.location = resp.redirect;
54
+ }
55
+ });
56
+ }
57
+
58
+ </script>
59
+ <% end %>
@@ -2,28 +2,17 @@
2
2
  gravatar_id = Digest::MD5.hexdigest(@edituser.email.downcase)
3
3
  pic = "http://gravatar.com/avatar/#{gravatar_id}.png?s=150" #&d=/assets/caboose/default_user_pic.png"
4
4
  %>
5
- <h1>Edit User</h1>
5
+
6
+ <%= render :partial => 'caboose/users/admin_header' %>
7
+
6
8
  <p id='gravatar'><img src='<%= pic %>' /><a href='http://gravatar.com'>Update on gravatar</a></p>
7
9
  <p><div id='user_<%= @edituser.id %>_first_name' ></div></p>
8
10
  <p><div id='user_<%= @edituser.id %>_last_name' ></div></p>
9
11
  <p><div id='user_<%= @edituser.id %>_username' ></div></p>
10
12
  <p><div id='user_<%= @edituser.id %>_email' ></div></p>
11
13
  <p><div id='user_<%= @edituser.id %>_locked' ></div></p>
12
- <div id='roles'>
13
- <table class='data'>
14
- <% Caboose::Role.flat_tree(@site.id).each do |r| %>
15
- <% is_member = Caboose::RoleMembership.where(:role_id => r.id, :user_id => @edituser.id).exists? %>
16
- <tr><td><input type='checkbox' name='role<%= r.id %>' <%= is_member ? "checked='true'" : '' %> onclick="toggle_role(<%= @edituser.id %>, <%= r.id %>, $(this).prop('checked'));" /></td><td><%= r.name %></td></tr>
17
- <% end %>
18
- </table>
19
- </div>
20
- <div id='message'></div>
21
- <div id='controls'>
22
- <input type='button' value='Back' onclick="window.location='/admin/users';" />
23
- <input type='button' value='Login Logs for this User' onclick="window.location='/admin/login-logs?user_id=<%= @edituser.id %>';" />
24
- <input type='button' value='Reset Password' onclick="window.location='/admin/users/<%= @edituser.id %>/edit-password';" />
25
- <input type='button' value='Delete User' onclick="delete_user(<%= @edituser.id %>);" />
26
- </div>
14
+
15
+ <%= render :partial => 'caboose/users/admin_footer' %>
27
16
 
28
17
  <% content_for :caboose_css do %>
29
18
  <style type='text/css'>
@@ -51,44 +40,12 @@ $(document).ready(function() {
51
40
  });
52
41
  });
53
42
 
54
- function delete_user(user_id, confirm)
55
- {
56
- if (!confirm)
57
- {
58
- var p = $('<p/>').addClass('note confirm')
59
- .append('Are you sure you want to delete the user? ')
60
- .append($('<input/>').attr('type','button').val('Yes').click(function() { delete_user(user_id, true); })).append(' ')
61
- .append($('<input/>').attr('type','button').val('No').click(function() { $('#message').empty(); }));
62
- $('#message').empty().append(p);
63
- return;
64
- }
65
- $('#message').html("<p class='loading'>Deleting user...</p>");
66
- $.ajax({
67
- url: '/admin/users/' + user_id,
68
- type: 'delete',
69
- success: function(resp) {
70
- if (resp.error) $('#message').html("<p class='note error'>" + resp.error + "</p>");
71
- if (resp.redirect) window.location = resp.redirect;
72
- }
73
- });
74
- }
75
-
76
- function toggle_role(user_id, role_id, checked)
77
- {
78
- $.ajax({
79
- url: '/admin/users/' + user_id +'/roles/' + role_id,
80
- type: checked ? 'post' : 'delete',
81
- succes: function(resp) { }
82
- });
83
- }
84
-
85
43
  </script>
86
44
  <% end %>
87
45
 
88
46
  <% content_for :caboose_css do %>
89
47
  <style type='text/css'>
90
- #gravatar {
91
- float: right;
48
+ #gravatar {
92
49
  width: 150px;
93
50
  text-align: right;
94
51
  margin: 0 4px 0 0;
@@ -1,14 +1,15 @@
1
1
 
2
- <h1>Reset Password for <%= "#{@edituser.first_name} #{@edituser.last_name}" %></h1>
2
+ <%= render :partial => 'caboose/users/admin_header' %>
3
+
4
+ <h2>Reset Password for <%= "#{@edituser.first_name} #{@edituser.last_name}" %></h2>
3
5
  <form action='/admin/users/<%= @edituser.id %>' method='put' id='password_form'>
4
6
  <input type='hidden' name='authenticity_token' value='<%= form_authenticity_token %>' />
5
7
  <p><input type='password' name='password' id='password' value="" placeholder='Password' /></p>
6
8
  <p><input type='password' name='password2' id='password2' value="" placeholder='Confirm password' /></p>
7
9
  <div id='message'></div>
8
- <p>
9
- <input type='button' value='Back' onclick="window.location='/admin/users/<%= @edituser.id %>';" />
10
- <input type='button' value='Update Password' onclick="update_password();" />
11
- </p>
10
+ <p><input type='button' value='Update Password' onclick="update_password();" /></p>
11
+
12
+ <%= render :partial => 'caboose/users/admin_footer' %>
12
13
 
13
14
  <% content_for :caboose_js do %>
14
15
  <script type="text/javascript">
@@ -0,0 +1,52 @@
1
+
2
+ <%= render :partial => 'caboose/users/admin_header' %>
3
+
4
+ <div id='payment_method_container'></div>
5
+
6
+ <%= render :partial => 'caboose/users/admin_footer' %>
7
+
8
+ <% content_for :caboose_css do %>
9
+ <style type='text/css'>
10
+
11
+ .stripe_form { width: 400px; }
12
+ .stripe_form .card_number_container { position: relative; width: 100%; } .stripe_form .card_number_container input { padding-left: 30px; height: 37px; font-size: 15px; width: 100%; border-color: #b9b9b9; border-style: solid; border-width: 1px 1px 0px 1px; }
13
+ .stripe_form .card_exp_container { position: relative; width: 50% !important; float: left; } .stripe_form .card_exp_container input { padding-left: 30px; height: 37px; font-size: 15px; width: 100%; border-color: #b9b9b9; border-style: solid; border-width: 1px 1px 0px 1px; }
14
+ .stripe_form .card_cvc_container { position: relative; width: 50%; float: left; } .stripe_form .card_cvc_container input { padding-left: 30px; height: 37px; font-size: 15px; width: 100%; border-color: #b9b9b9; border-style: solid; border-width: 1px 1px 0px 0px; }
15
+ .stripe_form .card_name_container { position: relative; width: 50%; float: left; } .stripe_form .card_name_container input { padding-left: 10px; height: 37px !important; font-size: 15px; width: 100%; border-color: #b9b9b9; border-style: solid; border-width: 1px 0px 1px 1px; }
16
+ .stripe_form .card_zip_container { position: relative; width: 50%; float: left; margin-bottom: 4px; } .stripe_form .card_zip_container input { padding-left: 10px; height: 37px; font-size: 15px; width: 100%; border-color: #b9b9b9; border-style: solid; border-width: 1px 1px 1px 0px; }
17
+
18
+ .stripe_form .card_number_container .icon { position: absolute; top: 3px; left: 1px; transform-origin: 50% 50% 0; pointer-events: none; }
19
+ .stripe_form .card_exp_container .icon { position: absolute; top: 3px; left: 1px; transform-origin: 50% 50% 0; pointer-events: none; }
20
+ .stripe_form .card_cvc_container .icon { position: absolute; top: 3px; left: 1px; transform-origin: 50% 50% 0; pointer-events: none; }
21
+
22
+ .stripe_form .note { width: 100%; margin-bottom: 10px !important; text-align: center; }
23
+ .stripe_form .payment_controls { clear: left; margin-top: 4px !important; }
24
+
25
+ </style>
26
+ <%= stylesheet_link_tag "caboose/my_account", :media => "all" %>
27
+ <% end %>
28
+
29
+ <% content_for :caboose_js do %>
30
+ <%= javascript_include_tag 'https://js.stripe.com/v2/' %>
31
+ <%= javascript_include_tag 'caboose/checkout/stripe_payment_method_controller' %>
32
+ <%= javascript_include_tag 'caboose/model/all' %>
33
+ <%= javascript_include_tag 'caboose/united_states' %>
34
+ <%= javascript_include_tag 'caboose/jquery.payment' %>
35
+ <%= javascript_include_tag 'caboose/card' %>
36
+ <script type='text/javascript'>
37
+
38
+ var controller = false;
39
+ $(document).ready(function() {
40
+ controller = new StripePaymentMethodController({
41
+ cc: {
42
+ invoice: { total: 1.00 },
43
+ print_ready_message: function() {},
44
+ },
45
+ refresh_url: '/admin/users/<%= @edituser.id %>/stripe/json',
46
+ after_update_url: '/admin/users/<%= @edituser.id %>'
47
+ });
48
+ controller.print();
49
+ });
50
+
51
+ </script>
52
+ <% end %>
@@ -0,0 +1,35 @@
1
+
2
+ <%= render :partial => 'caboose/users/admin_header' %>
3
+
4
+ <div id='roles'>
5
+ <table class='data'>
6
+ <% Caboose::Role.flat_tree(@site.id).each do |r| %>
7
+ <% is_member = Caboose::RoleMembership.where(:role_id => r.id, :user_id => @edituser.id).exists? %>
8
+ <tr><td><input type='checkbox' name='role<%= r.id %>' <%= is_member ? "checked='true'" : '' %> onclick="toggle_role(<%= @edituser.id %>, <%= r.id %>, $(this).prop('checked'));" /></td><td><%= r.name %></td></tr>
9
+ <% end %>
10
+ </table>
11
+ </div>
12
+
13
+ <%= render :partial => 'caboose/users/admin_footer' %>
14
+
15
+ <% content_for :caboose_css do %>
16
+ <style type='text/css'>
17
+ #content input[type=checkbox] { position: relative; }
18
+ #roles {}
19
+ </style>
20
+ <% end %>
21
+ <% content_for :caboose_js do %>
22
+ <%= javascript_include_tag "caboose/model/all" %>
23
+ <script type="text/javascript">
24
+
25
+ function toggle_role(user_id, role_id, checked)
26
+ {
27
+ $.ajax({
28
+ url: '/admin/users/' + user_id +'/roles/' + role_id,
29
+ type: checked ? 'post' : 'delete',
30
+ succes: function(resp) { }
31
+ });
32
+ }
33
+
34
+ </script>
35
+ <% end %>
@@ -1,3 +1,3 @@
1
1
  module Caboose
2
- VERSION = '0.8.67'
2
+ VERSION = '0.8.68'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: caboose-cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.67
4
+ version: 0.8.68
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Barry
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-16 00:00:00.000000000 Z
11
+ date: 2016-09-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg
@@ -745,7 +745,6 @@ files:
745
745
  - app/assets/templates/caboose/product/images.jst.ejs
746
746
  - app/assets/templates/caboose/product/images_old.jst.ejs
747
747
  - app/assets/templates/caboose/product/options.jst.ejs
748
- - app/controllers/caboose/#checkout_controller.rb#
749
748
  - app/controllers/caboose/ab_options_controller.rb
750
749
  - app/controllers/caboose/ab_variants_controller.rb
751
750
  - app/controllers/caboose/admin_controller.rb
@@ -1210,8 +1209,11 @@ files:
1210
1209
  - app/views/caboose/subscriptions/admin_index.html.erb
1211
1210
  - app/views/caboose/users/_admin_footer.html.erb
1212
1211
  - app/views/caboose/users/_admin_header.html.erb
1212
+ - app/views/caboose/users/admin_delete_form.html.erb
1213
1213
  - app/views/caboose/users/admin_edit.html.erb
1214
1214
  - app/views/caboose/users/admin_edit_password.html.erb
1215
+ - app/views/caboose/users/admin_edit_payment_method.html.erb
1216
+ - app/views/caboose/users/admin_edit_roles.html.erb
1215
1217
  - app/views/caboose/users/admin_import_form.html.erb
1216
1218
  - app/views/caboose/users/admin_index.html.erb
1217
1219
  - app/views/caboose/users/admin_new.html.erb
@@ -1,464 +0,0 @@
1
- require 'authorize_net'
2
-
3
- module Caboose
4
- class CheckoutController < Caboose::ApplicationController
5
-
6
- before_filter :ensure_line_items, :only => [:step_one, :step_two]
7
- protect_from_forgery
8
-
9
- def ensure_line_items
10
- redirect_to '/checkout/empty' if @invoice.line_items.empty?
11
- end
12
-
13
- # @route GET /checkout/json
14
- def invoice_json
15
- render :json => @invoice.as_json(
16
- :include => [
17
- :customer,
18
- :shipping_address,
19
- :billing_address,
20
- :invoice_transactions,
21
- {
22
- :line_items => {
23
- :include => {
24
- :variant => {
25
- :include => [
26
- { :product_images => { :methods => :urls }},
27
- { :product => { :include => { :product_images => { :methods => :urls }}}}
28
- ],
29
- :methods => :title
30
- }
31
- }
32
- }
33
- },
34
- { :invoice_packages => { :include => [:shipping_package, :shipping_method] }},
35
- { :discounts => { :include => :gift_card }}
36
- ]
37
- )
38
- end
39
-
40
- # @route GET /checkout/stripe/json
41
- def stripe_json
42
- sc = @site.store_config
43
- u = logged_in_user
44
- render :json => {
45
- :stripe_key => sc.stripe_publishable_key.strip,
46
- :customer_id => u.stripe_customer_id,
47
- :card_last4 => u.card_last4,
48
- :card_brand => u.card_brand,
49
- :card_exp_month => u.card_exp_month,
50
- :card_exp_year => u.card_exp_year
51
- }
52
- end
53
-
54
- #===========================================================================
55
-
56
- # Step 1 - Login or register
57
- # @route GET /checkout
58
- def index
59
- if logged_in?
60
- if @invoice.customer_id.nil?
61
- @invoice.customer_id = logged_in_user.id
62
- @invoice.save
63
- end
64
- #redirect_to '/checkout/addresses'
65
- #return
66
-
67
- @invoice.verify_invoice_packages
68
-
69
- # See if any there are any empty invoice packages
70
- #@invoice.invoice_packages.each do |op|
71
- # count = 0
72
- # @invoice.line_items.each do |li|
73
- # count = count + 1 if li.invoice_package_id == op.id
74
- # end
75
- # op.destroy if count == 0
76
- #end
77
- #
78
- ## See if any line items aren't associated with an invoice package
79
- #line_items_attached = true
80
- #@invoice.line_items.each do |li|
81
- # line_items_attached = false if li.invoice_package_id.nil?
82
- #end
83
- #
84
- #ops = @invoice.invoice_packages
85
- #if ops.count == 0 || !line_items_attached
86
- # @invoice.calculate
87
- # LineItem.where(:invoice_id => @invoice.id).update_all(:invoice_package_id => nil)
88
- # InvoicePackage.where(:invoice_id => @invoice.id).destroy_all
89
- # InvoicePackage.create_for_invoice(@invoice)
90
- #end
91
-
92
- #render :file => "caboose/checkout/checkout_#{@site.store_config.pp_name}"
93
- render :file => "caboose/checkout/checkout"
94
- end
95
- end
96
-
97
- # Step 3 - Shipping method
98
- # @route GET /checkout/shipping/json
99
- def shipping_json
100
- render :json => { :error => 'Not logged in.' } and return if !logged_in?
101
- render :json => { :error => 'No shippable items.' } and return if !@invoice.has_shippable_items?
102
- render :json => { :error => 'Empty shipping address.' } and return if @invoice.shipping_address.nil?
103
-
104
- @invoice.calculate
105
-
106
- #ops = @invoice.invoice_packages
107
- #if params[:recalculate_invoice_packages] || ops.count == 0
108
- # # Remove any invoice packages
109
- # LineItem.where(:invoice_id => @invoice.id).update_all(:invoice_package_id => nil)
110
- # InvoicePackage.where(:invoice_id => @invoice.id).destroy_all
111
- #
112
- # # Calculate what shipping packages we'll need
113
- # InvoicePackage.create_for_invoice(@invoice)
114
- #end
115
-
116
- # Now get the rates for those packages
117
- rates = ShippingCalculator.rates(@invoice)
118
- render :json => rates
119
- end
120
-
121
- # Step 5 - Update Stripe Details
122
- # @route PUT /checkout/stripe-details
123
- def update_stripe_details
124
- render :json => false and return if !logged_in?
125
-
126
- sc = @site.store_config
127
- Stripe.api_key = sc.stripe_secret_key.strip
128
-
129
- u = logged_in_user
130
-
131
- c = nil
132
- if u.stripe_customer_id
133
- c = Stripe::Customer.retrieve(u.stripe_customer_id)
134
- begin
135
- c.source = params[:token]
136
- c.save
137
- rescue
138
- c = nil
139
- end
140
- end
141
-
142
- if c.nil?
143
- c = Stripe::Customer.create(
144
- :source => params[:token],
145
- :email => u.email,
146
- :metadata => { :user_id => u.id }
147
- )
148
- end
149
-
150
- u.stripe_customer_id = c.id
151
- u.card_last4 = params[:card][:last4]
152
- u.card_brand = params[:card][:brand]
153
- u.card_exp_month = params[:card][:exp_month]
154
- u.card_exp_year = params[:card][:exp_year]
155
- u.save
156
-
157
- render :json => {
158
- :success => true,
159
- :customer_id => u.stripe_customer_id
160
- }
161
- end
162
-
163
- # @route POST /checkout/confirm
164
- def confirm
165
- render :json => { :error => 'Not logged in.' } and return if !logged_in?
166
- #render :json => { :error => 'Invalid billing address.' } and return if @invoice.billing_address.nil?
167
- render :json => { :error => 'Invalid shipping address.' } and return if @invoice.has_shippable_items? && @invoice.shipping_address.nil?
168
- render :json => { :error => 'Invalid shipping methods.' } and return if @invoice.has_shippable_items? && @invoice.has_empty_shipping_methods?
169
-
170
- resp = Caboose::StdClass.new
171
- sc = @site.store_config
172
-
173
- # Make sure all the variants still exist
174
- @invoice.line_items.each do |li|
175
- v = Variant.where(:id => li.variant_id).first
176
- if v.nil? || v.status == 'Deleted'
177
- render :json => { :error => 'One or more of the products you are purchasing are no longer available.' }
178
- return
179
- end
180
- end
181
-
182
- error = false
183
- requires_payment = @invoice.line_items.count > 0 && @invoice.total > 0 && @invoice.payment_terms == Invoice::PAYMENT_TERMS_PIA
184
- if requires_payment
185
-
186
- ot = nil
187
- case sc.pp_name
188
- when StoreConfig::PAYMENT_PROCESSOR_AUTHNET
189
-
190
- when StoreConfig::PAYMENT_PROCESSOR_STRIPE
191
- Stripe.api_key = sc.stripe_secret_key.strip
192
- begin
193
- c = Stripe::Charge.create(
194
- :amount => (@invoice.total * 100).to_i,
195
- :currency => 'usd',
196
- :customer => logged_in_user.stripe_customer_id,
197
- :capture => false,
198
- :metadata => { :invoice_id => @invoice.id },
199
- :statement_descriptor => "Invoice ##{@invoice.id}"
200
- )
201
- rescue Exception => ex
202
- render :json => { :error => ex.message }
203
- return
204
- end
205
- ot = Caboose::InvoiceTransaction.create(
206
- :invoice_id => @invoice.id,
207
- :transaction_id => c.id,
208
- :transaction_type => c.captured ? Caboose::InvoiceTransaction::TYPE_AUTHCAP : Caboose::InvoiceTransaction::TYPE_AUTHORIZE,
209
- :payment_processor => sc.pp_name,
210
- :amount => c.amount/100.0,
211
- :date_processed => DateTime.now.utc,
212
- :success => c.status == 'succeeded'
213
- )
214
- end
215
-
216
- if !ot.success
217
- render :json => { :error => error }
218
- return
219
- else
220
- @invoice.financial_status = Invoice::FINANCIAL_STATUS_AUTHORIZED
221
- @invoice.take_gift_card_funds
222
- end
223
- end
224
-
225
- @invoice.status = Invoice::STATUS_PENDING
226
- @invoice.invoice_number = @site.store_config.next_invoice_number
227
-
228
- # Send out emails
229
- begin
230
- InvoicesMailer.configure_for_site(@site.id).customer_new_invoice(@invoice).deliver
231
- InvoicesMailer.configure_for_site(@site.id).fulfillment_new_invoice(@invoice).deliver
232
- rescue
233
- puts "=================================================================="
234
- puts "Error sending out invoice confirmation emails for invoice ID #{@invoice.id}"
235
- puts "=================================================================="
236
- end
237
-
238
- # Emit invoice event
239
- Caboose.plugin_hook('invoice_authorized', @invoice) if @invoice.total > 0
240
-
241
- # Save the invoice
242
- @invoice.save
243
-
244
- # Decrement quantities of variants
245
- @invoice.decrement_quantities
246
-
247
- # Clear the cart and re-initialize
248
- session[:cart_id] = nil
249
- init_cart
250
-
251
- resp.success = true
252
- resp.redirect = '/checkout/thanks'
253
- render :json => resp
254
- end
255
-
256
- # @route GET /checkout/thanks
257
- def thanks
258
- @logged_in_user = logged_in_user
259
-
260
- # Find the last invoice for the user
261
- @last_invoice = Invoice.where(:customer_id => @logged_in_user.id).reorder("id desc").limit(1).first
262
- add_ga_event('Ecommerce', 'Checkout', 'Payment', (@last_invoice.total*100).to_i)
263
- end
264
-
265
- #===========================================================================
266
-
267
- # @route GET /checkout/state-options
268
- def state_options
269
- options = Caboose::States.all.collect { |abbr, state| { 'value' => abbr, 'text' => abbr }}
270
- render :json => options
271
- end
272
-
273
- # @route GET /checkout/total
274
- def verify_total
275
- total = 0.00
276
- if logged_in?
277
- @invoice.calculate
278
- total = @invoice.total
279
- end
280
- render :json => total.to_f
281
- end
282
-
283
- # @route GET /checkout/address
284
- def address
285
- render :json => {
286
- :shipping_address => @invoice.shipping_address,
287
- :billing_address => @invoice.billing_address
288
- }
289
- end
290
-
291
- # @route PUT /checkout/addresses
292
- def update_addresses
293
-
294
- # Grab or create addresses
295
- shipping_address = if @invoice.shipping_address then @invoice.shipping_address else Address.new end
296
- billing_address = if @invoice.billing_address then @invoice.billing_address else Address.new end
297
-
298
- has_shippable_items = @invoice.has_shippable_items?
299
-
300
- # Shipping address
301
- if has_shippable_items
302
- shipping_address.first_name = params[:shipping][:first_name]
303
- shipping_address.last_name = params[:shipping][:last_name]
304
- shipping_address.company = params[:shipping][:company]
305
- shipping_address.address1 = params[:shipping][:address1]
306
- shipping_address.address2 = params[:shipping][:address2]
307
- shipping_address.city = params[:shipping][:city]
308
- shipping_address.state = params[:shipping][:state]
309
- shipping_address.zip = params[:shipping][:zip]
310
- end
311
-
312
- # Billing address
313
- if has_shippable_items && params[:use_as_billing]
314
- billing_address.update_attributes(shipping_address.attributes)
315
- else
316
- billing_address.first_name = params[:billing][:first_name]
317
- billing_address.last_name = params[:billing][:last_name]
318
- billing_address.company = params[:billing][:company]
319
- billing_address.address1 = params[:billing][:address1]
320
- billing_address.address2 = params[:billing][:address2]
321
- billing_address.city = params[:billing][:city]
322
- billing_address.state = params[:billing][:state]
323
- billing_address.zip = params[:billing][:zip]
324
- end
325
-
326
- # Save address info; generate ids
327
- render :json => { :success => false, :errors => shipping_address.errors.full_messages, :address => 'shipping' } and return if has_shippable_items && !shipping_address.save
328
- render :json => { :success => false, :errors => billing_address.errors.full_messages, :address => 'billing' } and return if !billing_address.save
329
-
330
- # Associate address info with invoice
331
- @invoice.shipping_address_id = shipping_address.id
332
- @invoice.billing_address_id = billing_address.id
333
-
334
- #render :json => { :redirect => 'checkout/shipping' }
335
- render :json => { :success => @invoice.save, :errors => @invoice.errors.full_messages }
336
- end
337
-
338
- # @route PUT /checkout/shipping-address
339
- def update_shipping_address
340
- resp = Caboose::StdClass.new
341
-
342
- # Grab or create addresses
343
- sa = @invoice.shipping_address
344
- if sa.nil?
345
- sa = Address.create
346
- @invoice.shipping_address_id = sa.id
347
- @invoice.save
348
- end
349
-
350
- save = true
351
- recalc_shipping = false
352
- params.each do |name, value|
353
- case name
354
- when 'address1' then recalc_shipping = true if sa.address1 != value
355
- when 'address2' then recalc_shipping = true if sa.address2 != value
356
- when 'city' then recalc_shipping = true if sa.city != value
357
- when 'state' then recalc_shipping = true if sa.state != value
358
- when 'zip' then recalc_shipping = true if sa.zip != value
359
- end
360
- case name
361
- when 'name' then sa.name = value
362
- when 'first_name' then sa.first_name = value
363
- when 'last_name' then sa.last_name = value
364
- when 'street' then sa.street = value
365
- when 'address1' then sa.address1 = value
366
- when 'address2' then sa.address2 = value
367
- when 'company' then sa.company = value
368
- when 'city' then sa.city = value
369
- when 'state' then sa.state = value
370
- when 'province' then sa.province = value
371
- when 'province_code' then sa.province_code = value
372
- when 'zip' then sa.zip = value
373
- when 'country' then sa.country = value
374
- when 'country_code' then sa.country_code = value
375
- when 'phone' then sa.phone = value
376
- end
377
- end
378
- if recalc_shipping
379
- @invoice.invoice_packages.each do |op|
380
- op.shipping_method_id = nil
381
- op.total = nil
382
- op.save
383
- end
384
- end
385
-
386
- resp.success = save && sa.save
387
- render :json => resp
388
- end
389
-
390
- # @route PUT /checkout/billing-address
391
- def update_billing_address
392
-
393
- # Grab or create addresses
394
- ba = @invoice.billing_address
395
- if ba.nil?
396
- ba = Address.create
397
- @invoice.billing_address_id = ba.id
398
- @invoice.save
399
- end
400
-
401
- ba.first_name = params[:first_name]
402
- ba.last_name = params[:last_name]
403
- ba.company = params[:company]
404
- ba.address1 = params[:address1]
405
- ba.address2 = params[:address2]
406
- ba.city = params[:city]
407
- ba.state = params[:state]
408
- ba.zip = params[:zip]
409
- ba.save
410
-
411
- render :json => { :success => true }
412
- end
413
-
414
- # @route POST /checkout/attach-user
415
- def attach_user
416
- render :json => { :success => false, :errors => ['User is not logged in'] } and return if !logged_in?
417
- @invoice.customer_id = logged_in_user.id
418
- #Caboose.log("Attaching user to invoice: customer_id = #{@invoice.customer_id}")
419
- render :json => { :success => @invoice.save, :errors => @invoice.errors.full_messages, :logged_in => logged_in? }
420
- end
421
-
422
- # @route POST /checkout/guest
423
- def attach_guest
424
- resp = Caboose::StdClass.new
425
- email = params[:email]
426
-
427
- if email != params[:confirm_email]
428
- resp.error = "Emails do not match."
429
- elsif Caboose::User.where(:email => email, :is_guest => false).exists?
430
- resp.error = "A user with that email address already exists."
431
- else
432
- user = Caboose::User.where(:email => email, :is_guest => true).first
433
- if user.nil?
434
- user = Caboose::User.create(:email => email)
435
- user.is_guest = true
436
- user.save
437
- user = Caboose::User.where(:email => email).first
438
- end
439
- @invoice.customer_id = user.id
440
- login_user(user)
441
-
442
- if !@invoice.valid?
443
- resp.errors = @invoice.errors.full_messages
444
- else
445
- @invoice.save
446
- resp.redirect = '/checkout/addresses'
447
- end
448
- end
449
- render :json => resp
450
- end
451
-
452
- # @route PUT /checkout/shipping
453
- def update_shipping
454
- op = InvoicePackage.find(params[:invoice_package_id])
455
- op.shipping_method_id = params[:shipping_method_id]
456
- op.total = params[:total]
457
- op.save
458
- op.invoice.calculate
459
-
460
- render :json => { :success => true }
461
- end
462
-
463
- end
464
- end