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
data/lib/pay/braintree/charge.rb
CHANGED
@@ -1,26 +1,24 @@
|
|
1
1
|
module Pay
|
2
2
|
module Braintree
|
3
|
-
|
4
|
-
|
3
|
+
class Charge
|
4
|
+
attr_reader :pay_charge
|
5
5
|
|
6
|
-
|
7
|
-
scope :braintree, -> { where(processor: :braintree) }
|
8
|
-
end
|
6
|
+
delegate :processor_id, to: :pay_charge
|
9
7
|
|
10
|
-
def
|
11
|
-
|
8
|
+
def initialize(pay_charge)
|
9
|
+
@pay_charge = pay_charge
|
12
10
|
end
|
13
11
|
|
14
|
-
def
|
12
|
+
def charge
|
15
13
|
Pay.braintree_gateway.transaction.find(processor_id)
|
16
14
|
rescue ::Braintree::Braintree::Error => e
|
17
15
|
raise Pay::Braintree::Error, e
|
18
16
|
end
|
19
17
|
|
20
|
-
def
|
18
|
+
def refund!(amount_to_refund)
|
21
19
|
Pay.braintree_gateway.transaction.refund(processor_id, amount_to_refund / 100.0)
|
22
20
|
|
23
|
-
update(amount_refunded: amount_to_refund)
|
21
|
+
pay_charge.update(amount_refunded: amount_to_refund)
|
24
22
|
rescue ::Braintree::BraintreeError => e
|
25
23
|
raise Pay::Braintree::Error, e
|
26
24
|
end
|
@@ -1,44 +1,64 @@
|
|
1
1
|
module Pay
|
2
2
|
module Braintree
|
3
|
-
|
4
|
-
|
3
|
+
class Subscription
|
4
|
+
attr_reader :pay_subscription
|
5
|
+
|
6
|
+
delegate :active?,
|
7
|
+
:canceled?,
|
8
|
+
:ends_at,
|
9
|
+
:name,
|
10
|
+
:on_trial?,
|
11
|
+
:owner,
|
12
|
+
:processor_subscription,
|
13
|
+
:processor_id,
|
14
|
+
:prorate,
|
15
|
+
:prorate?,
|
16
|
+
:processor_plan,
|
17
|
+
:quantity?,
|
18
|
+
:quantity,
|
19
|
+
:trial_ends_at,
|
20
|
+
to: :pay_subscription
|
21
|
+
|
22
|
+
def initialize(pay_subscription)
|
23
|
+
@pay_subscription = pay_subscription
|
24
|
+
end
|
5
25
|
|
6
|
-
def
|
26
|
+
def cancel
|
7
27
|
subscription = processor_subscription
|
8
28
|
|
9
29
|
if on_trial?
|
10
30
|
gateway.subscription.cancel(processor_subscription.id)
|
11
|
-
update(status: :canceled, ends_at: trial_ends_at)
|
31
|
+
pay_subscription.update(status: :canceled, ends_at: trial_ends_at)
|
12
32
|
else
|
13
33
|
gateway.subscription.update(subscription.id, {
|
14
34
|
number_of_billing_cycles: subscription.current_billing_cycle
|
15
35
|
})
|
16
|
-
update(status: :canceled, ends_at: subscription.billing_period_end_date.to_date)
|
36
|
+
pay_subscription.update(status: :canceled, ends_at: subscription.billing_period_end_date.to_date)
|
17
37
|
end
|
18
38
|
rescue ::Braintree::BraintreeError => e
|
19
39
|
raise Pay::Braintree::Error, e
|
20
40
|
end
|
21
41
|
|
22
|
-
def
|
42
|
+
def cancel_now!
|
23
43
|
gateway.subscription.cancel(processor_subscription.id)
|
24
|
-
update(status: :canceled, ends_at: Time.zone.now)
|
44
|
+
pay_subscription.update(status: :canceled, ends_at: Time.zone.now)
|
25
45
|
rescue ::Braintree::BraintreeError => e
|
26
46
|
raise Pay::Braintree::Error, e
|
27
47
|
end
|
28
48
|
|
29
|
-
def
|
49
|
+
def on_grace_period?
|
30
50
|
canceled? && Time.zone.now < ends_at
|
31
51
|
end
|
32
52
|
|
33
|
-
def
|
53
|
+
def paused?
|
34
54
|
false
|
35
55
|
end
|
36
56
|
|
37
|
-
def
|
57
|
+
def pause
|
38
58
|
raise NotImplementedError, "Braintree does not support pausing subscriptions"
|
39
59
|
end
|
40
60
|
|
41
|
-
def
|
61
|
+
def resume
|
42
62
|
unless on_grace_period?
|
43
63
|
raise StandardError, "You can only resume subscriptions within their grace period."
|
44
64
|
end
|
@@ -53,7 +73,6 @@ module Pay
|
|
53
73
|
trial_duration: duration.to_i,
|
54
74
|
trial_duration_unit: :day
|
55
75
|
)
|
56
|
-
|
57
76
|
else
|
58
77
|
subscription = processor_subscription
|
59
78
|
|
@@ -63,12 +82,12 @@ module Pay
|
|
63
82
|
})
|
64
83
|
end
|
65
84
|
|
66
|
-
update(status: :active)
|
85
|
+
pay_subscription.update(status: :active)
|
67
86
|
rescue ::Braintree::BraintreeError => e
|
68
87
|
raise Pay::Braintree::Error, e
|
69
88
|
end
|
70
89
|
|
71
|
-
def
|
90
|
+
def swap(plan)
|
72
91
|
if on_grace_period? && processor_plan == plan
|
73
92
|
resume
|
74
93
|
return
|
@@ -99,7 +118,7 @@ module Pay
|
|
99
118
|
})
|
100
119
|
|
101
120
|
if result.success?
|
102
|
-
update(status: :active, processor_plan: braintree_plan.id, ends_at: nil)
|
121
|
+
pay_subscription.update(status: :active, processor_plan: braintree_plan.id, ends_at: nil)
|
103
122
|
else
|
104
123
|
raise Error, "Braintree failed to swap plans: #{result.message}"
|
105
124
|
end
|
@@ -12,7 +12,7 @@ module Pay
|
|
12
12
|
return unless pay_subscription.present?
|
13
13
|
|
14
14
|
billable = pay_subscription.owner
|
15
|
-
charge = billable.
|
15
|
+
charge = Pay::Braintree::Billable.new(billable).save_transaction(subscription.transactions.first)
|
16
16
|
|
17
17
|
if Pay.send_emails
|
18
18
|
Pay::UserMailer.with(billable: billable, charge: charge).receipt.deliver_later
|
@@ -12,7 +12,7 @@ module Pay
|
|
12
12
|
return unless pay_subscription.present?
|
13
13
|
|
14
14
|
# billable = pay_subscription.owner
|
15
|
-
# charge = billable.
|
15
|
+
# charge = Pay::Braintree::Billable.new(billable).save_transaction(subscription.transactions.first)
|
16
16
|
|
17
17
|
# if Pay.send_emails
|
18
18
|
# Pay::UserMailer.with(billable: billable, charge: charge).receipt.deliver_later
|
data/lib/pay/engine.rb
CHANGED
@@ -1,32 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# rubocop:disable Lint/HandleExceptions
|
4
|
-
begin
|
5
|
-
require "braintree"
|
6
|
-
rescue LoadError
|
7
|
-
end
|
8
|
-
|
9
|
-
begin
|
10
|
-
require "stripe"
|
11
|
-
rescue LoadError
|
12
|
-
end
|
13
|
-
|
14
|
-
begin
|
15
|
-
require "paddle_pay"
|
16
|
-
rescue LoadError
|
17
|
-
end
|
18
|
-
# rubocop:enable Lint/HandleExceptions
|
19
|
-
|
20
3
|
module Pay
|
21
4
|
class Engine < ::Rails::Engine
|
22
5
|
engine_name "pay"
|
23
6
|
|
24
7
|
initializer "pay.processors" do |app|
|
25
|
-
# Include processor backends
|
26
|
-
require "pay/stripe" if defined? ::Stripe
|
27
|
-
require "pay/braintree" if defined? ::Braintree
|
28
|
-
require "pay/paddle" if defined? ::PaddlePay
|
29
|
-
|
30
8
|
if Pay.automount_routes
|
31
9
|
app.routes.append do
|
32
10
|
mount Pay::Engine, at: Pay.routes_path, as: "pay"
|
data/lib/pay/errors.rb
CHANGED
@@ -26,48 +26,4 @@ module Pay
|
|
26
26
|
I18n.t("errors.invalid_payment")
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
30
|
-
module Braintree
|
31
|
-
class Error < Error
|
32
|
-
def message
|
33
|
-
result.message
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
class AuthorizationError < Braintree::Error
|
38
|
-
def message
|
39
|
-
I18n.t("errors.braintree.authorization")
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
module Stripe
|
45
|
-
class Error < Error
|
46
|
-
def message
|
47
|
-
I18n.t("errors.stripe.#{result.code}", default: result.message)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
module Paddle
|
53
|
-
class Error < Error
|
54
|
-
def message
|
55
|
-
I18n.t("errors.paddle.#{result.code}", default: result.message)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
class BraintreeError < Braintree::Error
|
61
|
-
def message
|
62
|
-
ActiveSupport::Deprecation.warn("Pay::BraintreeError is deprecated. Instead, use `Pay::Braintree::Error`.")
|
63
|
-
super
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
class BraintreeAuthorizationError < BraintreeError
|
68
|
-
def message
|
69
|
-
ActiveSupport::Deprecation.warn("Pay::BraintreeAuthorizationError is deprecated. Instead, use `Pay::Braintree::AuthorizationError`.")
|
70
|
-
I18n.t("errors.braintree.authorization")
|
71
|
-
end
|
72
|
-
end
|
73
29
|
end
|
data/lib/pay/paddle.rb
CHANGED
@@ -1,38 +1,52 @@
|
|
1
|
-
require "pay/env"
|
2
|
-
require "pay/paddle/billable"
|
3
|
-
require "pay/paddle/charge"
|
4
|
-
require "pay/paddle/subscription"
|
5
|
-
require "pay/paddle/webhooks"
|
6
|
-
|
7
1
|
module Pay
|
8
2
|
module Paddle
|
9
|
-
|
3
|
+
autoload :Billable, "pay/paddle/billable"
|
4
|
+
autoload :Charge, "pay/paddle/charge"
|
5
|
+
autoload :Subscription, "pay/paddle/subscription"
|
6
|
+
autoload :Error, "pay/paddle/error"
|
7
|
+
|
8
|
+
module Webhooks
|
9
|
+
autoload :SignatureVerifier, "pay/paddle/webhooks/signature_verifier"
|
10
|
+
autoload :SubscriptionCreated, "pay/paddle/webhooks/subscription_created"
|
11
|
+
autoload :SubscriptionCancelled, "pay/paddle/webhooks/subscription_cancelled"
|
12
|
+
autoload :SubscriptionPaymentRefunded, "pay/paddle/webhooks/subscription_payment_refunded"
|
13
|
+
autoload :SubscriptionPaymentSucceeded, "pay/paddle/webhooks/subscription_payment_succeeded"
|
14
|
+
autoload :SubscriptionUpdated, "pay/paddle/webhooks/subscription_updated"
|
15
|
+
end
|
10
16
|
|
11
|
-
extend
|
17
|
+
extend Env
|
12
18
|
|
13
|
-
def setup
|
19
|
+
def self.setup
|
14
20
|
::PaddlePay.config.vendor_id = vendor_id
|
15
21
|
::PaddlePay.config.vendor_auth_code = vendor_auth_code
|
16
22
|
|
17
|
-
|
18
|
-
Pay.subscription_model.include Pay::Paddle::Subscription
|
19
|
-
Pay.billable_models.each { |model| model.include Pay::Paddle::Billable }
|
23
|
+
configure_webhooks
|
20
24
|
end
|
21
25
|
|
22
|
-
def vendor_id
|
26
|
+
def self.vendor_id
|
23
27
|
find_value_by_name(:paddle, :vendor_id)
|
24
28
|
end
|
25
29
|
|
26
|
-
def vendor_auth_code
|
30
|
+
def self.vendor_auth_code
|
27
31
|
find_value_by_name(:paddle, :vendor_auth_code)
|
28
32
|
end
|
29
33
|
|
30
|
-
def public_key_base64
|
34
|
+
def self.public_key_base64
|
31
35
|
find_value_by_name(:paddle, :public_key_base64)
|
32
36
|
end
|
33
37
|
|
34
|
-
def passthrough(owner:, **options)
|
38
|
+
def self.passthrough(owner:, **options)
|
35
39
|
options.merge(owner_sgid: owner.to_sgid.to_s).to_json
|
36
40
|
end
|
41
|
+
|
42
|
+
def self.configure_webhooks
|
43
|
+
Pay::Webhooks.configure do |events|
|
44
|
+
events.subscribe "paddle.subscription_created", Pay::Paddle::Webhooks::SubscriptionCreated.new
|
45
|
+
events.subscribe "paddle.subscription_updated", Pay::Paddle::Webhooks::SubscriptionUpdated.new
|
46
|
+
events.subscribe "paddle.subscription_cancelled", Pay::Paddle::Webhooks::SubscriptionCancelled.new
|
47
|
+
events.subscribe "paddle.subscription_payment_succeeded", Pay::Paddle::Webhooks::SubscriptionPaymentSucceeded.new
|
48
|
+
events.subscribe "paddle.subscription_payment_refunded", Pay::Paddle::Webhooks::SubscriptionPaymentRefunded.new
|
49
|
+
end
|
50
|
+
end
|
37
51
|
end
|
38
52
|
end
|
data/lib/pay/paddle/billable.rb
CHANGED
@@ -1,27 +1,32 @@
|
|
1
1
|
module Pay
|
2
2
|
module Paddle
|
3
|
-
|
4
|
-
|
3
|
+
class Billable
|
4
|
+
attr_reader :billable
|
5
5
|
|
6
|
-
|
7
|
-
|
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
|
-
def
|
17
|
+
def customer
|
11
18
|
# pass
|
12
19
|
end
|
13
20
|
|
14
|
-
def
|
21
|
+
def charge(amount, options = {})
|
22
|
+
subscription = billable.subscription
|
15
23
|
return unless subscription.processor_id
|
16
24
|
raise Pay::Error, "A charge_name is required to create a one-time charge" if options[:charge_name].nil?
|
17
25
|
response = PaddlePay::Subscription::Charge.create(subscription.processor_id, amount.to_f / 100, options[:charge_name], options)
|
18
|
-
charge = charges.find_or_initialize_by(
|
19
|
-
processor: :paddle,
|
20
|
-
processor_id: response[:invoice_id]
|
21
|
-
)
|
26
|
+
charge = billable.charges.find_or_initialize_by(processor: :paddle, processor_id: response[:invoice_id])
|
22
27
|
charge.update(
|
23
28
|
amount: Integer(response[:amount].to_f * 100),
|
24
|
-
card_type: subscription.
|
29
|
+
card_type: processor_subscription(subscription.processor_id).payment_information[:payment_method],
|
25
30
|
paddle_receipt_url: response[:receipt_url],
|
26
31
|
created_at: Time.zone.parse(response[:payment_date])
|
27
32
|
)
|
@@ -30,46 +35,45 @@ module Pay
|
|
30
35
|
raise Pay::Paddle::Error, e
|
31
36
|
end
|
32
37
|
|
33
|
-
def
|
38
|
+
def subscribe(name: Pay.default_product_name, plan: Pay.default_plan_name, **options)
|
34
39
|
# pass
|
35
40
|
end
|
36
41
|
|
37
|
-
def
|
42
|
+
def update_card(token)
|
38
43
|
sync_payment_information_from_paddle
|
39
44
|
end
|
40
45
|
|
41
|
-
def
|
46
|
+
def update_email!
|
42
47
|
# pass
|
43
48
|
end
|
44
49
|
|
45
|
-
def
|
50
|
+
def trial_end_date(subscription)
|
46
51
|
return unless subscription.state == "trialing"
|
47
52
|
Time.zone.parse(subscription.next_payment[:date]).end_of_day
|
48
53
|
end
|
49
54
|
|
50
|
-
def
|
55
|
+
def processor_subscription(subscription_id, options = {})
|
51
56
|
hash = PaddlePay::Subscription::User.list({subscription_id: subscription_id}, options).try(:first)
|
52
57
|
OpenStruct.new(hash)
|
53
58
|
rescue ::PaddlePay::PaddlePayError => e
|
54
59
|
raise Pay::Paddle::Error, e
|
55
60
|
end
|
56
61
|
|
57
|
-
def
|
62
|
+
def invoice!(options = {})
|
58
63
|
# pass
|
59
64
|
end
|
60
65
|
|
61
|
-
def
|
66
|
+
def upcoming_invoice
|
62
67
|
# pass
|
63
68
|
end
|
64
69
|
|
65
|
-
def
|
66
|
-
payment_information
|
67
|
-
update!(payment_information) unless payment_information.empty?
|
70
|
+
def sync_payment_information
|
71
|
+
billable.update!(payment_information(billable.subscription.processor_id))
|
68
72
|
rescue ::PaddlePay::PaddlePayError => e
|
69
73
|
raise Pay::Paddle::Error, e
|
70
74
|
end
|
71
75
|
|
72
|
-
def
|
76
|
+
def payment_information(subscription_id)
|
73
77
|
subscription_user = PaddlePay::Subscription::User.list({subscription_id: subscription_id}).try(:first)
|
74
78
|
payment_information = subscription_user ? subscription_user[:payment_information] : nil
|
75
79
|
return {} if payment_information.nil?
|
data/lib/pay/paddle/charge.rb
CHANGED
@@ -1,19 +1,15 @@
|
|
1
1
|
module Pay
|
2
2
|
module Paddle
|
3
|
-
|
4
|
-
|
3
|
+
class Charge
|
4
|
+
attr_reader :pay_charge
|
5
5
|
|
6
|
-
|
7
|
-
scope :paddle, -> { where(processor: :paddle) }
|
6
|
+
delegate :processor_id, :owner, to: :pay_charge
|
8
7
|
|
9
|
-
|
8
|
+
def initialize(pay_charge)
|
9
|
+
@pay_charge = pay_charge
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
processor == "paddle"
|
14
|
-
end
|
15
|
-
|
16
|
-
def paddle_charge
|
12
|
+
def charge
|
17
13
|
return unless owner.subscription
|
18
14
|
payments = PaddlePay::Subscription::Payment.list({subscription_id: owner.subscription.processor_id})
|
19
15
|
charges = payments.select { |p| p[:id].to_s == processor_id }
|
@@ -22,12 +18,12 @@ module Pay
|
|
22
18
|
raise Pay::Paddle::Error, e
|
23
19
|
end
|
24
20
|
|
25
|
-
def
|
21
|
+
def refund!(amount_to_refund)
|
26
22
|
return unless owner.subscription
|
27
23
|
payments = PaddlePay::Subscription::Payment.list({subscription_id: owner.subscription.processor_id, is_paid: 1})
|
28
24
|
if payments.count > 0
|
29
25
|
PaddlePay::Subscription::Payment.refund(payments.last[:id], {amount: amount_to_refund})
|
30
|
-
update(amount_refunded: amount_to_refund)
|
26
|
+
pay_charge.update(amount_refunded: amount_to_refund)
|
31
27
|
else
|
32
28
|
raise Error, "Payment not found"
|
33
29
|
end
|