payola-payments 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/payola/checkout_button.js +9 -9
  3. data/app/assets/javascripts/payola/form.js +6 -6
  4. data/app/assets/javascripts/payola/subscription_form.js +6 -6
  5. data/app/controllers/concerns/payola/affiliate_behavior.rb +17 -0
  6. data/app/controllers/concerns/payola/async_behavior.rb +36 -0
  7. data/app/controllers/payola/subscriptions_controller.rb +31 -46
  8. data/app/controllers/payola/transactions_controller.rb +16 -32
  9. data/app/mailers/payola/admin_mailer.rb +7 -15
  10. data/app/mailers/payola/receipt_mailer.rb +2 -0
  11. data/app/models/concerns/payola/guid_behavior.rb +20 -0
  12. data/app/models/concerns/payola/plan.rb +0 -1
  13. data/app/models/payola/sale.rb +6 -12
  14. data/app/models/payola/subscription.rb +9 -12
  15. data/app/services/payola/charge_card.rb +42 -33
  16. data/app/services/payola/create_plan.rb +2 -2
  17. data/app/services/payola/invoice_behavior.rb +55 -0
  18. data/app/services/payola/invoice_failed.rb +4 -29
  19. data/app/services/payola/invoice_paid.rb +4 -31
  20. data/lib/payola.rb +13 -11
  21. data/lib/payola/version.rb +1 -1
  22. data/spec/concerns/plan_spec.rb +0 -5
  23. data/spec/controllers/payola/subscriptions_controller_spec.rb +10 -1
  24. data/spec/controllers/payola/transactions_controller_spec.rb +10 -1
  25. data/spec/dummy/app/models/subscription_plan_without_interval_count.rb +3 -0
  26. data/spec/dummy/config/environments/test.rb +2 -0
  27. data/spec/dummy/db/development.sqlite3 +0 -0
  28. data/spec/dummy/db/migrate/20141120170744_create_subscription_plan_without_interval_counts.rb +12 -0
  29. data/spec/dummy/db/schema.rb +10 -1
  30. data/spec/dummy/db/test.sqlite3 +0 -0
  31. data/spec/dummy/log/development.log +222 -0
  32. data/spec/dummy/log/test.log +15830 -141203
  33. data/spec/factories/subscription_plan.rb +7 -0
  34. data/spec/mailers/payola/admin_mailer_spec.rb +35 -0
  35. data/spec/mailers/payola/receipt_mailer_spec.rb +52 -0
  36. data/spec/models/payola/subscription_spec.rb +21 -0
  37. data/spec/payola_spec.rb +6 -2
  38. data/spec/services/payola/create_plan_spec.rb +9 -0
  39. data/spec/services/payola/process_sale_spec.rb +15 -0
  40. data/spec/services/payola/process_subscription_spec.rb +15 -0
  41. data/spec/services/payola/send_mail_spec.rb +25 -0
  42. data/spec/spec_helper.rb +13 -0
  43. data/spec/worker_spec.rb +55 -0
  44. metadata +40 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d521cb632f52fe32dbb63dd06926fd551fb0f44b
4
- data.tar.gz: 6c9f77ab172e04d2b89cb4fe8c257ec2ae4efcb7
3
+ metadata.gz: 4c4d4f9f5bd8ecf269a31f484690a7fdd910e39d
4
+ data.tar.gz: 4caf45459de1c9d0913cd6c025d86cf96ea805aa
5
5
  SHA512:
6
- metadata.gz: a27328550b968b7824f42f91b8fafe9562cf9fef30bc5b482e752aa83f2822f396664579ed3983ead027b577863a81cc4c464bcc22a6c7e1bb3a51720824c34b
7
- data.tar.gz: 1fe5bcdc56753e6887a1bd70cc8465bd4c1fb807be1c6802b7e6258ee76c4f076f2dab9cb9a53a437459204ffaf45fed790c459bd03f12665779280de08a4340
6
+ metadata.gz: 14920d40f2f7d4ebaeadfc6e34c75dea86a277eecf3d2f0e44f6e85e2106a0ef16e63f90b32fb2adec4099137572950f2a64e2882259e01d3ac0898b49e61118
7
+ data.tar.gz: 598088dfc2c1a12c955e801522ff2ec8c21c04846971df7f399635b5eee9f1e14ac9b32f5d5d570993975269fe8accfe57977555763ea39608aa517d780e6a23
@@ -7,13 +7,13 @@ var PayolaCheckout = {
7
7
  },
8
8
 
