pay 1.0.2 → 2.0.0

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.

Potentially problematic release.


This version of pay might be problematic. Click here for more details.

Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +99 -31
  3. data/Rakefile +19 -19
  4. data/app/controllers/pay/payments_controller.rb +7 -0
  5. data/app/controllers/pay/webhooks/braintree_controller.rb +19 -6
  6. data/app/mailers/pay/application_mailer.rb +2 -2
  7. data/app/mailers/pay/user_mailer.rb +12 -0
  8. data/app/models/pay/subscription.rb +41 -10
  9. data/app/views/layouts/pay/application.html.erb +11 -5
  10. data/app/views/pay/payments/show.html.erb +134 -0
  11. data/app/views/pay/user_mailer/payment_action_required.html.erb +6 -0
  12. data/config/locales/en.yml +17 -0
  13. data/config/routes.rb +3 -2
  14. data/db/migrate/20190816015720_add_status_to_subscriptions.rb +14 -0
  15. data/lib/generators/pay/email_views_generator.rb +3 -3
  16. data/lib/generators/pay/views_generator.rb +13 -0
  17. data/lib/pay/billable/sync_email.rb +3 -4
  18. data/lib/pay/billable.rb +25 -18
  19. data/lib/pay/braintree/billable.rb +88 -82
  20. data/lib/pay/braintree/charge.rb +0 -2
  21. data/lib/pay/braintree/subscription.rb +74 -72
  22. data/lib/pay/braintree.rb +6 -6
  23. data/lib/pay/engine.rb +10 -10
  24. data/lib/pay/env.rb +0 -1
  25. data/lib/pay/payment.rb +52 -0
  26. data/lib/pay/receipts.rb +7 -7
  27. data/lib/pay/stripe/billable.rb +68 -37
  28. data/lib/pay/stripe/charge.rb +0 -2
  29. data/lib/pay/stripe/subscription.rb +7 -6
  30. data/lib/pay/stripe/webhooks/charge_refunded.rb +0 -2
  31. data/lib/pay/stripe/webhooks/charge_succeeded.rb +9 -10
  32. data/lib/pay/stripe/webhooks/customer_deleted.rb +5 -7
  33. data/lib/pay/stripe/webhooks/customer_updated.rb +0 -2
  34. data/lib/pay/stripe/webhooks/payment_action_required.rb +27 -0
  35. data/lib/pay/stripe/webhooks/{source_deleted.rb → payment_method_updated.rb} +1 -3
  36. data/lib/pay/stripe/webhooks/subscription_created.rb +6 -11
  37. data/lib/pay/stripe/webhooks/subscription_deleted.rb +1 -3
  38. data/lib/pay/stripe/webhooks/subscription_renewing.rb +0 -2
  39. data/lib/pay/stripe/webhooks/subscription_updated.rb +13 -10
  40. data/lib/pay/stripe/webhooks.rb +17 -11
  41. data/lib/pay/stripe.rb +5 -5
  42. data/lib/pay/version.rb +1 -1
  43. data/lib/pay.rb +42 -15
  44. metadata +27 -39
@@ -10,12 +10,12 @@ module Pay
10
10
 
11
11
  if on_trial?
12
12
  gateway.subscription.cancel(processor_subscription.id)
13
- update(ends_at: trial_ends_at)
13
+ update(status: :canceled, ends_at: trial_ends_at)
14
14
  else
15
15
  gateway.subscription.update(subscription.id, {
16
- number_of_billing_cycles: subscription.current_billing_cycle
16
+ number_of_billing_cycles: subscription.current_billing_cycle,
17
17
  })
18
- update(ends_at: subscription.billing_period_end_date)
18
+ update(status: :canceled, ends_at: subscription.billing_period_end_date.to_date)
19
19
  end
20
20
  rescue ::Braintree::BraintreeError => e
21
21
  raise Error, e.message
@@ -23,13 +23,13 @@ module Pay
23
23
 
24
24
  def braintree_cancel_now!
25
25
  gateway.subscription.cancel(processor_subscription.id)
26
- update(ends_at: Time.zone.now)
26
+ update(status: :canceled, ends_at: Time.zone.now)
27
27
  rescue ::Braintree::BraintreeError => e
