pay 6.8.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/pay/webhooks/paddle_billing_controller.rb +51 -0
  3. data/app/controllers/pay/webhooks/{paddle_controller.rb → paddle_classic_controller.rb} +6 -6
  4. data/app/mailers/pay/application_mailer.rb +5 -1
  5. data/app/models/pay/charge.rb +1 -2
  6. data/app/models/pay/customer.rb +1 -2
  7. data/app/models/pay/merchant.rb +1 -3
  8. data/app/models/pay/payment_method.rb +1 -2
  9. data/app/models/pay/subscription.rb +10 -11
  10. data/app/models/pay/webhook.rb +10 -5
  11. data/app/views/pay/payments/show.html.erb +10 -17
  12. data/config/locales/en.yml +1 -1
  13. data/config/routes.rb +2 -1
  14. data/db/migrate/1_create_pay_tables.rb +6 -1
  15. data/lib/pay/braintree/subscription.rb +12 -2
  16. data/lib/pay/engine.rb +3 -2
  17. data/lib/pay/env.rb +1 -7
  18. data/lib/pay/fake_processor/subscription.rb +11 -1
  19. data/lib/pay/lemon_squeezy/billable.rb +90 -0
  20. data/lib/pay/lemon_squeezy/charge.rb +68 -0
  21. data/lib/pay/{paddle → lemon_squeezy}/error.rb +1 -1
  22. data/lib/pay/lemon_squeezy/payment_method.rb +40 -0
  23. data/lib/pay/lemon_squeezy/subscription.rb +185 -0
  24. data/lib/pay/lemon_squeezy/webhooks/subscription.rb +11 -0
  25. data/lib/pay/lemon_squeezy/webhooks/transaction_completed.rb +11 -0
  26. data/lib/pay/lemon_squeezy.rb +138 -0
  27. data/lib/pay/paddle_billing/billable.rb +90 -0
  28. data/lib/pay/paddle_billing/charge.rb +68 -0
  29. data/lib/pay/paddle_billing/error.rb +7 -0
  30. data/lib/pay/paddle_billing/payment_method.rb +40 -0
  31. data/lib/pay/paddle_billing/subscription.rb +185 -0
  32. data/lib/pay/paddle_billing/webhooks/subscription.rb +11 -0
  33. data/lib/pay/paddle_billing/webhooks/transaction_completed.rb +11 -0
  34. data/lib/pay/paddle_billing.rb +58 -0
  35. data/lib/pay/{paddle → paddle_classic}/billable.rb +9 -10
  36. data/lib/pay/paddle_classic/charge.rb +35 -0
  37. data/lib/pay/paddle_classic/error.rb +7 -0
  38. data/lib/pay/{paddle → paddle_classic}/payment_method.rb +4 -4
  39. data/lib/pay/{paddle → paddle_classic}/subscription.rb +39 -30
  40. data/lib/pay/{paddle → paddle_classic}/webhooks/signature_verifier.rb +4 -4
  41. data/lib/pay/{paddle → paddle_classic}/webhooks/subscription_cancelled.rb +5 -4
  42. data/lib/pay/{paddle → paddle_classic}/webhooks/subscription_created.rb +2 -2
  43. data/lib/pay/{paddle → paddle_classic}/webhooks/subscription_payment_refunded.rb +2 -2
  44. data/lib/pay/{paddle → paddle_classic}/webhooks/subscription_payment_succeeded.rb +7 -7
  45. data/lib/pay/{paddle → paddle_classic}/webhooks/subscription_updated.rb +2 -2
  46. data/lib/pay/paddle_classic.rb +82 -0
  47. data/lib/pay/receipts.rb +1 -1
  48. data/lib/pay/stripe/billable.rb +6 -2
  49. data/lib/pay/stripe/charge.rb +8 -4
  50. data/lib/pay/stripe/payment_method.rb +9 -1
  51. data/lib/pay/stripe/subscription.rb +54 -4
  52. data/lib/pay/stripe.rb +3 -4
  53. data/lib/pay/version.rb +1 -1
  54. data/lib/pay.rb +3 -2
  55. data/lib/tasks/pay.rake +2 -2
  56. metadata +33 -17
  57. data/lib/pay/paddle/charge.rb +0 -35
  58. data/lib/pay/paddle/response.rb +0 -0
  59. data/lib/pay/paddle.rb +0 -80
