payola-payments 1.1.4 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +5 -13
  2. data/app/assets/javascripts/payola/form.js +1 -0
  3. data/app/assets/javascripts/payola/subscription_form.js +74 -0
  4. data/app/controllers/payola/application_controller.rb +1 -2
  5. data/app/controllers/payola/subscriptions_controller.rb +94 -0
  6. data/app/models/concerns/payola/plan.rb +50 -0
  7. data/app/models/payola/subscription.rb +161 -0
  8. data/app/services/payola/cancel_subscription.rb +12 -0
  9. data/app/services/payola/change_subscription_plan.rb +29 -0
  10. data/app/services/payola/create_plan.rb +17 -0
  11. data/app/services/payola/create_subscription.rb +20 -0
  12. data/app/services/payola/invoice_failed.rb +42 -0
  13. data/app/services/payola/invoice_paid.rb +43 -0
  14. data/app/services/payola/process_subscription.rb +7 -0
  15. data/app/services/payola/start_subscription.rb +41 -0
  16. data/app/services/payola/sync_subscription.rb +11 -0
  17. data/app/services/payola/update_card.rb +27 -0
  18. data/app/services/payola/update_subscription.rb +11 -0
  19. data/app/views/payola/subscriptions/_cancel.html.erb +10 -0
  20. data/app/views/payola/subscriptions/_change_plan.html.erb +10 -0
  21. data/config/routes.rb +7 -0
  22. data/db/migrate/20141105043439_create_payola_subscriptions.rb +31 -0
  23. data/db/migrate/20141106034610_add_currency_to_payola_subscriptions.rb +6 -0
  24. data/db/migrate/20141107025420_add_guid_to_payola_subscriptions.rb +6 -0
  25. data/db/migrate/20141109203101_add_stripe_status_to_payola_subscription.rb +5 -0
  26. data/db/migrate/20141112024805_add_affiliate_id_to_payola_subscriptions.rb +5 -0
  27. data/db/migrate/20141114032013_add_coupon_code_to_payola_subscriptions.rb +5 -0
  28. data/db/migrate/20141114154223_add_signed_custom_fields_to_payola_subscription.rb +5 -0
  29. data/db/migrate/20141114163841_add_addresses_to_payola_subscription.rb +6 -0
  30. data/lib/payola.rb +11 -0
  31. data/lib/payola/engine.rb +10 -2
  32. data/lib/payola/version.rb +1 -1
  33. data/spec/concerns/plan_spec.rb +43 -0
  34. data/spec/controllers/payola/subscriptions_controller_spec.rb +148 -0
  35. data/spec/dummy/app/controllers/application_controller.rb +4 -0
  36. data/spec/dummy/app/controllers/home_controller.rb +6 -0
  37. data/spec/dummy/app/controllers/subscribe_controller.rb +11 -0
  38. data/spec/dummy/app/models/subscription_plan.rb +3 -0
  39. data/spec/dummy/app/views/home/index.html.erb +7 -0
  40. data/spec/dummy/app/views/subscribe/index.html.erb +21 -0
  41. data/spec/dummy/app/views/subscribe/show.html.erb +4 -0
  42. data/spec/dummy/config/initializers/payola.rb +4 -0
  43. data/spec/dummy/config/routes.rb +4 -0
  44. data/spec/dummy/db/development.sqlite3 +0 -0
  45. data/spec/dummy/db/migrate/20141105010234_create_subscription_plans.rb +14 -0
  46. data/spec/dummy/db/schema.rb +51 -1
  47. data/spec/dummy/db/test.sqlite3 +0 -0
  48. data/spec/dummy/log/development.log +275 -0
  49. data/spec/dummy/log/test.log +109420 -0
  50. data/spec/dummy/tmp/cache/assets/development/sprockets/0e585aeb88c1555ae8f5292f7c7a9068 +0 -0
  51. data/spec/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  52. data/spec/dummy/tmp/cache/assets/development/sprockets/1b54952339cbc96811097cee5f8923b4 +0 -0
  53. data/spec/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  54. data/spec/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  55. data/spec/dummy/tmp/cache/assets/development/sprockets/5afa4bc970e0bc781b3500c696ba25ff +0 -0
  56. data/spec/dummy/tmp/cache/assets/development/sprockets/664efeb51d1b486dcfc30d142db56f3c +0 -0
  57. data/spec/dummy/tmp/cache/assets/development/sprockets/68a3bbdc64a0729b5896fa1e33fce4b1 +0 -0
  58. data/spec/dummy/tmp/cache/assets/development/sprockets/96b1ccdc193a02b2bbea195310262fa5 +0 -0
  59. data/spec/dummy/tmp/cache/assets/development/sprockets/aea159adbc0944b120d91d5b578612ba +0 -0
  60. data/spec/dummy/tmp/cache/assets/development/sprockets/b20dab973e971c61bc7e334a38453ae0 +0 -0
  61. data/spec/dummy/tmp/cache/assets/development/sprockets/b83da90cb58011313e13a97a4a41cb6e +0 -0
  62. data/spec/dummy/tmp/cache/assets/development/sprockets/c0b954b40f2881a6d286061bc069643e +0 -0
  63. data/spec/dummy/tmp/cache/assets/development/sprockets/c5b3877d49b39932a7557611cefca9a6 +0 -0
  64. data/spec/dummy/tmp/cache/assets/development/sprockets/ca491e325ff6948be9292f701aa4ce64 +0 -0
  65. data/spec/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  66. data/spec/dummy/tmp/cache/assets/development/sprockets/d3f4b67cc032016dfeebc71f2148b9dc +0 -0
  67. data/spec/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  68. data/spec/dummy/tmp/cache/assets/development/sprockets/d9856638a3c7b9cfd9d1b884e3b33982 +0 -0
  69. data/spec/dummy/tmp/cache/assets/development/sprockets/ddba6e841f28d3005e828fbfffd18b74 +0 -0
  70. data/spec/dummy/tmp/cache/assets/development/sprockets/df935e399019055729aa968bd7062096 +0 -0
  71. data/spec/dummy/tmp/cache/assets/development/sprockets/ef82c31948061751bb026663b54484e1 +0 -0
  72. data/spec/dummy/tmp/cache/assets/development/sprockets/f0b5d4bea0c6cdd1904e1e9a0a45532f +0 -0
  73. data/spec/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  74. data/spec/factories/payola_subscriptions.rb +25 -0
  75. data/spec/factories/subscription_plan.rb +9 -0
  76. data/spec/models/payola/subscription_spec.rb +50 -0
  77. data/spec/services/payola/cancel_subscription_spec.rb +29 -0
  78. data/spec/services/payola/change_subscription_plan_spec.rb +31 -0
  79. data/spec/services/payola/charge_card_spec.rb +9 -5
  80. data/spec/services/payola/create_plan_spec.rb +24 -0
  81. data/spec/services/payola/create_subscription_spec.rb +65 -0
  82. data/spec/services/payola/invoice_failed_spec.rb +29 -0
  83. data/spec/services/payola/invoice_paid_spec.rb +49 -0
  84. data/spec/services/payola/start_subscription_spec.rb +36 -0
  85. data/spec/services/payola/sync_subscription_spec.rb +14 -0
  86. data/spec/services/payola/update_card_spec.rb +26 -0
  87. metadata +95 -30
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- OGQyNWRjNTdhYmQyNGU4MjFkNzM4MzY0MzZjNWM4YjU2NzRhMWU2MA==
5
- data.tar.gz: !binary |-
6
- N2Q0MmIyZmJiOGJhYThjOWUyYTlhM2Q4NTc4Mjg3MWQxMGFiMDQ2Mw==
2
+ SHA1:
3
+ metadata.gz: d521cb632f52fe32dbb63dd06926fd551fb0f44b
4
+ data.tar.gz: 6c9f77ab172e04d2b89cb4fe8c257ec2ae4efcb7
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NDE0NjlkYmJkMzkyYjI5MGQ2ZGI5ODg0ODU4ZWUxM2IwNzhkODQ4MjVlYTQy
10
- MTU1NmM2NzcyMTAzZDllOThhNzE2MTIwZGJhYzkzY2UyZjNkMmFkZGIzMzNi
11
- ZTU1MDIzOWFkNmE3M2Y0ODJhNDU0Y2E4YmJiMDQ4M2IwNzVhYWU=
12
- data.tar.gz: !binary |-
13
- ZDc2YzBjYmExZTYzM2Y2MGQyNDJlYzAwZWZmZTBlYmQ2Nzg2MmFkMWZmODFm
14
- MzY4ZTdlNjU2ZGJkYmJkMDQ2OTcwNTk0YTBlMjYzNjE0ZDI2YWMzYTJlZWE3
15
- MTM3M2ZhMDExY2UyMDNmMTk0YjRmZjhkMWRiMWI2MjMxOTMxZDA=
6
+ metadata.gz: a27328550b968b7824f42f91b8fafe9562cf9fef30bc5b482e752aa83f2822f396664579ed3983ead027b577863a81cc4c464bcc22a6c7e1bb3a51720824c34b
7
+ data.tar.gz: 1fe5bcdc56753e6887a1bd70cc8465bd4c1fb807be1c6802b7e6258ee76c4f076f2dab9cb9a53a437459204ffaf45fed790c459bd03f12665779280de08a4340
@@ -47,6 +47,7 @@ var PayolaPaymentForm = {
47
47
  $.get(base_path + '/status/' + guid, function(data) {
48
48
  if (data.status === "finished") {
49
49
  form.append($('<input type="hidden" name="payola_sale_guid"></input>').val(guid));
50
+ form.append($('<input type="hidden" name="authenticity_token"></input>').val($('meta[name="csrf-token"]').attr("content")));
50
51
  form.get(0).submit();
51
52
  } else if (data.status === "errored") {
52
53
  PayolaPaymentForm.showError(form, data.error);
@@ -0,0 +1,74 @@
1
+ var PayolaSubscriptionForm = {
2
+ initialize: function() {
3
+ $(document).on('submit', '.payola-subscription-form', function() {
4
+ return PayolaSubscriptionForm.handleSubmit($(this));
5
+ });
6
+ },
7
+
8
+ handleSubmit: function(form) {
9
+ $(':submit').prop('disabled', true);
10
+ $('.payola-spinner').show();
11
+ Stripe.card.createToken(form, function(status, response) {
12
+ PayolaSubscriptionForm.stripeResponseHandler(form, status, response);
13
+ });
14
+ return false;
15
+ },
16
+
17
+ stripeResponseHandler: function(form, status, response) {
18
+ if (response.error) {
19
+ PayolaSubscriptionForm.showError(form, response.error.message);
20
+ $(':submit').prop('disabled', false);
21
+ } else {
22
+ var email = form.find("[data-payola='email']").val();
23
+ var coupon = form.find("[data-payola='coupon']").val();
24
+
25
+ var base_path = form.data('payola-base-path');
26
+ var plan_type = form.data('payola-plan-type');
27
+ var plan_id = form.data('payola-plan-id');
28
+
29
+ var data_form = $('<form></form>');
30
+ data_form.append($('<input type="hidden" name="stripeToken">').val(response.id));
31
+ data_form.append($('<input type="hidden" name="stripeEmail">').val(email));
32
+ data_form.append($('<input type="hidden" name="coupon">').val(coupon));
33
+ data_form.append(form.find('input[name="authenticity_token"]'));
34
+ $.ajax({
35
+ type: "POST",
36
+ url: base_path + "/subscribe/" + plan_type + "/" + plan_id,
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) }
40
+ });
41
+ }
42
+ },
43
+
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)
47
+ }
48
+ $.get(base_path + '/subscription_status/' + guid, function(data) {
49
+ if (data.status === "active") {
50
+ form.append($('<input type="hidden" name="payola_subscription_guid"></input>').val(guid));
51
+ form.append($('<input type="hidden" name="authenticity_token"></input>').val($('meta[name="csrf-token"]').attr("content")));
52
+ form.get(0).submit();
53
+ } else if (data.status === "errored") {
54
+ PayolaSubscriptionForm.showError(form, data.error);
55
+ } else {
56
+ setTimeout(function() { PayolaSubscriptionForm.poll(form, num_retries_left - 1, guid, base_path) }, 500);
57
+ }
58
+ });
59
+ },
60
+
61
+ showError: function(form, message) {
62
+ $('.payola-spinner').hide();
63
+ var error_selector = form.data('payola-error-selector');
64
+ if (error_selector) {
65
+ $(error_selector).text(message);
66
+ $(error_selector).show();
67
+ } else {
68
+ form.find('.payola-payment-error').text(message);
69
+ form.find('.payola-payment-error').show();
70
+ }
71
+ }
72
+ };
73
+
74
+ $(function() { PayolaSubscriptionForm.initialize() } );
@@ -1,6 +1,5 @@
1
1
  module Payola