28
28
  raise Error, e.message
29
29
  end
30
30
 
31
31
  def braintree_resume
32
- if cancelled? && on_trial?
32
+ if canceled? && on_trial?
33
33
  duration = trial_ends_at.to_date - Date.today
34
34
 
35
35
  owner.subscribe(
@@ -45,9 +45,11 @@ module Pay
45
45
 
46
46
  gateway.subscription.update(subscription.id, {
47
47
  never_expires: true,
48
- number_of_billing_cycles: nil
48
+ number_of_billing_cycles: nil,
49
49
  })
50
50
  end
51
+
52
+ update(status: :active)
51
53
  rescue ::Braintree::BraintreeError => e
52
54
  raise Error, e.message
53
55
  end
@@ -58,8 +60,8 @@ module Pay
58
60
  return
59
61
  end
60
62
 
61
- if !active?
62
- owner.subscribe(name, plan, processor, trial_period: false)
63
+ unless active?
64
+ owner.subscribe(name: name, plan: plan, trial_period: false)
63
65
  return
64
66
  end
65
67
 
@@ -79,11 +81,11 @@ module Pay
79
81
  number_of_billing_cycles: nil,
80
82
  options: {
81
83
  prorate_charges: prorate?,
82
- }
84
+ },
83
85
  })
84
86
 
85
87
  if result.success?
86
- update(processor_plan: braintree_plan.id, ends_at: nil)
88
+ update(status: :active, processor_plan: braintree_plan.id, ends_at: nil)
87
89
  else
88
90
  raise Error, "Braintree failed to swap plans: #{result.message}"
89
91
  end
@@ -93,81 +95,81 @@ module Pay
93
95
 
94
96
  private
95
97
 
96
- def gateway
97
- Pay.braintree_gateway
98
- end
98
+ def gateway
99
+ Pay.braintree_gateway
100
+ end
99
101
 
100
- def would_change_billing_frequency?(plan)
101
- plan.billing_frequency != find_braintree_plan(processor_plan).billing_frequency
102
- end
102
+ def would_change_billing_frequency?(plan)
103
+ plan.billing_frequency != find_braintree_plan(processor_plan).billing_frequency
104
+ end
103
105
 
104
- def find_braintree_plan(id)
105
- @braintree_plans ||= gateway.plan.all
106
- @braintree_plans.find{ |p| p.id == id }
107
- end
106
+ def find_braintree_plan(id)
107
+ @braintree_plans ||= gateway.plan.all
108
+ @braintree_plans.find { |p| p.id == id }
109
+ end
108
110
 
109
- # Helper methods for swapping plans
110
- def switching_to_monthly_plan?(current_plan, plan)
111
- current_plan.billing_frequency == 12 && plan.billing_frequency == 1
112
- end
111
+ # Helper methods for swapping plans
112
+ def switching_to_monthly_plan?(current_plan, plan)
113
+ current_plan.billing_frequency == 12 && plan.billing_frequency == 1
114
+ end
113
115
 
114
- def discount_for_switching_to_monthly(current_plan, plan)
115
- cycles = (money_remaining_on_yearly_plan(current_plan) / plan.price).floor
116
- OpenStruct.new(
117
- amount: plan.price,
118
- number_of_billing_cycles: cycles
119
- )
120
- end
116
+ def discount_for_switching_to_monthly(current_plan, plan)
117
+ cycles = (money_remaining_on_yearly_plan(current_plan) / plan.price).floor
118
+ OpenStruct.new(
119
+ amount: plan.price,
120
+ number_of_billing_cycles: cycles
121
+ )
122
+ end
121
123
 
122
- def money_remaining_on_yearly_plan(current_plan)
123
- end_date = processor_subscription.billing_period_end_date.to_date
124
- (current_plan.price / 365) * (end_date - Date.today)
125
- end
124
+ def money_remaining_on_yearly_plan(current_plan)
125
+ end_date = processor_subscription.billing_period_end_date.to_date
126
+ (current_plan.price / 365) * (end_date - Date.today)
127
+ end
126
128
 