@@ -0,0 +1,185 @@
1
+ module Pay
2
+ module PaddleBilling
3
+ class Subscription
4
+ attr_reader :pay_subscription
5
+
6
+ delegate :active?,
7
+ :canceled?,
8
+ :on_grace_period?,
9
+ :on_trial?,
10
+ :ends_at,
11
+ :name,
12
+ :owner,
13
+ :pause_starts_at,
14
+ :pause_starts_at?,
15
+ :processor_id,
16
+ :processor_plan,
17
+ :processor_subscription,
18
+ :prorate,
19
+ :prorate?,
20
+ :quantity,
21
+ :quantity?,
22
+ :trial_ends_at,
23
+ to: :pay_subscription
24
+
25
+ def self.sync_from_transaction(transaction_id)
26
+ transaction = ::Paddle::Transaction.retrieve(id: transaction_id)
27
+ sync(transaction.subscription_id) if transaction.subscription_id
28
+ end
29
+
30
+ def self.sync(subscription_id, object: nil, name: Pay.default_product_name)
31
+ # Passthrough is not return from this API, so we can't use that
32
+ object ||= ::Paddle::Subscription.retrieve(id: subscription_id)
33
+
34
+ pay_customer = Pay::Customer.find_by(processor: :paddle_billing, processor_id: object.customer_id)
35
+ return unless pay_customer
36
+
37
+ attributes = {
38
+ current_period_end: object.current_billing_period&.ends_at,
39
+ current_period_start: object.current_billing_period&.starts_at,
40
+ ends_at: (object.canceled_at ? Time.parse(object.canceled_at) : nil),
41
+ metadata: object.custom_data,
42
+ paddle_cancel_url: object.management_urls&.cancel,
43
+ paddle_update_url: object.management_urls&.update_payment_method,
44
+ pause_starts_at: (object.paused_at ? Time.parse(object.paused_at) : nil),
45
+ status: object.status
46
+ }
47
+
48
+ if object.items&.first
49
+ item = object.items.first
50
+ attributes[:processor_plan] = item.price.id
51
+ attributes[:quantity] = item.quantity
52
+ end
53
+
54
+ case attributes[:status]
55
+ when "canceled"
56
+ # Remove payment methods since customer cannot be reused after cancelling
57
+ Pay::PaymentMethod.where(customer_id: object.customer_id).destroy_all
58
+ when "trialing"
59
+ attributes[:trial_ends_at] = Time.parse(object.next_billed_at)
60
+ when "paused"
61
+ attributes[:pause_starts_at] = Time.parse(object.paused_at)
62
+ end
63
+
64
+ case object.scheduled_change&.action
65
+ when "cancel"
66
+ attributes[:ends_at] = Time.parse(object.scheduled_change.effective_at)
67
+ when "pause"
68
+ attributes[:pause_starts_at] = Time.parse(object.scheduled_change.effective_at)
69
+ when "resume"
70
+ attributes[:pause_resumes_at] = Time.parse(object.scheduled_change.effective_at)
71
+ end
72
+
73
+ # Update or create the subscription
74
+ if (pay_subscription = pay_customer.subscriptions.find_by(processor_id: subscription_id))
75
+ pay_subscription.with_lock do
76
+ pay_subscription.update!(attributes)
77
+ end
78
+ pay_subscription
79
+ else
80
+ pay_customer.subscriptions.create!(attributes.merge(name: name, processor_id: subscription_id))
81
+ end
82
+ end
83
+
84
+ def initialize(pay_subscription)
85
+ @pay_subscription = pay_subscription
86
+ end
87
+
88
+ def subscription(**options)
89
+ @paddle_billing_subscription ||= ::Paddle::Subscription.retrieve(id: processor_id, **options)
90
+ end
91
+
92
+ # Get a transaction to update payment method
93
+ def payment_method_transaction
94
+ ::Paddle::Subscription.get_transaction(id: processor_id)
95
+ end
96
+
97
+ # If a subscription is paused, cancel immediately
98
+ # Otherwise, cancel at period end
99
+ def cancel(**options)
100
+ return if canceled?
101
+
102
+ response = ::Paddle::Subscription.cancel(
103
+ id: processor_id,
104
+ effective_from: options.fetch(:effective_from, (paused? ? "immediately" : "next_billing_period"))
105
+ )
106
+ pay_subscription.update(
107
+ status: response.status,
108
+ ends_at: response.scheduled_change.effective_at
109
+ )
110
+ rescue ::Paddle::Error => e
111
+ raise Pay::PaddleBilling::Error, e
112
+ end
113
+
114
+ def cancel_now!(**options)
115
+ cancel(options.merge(effective_from: "immediately"))
116
+ rescue ::Paddle::Error => e
117
+ raise Pay::PaddleBilling::Error, e
118
+ end
119
+
120
+ def change_quantity(quantity, **options)
121
+ items = [{
122
+ price_id: processor_plan,
123
+ quantity: quantity
124
+ }]
125
+
126
+ ::Paddle::Subscription.update(id: processor_id, items: items, proration_billing_mode: "prorated_immediately")
127
+ rescue ::Paddle::Error => e
128
+ raise Pay::PaddleBilling::Error, e
129
+ end
130
+
131
+ # A subscription could be set to cancel or pause in the future
132
+ # It is considered on grace period until the cancel or pause time begins
133
+ def on_grace_period?
134
+ (canceled? && Time.current < ends_at) || (paused? && pause_starts_at? && Time.current < pause_starts_at)
135
+ end
136
+
137
+ def paused?
138
+ pay_subscription.status == "paused"
139
+ end
140
+
141
+ def pause
142
+ response = ::Paddle::Subscription.pause(id: processor_id)
143
+ pay_subscription.update!(status: :paused, pause_starts_at: response.scheduled_change.effective_at)
144
+ rescue ::Paddle::Error => e
145
+ raise Pay::PaddleBilling::Error, e
146
+ end
147
+
148
+ def resumable?
149
+ paused?
150
+ end
151
+
152
+ def resume
153
+ unless resumable?
154
+ raise StandardError, "You can only resume paused subscriptions."
155
+ end
156
+
157
+ # Paddle Billing API only allows "resuming" subscriptions when they are paused
158
+ # So cancel the scheduled change if it is in the future
159
+ if paused? && pause_starts_at? && Time.current < pause_starts_at
160
+ ::Paddle::Subscription.update(id: processor_id, scheduled_change: nil)
161
+ else
162
+ ::Paddle::Subscription.resume(id: processor_id, effective_from: "immediately")
163
+ end
164
+
165
+ pay_subscription.update(status: :active, pause_starts_at: nil)
166
+ rescue ::Paddle::Error => e
167
+ raise Pay::PaddleBilling::Error, e
168
+ end
169
+
170
+ def swap(plan, **options)
171
+ items = [{
172
+ price_id: plan,
173
+ quantity: quantity || 1
174
+ }]
175
+
176
+ ::Paddle::Subscription.update(id: processor_id, items: items, proration_billing_mode: "prorated_immediately")
177
+ pay_subscription.update(processor_plan: plan, ends_at: nil, status: :active)
178
+ end
179
+
180
+ # Retries the latest invoice for a Past Due subscription
181
+ def retry_failed_payment
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,11 @@
1
+ module Pay
2
+ module PaddleBilling
3
+ module Webhooks
4
+ class Subscription
5
+ def call(event)
6
+ Pay::PaddleBilling::Subscription.sync(event.id, object: event)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Pay
2
+ module PaddleBilling
3
+ module Webhooks
4
+ class TransactionCompleted
5
+ def call(event)
6
+ Pay::PaddleBilling::Charge.sync(event.id)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,58 @@
1
+ module Pay
2
+ module PaddleBilling
3
+ autoload :Billable, "pay/paddle_billing/billable"
4
+ autoload :Charge, "pay/paddle_billing/charge"
5
+ autoload :Error, "pay/paddle_billing/error"
6
+ autoload :PaymentMethod, "pay/paddle_billing/payment_method"
7
+ autoload :Subscription, "pay/paddle_billing/subscription"
8
+
9
+ module Webhooks
10
+ autoload :Subscription, "pay/paddle_billing/webhooks/subscription"
11
+ autoload :TransactionCompleted, "pay/paddle_billing/webhooks/transaction_completed"
12
+ end
13
+
14
+ extend Env
15
+
16
+ def self.enabled?
17
+ return false unless Pay.enabled_processors.include?(:paddle_billing) && defined?(::Paddle)
18
+
19
+ Pay::Engine.version_matches?(required: "~> 2.1", current: ::Paddle::VERSION) || (raise "[Pay] paddle gem must be version ~> 2.1")
20
+ end
21
+
22
+ def self.setup
23
+ ::Paddle.config.environment = environment
24
+ ::Paddle.config.api_key = api_key
25
+ end
26
+
27
+ def self.environment
28
+ find_value_by_name(:paddle_billing, :environment) || "production"
29
+ end
30
+
31
+ def self.client_token
32
+ find_value_by_name(:paddle_billing, :client_token)
33
+ end
34
+
35
+ def self.api_key
36
+ find_value_by_name(:paddle_billing, :api_key)
37
+ end
38
+
39
+ def self.signing_secret
40
+ find_value_by_name(:paddle_billing, :signing_secret)
41
+ end
42
+
43
+ def self.configure_webhooks
44
+ Pay::Webhooks.configure do |events|
45
+ events.subscribe "paddle_billing.subscription.activated", Pay::PaddleBilling::Webhooks::Subscription.new
46
+ events.subscribe "paddle_billing.subscription.canceled", Pay::PaddleBilling::Webhooks::Subscription.new
47
+ events.subscribe "paddle_billing.subscription.created", Pay::PaddleBilling::Webhooks::Subscription.new
48
+ events.subscribe "paddle_billing.subscription.imported", Pay::PaddleBilling::Webhooks::Subscription.new
49
+ events.subscribe "paddle_billing.subscription.past_due", Pay::PaddleBilling::Webhooks::Subscription.new
50
+ events.subscribe "paddle_billing.subscription.paused", Pay::PaddleBilling::Webhooks::Subscription.new
51
+ events.subscribe "paddle_billing.subscription.resumed", Pay::PaddleBilling::Webhooks::Subscription.new
52
+ events.subscribe "paddle_billing.subscription.trialing", Pay::PaddleBilling::Webhooks::Subscription.new
53
+ events.subscribe "paddle_billing.subscription.updated", Pay::PaddleBilling::Webhooks::Subscription.new
54
+ events.subscribe "paddle_billing.transaction.completed", Pay::PaddleBilling::Webhooks::TransactionCompleted.new
55
+ end
56
+ end
57
+ end
58
+ end
@@ -1,5 +1,5 @@
1
1
  module Pay
