pay 2.3.1 → 2.4.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/README.md +5 -2
- data/app/controllers/pay/webhooks/braintree_controller.rb +1 -1
- data/app/mailers/pay/user_mailer.rb +14 -35
- data/app/models/pay/subscription.rb +4 -2
- data/app/views/pay/user_mailer/payment_action_required.html.erb +1 -1
- data/app/views/pay/user_mailer/receipt.html.erb +6 -6
- data/app/views/pay/user_mailer/refund.html.erb +6 -6
- data/app/views/pay/user_mailer/subscription_renewing.html.erb +1 -1
- data/config/locales/en.yml +137 -0
- data/lib/pay.rb +6 -41
- data/lib/pay/billable.rb +9 -9
- data/lib/pay/braintree/billable.rb +11 -11
- data/lib/pay/braintree/charge.rb +3 -3
- data/lib/pay/braintree/subscription.rb +9 -5
- data/lib/pay/errors.rb +73 -0
- data/lib/pay/paddle/billable.rb +34 -5
- data/lib/pay/paddle/charge.rb +2 -2
- data/lib/pay/paddle/subscription.rb +18 -7
- data/lib/pay/paddle/webhooks/subscription_cancelled.rb +1 -1
- data/lib/pay/paddle/webhooks/subscription_created.rb +1 -1
- data/lib/pay/paddle/webhooks/subscription_payment_refunded.rb +2 -2
- data/lib/pay/paddle/webhooks/subscription_payment_succeeded.rb +8 -29
- data/lib/pay/paddle/webhooks/subscription_updated.rb +15 -12
- data/lib/pay/receipts.rb +6 -6
- data/lib/pay/stripe/billable.rb +4 -4
- data/lib/pay/stripe/charge.rb +2 -2
- data/lib/pay/stripe/subscription.rb +8 -4
- data/lib/pay/stripe/webhooks/charge_refunded.rb +2 -2
- data/lib/pay/stripe/webhooks/charge_succeeded.rb +1 -1
- data/lib/pay/stripe/webhooks/payment_action_required.rb +1 -1
- data/lib/pay/stripe/webhooks/subscription_created.rb +1 -1
- data/lib/pay/stripe/webhooks/subscription_renewing.rb +4 -3
- data/lib/pay/version.rb +1 -1
- metadata +11 -74
@@ -20,7 +20,7 @@ module Pay
|
|
20
20
|
last_name: try(:last_name),
|
21
21
|
payment_method_nonce: card_token
|
22
22
|
)
|
23
|
-
raise
|
23
|
+
raise Pay::Braintree::Error, result unless result.success?
|
24
24
|
|
25
25
|
update(processor: "braintree", processor_id: result.customer.id)
|
26
26
|
|
@@ -33,7 +33,7 @@ module Pay
|
|
33
33
|
rescue ::Braintree::AuthorizationError
|
34
34
|
raise BraintreeAuthorizationError
|
35
35
|
rescue ::Braintree::BraintreeError => e
|
36
|
-
raise
|
36
|
+
raise Pay::Braintree::Error, e
|
37
37
|
end
|
38
38
|
|
39
39
|
# Handles Billable#charge
|
@@ -47,13 +47,13 @@ module Pay
|
|
47
47
|
}.merge(options)
|
48
48
|
|
49
49
|
result = gateway.transaction.sale(args)
|
50
|
-
raise
|
50
|
+
raise Pay::Braintree::Error, result unless result.success?
|
51
51
|
|
52
52
|
save_braintree_transaction(result.transaction)
|
53
53
|
rescue ::Braintree::AuthorizationError
|
54
|
-
raise
|
54
|
+
raise Pay::Braintree::AuthorizationError
|
55
55
|
rescue ::Braintree::BraintreeError => e
|
56
|
-
raise
|
56
|
+
raise Pay::Braintree::Error, e
|
57
57
|
end
|
58
58
|
|
59
59
|
# Handles Billable#subscribe
|
@@ -74,13 +74,13 @@ module Pay
|
|
74
74
|
)
|
75
75
|
|
76
76
|
result = gateway.subscription.create(subscription_options)
|
77
|
-
raise
|
77
|
+
raise Pay::Braintree::Error, result unless result.success?
|
78
78
|
|
79
79
|
create_subscription(result.subscription, "braintree", name, plan, status: :active)
|
80
80
|
rescue ::Braintree::AuthorizationError
|
81
|
-
raise
|
81
|
+
raise Pay::Braintree::AuthorizationError
|
82
82
|
rescue ::Braintree::BraintreeError => e
|
83
|
-
raise
|
83
|
+
raise Pay::Braintree::Error, e
|
84
84
|
end
|
85
85
|
|
86
86
|
# Handles Billable#update_card
|
@@ -95,15 +95,15 @@ module Pay
|
|
95
95
|
verify_card: true
|
96
96
|
}
|
97
97
|
)
|
98
|
-
raise
|
98
|
+
raise Pay::Braintree::Error, result unless result.success?
|
99
99
|
|
100
100
|
update_braintree_card_on_file result.payment_method
|
101
101
|
update_subscriptions_to_payment_method(result.payment_method.token)
|
102
102
|
true
|
103
103
|
rescue ::Braintree::AuthorizationError
|
104
|
-
raise
|
104
|
+
raise Pay::Braintree::AuthorizationError
|
105
105
|
rescue ::Braintree::BraintreeError => e
|
106
|
-
raise
|
106
|
+
raise Pay::Braintree::Error, e
|
107
107
|
end
|
108
108
|
|
109
109
|
def update_braintree_email!
|
data/lib/pay/braintree/charge.rb
CHANGED
@@ -13,8 +13,8 @@ module Pay
|
|
13
13
|
|
14
14
|
def braintree_charge
|
15
15
|
Pay.braintree_gateway.transaction.find(processor_id)
|
16
|
-
rescue ::Braintree::
|
17
|
-
raise Error, e
|
16
|
+
rescue ::Braintree::Braintree::Error => e
|
17
|
+
raise Pay::Braintree::Error, e
|
18
18
|
end
|
19
19
|
|
20
20
|
def braintree_refund!(amount_to_refund)
|
@@ -22,7 +22,7 @@ module Pay
|
|
22
22
|
|
23
23
|
update(amount_refunded: amount_to_refund)
|
24
24
|
rescue ::Braintree::BraintreeError => e
|
25
|
-
raise Error, e
|
25
|
+
raise Pay::Braintree::Error, e
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -24,14 +24,18 @@ module Pay
|
|
24
24
|
update(status: :canceled, ends_at: subscription.billing_period_end_date.to_date)
|
25
25
|
end
|
26
26
|
rescue ::Braintree::BraintreeError => e
|
27
|
-
raise Error, e
|
27
|
+
raise Pay::Braintree::Error, e
|
28
28
|
end
|
29
29
|
|
30
30
|
def braintree_cancel_now!
|
31
31
|
gateway.subscription.cancel(processor_subscription.id)
|
32
32
|
update(status: :canceled, ends_at: Time.zone.now)
|
33
33
|
rescue ::Braintree::BraintreeError => e
|
34
|
-
raise Error, e
|
34
|
+
raise Pay::Braintree::Error, e
|
35
|
+
end
|
36
|
+
|
37
|
+
def braintree_on_grace_period?
|
38
|
+
canceled? && Time.zone.now < ends_at
|
35
39
|
end
|
36
40
|
|
37
41
|
def braintree_resume
|
@@ -57,7 +61,7 @@ module Pay
|
|
57
61
|
|
58
62
|
update(status: :active)
|
59
63
|
rescue ::Braintree::BraintreeError => e
|
60
|
-
raise Error, e
|
64
|
+
raise Pay::Braintree::Error, e
|
61
65
|
end
|
62
66
|
|
63
67
|
def braintree_swap(plan)
|
@@ -96,7 +100,7 @@ module Pay
|
|
96
100
|
raise Error, "Braintree failed to swap plans: #{result.message}"
|
97
101
|
end
|
98
102
|
rescue ::Braintree::BraintreeError => e
|
99
|
-
raise Error, e
|
103
|
+
raise Pay::Braintree::Error, e
|
100
104
|
end
|
101
105
|
|
102
106
|
private
|
@@ -174,7 +178,7 @@ module Pay
|
|
174
178
|
|
175
179
|
cancel_now!
|
176
180
|
|
177
|
-
owner.subscribe(options.merge(name: name, plan: plan.id))
|
181
|
+
owner.subscribe(**options.merge(name: name, plan: plan.id))
|
178
182
|
end
|
179
183
|
end
|
180
184
|
end
|
data/lib/pay/errors.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
module Pay
|
2
|
+
class Error < StandardError
|
3
|
+
attr_reader :result
|
4
|
+
|
5
|
+
def initialize(result = nil)
|
6
|
+
@result = result
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class PaymentError < StandardError
|
11
|
+
attr_reader :payment
|
12
|
+
|
13
|
+
def initialize(payment)
|
14
|
+
@payment = payment
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class ActionRequired < PaymentError
|
19
|
+
def message
|
20
|
+
I18n.t("errors.action_required")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class InvalidPaymentMethod < PaymentError
|
25
|
+
def message
|
26
|
+
I18n.t("errors.invalid_payment")
|
27
|
+
end
|
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
|
+
end
|
data/lib/pay/paddle/billable.rb
CHANGED
@@ -23,11 +23,11 @@ module Pay
|
|
23
23
|
amount: Integer(response[:amount].to_f * 100),
|
24
24
|
card_type: subscription.processor_subscription.payment_information[:payment_method],
|
25
25
|
paddle_receipt_url: response[:receipt_url],
|
26
|
-
created_at:
|
26
|
+
created_at: Time.zone.parse(response[:payment_date])
|
27
27
|
)
|
28
28
|
charge
|
29
29
|
rescue ::PaddlePay::PaddlePayError => e
|
30
|
-
raise Error, e
|
30
|
+
raise Pay::Paddle::Error, e
|
31
31
|
end
|
32
32
|
|
33
33
|
def create_paddle_subscription(name, plan, options = {})
|
@@ -35,7 +35,7 @@ module Pay
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def update_paddle_card(token)
|
38
|
-
|
38
|
+
sync_payment_information_from_paddle
|
39
39
|
end
|
40
40
|
|
41
41
|
def update_paddle_email!
|
@@ -44,14 +44,14 @@ module Pay
|
|
44
44
|
|
45
45
|
def paddle_trial_end_date(subscription)
|
46
46
|
return unless subscription.state == "trialing"
|
47
|
-
|
47
|
+
Time.zone.parse(subscription.next_payment[:date]).end_of_day
|
48
48
|
end
|
49
49
|
|
50
50
|
def paddle_subscription(subscription_id, options = {})
|
51
51
|
hash = PaddlePay::Subscription::User.list({subscription_id: subscription_id}, options).try(:first)
|
52
52
|
OpenStruct.new(hash)
|
53
53
|
rescue ::PaddlePay::PaddlePayError => e
|
54
|
-
raise Error, e
|
54
|
+
raise Pay::Paddle::Error, e
|
55
55
|
end
|
56
56
|
|
57
57
|
def paddle_invoice!(options = {})
|
@@ -61,6 +61,35 @@ module Pay
|
|
61
61
|
def paddle_upcoming_invoice
|
62
62
|
# pass
|
63
63
|
end
|
64
|
+
|
65
|
+
def sync_payment_information_from_paddle
|
66
|
+
payment_information = paddle_payment_information(subscription.processor_id)
|
67
|
+
update!(payment_information) unless payment_information.empty?
|
68
|
+
rescue ::PaddlePay::PaddlePayError => e
|
69
|
+
raise Pay::Paddle::Error, e
|
70
|
+
end
|
71
|
+
|
72
|
+
def paddle_payment_information(subscription_id)
|
73
|
+
subscription_user = PaddlePay::Subscription::User.list({subscription_id: subscription_id}).try(:first)
|
74
|
+
payment_information = subscription_user ? subscription_user[:payment_information] : nil
|
75
|
+
return {} if payment_information.nil?
|
76
|
+
|
77
|
+
case payment_information[:payment_method]
|
78
|
+
when "card"
|
79
|
+
{
|
80
|
+
card_type: payment_information[:card_type],
|
81
|
+
card_last4: payment_information[:last_four_digits],
|
82
|
+
card_exp_month: payment_information[:expiry_date].split("/").first,
|
83
|
+
card_exp_year: payment_information[:expiry_date].split("/").last
|
84
|
+
}
|
85
|
+
when "paypal"
|
86
|
+
{
|
87
|
+
card_type: "PayPal"
|
88
|
+
}
|
89
|
+
else
|
90
|
+
{}
|
91
|
+
end
|
92
|
+
end
|
64
93
|
end
|
65
94
|
end
|
66
95
|
end
|
data/lib/pay/paddle/charge.rb
CHANGED
@@ -19,7 +19,7 @@ module Pay
|
|
19
19
|
charges = payments.select { |p| p[:id].to_s == processor_id }
|
20
20
|
charges.try(:first)
|
21
21
|
rescue ::PaddlePay::PaddlePayError => e
|
22
|
-
raise Error, e
|
22
|
+
raise Pay::Paddle::Error, e
|
23
23
|
end
|
24
24
|
|
25
25
|
def paddle_refund!(amount_to_refund)
|
@@ -32,7 +32,7 @@ module Pay
|
|
32
32
|
raise Error, "Payment not found"
|
33
33
|
end
|
34
34
|
rescue ::PaddlePay::PaddlePayError => e
|
35
|
-
raise Error, e
|
35
|
+
raise Pay::Paddle::Error, e
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -8,6 +8,7 @@ module Pay
|
|
8
8
|
|
9
9
|
store_accessor :data, :paddle_update_url
|
10
10
|
store_accessor :data, :paddle_cancel_url
|
11
|
+
store_accessor :data, :paddle_paused_from
|
11
12
|
end
|
12
13
|
|
13
14
|
def paddle?
|
@@ -20,31 +21,41 @@ module Pay
|
|
20
21
|
if on_trial?
|
21
22
|
update(status: :canceled, ends_at: trial_ends_at)
|
22
23
|
else
|
23
|
-
update(status: :canceled, ends_at:
|
24
|
+
update(status: :canceled, ends_at: Time.zone.parse(subscription.next_payment[:date]))
|
24
25
|
end
|
25
26
|
rescue ::PaddlePay::PaddlePayError => e
|
26
|
-
raise Error, e
|
27
|
+
raise Pay::Paddle::Error, e
|
27
28
|
end
|
28
29
|
|
29
30
|
def paddle_cancel_now!
|
30
31
|
PaddlePay::Subscription::User.cancel(processor_id)
|
31
32
|
update(status: :canceled, ends_at: Time.zone.now)
|
32
33
|
rescue ::PaddlePay::PaddlePayError => e
|
33
|
-
raise Error, e
|
34
|
+
raise Pay::Paddle::Error, e
|
35
|
+
end
|
36
|
+
|
37
|
+
def paddle_on_grace_period?
|
38
|
+
canceled? && Time.zone.now < ends_at || paused? && Time.zone.now < paddle_paused_from
|
39
|
+
end
|
40
|
+
|
41
|
+
def paddle_paused?
|
42
|
+
paddle_paused_from.present?
|
34
43
|
end
|
35
44
|
|
36
45
|
def paddle_pause
|
37
46
|
attributes = {pause: true}
|
38
47
|
response = PaddlePay::Subscription::User.update(processor_id, attributes)
|
39
|
-
update(
|
48
|
+
update(paddle_paused_from: Time.zone.parse(response[:next_payment][:date]))
|
49
|
+
rescue ::PaddlePay::PaddlePayError => e
|
50
|
+
raise Pay::Paddle::Error, e
|
40
51
|
end
|
41
52
|
|
42
53
|
def paddle_resume
|
43
54
|
attributes = {pause: false}
|
44
55
|
PaddlePay::Subscription::User.update(processor_id, attributes)
|
45
|
-
update(status: :active,
|
56
|
+
update(status: :active, paddle_paused_from: nil)
|
46
57
|
rescue ::PaddlePay::PaddlePayError => e
|
47
|
-
raise Error, e
|
58
|
+
raise Pay::Paddle::Error, e
|
48
59
|
end
|
49
60
|
|
50
61
|
def paddle_swap(plan)
|
@@ -52,7 +63,7 @@ module Pay
|
|
52
63
|
attributes[:quantity] = quantity if quantity?
|
53
64
|
PaddlePay::Subscription::User.update(processor_id, attributes)
|
54
65
|
rescue ::PaddlePay::PaddlePayError => e
|
55
|
-
raise Error, e
|
66
|
+
raise Pay::Paddle::Error, e
|
56
67
|
end
|
57
68
|
end
|
58
69
|
end
|
@@ -10,7 +10,7 @@ module Pay
|
|
10
10
|
|
11
11
|
# User canceled subscriptions have an ends_at
|
12
12
|
# Automatically canceled subscriptions need this value set
|
13
|
-
subscription.update!(ends_at:
|
13
|
+
subscription.update!(ends_at: Time.zone.parse(data["cancellation_effective_date"])) if subscription.ends_at.blank? && data["cancellation_effective_date"].present?
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -22,7 +22,7 @@ module Pay
|
|
22
22
|
return
|
23
23
|
end
|
24
24
|
|
25
|
-
subscription = Pay.subscription_model.new(owner: owner, name:
|
25
|
+
subscription = Pay.subscription_model.new(owner: owner, name: Pay.default_product_name, processor: "paddle", processor_id: data["subscription_id"], status: :active)
|
26
26
|
end
|
27
27
|
|
28
28
|
subscription.quantity = data["quantity"]
|
@@ -10,9 +10,9 @@ module Pay
|
|
10
10
|
notify_user(charge.owner, charge)
|
11
11
|
end
|
12
12
|
|
13
|
-
def notify_user(
|
13
|
+
def notify_user(billable, charge)
|
14
14
|
if Pay.send_emails
|
15
|
-
Pay::UserMailer.
|
15
|
+
Pay::UserMailer.with(billable: billable, charge: charge).refund.deliver_later
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -21,41 +21,20 @@ module Pay
|
|
21
21
|
amount: Integer(data["sale_gross"].to_f * 100),
|
22
22
|
card_type: data["payment_method"],
|
23
23
|
paddle_receipt_url: data["receipt_url"],
|
24
|
-
created_at:
|
25
|
-
}
|
24
|
+
created_at: Time.zone.parse(data["event_time"])
|
25
|
+
}
|
26
26
|
|
27
|
-
|
27
|
+
payment_information = user.paddle_payment_information(data["subscription_id"])
|
28
|
+
|
29
|
+
charge.update(params.merge(payment_information))
|
30
|
+
user.update(payment_information)
|
28
31
|
|
29
32
|
charge
|
30
33
|
end
|
31
34
|
|
32
|
-
def notify_user(
|
35
|
+
def notify_user(billable, charge)
|
33
36
|
if Pay.send_emails && charge.respond_to?(:receipt)
|
34
|
-
Pay::UserMailer.
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def payment_params(subscription_id)
|
41
|
-
subscription_user = PaddlePay::Subscription::User.list({subscription_id: subscription_id}).try(:first)
|
42
|
-
payment_information = subscription_user ? subscription_user[:payment_information] : nil
|
43
|
-
return {} if payment_information.nil?
|
44
|
-
|
45
|
-
case payment_information[:payment_method]
|
46
|
-
when "card"
|
47
|
-
{
|
48
|
-
card_type: payment_information[:card_type],
|
49
|
-
card_last4: payment_information[:last_four_digits],
|
50
|
-
card_exp_month: payment_information[:expiry_date].split("/").first,
|
51
|
-
card_exp_year: payment_information[:expiry_date].split("/").last
|
52
|
-
}
|
53
|
-
when "paypal"
|
54
|
-
{
|
55
|
-
card_type: "PayPal"
|
56
|
-
}
|
57
|
-
else
|
58
|
-
{}
|
37
|
+
Pay::UserMailer.with(billable: billable, charge: charge).receipt.deliver_later
|
59
38
|
end
|
60
39
|
end
|
61
40
|
end
|