2
- class ApplicationController < ActionController::Base
3
- helper ApplicationHelper
2
+ class ApplicationController < ::ApplicationController
4
3
  helper PriceHelper
5
4
  end
6
5
  end
@@ -0,0 +1,94 @@
1
+ module Payola
2
+ class SubscriptionsController < ApplicationController
3
+ before_filter :find_plan_and_coupon_and_affiliate, only: [:create, :change_plan]
4
+ before_filter :check_modify_permissions, only: [:destroy, :change_plan, :update_card]
5
+
6
+ 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
12
+ end
13
+
14
+ 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}
18
+ end
19
+
20
+ 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
35
+ end
36
+
37
+ def destroy
38
+ subscription = Subscription.find_by!(guid: params[:guid])
39
+ Payola::CancelSubscription.call(subscription)
40
+ redirect_to confirm_subscription_path(subscription)
41
+ end
42
+
43
+ def change_plan
44
+ subscription = Subscription.find_by!(guid: params[:guid])
45
+ Payola::ChangeSubscriptionPlan.call(subscription, @plan)
46
+
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
52
+ end
53
+
54
+ def update_card
55
+ subscription = Subscription.find_by!(guid: params[:guid])
56
+ Payola::UpdateCard.call(subscription, params[:stripeToken])
57
+
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
63
+ end
64
+
65
+ private
66
+
67
+ def find_plan_and_coupon_and_affiliate
68
+ @plan_class = Payola.subscribables[params[:plan_class]]
69
+
70
+ raise ActionController::RoutingError.new('Not Found') unless @plan_class && @plan_class.subscribable?
71
+
72
+ @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
81
+
82
+ end
83
+
84
+ def check_modify_permissions
85
+ subscription = Subscription.find_by!(guid: params[:guid])
86
+ if self.respond_to?(:payola_can_modify_subscription?)
87
+ redirect_to(
88
+ confirm_subscription_path(subscription),
89
+ alert: "You cannot modify this subscription."
90
+ ) and return unless self.payola_can_modify_subscription?(subscription)
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,50 @@
1
+ require 'active_support/concern'
2
+
3
+ module Payola
4
+ module Plan
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ validates_presence_of :amount
9
+ validates_presence_of :interval
10
+ validates_presence_of :interval_count
11
+ validates_presence_of :stripe_id
12
+ validates_presence_of :name
13
+
14
+ validates_uniqueness_of :stripe_id
15
+
16
+ before_save :create_stripe_plan, on: :create
17
+
18
+ has_many :subscriptions, :class_name => "Payola::Subscription"
19
+
20
+ Payola.register_subscribable(self)
21
+ end
22
+
23
+ def create_stripe_plan
24
+ Payola::CreatePlan.call(self)
25
+ end
26
+
27
+ def plan_class
28
+ self.class.plan_class
29
+ end
30
+
31
+ def product_class
32
+ plan_class
33
+ end
34
+
35
+ def price
36
+ amount
37
+ end
38
+
39
+ module ClassMethods
40
+ def subscribable?
41
+ true
42
+ end
43
+
44
+ def plan_class
45
+ self.to_s.underscore
46
+ end
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,161 @@
1
+ require 'aasm'
2
+
3
+ module Payola
4
+ class Subscription < ActiveRecord::Base
5
+
6
+ validates_presence_of :email
7
+ validates_presence_of :plan_id
8
+ validates_presence_of :plan_type
9
+ validates_presence_of :stripe_token
10
+ validates_presence_of :currency
11
+
12
+ validates_uniqueness_of :guid
13
+
14
+ before_save :populate_guid
15
+
16
+ belongs_to :plan, polymorphic: true
17
+ belongs_to :owner, polymorphic: true
18
+ belongs_to :affiliate
19
+
20
+ has_many :sales, class_name: 'Payola::Sale'
21
+
22
+ include AASM
23
+
24
+ attr_accessor :old_plan
25
+
26
+ aasm column: 'state', skip_validation_on_save: true do
27
+ state :pending, initial: true
28
+ state :processing
29
+ state :active
30
+ state :canceled
31
+ state :errored
32
+
33
+ event :process, after: :start_subscription do
34
+ transitions from: :pending, to: :processing
35
+ end
36
+
37
+ event :activate, after: :instrument_activate do
38
+ transitions from: :processing, to: :active
39
+ end
40
+
41
+ event :cancel, after: :instrument_canceled do
42
+ transitions from: :active, to: :canceled
43
+ end
44
+
45
+ event :fail, after: :instrument_fail do
46
+ transitions from: [:pending, :processing], to: :errored
47
+ end
48
+
49
+ event :refund, after: :instrument_refund do
50
+ transitions from: :finished, to: :refunded
51
+ end
52
+ end
53
+
54
+ def name
55
+ self.plan.name
56
+ end
57
+
58
+ def price
59
+ self.plan.amount
60
+ end
61
+
62
+ def redirect_path(sale)
63
+ self.plan.redirect_path(self)
64
+ end
65
+
66
+ def verifier
67
+ @verifier ||= ActiveSupport::MessageVerifier.new(Payola.secret_key_for_sale(self), digest: 'SHA256')
68
+ end
69
+
70
+ def verify_charge
71
+ begin
72
+ self.verify_charge!
73
+ rescue RuntimeError => e
74
+ self.error = e.message
75
+ self.fail!
76
+ end
77
+ end
78
+
79
+ def verify_charge!
80
+ if Payola.charge_verifier.arity > 1
81
+ Payola.charge_verifier.call(self, custom_fields)
82
+ else
83
+ Payola.charge_verifier.call(self)
84
+ end
85
+ end
86
+
87
+ def custom_fields
88
+ if self.signed_custom_fields.present?
89
+ verifier.verify(self.signed_custom_fields)
90
+ else
91
+ nil
92
+ end
93
+ end
94
+
95
+ def sync_with!(stripe_sub)
96
+ self.current_period_start = Time.at(stripe_sub.current_period_start)
97
+ self.current_period_end = Time.at(stripe_sub.current_period_end)
98
+ self.ended_at = Time.at(stripe_sub.ended_at) if stripe_sub.ended_at
99
+ self.trial_start = Time.at(stripe_sub.trial_start) if stripe_sub.trial_start
100
+ self.trial_end = Time.at(stripe_sub.trial_end) if stripe_sub.trial_end
101
+ self.quantity = stripe_sub.quantity
102
+ self.stripe_status = stripe_sub.status
103
+
104
+ self.save!
105
+ self
106
+ end
107
+
108
+ def to_param
109
+ guid
110
+ end
111
+
112
+ def instrument_plan_changed(old_plan)
113
+ self.old_plan = old_plan
114
+ Payola.instrument(instrument_key('plan_changed'), self)
115
+ Payola.instrument(instrument_key('plan_changed', false), self)
116
+ end
117
+
118
+ private
119
+
120
+ def start_subscription
121
+ Payola::StartSubscription.call(self)
122
+ end
123
+
124
+ def instrument_activate
125
+ Payola.instrument(instrument_key('active'), self)
126
+ Payola.instrument(instrument_key('active', false), self)
127
+ end
128
+
129
+ def instrument_canceled
130
+ Payola.instrument(instrument_key('canceled'), self)
131
+ Payola.instrument(instrument_key('canceled', false), self)
132
+ end
133
+
134
+ def instrument_fail
135
+ Payola.instrument(instrument_key('failed'), self)
136
+ Payola.instrument(instrument_key('failed', false), self)
137
+ end
138
+
139
+ def instrument_refund
140
+ Payola.instrument(instrument_key('refunded'), self)
141
+ Payola.instrument(instrument_key('refunded', false), self)
142
+ end
143
+
144
+ def instrument_key(instrument_type, include_class=true)
145
+ if include_class
146
+ "payola.#{plan_type}.subscription.#{instrument_type}"
147
+ else
148
+ "payola.subscription.#{instrument_type}"
149
+ end
150
+ end
151
+
152
+ def populate_guid
153
+ if new_record?
154
+ while !valid? || self.guid.nil?
155
+ self.guid = SecureRandom.random_number(1_000_000_000).to_s(32)
156
+ end
157
+ end
158
+ end
159
+
160
+ end
161
+ end
@@ -0,0 +1,12 @@
1
+ module Payola
2
+ class CancelSubscription
3
+ def self.call(subscription)
4
+ secret_key = Payola.secret_key_for_sale(subscription)
5
+ customer = Stripe::Customer.retrieve(subscription.stripe_customer_id, secret_key)
6
+ customer.subscriptions.retrieve(subscription.stripe_id,secret_key).delete
7
+ subscription.cancel!
8
+ end
9
+
10
+ end
11
+ end
12
+
@@ -0,0 +1,29 @@
1
+ module Payola
2
+ class ChangeSubscriptionPlan
3
+ def self.call(subscription, plan)
4
+ secret_key = Payola.secret_key_for_sale(subscription)
5
+ old_plan = subscription.plan
6
+
7
+ begin
8
+ customer = Stripe::Customer.retrieve(subscription.stripe_customer_id, secret_key)
9
+ sub = customer.subscriptions.retrieve(subscription.stripe_id)
10
+
11
+ prorate = plan.respond_to?(:should_prorate?) ? plan.should_prorate?(subscription) : true
12
+
13
+ sub.plan = plan.stripe_id
14
+ sub.prorate = prorate
15
+ sub.save
16
+
17
+ subscription.plan = plan
18
+ subscription.save!
19
+
20
+ subscription.instrument_plan_changed(old_plan)
21
+
22
+ rescue RuntimeError, Stripe::StripeError => e
23
+ subscription.errors[:base] << e.message
24
+ end
25
+
26
+ subscription
27
+ end
28
+ end
29
+ end