2
- module Paddle
2
+ module PaddleClassic
3
3
  class Billable
4
4
  attr_reader :pay_customer
5
5
 
@@ -27,7 +27,7 @@ module Pay
27
27
  return unless subscription.processor_id
28
28
  raise Pay::Error, "A charge_name is required to create a one-time charge" if options[:charge_name].nil?
29
29
 
30
- response = PaddlePay::Subscription::Charge.create(subscription.processor_id, amount.to_f / 100, options[:charge_name], options)
30
+ response = PaddleClassic.client.charges.create(subscription_id: subscription.processor_id, amount: amount.to_f / 100, charge_name: options[:charge_name])
31
31
 
32
32
  attributes = {
33
33
  amount: (response[:amount].to_f * 100).to_i,
@@ -36,13 +36,13 @@ module Pay
36
36
  }
37
37
 
38
38
  # Lookup subscription payment method details
39
- attributes.merge! Pay::Paddle::PaymentMethod.payment_method_details_for(subscription_id: subscription.processor_id)
39
+ attributes.merge! Pay::PaddleClassic::PaymentMethod.payment_method_details_for(subscription_id: subscription.processor_id)
40
40
 
41
41
  charge = pay_customer.charges.find_or_initialize_by(processor_id: response[:invoice_id])
42
42
  charge.update(attributes)
