pay 2.5.0 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of pay might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/app/models/pay/charge.rb +22 -3
- data/app/models/pay/subscription.rb +23 -24
- data/app/views/pay/stripe/_checkout_button.html.erb +21 -0
- data/lib/pay.rb +9 -12
- data/lib/pay/billable.rb +33 -33
- data/lib/pay/billable/sync_email.rb +1 -1
- data/lib/pay/braintree.rb +34 -16
- data/lib/pay/braintree/authorization_error.rb +9 -0
- data/lib/pay/braintree/billable.rb +33 -30
- data/lib/pay/braintree/charge.rb +8 -10
- data/lib/pay/braintree/error.rb +9 -0
- data/lib/pay/braintree/subscription.rb +34 -15
- data/lib/pay/braintree/webhooks/subscription_charged_successfully.rb +1 -1
- data/lib/pay/braintree/webhooks/subscription_charged_unsuccessfully.rb +1 -1
- data/lib/pay/engine.rb +0 -22
- data/lib/pay/errors.rb +0 -44
- data/lib/pay/paddle.rb +30 -16
- data/lib/pay/paddle/billable.rb +26 -22
- data/lib/pay/paddle/charge.rb +8 -12
- data/lib/pay/paddle/error.rb +9 -0
- data/lib/pay/paddle/subscription.rb +29 -18
- data/lib/pay/paddle/webhooks/subscription_payment_succeeded.rb +1 -1
- data/lib/pay/stripe.rb +62 -14
- data/lib/pay/stripe/billable.rb +127 -69
- data/lib/pay/stripe/charge.rb +9 -15
- data/lib/pay/stripe/error.rb +9 -0
- data/lib/pay/stripe/subscription.rb +27 -11
- data/lib/pay/stripe/webhooks/charge_succeeded.rb +1 -20
- data/lib/pay/version.rb +1 -1
- data/lib/pay/webhooks.rb +13 -0
- metadata +11 -56
- data/lib/pay/braintree/webhooks.rb +0 -11
- data/lib/pay/paddle/webhooks.rb +0 -9
- data/lib/pay/stripe/webhooks.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f67175eed41645fc10868070414e33e205dc6970be39038715fbde5c18496932
|
4
|
+
data.tar.gz: bd725f34c55707aaf30c1e46ecc111a9c00b69f8275d87c7d94f8640b24d84c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 47b06c20aef2c34454f40bb734c4d1bdd648e9f9f4380c7b5c8d246357036f46b92511bc36ebf7b3b1ec00234700848ad3b12b1eb76c2e274a420e5bc650608b
|
7
|
+
data.tar.gz: 033e3b12a1a1a6f9b7b7bb2e447cb4a1acfb0cf3d35da7d5f00e187f6301d5cc59a9a3bec0d1577f8a6764286d93dbfefe16553939fc8c83213ee1c6668b09b9
|
data/app/models/pay/charge.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Pay
|
2
|
-
class Charge < ApplicationRecord
|
2
|
+
class Charge < Pay::ApplicationRecord
|
3
3
|
self.table_name = Pay.chargeable_table
|
4
4
|
|
5
5
|
# Only serialize for non-json columns
|
@@ -18,13 +18,32 @@ module Pay
|
|
18
18
|
validates :processor_id, presence: true
|
19
19
|
validates :card_type, presence: true
|
20
20
|
|
21
|
+
store_accessor :data, :paddle_receipt_url
|
22
|
+
|
23
|
+
# Helpers for payment processors
|
24
|
+
%w[braintree stripe paddle].each do |processor_name|
|
25
|
+
define_method "#{processor_name}?" do
|
26
|
+
processor == processor_name
|
27
|
+
end
|
28
|
+
|
29
|
+
scope processor_name, -> { where(processor: processor_name) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def payment_processor
|
33
|
+
@payment_processor ||= payment_processor_for(processor).new(self)
|
34
|
+
end
|
35
|
+
|
36
|
+
def payment_processor_for(name)
|
37
|
+
"Pay::#{name.to_s.classify}::Charge".constantize
|
38
|
+
end
|
39
|
+
|
21
40
|
def processor_charge
|
22
|
-
|
41
|
+
payment_processor.charge
|
23
42
|
end
|
24
43
|
|
25
44
|
def refund!(refund_amount = nil)
|
26
45
|
refund_amount ||= amount
|
27
|
-
|
46
|
+
payment_processor.refund!(refund_amount)
|
28
47
|
end
|
29
48
|
|
30
49
|
def charged_to
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Pay
|
2
|
-
class Subscription < ApplicationRecord
|
2
|
+
class Subscription < Pay::ApplicationRecord
|
3
3
|
self.table_name = Pay.subscription_table
|
4
4
|
|
5
5
|
STATUSES = %w[incomplete incomplete_expired trialing active past_due canceled unpaid paused]
|
@@ -27,6 +27,11 @@ module Pay
|
|
27
27
|
scope :incomplete, -> { where(status: :incomplete) }
|
28
28
|
scope :past_due, -> { where(status: :past_due) }
|
29
29
|
|
30
|
+
# TODO: Include these with a module
|
31
|
+
store_accessor :data, :paddle_update_url
|
32
|
+
store_accessor :data, :paddle_cancel_url
|
33
|
+
store_accessor :data, :paddle_paused_from
|
34
|
+
|
30
35
|
attribute :prorate, :boolean, default: true
|
31
36
|
|
32
37
|
# Helpers for payment processors
|
@@ -38,6 +43,21 @@ module Pay
|
|
38
43
|
scope processor_name, -> { where(processor: processor_name) }
|
39
44
|
end
|
40
45
|
|
46
|
+
def payment_processor
|
47
|
+
@payment_processor ||= payment_processor_for(processor).new(self)
|
48
|
+
end
|
49
|
+
|
50
|
+
def payment_processor_for(name)
|
51
|
+
"Pay::#{name.to_s.classify}::Subscription".constantize
|
52
|
+
end
|
53
|
+
|
54
|
+
delegate :on_grace_period?,
|
55
|
+
:paused?,
|
56
|
+
:pause,
|
57
|
+
:cancel,
|
58
|
+
:cancel_now!,
|
59
|
+
to: :payment_processor
|
60
|
+
|
41
61
|
def no_prorate
|
42
62
|
self.prorate = false
|
43
63
|
end
|
@@ -58,11 +78,6 @@ module Pay
|
|
58
78
|
canceled?
|
59
79
|
end
|
60
80
|
|
61
|
-
def on_grace_period?
|
62
|
-
return unless processor?
|
63
|
-
send("#{processor}_on_grace_period?")
|
64
|
-
end
|
65
|
-
|
66
81
|
def active?
|
67
82
|
["trialing", "active"].include?(status) && (ends_at.nil? || on_grace_period? || on_trial?)
|
68
83
|
end
|
@@ -79,30 +94,14 @@ module Pay
|
|
79
94
|
past_due? || incomplete?
|
80
95
|
end
|
81
96
|
|
82
|
-
def paused?
|
83
|
-
send("#{processor}_paused?")
|
84
|
-
end
|
85
|
-
|
86
|
-
def pause
|
87
|
-
send("#{processor}_pause")
|
88
|
-
end
|
89
|
-
|
90
|
-
def cancel
|
91
|
-
send("#{processor}_cancel")
|
92
|
-
end
|
93
|
-
|
94
|
-
def cancel_now!
|
95
|
-
send("#{processor}_cancel_now!")
|
96
|
-
end
|
97
|
-
|
98
97
|
def resume
|
99
|
-
|
98
|
+
payment_processor.resume
|
100
99
|
update(ends_at: nil, status: "active")
|
101
100
|
self
|
102
101
|
end
|
103
102
|
|
104
103
|
def swap(plan)
|
105
|
-
|
104
|
+
payment_processor.swap(plan)
|
106
105
|
update(processor_plan: plan, ends_at: nil)
|
107
106
|
end
|
108
107
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<%= button_tag title,
|
2
|
+
id: "checkout-#{session.id}",
|
3
|
+
class: local_assigns[:class],
|
4
|
+
style: (local_assigns[:class] || local_assigns[:style]) ? local_assigns[:style] : 'background-color:#6772E5;color:#FFF;padding:8px 12px;border:0;border-radius:4px;font-size:1em'
|
5
|
+
%>
|
6
|
+
<%= tag.div id: "error-for-#{session.id}" %>
|
7
|
+
|
8
|
+
<script>
|
9
|
+
(() => {
|
10
|
+
const checkoutButton = document.getElementById("checkout-<%= session.id %>");
|
11
|
+
checkoutButton.addEventListener('click', function () {
|
12
|
+
Stripe("<%= Pay::Stripe.public_key %>").redirectToCheckout({
|
13
|
+
sessionId: '<%= session.id %>'
|
14
|
+
}).then(function (result) {
|
15
|
+
if (result.error) {
|
16
|
+
document.getElementById('error-message').innerText = result.error.message;
|
17
|
+
}
|
18
|
+
});
|
19
|
+
});
|
20
|
+
})()
|
21
|
+
</script>
|
data/lib/pay.rb
CHANGED
@@ -1,22 +1,19 @@
|
|
1
1
|
require "pay/version"
|
2
2
|
require "pay/engine"
|
3
|
-
require "pay/billable"
|
4
|
-
require "pay/receipts"
|
5
|
-
require "pay/payment"
|
6
3
|
require "pay/errors"
|
7
4
|
|
8
5
|
module Pay
|
9
|
-
|
10
|
-
|
6
|
+
autoload :Billable, "pay/billable"
|
7
|
+
autoload :Env, "pay/env"
|
8
|
+
autoload :Payment, "pay/payment"
|
9
|
+
autoload :Receipts, "pay/receipts"
|
11
10
|
|
12
|
-
|
13
|
-
|
11
|
+
# Payment processors
|
12
|
+
autoload :Braintree, "pay/braintree"
|
13
|
+
autoload :Paddle, "pay/paddle"
|
14
|
+
autoload :Stripe, "pay/stripe"
|
14
15
|
|
15
|
-
|
16
|
-
@delegator ||= Delegator.new
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
16
|
+
autoload :Webhooks, "pay/webhooks"
|
20
17
|
|
21
18
|
# Define who owns the subscription
|
22
19
|
mattr_accessor :billable_class
|
data/lib/pay/billable.rb
CHANGED
@@ -17,9 +17,6 @@ module Pay
|
|
17
17
|
|
18
18
|
included do |base|
|
19
19
|
include Pay::Billable::SyncEmail
|
20
|
-
include Pay::Stripe::Billable if defined? ::Stripe
|
21
|
-
include Pay::Braintree::Billable if defined? ::Braintree
|
22
|
-
include Pay::Paddle::Billable if defined? ::PaddlePay
|
23
20
|
|
24
21
|
has_many :charges, class_name: Pay.chargeable_class, foreign_key: :owner_id, inverse_of: :owner, as: :owner
|
25
22
|
has_many :subscriptions, class_name: Pay.subscription_class, foreign_key: :owner_id, inverse_of: :owner, as: :owner
|
@@ -29,17 +26,34 @@ module Pay
|
|
29
26
|
attribute :card_token, :string
|
30
27
|
end
|
31
28
|
|
29
|
+
def payment_processor
|
30
|
+
@payment_processor ||= payment_processor_for(processor).new(self)
|
31
|
+
end
|
32
|
+
|
33
|
+
def payment_processor_for(name)
|
34
|
+
"Pay::#{name.to_s.classify}::Billable".constantize
|
35
|
+
end
|
36
|
+
|
37
|
+
# Reset the payment processor when it changes
|
32
38
|
def processor=(value)
|
33
39
|
super(value)
|
34
40
|
self.processor_id = nil if processor_changed?
|
41
|
+
@payment_processor = nil
|
35
42
|
end
|
36
43
|
|
44
|
+
def processor
|
45
|
+
super.inquiry
|
46
|
+
end
|
47
|
+
|
48
|
+
delegate :charge, to: :payment_processor
|
49
|
+
delegate :subscribe, to: :payment_processor
|
50
|
+
delegate :update_card, to: :payment_processor
|
51
|
+
|
37
52
|
def customer
|
38
|
-
check_for_processor
|
39
53
|
raise Pay::Error, I18n.t("errors.email_required") if email.nil?
|
40
54
|
|
41
|
-
customer =
|
42
|
-
update_card(card_token) if card_token.present?
|
55
|
+
customer = payment_processor.customer
|
56
|
+
payment_processor.update_card(card_token) if card_token.present?
|
43
57
|
customer
|
44
58
|
end
|
45
59
|
|
@@ -47,20 +61,9 @@ module Pay
|
|
47
61
|
[try(:first_name), try(:last_name)].compact.join(" ")
|
48
62
|
end
|
49
63
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
def subscribe(name: Pay.default_product_name, plan: Pay.default_plan_name, **options)
|
56
|
-
check_for_processor
|
57
|
-
send("create_#{processor}_subscription", name, plan, options)
|
58
|
-
end
|
59
|
-
|
60
|
-
def update_card(token)
|
61
|
-
check_for_processor
|
62
|
-
customer if processor_id.nil?
|
63
|
-
send("update_#{processor}_card", token)
|
64
|
+
def create_setup_intent
|
65
|
+
ActiveSupport::Deprecation.warn("This method will be removed in the next release. Use `@billable.payment_processor.create_setup_intent` instead.")
|
66
|
+
payment_processor.create_setup_intent
|
64
67
|
end
|
65
68
|
|
66
69
|
def on_trial?(name: Pay.default_product_name, plan: nil)
|
@@ -77,8 +80,7 @@ module Pay
|
|
77
80
|
end
|
78
81
|
|
79
82
|
def processor_subscription(subscription_id, options = {})
|
80
|
-
|
81
|
-
send("#{processor}_subscription", subscription_id, options)
|
83
|
+
payment_processor.processor_subscription(subscription_id, options)
|
82
84
|
end
|
83
85
|
|
84
86
|
def subscribed?(name: Pay.default_product_name, processor_plan: nil)
|
@@ -100,11 +102,13 @@ module Pay
|
|
100
102
|
end
|
101
103
|
|
102
104
|
def invoice!(options = {})
|
103
|
-
|
105
|
+
ActiveSupport::Deprecation.warn("This will be removed in the next release. Use `@billable.payment_processor.invoice!` instead.")
|
106
|
+
payment_processor.invoice!(options)
|
104
107
|
end
|
105
108
|
|
106
109
|
def upcoming_invoice
|
107
|
-
|
110
|
+
ActiveSupport::Deprecation.warn("This will be removed in the next release. Use `@billable.payment_processor.upcoming_invoice` instead.")
|
111
|
+
payment_processor.upcoming_invoice
|
108
112
|
end
|
109
113
|
|
110
114
|
def stripe?
|
@@ -116,7 +120,7 @@ module Pay
|
|
116
120
|
end
|
117
121
|
|
118
122
|
def paypal?
|
119
|
-
|
123
|
+
card_type == "PayPal"
|
120
124
|
end
|
121
125
|
|
122
126
|
def paddle?
|
@@ -127,14 +131,8 @@ module Pay
|
|
127
131
|
subscription(name: name)&.has_incomplete_payment?
|
128
132
|
end
|
129
133
|
|
130
|
-
private
|
131
|
-
|
132
|
-
def check_for_processor
|
133
|
-
raise StandardError, I18n.t("errors.no_processor", class_name: self.class.name) unless processor
|
134
|
-
end
|
135
|
-
|
136
134
|
# Used for creating a Pay::Subscription in the database
|
137
|
-
def
|
135
|
+
def create_pay_subscription(subscription, processor, name, plan, options = {})
|
138
136
|
options[:quantity] ||= 1
|
139
137
|
|
140
138
|
options.merge!(
|
@@ -142,12 +140,14 @@ module Pay
|
|
142
140
|
processor: processor,
|
143
141
|
processor_id: subscription.id,
|
144
142
|
processor_plan: plan,
|
145
|
-
trial_ends_at:
|
143
|
+
trial_ends_at: payment_processor.trial_end_date(subscription),
|
146
144
|
ends_at: nil
|
147
145
|
)
|
148
146
|
subscriptions.create!(options)
|
149
147
|
end
|
150
148
|
|
149
|
+
private
|
150
|
+
|
151
151
|
def default_generic_trial?(name, plan)
|
152
152
|
# Generic trials don't have plans or custom names
|
153
153
|
plan.nil? && name == "default" && on_generic_trial?
|
data/lib/pay/braintree.rb
CHANGED
@@ -1,16 +1,24 @@
|
|
1
|
-
require "pay/env"
|
2
|
-
require "pay/braintree/billable"
|
3
|
-
require "pay/braintree/charge"
|
4
|
-
require "pay/braintree/subscription"
|
5
|
-
require "pay/braintree/webhooks"
|
6
|
-
|
7
1
|
module Pay
|
8
2
|
module Braintree
|
9
|
-
|
3
|
+
autoload :Billable, "pay/braintree/billable"
|
4
|
+
autoload :Charge, "pay/braintree/charge"
|
5
|
+
autoload :Subscription, "pay/braintree/subscription"
|
6
|
+
autoload :Error, "pay/braintree/error"
|
7
|
+
autoload :AuthorizationError, "pay/braintree/authorization_error"
|
8
|
+
|
9
|
+
module Webhooks
|
10
|
+
autoload :SubscriptionCanceled, "pay/braintree/webhooks/subscription_canceled"
|
11
|
+
autoload :SubscriptionChargedSuccessfully, "pay/braintree/webhooks/subscription_charged_successfully"
|
12
|
+
autoload :SubscriptionChargedUnsuccessfully, "pay/braintree/webhooks/subscription_charged_unsuccessfully"
|
13
|
+
autoload :SubscriptionExpired, "pay/braintree/webhooks/subscription_expired"
|
14
|
+
autoload :SubscriptionTrialEnded, "pay/braintree/webhooks/subscription_trial_ended"
|
15
|
+
autoload :SubscriptionWentActive, "pay/braintree/webhooks/subscription_went_active"
|
16
|
+
autoload :SubscriptionWentPastDue, "pay/braintree/webhooks/subscription_went_past_due"
|
17
|
+
end
|
10
18
|
|
11
|
-
extend
|
19
|
+
extend Env
|
12
20
|
|
13
|
-
def setup
|
21
|
+
def self.setup
|
14
22
|
Pay.braintree_gateway = ::Braintree::Gateway.new(
|
15
23
|
environment: environment.to_sym,
|
16
24
|
merchant_id: merchant_id,
|
@@ -18,25 +26,35 @@ module Pay
|
|
18
26
|
private_key: private_key
|
19
27
|
)
|
20
28
|
|
21
|
-
|
22
|
-
Pay.subscription_model.include Pay::Braintree::Subscription
|
23
|
-
Pay.billable_models.each { |model| model.include Pay::Braintree::Billable }
|
29
|
+
configure_webhooks
|
24
30
|
end
|
25
31
|
|
26
|
-
def public_key
|
32
|
+
def self.public_key
|
27
33
|
find_value_by_name(:braintree, :public_key)
|
28
34
|
end
|
29
35
|
|
30
|
-
def private_key
|
36
|
+
def self.private_key
|
31
37
|
find_value_by_name(:braintree, :private_key)
|
32
38
|
end
|
33
39
|
|
34
|
-
def merchant_id
|
40
|
+
def self.merchant_id
|
35
41
|
find_value_by_name(:braintree, :merchant_id)
|
36
42
|
end
|
37
43
|
|
38
|
-
def environment
|
44
|
+
def self.environment
|
39
45
|
find_value_by_name(:braintree, :environment) || "sandbox"
|
40
46
|
end
|
47
|
+
|
48
|
+
def self.configure_webhooks
|
49
|
+
Pay::Webhooks.configure do |events|
|
50
|
+
events.subscribe "braintree.subscription_canceled", Pay::Braintree::Webhooks::SubscriptionCanceled.new
|
51
|
+
events.subscribe "braintree.subscription_charged_successfully", Pay::Braintree::Webhooks::SubscriptionChargedSuccessfully.new
|
52
|
+
events.subscribe "braintree.subscription_charged_unsuccessfully", Pay::Braintree::Webhooks::SubscriptionChargedUnsuccessfully.new
|
53
|
+
events.subscribe "braintree.subscription_expired", Pay::Braintree::Webhooks::SubscriptionExpired.new
|
54
|
+
events.subscribe "braintree.subscription_trial_ended", Pay::Braintree::Webhooks::SubscriptionTrialEnded.new
|
55
|
+
events.subscribe "braintree.subscription_went_active", Pay::Braintree::Webhooks::SubscriptionWentActive.new
|
56
|
+
events.subscribe "braintree.subscription_went_past_due", Pay::Braintree::Webhooks::SubscriptionWentPastDue.new
|
57
|
+
end
|
58
|
+
end
|
41
59
|
end
|
42
60
|
end
|
@@ -1,16 +1,23 @@
|
|
1
1
|
module Pay
|
2
2
|
module Braintree
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
class Billable
|
4
|
+
attr_reader :billable
|
5
|
+
|
6
|
+
delegate :processor_id,
|
7
|
+
:processor_id?,
|
8
|
+
:email,
|
9
|
+
:customer_name,
|
10
|
+
:card_token,
|
11
|
+
to: :billable
|
12
|
+
|
13
|
+
def initialize(billable)
|
14
|
+
@billable = billable
|
8
15
|
end
|
9
16
|
|
10
17
|
# Handles Billable#customer
|
11
18
|
#
|
12
19
|
# Returns Braintree::Customer
|
13
|
-
def
|
20
|
+
def customer
|
14
21
|
if processor_id?
|
15
22
|
gateway.customer.find(processor_id)
|
16
23
|
else
|
@@ -22,16 +29,16 @@ module Pay
|
|
22
29
|
)
|
23
30
|
raise Pay::Braintree::Error, result unless result.success?
|
24
31
|
|
25
|
-
update(processor: "braintree", processor_id: result.customer.id)
|
32
|
+
billable.update(processor: "braintree", processor_id: result.customer.id)
|
26
33
|
|
27
34
|
if card_token.present?
|
28
|
-
|
35
|
+
update_card_on_file result.customer.payment_methods.last
|
29
36
|
end
|
30
37
|
|
31
38
|
result.customer
|
32
39
|
end
|
33
40
|
rescue ::Braintree::AuthorizationError
|
34
|
-
raise
|
41
|
+
raise Pay::Braintree::AuthorizationError
|
35
42
|
rescue ::Braintree::BraintreeError => e
|
36
43
|
raise Pay::Braintree::Error, e
|
37
44
|
end
|
@@ -39,7 +46,7 @@ module Pay
|
|
39
46
|
# Handles Billable#charge
|
40
47
|
#
|
41
48
|
# Returns a Pay::Charge
|
42
|
-
def
|
49
|
+
def charge(amount, options = {})
|
43
50
|
args = {
|
44
51
|
amount: amount.to_i / 100.0,
|
45
52
|
customer_id: customer.id,
|
@@ -49,7 +56,7 @@ module Pay
|
|
49
56
|
result = gateway.transaction.sale(args)
|
50
57
|
raise Pay::Braintree::Error, result unless result.success?
|
51
58
|
|
52
|
-
|
59
|
+
save_transaction(result.transaction)
|
53
60
|
rescue ::Braintree::AuthorizationError
|
54
61
|
raise Pay::Braintree::AuthorizationError
|
55
62
|
rescue ::Braintree::BraintreeError => e
|
@@ -59,7 +66,7 @@ module Pay
|
|
59
66
|
# Handles Billable#subscribe
|
60
67
|
#
|
61
68
|
# Returns Pay::Subscription
|
62
|
-
def
|
69
|
+
def subscribe(name: Pay.default_product_name, plan: Pay.default_plan_name, **options)
|
63
70
|
token = customer.payment_methods.find(&:default?).try(:token)
|
64
71
|
raise Pay::Error, "Customer has no default payment method" if token.nil?
|
65
72
|
|
@@ -76,7 +83,7 @@ module Pay
|
|
76
83
|
result = gateway.subscription.create(subscription_options)
|
77
84
|
raise Pay::Braintree::Error, result unless result.success?
|
78
85
|
|
79
|
-
|
86
|
+
billable.create_pay_subscription(result.subscription, "braintree", name, plan, status: :active)
|
80
87
|
rescue ::Braintree::AuthorizationError
|
81
88
|
raise Pay::Braintree::AuthorizationError
|
82
89
|
rescue ::Braintree::BraintreeError => e
|
@@ -86,7 +93,7 @@ module Pay
|
|
86
93
|
# Handles Billable#update_card
|
87
94
|
#
|
88
95
|
# Returns true if successful
|
89
|
-
def
|
96
|
+
def update_card(token)
|
90
97
|
result = gateway.payment_method.create(
|
91
98
|
customer_id: processor_id,
|
92
99
|
payment_method_nonce: token,
|
@@ -97,7 +104,7 @@ module Pay
|
|
97
104
|
)
|
98
105
|
raise Pay::Braintree::Error, result unless result.success?
|
99
106
|
|
100
|
-
|
107
|
+
update_card_on_file result.payment_method
|
101
108
|
update_subscriptions_to_payment_method(result.payment_method.token)
|
102
109
|
true
|
103
110
|
rescue ::Braintree::AuthorizationError
|
@@ -106,29 +113,25 @@ module Pay
|
|
106
113
|
raise Pay::Braintree::Error, e
|
107
114
|
end
|
108
115
|
|
109
|
-
def
|
110
|
-
|
111
|
-
email: email,
|
112
|
-
first_name: try(:first_name),
|
113
|
-
last_name: try(:last_name)
|
114
|
-
)
|
116
|
+
def update_email!
|
117
|
+
gateway.customer.update(processor_id, email: email, first_name: try(:first_name), last_name: try(:last_name))
|
115
118
|
end
|
116
119
|
|
117
|
-
def
|
120
|
+
def trial_end_date(subscription)
|
118
121
|
return unless subscription.trial_period
|
119
122
|
# Braintree returns dates without time zones, so we'll assume they're UTC
|
120
123
|
subscription.first_billing_date.end_of_day
|
121
124
|
end
|
122
125
|
|
123
126
|
def update_subscriptions_to_payment_method(token)
|
124
|
-
subscriptions.braintree.each do |subscription|
|
127
|
+
billable.subscriptions.braintree.each do |subscription|
|
125
128
|
if subscription.active?
|
126
129
|
gateway.subscription.update(subscription.processor_id, {payment_method_token: token})
|
127
130
|
end
|
128
131
|
end
|
129
132
|
end
|
130
133
|
|
131
|
-
def
|
134
|
+
def processor_subscription(subscription_id, options = {})
|
132
135
|
gateway.subscription.find(subscription_id)
|
133
136
|
end
|
134
137
|
|
@@ -140,11 +143,11 @@ module Pay
|
|
140
143
|
# pass
|
141
144
|
end
|
142
145
|
|
143
|
-
def
|
146
|
+
def save_transaction(transaction)
|
144
147
|
attrs = card_details_for_braintree_transaction(transaction)
|
145
148
|
attrs[:amount] = transaction.amount.to_f * 100
|
146
149
|
|
147
|
-
charge = charges.find_or_initialize_by(
|
150
|
+
charge = billable.charges.find_or_initialize_by(
|
148
151
|
processor: :braintree,
|
149
152
|
processor_id: transaction.id
|
150
153
|
)
|
@@ -158,10 +161,10 @@ module Pay
|
|
158
161
|
Pay.braintree_gateway
|
159
162
|
end
|
160
163
|
|
161
|
-
def
|
164
|
+
def update_card_on_file(payment_method)
|
162
165
|
case payment_method
|
163
166
|
when ::Braintree::CreditCard
|
164
|
-
update!(
|
167
|
+
billable.update!(
|
165
168
|
card_type: payment_method.card_type,
|
166
169
|
card_last4: payment_method.last_4,
|
167
170
|
card_exp_month: payment_method.expiration_month,
|
@@ -169,14 +172,14 @@ module Pay
|
|
169
172
|
)
|
170
173
|
|
171
174
|
when ::Braintree::PayPalAccount
|
172
|
-
update!(
|
175
|
+
billable.update!(
|
173
176
|
card_type: "PayPal",
|
174
177
|
card_last4: payment_method.email
|
175
178
|
)
|
176
179
|
end
|
177
180
|
|
178
181
|
# Clear the card token so we don't accidentally update twice
|
179
|
-
|
182
|
+
billable.card_token = nil
|
180
183
|
end
|
181
184
|
|
182
185
|
def card_details_for_braintree_transaction(transaction)
|