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.

Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -2
  3. data/app/controllers/pay/webhooks/braintree_controller.rb +1 -1
  4. data/app/mailers/pay/user_mailer.rb +14 -35
  5. data/app/models/pay/subscription.rb +4 -2
  6. data/app/views/pay/user_mailer/payment_action_required.html.erb +1 -1
  7. data/app/views/pay/user_mailer/receipt.html.erb +6 -6
  8. data/app/views/pay/user_mailer/refund.html.erb +6 -6
  9. data/app/views/pay/user_mailer/subscription_renewing.html.erb +1 -1
  10. data/config/locales/en.yml +137 -0
  11. data/lib/pay.rb +6 -41
  12. data/lib/pay/billable.rb +9 -9
  13. data/lib/pay/braintree/billable.rb +11 -11
  14. data/lib/pay/braintree/charge.rb +3 -3
  15. data/lib/pay/braintree/subscription.rb +9 -5
  16. data/lib/pay/errors.rb +73 -0
  17. data/lib/pay/paddle/billable.rb +34 -5
  18. data/lib/pay/paddle/charge.rb +2 -2
  19. data/lib/pay/paddle/subscription.rb +18 -7
  20. data/lib/pay/paddle/webhooks/subscription_cancelled.rb +1 -1
  21. data/lib/pay/paddle/webhooks/subscription_created.rb +1 -1
  22. data/lib/pay/paddle/webhooks/subscription_payment_refunded.rb +2 -2
  23. data/lib/pay/paddle/webhooks/subscription_payment_succeeded.rb +8 -29
  24. data/lib/pay/paddle/webhooks/subscription_updated.rb +15 -12
  25. data/lib/pay/receipts.rb +6 -6
  26. data/lib/pay/stripe/billable.rb +4 -4
  27. data/lib/pay/stripe/charge.rb +2 -2
  28. data/lib/pay/stripe/subscription.rb +8 -4
  29. data/lib/pay/stripe/webhooks/charge_refunded.rb +2 -2
  30. data/lib/pay/stripe/webhooks/charge_succeeded.rb +1 -1
  31. data/lib/pay/stripe/webhooks/payment_action_required.rb +1 -1
  32. data/lib/pay/stripe/webhooks/subscription_created.rb +1 -1
  33. data/lib/pay/stripe/webhooks/subscription_renewing.rb +4 -3
  34. data/lib/pay/version.rb +1 -1
  35. 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 BraintreeError.new(result), result.message unless result.success?
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 BraintreeError, e.message
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 BraintreeError.new(result), result.message unless result.success?
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 BraintreeAuthorizationError
54
+ raise Pay::Braintree::AuthorizationError
55
55
  rescue ::Braintree::BraintreeError => e
56
- raise BraintreeError, e.message
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 BraintreeError.new(result), result.message unless result.success?
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 BraintreeAuthorizationError
81
+ raise Pay::Braintree::AuthorizationError
82
82
  rescue ::Braintree::BraintreeError => e
83
- raise BraintreeError, e.message
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 BraintreeError.new(result), result.message unless result.success?
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 BraintreeAuthorizationError
104
+ raise Pay::Braintree::AuthorizationError
105
105
  rescue ::Braintree::BraintreeError => e
106
- raise BraintreeError, e.message
106
+ raise Pay::Braintree::Error, e
107
107
  end
108
108
 
109
109
  def update_braintree_email!
@@ -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::BraintreeError => e
17
- raise Error, e.message
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.message
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.message
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.message
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.message
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.message
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
@@ -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
@@ -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: DateTime.parse(response[:payment_date])
26
+ created_at: Time.zone.parse(response[:payment_date])
27
27
  )
28
28
  charge
29
29
  rescue ::PaddlePay::PaddlePayError => e
30
- raise Error, e.message
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
- # pass
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
- DateTime.parse(subscription.next_payment[:date]).end_of_day
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.message
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
@@ -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.message
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.message
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: DateTime.parse(subscription.next_payment[:date]))
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.message
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.message
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(status: :paused, ends_at: DateTime.parse(response[:next_payment][:date]))
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, ends_at: nil)
56
+ update(status: :active, paddle_paused_from: nil)
46
57
  rescue ::PaddlePay::PaddlePayError => e
47
- raise Error, e.message
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.message
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: DateTime.parse(data["cancellation_effective_date"])) if subscription.ends_at.blank? && data["cancellation_effective_date"].present?
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: "default", processor: "paddle", processor_id: data["subscription_id"], status: :active)
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(user, charge)
13
+ def notify_user(billable, charge)
14
14
  if Pay.send_emails
15
- Pay::UserMailer.refund(user, charge).deliver_later
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: DateTime.parse(data["event_time"])
25
- }.merge(payment_params(data["subscription_id"]))
24
+ created_at: Time.zone.parse(data["event_time"])
25
+ }
26
26
 
27
- charge.update(params)
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(user, charge)
35
+ def notify_user(billable, charge)
33
36
  if Pay.send_emails && charge.respond_to?(:receipt)
34
- Pay::UserMailer.receipt(user, charge).deliver_later
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