43
43
  charge
44
- rescue ::PaddlePay::PaddlePayError => e
45
- raise Pay::Paddle::Error, e
44
+ rescue ::Paddle::Error => e
45
+ raise Pay::PaddleClassic::Error, e
46
46
  end
47
47
 
48
48
  def subscribe(name: Pay.default_product_name, plan: Pay.default_plan_name, **options)
@@ -52,7 +52,7 @@ module Pay
52
52
  # Paddle does not use payment method tokens. The method signature has it here
53
53
  # to have a uniform API with the other payment processors.
54
54
  def add_payment_method(token = nil, default: true)
55
- Pay::Paddle::PaymentMethod.sync(pay_customer: pay_customer)
55
+ Pay::PaddleClassic::PaymentMethod.sync(pay_customer: pay_customer)
56
56
  end
57
57
 
58
58
  def trial_end_date(subscription)
@@ -61,10 +61,9 @@ module Pay
61
61
  end
62
62
 
63
63
  def processor_subscription(subscription_id, options = {})
64
- hash = PaddlePay::Subscription::User.list({subscription_id: subscription_id}, options).try(:first)
65
- OpenStruct.new(hash)
66
- rescue ::PaddlePay::PaddlePayError => e
67
- raise Pay::Paddle::Error, e
64
+ PaddleClassic.client.users.list(subscription_id: subscription_id).data.try(:first)
65
+ rescue ::Paddle::Error => e
66
+ raise Pay::PaddleClassic::Error, e
68
67
  end