127
- def discount_for_switching_to_yearly
128
- amount = 0
129
+ def discount_for_switching_to_yearly
130
+ amount = 0
129
131
 
130
- processor_subscription.discounts.each do |discount|
131
- if discount.id == 'plan-credit'
132
- amount += discount.amount * discount.number_of_billing_cycles
133
- end
132
+ processor_subscription.discounts.each do |discount|
133
+ if discount.id == "plan-credit"
134
+ amount += discount.amount * discount.number_of_billing_cycles
134
135
  end
135
-
136
- OpenStruct.new(
137
- amount: amount,
138
- number_of_billing_cycles: 1
139
- )
140
136
  end
141
137
 
142
- def swap_across_frequencies(plan)
143
- current_plan = find_braintree_plan(processor_plan)
144
-
145
- discount = if switching_to_monthly_plan?(current_plan, plan)
146
- discount_for_switching_to_monthly(current_plan, plan)
147
- else
148
- discount_for_switching_to_yearly
149
- end
150
-
151
- options = {}
152
-
153
- if discount.amount > 0 && discount.number_of_billing_cycles > 0
154
- options = {
155
- discounts: {
156
- add: [
157
- {
158
- inherited_from_id: 'plan-credit',
159
- amount: discount.amount,
160
- number_of_billing_cycles: discount.number_of_billing_cycles
161
- }
162
- ]
163
- }
164
- }
165
- end
138
+ OpenStruct.new(
139
+ amount: amount,
140
+ number_of_billing_cycles: 1
141
+ )
142
+ end
166
143
 
167
- cancel_now!
144
+ def swap_across_frequencies(plan)
145
+ current_plan = find_braintree_plan(processor_plan)
168
146
 
169
- owner.subscribe(options.merge(name: name, plan: plan.id))
147
+ discount = if switching_to_monthly_plan?(current_plan, plan)
148
+ discount_for_switching_to_monthly(current_plan, plan)
149
+ else
150
+ discount_for_switching_to_yearly
170
151
  end
152
+
153
+ options = {}
154
+
155
+ if discount.amount > 0 && discount.number_of_billing_cycles > 0
156
+ options = {
157
+ discounts: {
158
+ add: [
159
+ {
160
+ inherited_from_id: "plan-credit",
161
+ amount: discount.amount,
162
+ number_of_billing_cycles: discount.number_of_billing_cycles,
163
+ },
164
+ ],
165
+ },
166
+ }
167
+ end
168
+
169
+ cancel_now!
170
+
171
+ owner.subscribe(options.merge(name: name, plan: plan.id))
172
+ end
171
173
  end
172
174
  end
173
175
  end
data/lib/pay/braintree.rb CHANGED
@@ -1,7 +1,7 @@
1
- require 'pay/env'
2
- require 'pay/braintree/billable'
3
- require 'pay/braintree/charge'
4
- require 'pay/braintree/subscription'
1
+ require "pay/env"
2
+ require "pay/braintree/billable"
3
+ require "pay/braintree/charge"
4
+ require "pay/braintree/subscription"
5
5
 
6
6
  module Pay
7
7
  module Braintree
@@ -13,7 +13,7 @@ module Pay
13
13
  Pay.braintree_gateway = ::Braintree::Gateway.new(
14
14
  environment: environment.to_sym,
15
15
  merchant_id: merchant_id,
16
- public_key: public_key,
16
+ public_key: public_key,
17
17
  private_key: private_key
18
18
  )
19
19
 
@@ -35,7 +35,7 @@ module Pay
35
35
  end
36
36
 
37
37
  def environment
38
- find_value_by_name(:braintree, :environment) || 'sandbox'
38
+ find_value_by_name(:braintree, :environment) || "sandbox"
39
39
  end
40
40
  end
41
41
  end
data/lib/pay/engine.rb CHANGED
@@ -2,35 +2,35 @@
2
2
 
3
3
  # rubocop:disable Lint/HandleExceptions
4
4
  begin
5
- require 'braintree'
5
+ require "braintree"
6
6
  rescue LoadError
7
7
  end
8
8
 
9
9
  begin
10
- require 'stripe'
11
- require 'stripe_event'
10
+ require "stripe"
11
+ require "stripe_event"
12
12
  rescue LoadError
