pay 7.3.0 → 8.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/app/controllers/pay/webhooks/lemon_squeezy_controller.rb +45 -0
  4. data/app/jobs/pay/customer_sync_job.rb +1 -1
  5. data/app/models/concerns/pay/routing.rb +13 -0
  6. data/{lib → app/models}/pay/braintree/charge.rb +5 -12
  7. data/{lib/pay/braintree/billable.rb → app/models/pay/braintree/customer.rb} +31 -71
  8. data/{lib → app/models}/pay/braintree/payment_method.rb +1 -9
  9. data/{lib → app/models}/pay/braintree/subscription.rb +14 -52
  10. data/app/models/pay/charge.rb +8 -27
  11. data/app/models/pay/customer.rb +2 -15
  12. data/app/models/pay/fake_processor/charge.rb +13 -0
  13. data/{lib/pay/fake_processor/billable.rb → app/models/pay/fake_processor/customer.rb} +20 -37
  14. data/{lib → app/models}/pay/fake_processor/merchant.rb +2 -9
  15. data/app/models/pay/fake_processor/payment_method.rb +11 -0
  16. data/app/models/pay/fake_processor/subscription.rb +60 -0
  17. data/app/models/pay/lemon_squeezy/charge.rb +86 -0
  18. data/app/models/pay/lemon_squeezy/customer.rb +78 -0
  19. data/app/models/pay/lemon_squeezy/payment_method.rb +27 -0
  20. data/app/models/pay/lemon_squeezy/subscription.rb +129 -0
  21. data/app/models/pay/merchant.rb +0 -11
  22. data/{lib → app/models}/pay/paddle_billing/charge.rb +2 -8
  23. data/{lib/pay/paddle_billing/billable.rb → app/models/pay/paddle_billing/customer.rb} +18 -35
  24. data/{lib → app/models}/pay/paddle_billing/payment_method.rb +2 -12
  25. data/{lib → app/models}/pay/paddle_billing/subscription.rb +9 -33
  26. data/{lib → app/models}/pay/paddle_classic/charge.rb +13 -18
  27. data/{lib/pay/paddle_classic/billable.rb → app/models/pay/paddle_classic/customer.rb} +9 -31
  28. data/{lib → app/models}/pay/paddle_classic/payment_method.rb +1 -11
  29. data/{lib → app/models}/pay/paddle_classic/subscription.rb +11 -36
  30. data/app/models/pay/payment_method.rb +0 -5
  31. data/{lib → app/models}/pay/stripe/charge.rb +6 -22
  32. data/{lib/pay/stripe/billable.rb → app/models/pay/stripe/customer.rb} +73 -108
  33. data/{lib → app/models}/pay/stripe/merchant.rb +2 -11
  34. data/{lib → app/models}/pay/stripe/payment_method.rb +2 -10
  35. data/{lib → app/models}/pay/stripe/subscription.rb +37 -71
  36. data/app/models/pay/subscription.rb +7 -37
  37. data/app/models/pay/webhook.rb +2 -0
  38. data/config/routes.rb +1 -0
  39. data/db/migrate/2_add_pay_sti_columns.rb +24 -0
  40. data/lib/pay/attributes.rb +11 -3
  41. data/lib/pay/braintree.rb +25 -6
  42. data/lib/pay/engine.rb +2 -0
  43. data/lib/pay/fake_processor.rb +2 -6
  44. data/lib/pay/lemon_squeezy/webhooks/order.rb +11 -0
  45. data/lib/pay/lemon_squeezy/webhooks/subscription.rb +3 -3
  46. data/lib/pay/lemon_squeezy/webhooks/subscription_payment.rb +11 -0
  47. data/lib/pay/lemon_squeezy.rb +56 -104
  48. data/lib/pay/paddle_billing.rb +15 -6
  49. data/lib/pay/paddle_classic.rb +11 -9
  50. data/lib/pay/receipts.rb +6 -6
  51. data/lib/pay/stripe/webhooks/customer_updated.rb +1 -1
  52. data/lib/pay/stripe.rb +15 -6
  53. data/lib/pay/version.rb +1 -1
  54. data/lib/pay.rb +12 -1
  55. metadata +34 -38
  56. data/app/views/pay/stripe/_checkout_button.html.erb +0 -21
  57. data/lib/pay/braintree/authorization_error.rb +0 -9
  58. data/lib/pay/braintree/error.rb +0 -23
  59. data/lib/pay/fake_processor/charge.rb +0 -21
  60. data/lib/pay/fake_processor/error.rb +0 -6
  61. data/lib/pay/fake_processor/payment_method.rb +0 -21
  62. data/lib/pay/fake_processor/subscription.rb +0 -90
  63. data/lib/pay/lemon_squeezy/billable.rb +0 -90
  64. data/lib/pay/lemon_squeezy/charge.rb +0 -68
  65. data/lib/pay/lemon_squeezy/error.rb +0 -7
  66. data/lib/pay/lemon_squeezy/payment_method.rb +0 -40
  67. data/lib/pay/lemon_squeezy/subscription.rb +0 -185
  68. data/lib/pay/lemon_squeezy/webhooks/transaction_completed.rb +0 -11
  69. data/lib/pay/paddle_billing/error.rb +0 -7
  70. data/lib/pay/paddle_classic/error.rb +0 -7
  71. data/lib/pay/stripe/error.rb +0 -7
@@ -1,185 +0,0 @@
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
@@ -1,11 +0,0 @@
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
@@ -1,7 +0,0 @@
1
- module Pay
2
- module PaddleBilling
3
- class Error < Pay::Error
4
- delegate :message, to: :cause
5
- end
6
- end
7
- end
@@ -1,7 +0,0 @@
1
- module Pay
2
- module PaddleClassic
3
- class Error < Pay::Error
4
- delegate :message, to: :cause
5
- end
6
- end
7
- end
@@ -1,7 +0,0 @@
1
- module Pay
2
- module Stripe
3
- class Error < Pay::Error
4
- delegate :message, to: :cause
5
- end
6
- end
7
- end