9
9
  handleCheckoutButtonClick: function(button) {
10
- form = button.parent('form');
11
- options = form.data();
10
+ var form = button.parent('form');
11
+ var options = form.data();
12
12
 
13
13
  var handler = StripeCheckout.configure({
14
14
  key: options.publishable_key,
15
15
  image: options.product_image_path,
16
- token: function(token) { PayolaCheckout.tokenHandler(token, options) },
16
+ token: function(token) { PayolaCheckout.tokenHandler(token, options); },
17
17
  name: options.name,
18
18
  description: options.description,
19
19
  amount: options.price,
@@ -45,8 +45,8 @@ var PayolaCheckout = {
45
45
  type: "POST",
46
46
  url: options.base_path + "/buy/" + options.product_class + "/" + options.product_permalink,
47
47
  data: form.serialize(),
48
- success: function(data) { PayolaCheckout.poll(data.guid, 60, options) },
49
- error: function(data) { PayolaCheckout.showError(data.responseJSON.error, options) }
48
+ success: function(data) { PayolaCheckout.poll(data.guid, 60, options); },
49
+ error: function(data) { PayolaCheckout.showError(data.responseJSON.error, options); }
50
50
  });
51
51
  },
52
52
 
@@ -60,7 +60,7 @@ var PayolaCheckout = {
60
60
  },
61
61
 
62
62
  poll: function(guid, num_retries_left, options) {
63
- if (num_retries_left == 0) {
63
+ if (num_retries_left === 0) {
64
64
  PayolaCheckout.showError("This seems to be taking too long. Please contact support and give them transaction ID: " + guid, options);
65
65
  return;
66
66
  }
@@ -71,9 +71,9 @@ var PayolaCheckout = {
71
71
  } else if (data.status === "errored") {
72
72
  PayolaCheckout.showError(data.error, options);
73
73
  } else {
74
- setTimeout(function() { PayolaCheckout.poll(guid, num_retries_left - 1, options) }, 500);
74
+ setTimeout(function() { PayolaCheckout.poll(guid, num_retries_left - 1, options); }, 500);
75
75
  }
76
76
  });
77
77
  }
78
- }
79
- PayolaCheckout.initialize();
78
+ };
79
+ $(function() { PayolaCheckout.initialize(); });
@@ -34,15 +34,15 @@ var PayolaPaymentForm = {
34
34
  type: "POST",
35
35
  url: base_path + "/buy/" + product + "/" + permalink,
36
36
  data: data_form.serialize(),
37
- success: function(data) { PayolaPaymentForm.poll(form, 60, data.guid, base_path) },
38
- error: function(data) { PayolaPaymentForm.showError(form, data.responseJSON.error) }
37
+ success: function(data) { PayolaPaymentForm.poll(form, 60, data.guid, base_path); },
38
+ error: function(data) { PayolaPaymentForm.showError(form, data.responseJSON.error); }
39
39
  });
40
40
  }
41
41
  },
42
42
 
43
43
  poll: function(form, num_retries_left, guid, base_path) {
44
- if (num_retries_left == 0) {
45
- PayolaPaymentForm.showError(form, "This seems to be taking too long. Please contact support and give them transaction ID: " + guid)
44
+ if (num_retries_left === 0) {
45
+ PayolaPaymentForm.showError(form, "This seems to be taking too long. Please contact support and give them transaction ID: " + guid);
46
46
  }
47
47
  $.get(base_path + '/status/' + guid, function(data) {
48
48
  if (data.status === "finished") {
@@ -52,7 +52,7 @@ var PayolaPaymentForm = {
52
52
  } else if (data.status === "errored") {
53
53
  PayolaPaymentForm.showError(form, data.error);
54
54
  } else {
55
- setTimeout(function() { PayolaPaymentForm.poll(form, num_retries_left - 1, guid, base_path) }, 500);
55
+ setTimeout(function() { PayolaPaymentForm.poll(form, num_retries_left - 1, guid, base_path); }, 500);
56
56
  }
57
57
  });
58
58
  },
@@ -68,4 +68,4 @@ var PayolaPaymentForm = {
68
68
  }
69
69
  };
70
70
 
71
- $(function() { PayolaPaymentForm.initialize() } );
71
+ $(function() { PayolaPaymentForm.initialize(); } );
@@ -35,15 +35,15 @@ var PayolaSubscriptionForm = {
35
35
  type: "POST",
36
36
  url: base_path + "/subscribe/" + plan_type + "/" + plan_id,
37
37
  data: data_form.serialize(),
38
- success: function(data) { PayolaSubscriptionForm.poll(form, 60, data.guid, base_path) },
39
- error: function(data) { PayolaSubscriptionForm.showError(form, data.responseJSON.error) }
38
+ success: function(data) { PayolaSubscriptionForm.poll(form, 60, data.guid, base_path); },
39
+ error: function(data) { PayolaSubscriptionForm.showError(form, data.responseJSON.error); }
40
40
  });