13
13
  end
14
14
  # rubocop:enable Lint/HandleExceptions
15
15
 
16
16
  module Pay
17
17
  class Engine < ::Rails::Engine
18
- engine_name 'pay'
18
+ engine_name "pay"
19
19
 
20
- initializer 'pay.processors' do |app|
20
+ initializer "pay.processors" do |app|
21
21
  # Include processor backends
22
- require 'pay/stripe' if defined? ::Stripe
23
- require 'pay/braintree' if defined? ::Braintree
22
+ require "pay/stripe" if defined? ::Stripe
23
+ require "pay/braintree" if defined? ::Braintree
24
24
 
25
- if Pay.automount_webhook_routes
25
+ if Pay.automount_routes
26
26
  app.routes.append do
27
- mount Pay::Engine, at: Pay.webhooks_path, as: 'pay'
27
+ mount Pay::Engine, at: Pay.routes_path, as: "pay"
28
28
  end
29
29
  end
30
30
  end
31
31
 
32
32
  config.to_prepare do
33
- Pay::Stripe.setup if defined? ::Stripe
33
+ Pay::Stripe.setup if defined? ::Stripe
34
34
  Pay::Braintree.setup if defined? ::Braintree
35
35
 
36
36
  Pay.charge_model.include Pay::Receipts if defined? ::Receipts::Receipt
data/lib/pay/env.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  module Pay
2
2
  module Env
3
-
4
3
  private
5
4
 
6
5
  # Search for environment variables
@@ -0,0 +1,52 @@
1
+ module Pay
2
+ class Payment
3
+ attr_reader :intent
4
+
5
+ delegate :id, :amount, :client_secret, :status, :confirm, to: :intent
6
+
7
+ def self.from_id(id)
8
+ intent = id.start_with?("seti_") ? ::Stripe::SetupIntent.retrieve(id) : ::Stripe::PaymentIntent.retrieve(id)
9
+ new(intent)
10
+ end
11
+
12
+ def initialize(intent)
13
+ @intent = intent
14
+ end
15
+
16
+ def requires_payment_method?
17
+ status == "requires_payment_method"
18
+ end
19
+
20
+ def requires_action?
21
+ status == "requires_action"
22
+ end
23
+
24
+ def canceled?
25
+ status == "canceled"
26
+ end
27
+
28
+ def cancelled?
29
+ canceled?
30
+ end
31
+
32
+ def succeeded?
33
+ status == "succeeded"
34
+ end
35
+
36
+ def payment_intent?
37
+ intent.is_a?(::Stripe::PaymentIntent)
38
+ end
39
+
40
+ def setup_intent?
41
+ intent.is_a?(::Stripe::SetupIntent)
42
+ end
43
+
44
+ def validate
45
+ if requires_payment_method?
46
+ raise Pay::InvalidPaymentMethod.new(self)
47
+ elsif requires_action?
48
+ raise Pay::ActionRequired.new(self)
49
+ end
50
+ end
51
+ end
52
+ end
data/lib/pay/receipts.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Pay
2
2
  module Receipts
3
3
  def filename
4
- "receipt-#{created_at.strftime('%Y-%m-%d')}.pdf"
4
+ "receipt-#{created_at.strftime("%Y-%m-%d")}.pdf"
5
5
  end
6
6
 
7
7
  def product
@@ -18,9 +18,9 @@ module Pay
18
18
  id: id,
19
19
  product: product,
20
20
  company: {
21
- name: Pay.business_name,
21
+ name: Pay.business_name,
22
22
  address: Pay.business_address,
23
- email: Pay.support_email,
23
+ email: Pay.support_email,
24
24
  },
25
25
  line_items: line_items
26
26
  )
@@ -28,11 +28,11 @@ module Pay
28
28
 
29
29
  def line_items
30
30
  line_items = [
31
- ["Date", created_at.to_s],
31
+ ["Date", created_at.to_s],
32
32
  ["Account Billed", "#{owner.name} (#{owner.email})"],
33
- ["Product", product],
34
- ["Amount", ActionController::Base.helpers.number_to_currency(amount / 100.0)],
35
- ["Charged to", charged_to],
33
+ ["Product", product],
34
+ ["Amount", ActionController::Base.helpers.number_to_currency(amount / 100.0)],
35
+ ["Charged to", charged_to],
36
36
  ]