69
68
  end
70
69
  end
@@ -0,0 +1,35 @@
1
+ module Pay
2
+ module PaddleClassic
3
+ class Charge
4
+ attr_reader :pay_charge
5
+
6
+ delegate :processor_id, :customer, to: :pay_charge
7
+
8
+ def initialize(pay_charge)
9
+ @pay_charge = pay_charge
10
+ end
11
+
12
+ def charge
13
+ return unless customer.subscription
14
+ payments = PaddleClassic.client.payments.list(subscription_id: customer.subscription.processor_id)
15
+ charges = payments.data.select { |p| p[:id].to_s == processor_id }
16
+ charges.try(:first)
17
+ rescue ::Paddle::Error => e
18
+ raise Pay::PaddleClassic::Error, e
19
+ end
20
+
21
+ def refund!(amount_to_refund)
22
+ return unless customer.subscription
23
+ payments = PaddleClassic.client.payments.list(subscription_id: customer.subscription.processor_id, is_paid: 1)
24
+ if payments.total > 0
25
+ PaddleClassic.client.payments.refund(order_id: payments.data.last[:id], amount: amount_to_refund)
26
+ pay_charge.update(amount_refunded: amount_to_refund)
27
+ else
28
+ raise Error, "Payment not found"
29
+ end
30
+ rescue ::Paddle::Error => e
31
+ raise Pay::PaddleClassic::Error, e
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,7 @@
1
+ module Pay
2
+ module PaddleClassic
3
+ class Error < Pay::Error
4
+ delegate :message, to: :cause
5
+ end
6
+ end
7
+ end
@@ -1,5 +1,5 @@
1
1
  module Pay
2
- module Paddle
2
+ module PaddleClassic
3
3
  class PaymentMethod
4
4
  attr_reader :pay_payment_method
5
5
 
@@ -17,12 +17,12 @@ module Pay
17
17
 
18
18
  payment_method.update!(attributes)
19
19
  payment_method
20
- rescue ::PaddlePay::PaddlePayError => e
21
- raise Pay::Paddle::Error, e
20
+ rescue ::Paddle::Error => e
21
+ raise Pay::PaddleClassic::Error, e
22
22
  end
23
23
 
24
24
  def self.payment_method_details_for(subscription_id:)
25
- subscription_user = PaddlePay::Subscription::User.list({subscription_id: subscription_id}).try(:first)
25
+ subscription_user = PaddleClassic.client.users.list(subscription_id: subscription_id).data.try(:first)
26
26
  payment_information = subscription_user ? subscription_user[:payment_information] : {}
27
27
 
28
28
  case payment_information[:payment_method]&.downcase
@@ -1,5 +1,5 @@
1
1
  module Pay
2
- module Paddle
2
+ module PaddleClassic
3
3
  class Subscription
4
4
  attr_reader :pay_subscription
5
5
 
@@ -24,14 +24,14 @@ module Pay
24
24
 
25
25
  def self.sync(subscription_id, object: nil, name: Pay.default_product_name)
26
26
  # Passthrough is not return from this API, so we can't use that