41
41
  }
42
42
  },
43
43
 
44
44
  poll: function(form, num_retries_left, guid, base_path) {
45
- if (num_retries_left == 0) {
46
- PayolaSubscriptionForm.showError(form, "This seems to be taking too long. Please contact support and give them transaction ID: " + guid)
45
+ if (num_retries_left === 0) {
46
+ PayolaSubscriptionForm.showError(form, "This seems to be taking too long. Please contact support and give them transaction ID: " + guid);
47
47
  }
48
48
  $.get(base_path + '/subscription_status/' + guid, function(data) {
49
49
  if (data.status === "active") {
@@ -53,7 +53,7 @@ var PayolaSubscriptionForm = {
53
53
  } else if (data.status === "errored") {
54
54
  PayolaSubscriptionForm.showError(form, data.error);
55
55
  } else {
56
- setTimeout(function() { PayolaSubscriptionForm.poll(form, num_retries_left - 1, guid, base_path) }, 500);
56
+ setTimeout(function() { PayolaSubscriptionForm.poll(form, num_retries_left - 1, guid, base_path); }, 500);
57
57
  }
58
58
  });
59
59
  },
@@ -71,4 +71,4 @@ var PayolaSubscriptionForm = {
71
71
  }
72
72
  };
73
73
 
74
- $(function() { PayolaSubscriptionForm.initialize() } );
74
+ $(function() { PayolaSubscriptionForm.initialize(); } );
@@ -0,0 +1,17 @@
1
+ module Payola
2
+ module AffiliateBehavior
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ before_filter :find_affiliate
7
+ end
8
+
9
+ def find_affiliate
10
+ affiliate_code = cookies[:aff] || params[:aff]
11
+ @affiliate = Affiliate.where('lower(code) = lower(?)', affiliate_code).first
12
+ if @affiliate
13
+ cookies[:aff] = affiliate_code
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,36 @@
1
+ module Payola
2
+ module AsyncBehavior
3
+ extend ActiveSupport::Concern
4
+
5
+ def show_object(object_class)
6
+ object = object_class.find_by!(guid: params[:guid])
7
+ redirector = object.redirector
8
+
9
+ new_path = redirector.respond_to?(:redirect_path) ? redirector.redirect_path(object) : '/'
10
+ redirect_to new_path
11
+ end
12
+
13
+ def object_status(object_class)
14
+ object = object_class.find_by(guid: params[:guid])
15
+ render nothing: true, status: 404 and return unless object
16
+ render json: {guid: object.guid, status: object.state, error: object.error}
17
+ end
18
+
19
+ def create_object(object_class, object_creator_class, object_processor_class, product_key, product)
20
+ create_params = params.permit!.merge(
21
+ product_key => product,
22
+ coupon: @coupon,
23
+ affiliate: @affiliate
24
+ )
25
+
26
+ object = object_creator_class.call(create_params)
27
+
28
+ if object.save
29
+ Payola.queue!(object_processor_class, object.guid)
30
+ render json: { guid: object.guid }
31
+ else
32
+ render json: { error: object.errors.full_messages.join(". ") }, status: 400
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,37 +1,21 @@
1
1
  module Payola
2
2
  class SubscriptionsController < ApplicationController
3
- before_filter :find_plan_and_coupon_and_affiliate, only: [:create, :change_plan]
3
+ include Payola::AffiliateBehavior
4
+ include Payola::AsyncBehavior
5
+
6
+ before_filter :find_plan_and_coupon, only: [:create, :change_plan]
4
7
  before_filter :check_modify_permissions, only: [:destroy, :change_plan, :update_card]
5
8
 
6
9
  def show
7
- subscription = Subscription.find_by!(guid: params[:guid])
8
- plan = subscription.plan
9
-
10
- new_path = plan.respond_to?(:redirect_path) ? plan.redirect_path(subscription) : '/'
11
- redirect_to new_path
10
+ show_object(Subscription)
12
11
  end
13
12
 
14
13
  def status
15
- @subscription = Subscription.where(guid: params[:guid]).first
16
- render nothing: true, status: 404 and return unless @subscription
17
- render json: {guid: @subscription.guid, status: @subscription.state, error: @subscription.error}
14
+ object_status(Subscription)
18
15
  end
19
16
 
20
17
  def create
21
- create_params = params.permit!.merge(
22
- plan: @plan,
23
- coupon: @coupon,
24
- affiliate: @affiliate
25
- )
26
-
27
- @subscription = CreateSubscription.call(create_params)
28
-
29
- if @subscription.save
30
- Payola.queue!(Payola::ProcessSubscription, @subscription.guid)
31
- render json: { guid: @subscription.guid }
32
- else
33
- render json: { error: @subscription.errors.full_messages.join(". ") }, status: 400
34
- end
18
+ create_object(Subscription, CreateSubscription, ProcessSubscription, :plan, @plan)
35
19
  end
36
20
 
37
21
  def destroy
@@ -41,44 +25,36 @@ module Payola
41
25
  end
42
26
 
43
27
  def change_plan
44
- subscription = Subscription.find_by!(guid: params[:guid])
45
- Payola::ChangeSubscriptionPlan.call(subscription, @plan)
28
+ @subscription = Subscription.find_by!(guid: params[:guid])
29
+ Payola::ChangeSubscriptionPlan.call(@subscription, @plan)
46
30
 
47
- if subscription.valid?
48
- redirect_to confirm_subscription_path(subscription), notice: "Subscription plan updated"
49
- else
50
- redirect_to confirm_subscription_path(subscription), alert: subscription.errors.full_messages.to_sentence
51
- end
31
+ confirm_with_message("Subscription plan updated")
52
32
  end
53
33
 
54
34
  def update_card
55
- subscription = Subscription.find_by!(guid: params[:guid])
56
- Payola::UpdateCard.call(subscription, params[:stripeToken])
35
+ @subscription = Subscription.find_by!(guid: params[:guid])
36
+ Payola::UpdateCard.call(@subscription, params[:stripeToken])
57
37
 
58
- if subscription.valid?
59
- redirect_to confirm_subscription_path(subscription), notice: "Card updated"
60
- else
61
- redirect_to confirm_subscription_path(subscription), alert: subscription.errors.full_messages.to_sentence
62
- end
38
+ confirm_with_message("Card updated")
63
39
  end
64
40
 
65
41
  private
66
42
 
67
- def find_plan_and_coupon_and_affiliate
43
+ def find_plan_and_coupon
44
+ find_plan
45
+ find_coupon
46
+ end
47
+
48
+ def find_plan
68
49
  @plan_class = Payola.subscribables[params[:plan_class]]
69
50
 
70
51
  raise ActionController::RoutingError.new('Not Found') unless @plan_class && @plan_class.subscribable?
71
52
 
72
53
  @plan = @plan_class.find_by!(id: params[:plan_id])
73
-
74
- @coupon = cookies[:cc] || params[:cc] || params[:coupon_code] || params[:coupon]
75
-
76
- affiliate_code = cookies[:aff] || params[:aff]
77
- @affiliate = Affiliate.where('lower(code) = lower(?)', affiliate_code).first
78
- if @affiliate
79
- cookies[:aff] = affiliate_code
80
- end
54
+ end
81
55
 
56
+ def find_coupon
57
+ @coupon = cookies[:cc] || params[:cc] || params[:coupon_code] || params[:coupon]
82
58
  end
83
59
 
84
60
  def check_modify_permissions
@@ -90,5 +66,14 @@ module Payola
90
66
  ) and return unless self.payola_can_modify_subscription?(subscription)