37
37
  line_items << ["Additional Info", owner.extra_billing_info] if owner.extra_billing_info?
38
38
  line_items
@@ -14,21 +14,32 @@ module Pay
14
14
  raise Error, e.message
15
15
  end
16
16
 
17
+ def create_setup_intent
18
+ ::Stripe::SetupIntent.create(
19
+ customer: processor_id,
20
+ usage: :off_session,
21
+ )
22
+ end
23
+
17
24
  # Handles Billable#charge
18
25
  #
19
26
  # Returns Pay::Charge
20
- def create_stripe_charge(amount, options={})
27
+ def create_stripe_charge(amount, options = {})
28
+ customer = stripe_customer
21
29
  args = {
22
30
  amount: amount,
23
- currency: 'usd',
31
+ confirm: true,
32
+ confirmation_method: :automatic,
33
+ currency: "usd",
24
34
  customer: customer.id,
25
- description: customer_name,
35
+ payment_method: customer.invoice_settings.default_payment_method,
26
36
  }.merge(options)
27
37
 
28
- stripe_charge = ::Stripe::Charge.create(args)
38
+ payment_intent = ::Stripe::PaymentIntent.create(args)
39
+ Pay::Payment.new(payment_intent).validate
29
40
 
30
- # Save the charge to the db, returns Charge
31
- Pay::Stripe::Webhooks::ChargeSucceeded.new.create_charge(self, stripe_charge)
41
+ # Create a new charge object
42
+ Stripe::Webhooks::ChargeSucceeded.new.create_charge(self, payment_intent.charges.first)
32
43
  rescue ::Stripe::StripeError => e
33
44
  raise Error, e.message
34
45
  end
@@ -36,10 +47,28 @@ module Pay
36
47
  # Handles Billable#subscribe
37
48
  #
38
49
  # Returns Pay::Subscription
39
- def create_stripe_subscription(name, plan, options={})
40
- opts = { plan: plan, trial_from_plan: true }.merge(options)
41
- stripe_sub = customer.subscriptions.create(opts)
42
- subscription = create_subscription(stripe_sub, 'stripe', name, plan)
50
+ def create_stripe_subscription(name, plan, options = {})
51
+ opts = {
52
+ expand: ["pending_setup_intent", "latest_invoice.payment_intent"],
53
+ items: [plan: plan],
54
+ off_session: true,
55
+ }.merge(options)
56
+
57
+ # Inherit trial from plan unless trial override was specified
58
+ opts[:trial_from_plan] = true unless opts[:trial_period_days]
59
+
60
+ stripe_sub = customer.subscriptions.create(opts)
61
+ subscription = create_subscription(stripe_sub, "stripe", name, plan, status: stripe_sub.status)
62
+
63
+ # No trial, card requires SCA
64
+ if subscription.incomplete?
65
+ Pay::Payment.new(stripe_sub.latest_invoice.payment_intent).validate
66
+
67
+ # Trial, card requires SCA
68
+ elsif subscription.on_trial? && stripe_sub.pending_setup_intent
69
+ Pay::Payment.new(stripe_sub.pending_setup_intent).validate
70
+ end
71
+
43
72
  subscription
44
73
  rescue ::Stripe::StripeError => e
45
74
  raise Error, e.message
@@ -48,17 +77,15 @@ module Pay
48
77
  # Handles Billable#update_card
49
78
  #
50
79
  # Returns true if successful
51
- def update_stripe_card(token)
80
+ def update_stripe_card(payment_method_id)
52
81
  customer = stripe_customer
53
- token = ::Stripe::Token.retrieve(token)
54
82
 
55
- return if token.card.id == customer.default_source
83
+ return true if payment_method_id == customer.invoice_settings.default_payment_method
56
84
 
57
- card = customer.sources.create(source: token.id)
58
- customer.default_source = card.id
59
- customer.save
85
+ payment_method = ::Stripe::PaymentMethod.attach(payment_method_id, customer: customer.id)
86
+ ::Stripe::Customer.update(customer.id, invoice_settings: {default_payment_method: payment_method.id})
60
87
 