27
- object ||= OpenStruct.new PaddlePay::Subscription::User.list({subscription_id: subscription_id}).try(:first)
27
+ object ||= PaddleClassic.client.users.list(subscription_id: subscription_id).data.try(:first)
28
28
 
29
- pay_customer = Pay::Customer.find_by(processor: :paddle, processor_id: object.user_id)
29
+ pay_customer = Pay::Customer.find_by(processor: :paddle_classic, processor_id: object.user_id)
30
30
 
31
31
  # If passthrough exists (only on webhooks) we can use it to create the Pay::Customer
32
32
  if pay_customer.nil? && object.passthrough
33
- owner = Pay::Paddle.owner_from_passthrough(object.passthrough)
34
- pay_customer = owner&.set_payment_processor(:paddle, processor_id: object.user_id)
33
+ owner = Pay::PaddleClassic.owner_from_passthrough(object.passthrough)
34
+ pay_customer = owner&.set_payment_processor(:paddle_classic, processor_id: object.user_id)
35
35
  end
36
36
 
37
37
  return unless pay_customer
@@ -40,7 +40,7 @@ module Pay
40
40
  paddle_cancel_url: object.cancel_url,
41
41
  paddle_update_url: object.update_url,
42
42
  processor_plan: object.plan_id || object.subscription_plan_id,
43
- quantity: object.quantity,
43
+ quantity: object.quantity || 1,
44
44
  status: object.state || object.status
45
45
  }
46
46
 
@@ -70,38 +70,45 @@ module Pay
70
70
  end
71
71
 
72
72
  def subscription(**options)
73
- hash = PaddlePay::Subscription::User.list({subscription_id: processor_id}, options).try(:first)
74
- OpenStruct.new(hash)
75
- rescue ::PaddlePay::PaddlePayError => e
76
- raise Pay::Paddle::Error, e
73
+ PaddleClassic.client.users.list(subscription_id: processor_id).data.try(:first)
74
+ rescue ::Paddle::Error => e
75
+ raise Pay::PaddleClassic::Error, e
77
76
  end
78
77
 
78
+ # Paddle subscriptions are canceled immediately, however we still want to give the user access to the end of the period they paid for
79
79
  def cancel(**options)
80
+ return if canceled?
81
+
80
82
  ends_at = if on_trial?
81
83
  trial_ends_at
82
84
  elsif paused?
83
85
  pause_starts_at
84
86
  else
85
- processor_subscription.next_payment&.fetch(:date) || Time.current
87
+ Time.parse(processor_subscription.next_payment.date)
86
88
  end
87
89
 
88
- PaddlePay::Subscription::User.cancel(processor_id)
89
- pay_subscription.update(status: :canceled, ends_at: ends_at)
90
+ PaddleClassic.client.users.cancel(subscription_id: processor_id)
91
+ pay_subscription.update(
92
+ status: (ends_at.future? ? :active : :canceled),
93
+ ends_at: ends_at
94
+ )
90
95
 
91
96
  # Remove payment methods since customer cannot be reused after cancelling
92
97
  Pay::PaymentMethod.where(customer_id: pay_subscription.customer_id).destroy_all
93
- rescue ::PaddlePay::PaddlePayError => e
94
- raise Pay::Paddle::Error, e
98
+ rescue ::Paddle::Error => e
99
+ raise Pay::PaddleClassic::Error, e
95
100
  end
96
101
 
97
102
  def cancel_now!(**options)
98
- PaddlePay::Subscription::User.cancel(processor_id)
103
+ return if canceled?
104
+
105
+ PaddleClassic.client.users.cancel(subscription_id: processor_id)
99
106
  pay_subscription.update(status: :canceled, ends_at: Time.current)
100
107
 
101
108
  # Remove payment methods since customer cannot be reused after cancelling
102
109
  Pay::PaymentMethod.where(customer_id: pay_subscription.customer_id).destroy_all
103
- rescue ::PaddlePay::PaddlePayError => e
104
- raise Pay::Paddle::Error, e
110
+ rescue ::Paddle::Error => e
111
+ raise Pay::PaddleClassic::Error, e
105
112
  end
106
113
 
107
114
  def change_quantity(quantity, **options)
@@ -119,23 +126,25 @@ module Pay
119
126
  end
120
127
 
121
128
  def pause
