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.

@@ -1,26 +1,24 @@
1
1
  module Pay
2
2
  module Braintree
3
- module Charge
4
- extend ActiveSupport::Concern
3
+ class Charge
4
+ attr_reader :pay_charge
5
5
 
6
- included do
7
- scope :braintree, -> { where(processor: :braintree) }
8
- end
6
+ delegate :processor_id, to: :pay_charge
9
7
 
10
- def braintree?
11
- processor == "braintree"
8
+ def initialize(pay_charge)
9
+ @pay_charge = pay_charge
12
10
  end
13
11
 
14
- def braintree_charge
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 braintree_refund!(amount_to_refund)
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
@@ -0,0 +1,9 @@
1
+ module Pay
2
+ module Braintree
3
+ class Error < Pay::Error
4
+ def message
5
+ result.message
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,44 +1,64 @@
1
1
  module Pay
2
2
  module Braintree
3
- module Subscription
4
- extend ActiveSupport::Concern
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 braintree_cancel
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 braintree_cancel_now!
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 braintree_on_grace_period?
49
+ def on_grace_period?
30
50
  canceled? && Time.zone.now < ends_at
31
51
  end
32
52
 
33
- def braintree_paused?
53
+ def paused?
34
54
  false
35
55
  end
36
56
 
37
- def braintree_pause
57
+ def pause
38
58
  raise NotImplementedError, "Braintree does not support pausing subscriptions"
39
59
  end
40
60
 
41
- def braintree_resume
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 braintree_swap(plan)
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.save_braintree_transaction(subscription.transactions.first)
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.save_braintree_transaction(subscription.transactions.first)
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
- include Env
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 self
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
- Pay.charge_model.include Pay::Paddle::Charge
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
@@ -1,27 +1,32 @@
1
1
  module Pay
2
2
  module Paddle
3
- module Billable
4
- extend ActiveSupport::Concern
3
+ class Billable
4
+ attr_reader :billable
5
5
 
6
- included do
7
- scope :paddle, -> { where(processor: :paddle) }
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 paddle_customer
17
+ def customer
11
18
  # pass
12
19
  end
13
20
 
14
- def create_paddle_charge(amount, options = {})
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.processor_subscription.payment_information[:payment_method],
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 create_paddle_subscription(name, plan, options = {})
38
+ def subscribe(name: Pay.default_product_name, plan: Pay.default_plan_name, **options)
34
39
  # pass
35
40
  end
36
41
 
37
- def update_paddle_card(token)
42
+ def update_card(token)
38
43
  sync_payment_information_from_paddle
39
44
  end
40
45
 
41
- def update_paddle_email!
46
+ def update_email!
42
47
  # pass
43
48
  end
44
49
 
45
- def paddle_trial_end_date(subscription)
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 paddle_subscription(subscription_id, options = {})
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 paddle_invoice!(options = {})
62
+ def invoice!(options = {})
58
63
  # pass
59
64
  end
60
65
 
61
- def paddle_upcoming_invoice
66
+ def upcoming_invoice
62
67
  # pass
63
68
  end
64
69
 
65
- def sync_payment_information_from_paddle
66
- payment_information = paddle_payment_information(subscription.processor_id)
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 paddle_payment_information(subscription_id)
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?
@@ -1,19 +1,15 @@
1
1
  module Pay
2
2
  module Paddle
3
- module Charge
4
- extend ActiveSupport::Concern
3
+ class Charge
4
+ attr_reader :pay_charge
5
5
 
6
- included do
7
- scope :paddle, -> { where(processor: :paddle) }
6
+ delegate :processor_id, :owner, to: :pay_charge
8
7
 
9
- store_accessor :data, :paddle_receipt_url
8
+ def initialize(pay_charge)
9
+ @pay_charge = pay_charge
10
10
  end
11
11
 
12
- def paddle?
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 paddle_refund!(amount_to_refund)
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