61
- update_stripe_card_on_file(card)
88
+ update_stripe_card_on_file(payment_method.card)
62
89
  true
63
90
  rescue ::Stripe::StripeError => e
64
91
  raise Error, e.message
@@ -71,13 +98,13 @@ module Pay
71
98
  customer.save
72
99
  end
73
100
 
74
- def stripe_subscription(subscription_id)
75
- ::Stripe::Subscription.retrieve(subscription_id)
101
+ def stripe_subscription(subscription_id, options = {})
102
+ ::Stripe::Subscription.retrieve(options.merge(id: subscription_id))
76
103
  end
77
104
 
78
- def stripe_invoice!
105
+ def stripe_invoice!(options = {})
79
106
  return unless processor_id?
80
- ::Stripe::Invoice.create(customer: processor_id).pay
107
+ ::Stripe::Invoice.create(options.merge(customer: processor_id)).pay
81
108
  end
82
109
 
83
110
  def stripe_upcoming_invoice
@@ -87,18 +114,18 @@ module Pay
87
114
  # Used by webhooks when the customer or source changes
88
115
  def sync_card_from_stripe
89
116
  stripe_cust = stripe_customer
90
- default_source_id = stripe_cust.default_source
117
+ default_payment_method_id = stripe_cust.invoice_settings.default_payment_method
91
118
 
92
- if default_source_id.present?
93
- card = stripe_customer.sources.data.find{ |s| s.id == default_source_id }
119
+ if default_payment_method_id.present?
120
+ payment_method = ::Stripe::PaymentMethod.retrieve(default_payment_method_id)
94
121
  update(
95
- card_type: card.brand,
96
- card_last4: card.last4,
97
- card_exp_month: card.exp_month,
98
- card_exp_year: card.exp_year
122
+ card_type: payment_method.card.brand,
123
+ card_last4: payment_method.card.last4,
124
+ card_exp_month: payment_method.card.exp_month,
125
+ card_exp_year: payment_method.card.exp_year
99
126
  )
100
127
 
101
- # Customer has no default payment source
128
+ # Customer has no default payment method
102
129
  else
103
130
  update(card_type: nil, card_last4: nil)
104
131
  end
@@ -107,29 +134,33 @@ module Pay
107
134
  private
108
135
 
109
136
  def create_stripe_customer
110
- customer = ::Stripe::Customer.create(email: email, source: card_token, description: customer_name)
111
- update(processor: 'stripe', processor_id: customer.id)
137
+ customer = ::Stripe::Customer.create(email: email, description: customer_name)
138
+ update(processor: "stripe", processor_id: customer.id)
112
139
 
113
140
  # Update the user's card on file if a token was passed in
114
- source = customer.sources.data.first
115
- if source.present?
116
- update_stripe_card_on_file customer.sources.retrieve(source.id)
141
+ if card_token.present?
142
+ ::Stripe::PaymentMethod.attach(card_token, {customer: customer.id})
143
+ customer.invoice_settings.default_payment_method = card_token
144
+ customer.save
145
+
146
+ update_stripe_card_on_file ::Stripe::PaymentMethod.retrieve(card_token).card
117
147
  end
118
148
 
119
149
  customer
120
150
  end
121
151
 
122
152
  def stripe_trial_end_date(stripe_sub)
153
+ # Times in Stripe are returned in UTC
123
154
  stripe_sub.trial_end.present? ? Time.at(stripe_sub.trial_end) : nil
124
155
  end
125
156
 
126
157
  # Save the card to the database as the user's current card
127
158
  def update_stripe_card_on_file(card)
128
159
  update!(
129
- card_type: card.brand,
130
- card_last4: card.last4,
160
+ card_type: card.brand.capitalize,
161
+ card_last4: card.last4,
131
162
  card_exp_month: card.exp_month,
132
- card_exp_year: card.exp_year
163
+ card_exp_year: card.exp_year
133
164
  )
134
165
 
135
166
  self.card_token = nil
@@ -1,6 +1,5 @@
1
1
  module Pay