122
- attributes = {pause: true}
123
- response = PaddlePay::Subscription::User.update(processor_id, attributes)
129
+ response = PaddleClassic.client.users.pause(subscription_id: processor_id)
124
130
  pay_subscription.update(status: :paused, pause_starts_at: Time.zone.parse(response.dig(:next_payment, :date)))
125
- rescue ::PaddlePay::PaddlePayError => e
126
- raise Pay::Paddle::Error, e
131
+ rescue ::Paddle::Error => e
132
+ raise Pay::PaddleClassic::Error, e
133
+ end
134
+
135
+ def resumable?
136
+ paused?
127
137
  end
128
138
 
129
139
  def resume
130
- unless paused?
140
+ unless resumable?
131
141
  raise StandardError, "You can only resume paused subscriptions."
132
142
  end
133
143
 
134
- attributes = {pause: false}
135
- PaddlePay::Subscription::User.update(processor_id, attributes)
144
+ PaddleClassic.client.users.unpause(subscription_id: processor_id)
136
145
  pay_subscription.update(status: :active, pause_starts_at: nil)
137
- rescue ::PaddlePay::PaddlePayError => e
138
- raise Pay::Paddle::Error, e
146
+ rescue ::Paddle::Error => e
147
+ raise Pay::PaddleClassic::Error, e
139
148
  end
140
149
 
141
150
  def swap(plan, **options)
@@ -143,11 +152,11 @@ module Pay
143
152
 
144
153
  attributes = {plan_id: plan, prorate: prorate}
145
154
  attributes[:quantity] = quantity if quantity?
146
- PaddlePay::Subscription::User.update(processor_id, attributes)
155
+ PaddleClassic.client.users.update(subscription_id: processor_id, **attributes)
147
156
 
148
157
  pay_subscription.update(processor_plan: plan, ends_at: nil, status: :active)
149
- rescue ::PaddlePay::PaddlePayError => e
150
- raise Pay::Paddle::Error, e
158
+ rescue ::Paddle::Error => e
159
+ raise Pay::PaddleClassic::Error, e
151
160
  end
152
161
 
153
162
  # Retries the latest invoice for a Past Due subscription
@@ -3,14 +3,14 @@ require "json"
3
3
  require "openssl"
4
4
 
5
5
  module Pay
6
- module Paddle
6
+ module PaddleClassic
7
7
  module Webhooks
8
8
  class SignatureVerifier
9
9
  def initialize(data)
10
10
  @data = data
11
- @public_key_file = Pay::Paddle.public_key_file
12
- @public_key = Pay::Paddle.public_key
13
- @public_key_base64 = Pay::Paddle.public_key_base64
11
+ @public_key_file = Pay::PaddleClassic.public_key_file
12
+ @public_key = Pay::PaddleClassic.public_key
13
+ @public_key_base64 = Pay::PaddleClassic.public_key_base64
14
14
  end
15
15
 
16
16
  def verify
@@ -1,23 +1,24 @@
1
1
  module Pay
2
- module Paddle
2
+ module PaddleClassic
3
3
  module Webhooks
4
4
  class SubscriptionCancelled
5
5
  def call(event)
6
- pay_subscription = Pay::Subscription.find_by_processor_and_id(:paddle, event.subscription_id)
6
+ pay_subscription = Pay::Subscription.find_by_processor_and_id(:paddle_classic, event.subscription_id)
7
7
 
8
8
  # We couldn't find the subscription for some reason, maybe it's from another service
9
9
  return if pay_subscription.nil?
10
10
 
11
11
  # User canceled subscriptions have an ends_at
12
12
  # Automatically cancelled subscriptions need this value set
13
+ # Paddle subscriptions are canceled immediately, however we still want to give the user access to the end of the period they paid for
13
14
  ends_at = Time.zone.parse(event.cancellation_effective_date)
14
15
  pay_subscription.update!(
15
- status: :canceled,
16
+ status: (ends_at.future? ? :active : :canceled),
16
17
  trial_ends_at: (ends_at if pay_subscription.trial_ends_at?),
17
18
  ends_at: ends_at
18
19
  )
19
20
 
20
- # Paddle doesn't allow reusing customers, so we should remove their payment methods
21
+ # Paddle classic doesn't allow reusing customers, so we should remove their payment methods
21
22
  Pay::PaymentMethod.where(customer_id: pay_subscription.customer_id).destroy_all