91
67
  end
92
68
  end
69
+
70
+ def confirm_with_message(message)
71
+ if @subscription.valid?
72
+ redirect_to confirm_subscription_path(@subscription), notice: message
73
+ else
74
+ redirect_to confirm_subscription_path(@subscription), alert: @subscription.errors.full_messages.to_sentence
75
+ end
76
+ end
77
+
93
78
  end
94
79
  end
@@ -1,47 +1,38 @@
1
1
  module Payola
2
2
  class TransactionsController < ApplicationController
3
- before_filter :find_product_and_coupon_and_affiliate, only: [:create]
3
+ include Payola::AffiliateBehavior
4
+ include Payola::AsyncBehavior
4
5
 
5
- def show
6
- sale = Sale.find_by!(guid: params[:guid])
7
- product = sale.product
6
+ before_filter :find_product_and_coupon, only: [:create]
8
7
 
9
- new_path = product.respond_to?(:redirect_path) ? product.redirect_path(sale) : '/'
10
- redirect_to new_path
8
+ def show
9
+ show_object(Sale)
11
10
  end
12
11
 
13
12
  def status
14
- @sale = Sale.where(guid: params[:guid]).first
15
- render nothing: true, status: 404 and return unless @sale
16
- render json: {guid: @sale.guid, status: @sale.state, error: @sale.error}
13
+ object_status(Sale)
17
14
  end