2
2
  module Stripe
3
-
4
3
  module Charge
5
4
  extend ActiveSupport::Concern
6
5
 
@@ -25,6 +24,5 @@ module Pay
25
24
  raise Error, e.message
26
25
  end
27
26
  end
28
-
29
27
  end
30
28
  end
@@ -10,15 +10,15 @@ module Pay
10
10
  subscription.cancel_at_period_end = true
11
11
  subscription.save
12
12
 
13
- new_ends_at = on_trial? ? trial_ends_at : Time.at(subscription.current_period_end)
14
- update(ends_at: new_ends_at)
13
+ new_ends_at = on_trial? ? trial_ends_at : Time.at(subscription.current_period_end)
14
+ update(ends_at: new_ends_at, status: :canceled)
15
15
  rescue ::Stripe::StripeError => e
16
16
  raise Error, e.message
17
17
  end
18
18
 
19
19
  def stripe_cancel_now!
20
- subscription = processor_subscription.delete
21
- update(ends_at: Time.zone.now)
20
+ processor_subscription.delete
21
+ update(ends_at: Time.zone.now, status: :canceled)
22
22
  rescue ::Stripe::StripeError => e
23
23
  raise Error, e.message
24
24
  end
@@ -26,7 +26,7 @@ module Pay
26
26
  def stripe_resume
27
27
  subscription = processor_subscription
28
28
  subscription.plan = processor_plan
29
- subscription.trial_end = on_trial? ? trial_ends_at.to_i : 'now'
29
+ subscription.trial_end = on_trial? ? trial_ends_at.to_i : "now"
30
30
  subscription.cancel_at_period_end = false
31
31
  subscription.save
32
32
  rescue ::Stripe::StripeError => e
@@ -35,9 +35,10 @@ module Pay
35
35
 
36
36
  def stripe_swap(plan)
37
37
  subscription = processor_subscription
38
+ subscription.cancel_at_period_end = false
38
39
  subscription.plan = plan
39
40
  subscription.prorate = prorate
40
- subscription.trial_end = on_trial? ? trial_ends_at.to_i : 'now'
41
+ subscription.trial_end = on_trial? ? trial_ends_at.to_i : "now"
41
42
  subscription.quantity = quantity if quantity?
42
43
  subscription.save
43
44
  rescue ::Stripe::StripeError => e
@@ -1,7 +1,6 @@
1
1
  module Pay
2
2
  module Stripe
3
3
  module Webhooks
4
-
5
4
  class ChargeRefunded
6
5
  def call(event)
7
6
  object = event.data.object
@@ -19,7 +18,6 @@ module Pay
19
18
  end
20
19
  end
21
20
  end
22
-
23
21
  end
24
22
  end
25
23
  end
@@ -1,11 +1,10 @@
1
1
  module Pay
2
2
  module Stripe
3
3
  module Webhooks
4
-
5
4
  class ChargeSucceeded
6
5
  def call(event)
7
6
  object = event.data.object
8
- user = Pay.user_model.find_by(
7
+ user = Pay.user_model.find_by(
9
8
  processor: :stripe,
10
9
  processor_id: object.customer
11
10
  )
@@ -20,17 +19,17 @@ module Pay
20
19
 
21
20
  def create_charge(user, object)
22
21
  charge = user.charges.find_or_initialize_by(
23
- processor: :stripe,
24
- processor_id: object.id,
22
+ processor: :stripe,
23
+ processor_id: object.id,
25
24
  )
26
25
 
27
26
  charge.update(
28
- amount: object.amount,
29
- card_last4: object.source.last4,
30
- card_type: object.source.brand,
31
- card_exp_month: object.source.exp_month,
32
- card_exp_year: object.source.exp_year,
33
- created_at: Time.zone.at(object.created)
27
+ amount: object.amount,
28
+ card_last4: object.payment_method_details.card.last4,
29
+ card_type: object.payment_method_details.card.brand,
30
+ card_exp_month: object.payment_method_details.card.exp_month,
31
+ card_exp_year: object.payment_method_details.card.exp_year,
32
+ created_at: Time.zone.at(object.created)
34
33
  )
35
34
 
36
35
  charge