22
23
  end
23
24
  end
@@ -1,9 +1,9 @@
1
1
  module Pay
2
- module Paddle
2
+ module PaddleClassic
3
3
  module Webhooks
4
4
  class SubscriptionCreated
5
5
  def call(event)
6
- Pay::Paddle::Subscription.sync(event.subscription_id, object: event)
6
+ Pay::PaddleClassic::Subscription.sync(event.subscription_id, object: event)
7
7
  end
8
8
  end
9
9
  end
@@ -1,9 +1,9 @@
1
1
  module Pay
2
- module Paddle
2
+ module PaddleClassic
3
3
  module Webhooks
4
4
  class SubscriptionPaymentRefunded
5
5
  def call(event)
6
- pay_charge = Pay::Charge.find_by_processor_and_id(:paddle, event.subscription_payment_id)
6
+ pay_charge = Pay::Charge.find_by_processor_and_id(:paddle_classic, event.subscription_payment_id)
7
7
  return unless pay_charge.present?
8
8
 
9
9
  pay_charge.update!(amount_refunded: (event.gross_refund.to_f * 100).to_i)
@@ -1,13 +1,13 @@
1
1
  module Pay
2
- module Paddle
2
+ module PaddleClassic
3
3
  module Webhooks
4
4
  class SubscriptionPaymentSucceeded
5
5
  def call(event)
6
- pay_customer = Pay::Customer.find_by(processor: :paddle, processor_id: event.user_id)
6
+ pay_customer = Pay::Customer.find_by(processor: :paddle_classic, processor_id: event.user_id)
7
7
 
8
8
  if pay_customer.nil?
9
- owner = Pay::Paddle.owner_from_passthrough(event.passthrough)
10
- pay_customer = owner&.set_payment_processor :paddle, processor_id: event.user_id
9
+ owner = Pay::PaddleClassic.owner_from_passthrough(event.passthrough)
10
+ pay_customer = owner&.set_payment_processor :paddle_classic, processor_id: event.user_id
11
11
  end
12
12
 
13
13
  if pay_customer.nil?
@@ -22,7 +22,7 @@ module Pay
22
22
  end
23
23
 
24
24
  def create_charge(pay_customer, event)
25
- payment_method_details = Pay::Paddle::PaymentMethod.payment_method_details_for(subscription_id: event.subscription_id)
25
+ payment_method_details = Pay::PaddleClassic::PaymentMethod.payment_method_details_for(subscription_id: event.subscription_id)
26
26
 
27
27
  attributes = {
28
28
  amount: (event.sale_gross.to_f * 100).to_i,
@@ -30,14 +30,14 @@ module Pay
30
30
  currency: event.currency,
31
31
  paddle_receipt_url: event.receipt_url,
32
32
  subscription: pay_customer.subscriptions.find_by(processor_id: event.subscription_id),
33
- metadata: Pay::Paddle.parse_passthrough(event.passthrough).except("owner_sgid")
33
+ metadata: Pay::PaddleClassic.parse_passthrough(event.passthrough).except("owner_sgid")
34
34
  }.merge(payment_method_details)
35
35
 
36
36
  pay_charge = pay_customer.charges.find_or_initialize_by(processor_id: event.subscription_payment_id)
37
37
  pay_charge.update!(attributes)
38
38
 
39
39
  # Update customer's payment method
40
- Pay::Paddle::PaymentMethod.sync(pay_customer: pay_customer, attributes: payment_method_details)
40
+ Pay::PaddleClassic::PaymentMethod.sync(pay_customer: pay_customer, attributes: payment_method_details)
41
41
 
42
42
  pay_charge
43
43
  end
@@ -1,9 +1,9 @@
1
1
  module Pay
2
- module Paddle
2
+ module PaddleClassic
3
3
  module Webhooks
4
4
  class SubscriptionUpdated
5
5
  def call(event)
6
- pay_subscription = Pay::Subscription.find_by_processor_and_id(:paddle, event["subscription_id"])
6
+ pay_subscription = Pay::Subscription.find_by_processor_and_id(:paddle_classic, event["subscription_id"])
7
7
 
8
8
  return if pay_subscription.nil?
9
9