18
15
 
19
16
  def create
20
- create_params = params.permit!.merge(
21
- product: @product,
22
- coupon: @coupon,
23
- affiliate: @affiliate
24
- )
25
-
26
- @sale = CreateSale.call(create_params)
27
-
28
- if @sale.save
29
- Payola.queue!(Payola::ProcessSale, @sale.guid)
30
- render json: { guid: @sale.guid }
31
- else
32
- render json: { error: @sale.errors.full_messages.join(". ") }, status: 400
33
- end
17
+ create_object(Sale, CreateSale, ProcessSale, :product, @product)
34
18
  end
35
19
 
36
20
  private
37
- def find_product_and_coupon_and_affiliate
21
+ def find_product_and_coupon
22
+ find_product
23
+ find_coupon
24
+ end
25
+
26
+ def find_product
38
27
  @product_class = Payola.sellables[params[:product_class]]
39
28
 
40
29
  raise ActionController::RoutingError.new('Not Found') unless @product_class && @product_class.sellable?
41
30
 
42
31
  @product = @product_class.find_by!(permalink: params[:permalink])
43
- coupon_code = cookies[:cc] || params[:cc] || params[:coupon_code]
32
+ end
44
33
 
34
+ def find_coupon
35
+ coupon_code = cookies[:cc] || params[:cc] || params[:coupon_code]
45
36
  @coupon = Coupon.where('lower(code) = lower(?)', coupon_code).first
46
37
  if @coupon
47
38
  cookies[:cc] = coupon_code
@@ -49,13 +40,6 @@ module Payola
49
40
  else
50
41
  @price = @product.price
51
42
  end
52
-
53
- affiliate_code = cookies[:aff] || params[:aff]
54
- @affiliate = Affiliate.where('lower(code) = lower(?)', affiliate_code).first
55
- if @affiliate
56
- cookies[:aff] = affiliate_code
57
- end
58
-
59
43
  end
60
44
 
61
45
  end
@@ -3,30 +3,22 @@ module Payola
3
3
  helper Payola::PriceHelper
4
4
 
5
5
  def receipt(sale_guid)
6
- ActiveRecord::Base.connection_pool.with_connection do
7
- @sale = Payola::Sale.find_by(guid: sale_guid)
8
- @product = @sale.product
9
- mail(from: Payola.support_email, to: Payola.support_email)
10
- end
6
+ send_admin_mail(sale_guid)
11
7
  end
12
8
 
13
9
  def refund(sale_guid)
14
- ActiveRecord::Base.connection_pool.with_connection do
15
- @sale = Payola::Sale.find_by(guid: sale_guid)
16
- @product = @sale.product
17
- mail(from: Payola.support_email, to: Payola.support_email)
18
- end
10
+ send_admin_mail(sale_guid)
19
11
  end
20
12
 
21
13
  def dispute(sale_guid)
22
- ActiveRecord::Base.connection_pool.with_connection do
23
- @sale = Payola::Sale.find_by(guid: sale_guid)
24
- @product = @sale.product
25
- mail(from: Payola.support_email, to: Payola.support_email)
26
- end
14
+ send_admin_mail(sale_guid)
27
15
  end
28
16
 
29
17
  def failure(sale_guid)
18
+ send_admin_mail(sale_guid)
19
+ end
20
+
21
+ def send_admin_mail(sale_guid)
30
22
  ActiveRecord::Base.connection_pool.with_connection do
31
23
  @sale = Payola::Sale.find_by(guid: sale_guid)
32
24
  @product = @sale.product
@@ -9,6 +9,8 @@ module Payola
9
9
  @product = @sale.product
10
10
 
11
11
  if Payola.pdf_receipt
12
+ require 'docverter'
13
+
12
14
  pdf = Docverter::Conversion.run do |c|
13
15
  c.from = 'html'
14
16
  c.to = 'pdf'
@@ -0,0 +1,20 @@
1
+ require 'active_support/concern'
2
+
3
+ module Payola
4
+ module GuidBehavior
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ before_save :populate_guid
9
+ validates_uniqueness_of :guid
10
+ end
11
+
12
+ def populate_guid
13
+ if new_record?
14
+ while !valid? || self.guid.nil?
15
+ self.guid = Payola.guid_generator.call
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end