pay 7.1.0 → 7.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 731897282e09b738950bdef4b213ef808bc39cae0bbc84c43840de743e9611f4
4
- data.tar.gz: 44624d892463cf3e40206fba9c812005ff4e8fab13642ed932d966c3ec02dafb
3
+ metadata.gz: 5976a641a8e7a7eafa74d343fa1bdb2ab4c1b07d234d44e1efafba5b9b34b34d
4
+ data.tar.gz: 57f00237ae29f1a611f714f473a05de859277cdc5bb515741cefa5f75426b393
5
5
  SHA512:
6
- metadata.gz: d4d24fca5a2619c32d5b0a6e45b2ca5ca20654719bca47bcc377799716e4aeb54a2059fe05ea522db24394ce366c6181fb0ba4051065d1a0039f48236ff48dca
7
- data.tar.gz: 5131748acaed2da28332e6d853b66b086c1354eafc7880669ae291cec664bbed35dfa194e7ddcb4060097e42fc18f5c0e2e5f69cf1a4fe7c40501926f2b208ea
6
+ metadata.gz: '0396532d1af2f80400facc5f6294d7b2f6bcbeab373d004a241e05eb8213a4c91c09ae3fd28655501fec298cfb75520c8506ce697629f41e21cfc961cb76b7bc'
7
+ data.tar.gz: 6e0a26efaf1eb11347ab34c2eac50a25ed59d4f6b9b8eaa11707eb6f3b0d72d4708c3dcb399cbf915999343fd35625397c00c800f90853634db8da00c24643a7
@@ -45,7 +45,7 @@ module Pay
45
45
 
46
46
  # Helpers for payment processors
47
47
  %w[braintree stripe paddle_billing paddle_classic fake_processor].each do |processor_name|
48
- define_method "#{processor_name}?" do
48
+ define_method :"#{processor_name}?" do
49
49
  customer.processor == processor_name
50
50
  end
51
51
 
@@ -28,7 +28,7 @@ module Pay
28
28
  %w[stripe braintree paddle_billing paddle_classic fake_processor].each do |processor_name|
29
29
  scope processor_name, -> { where(processor: processor_name) }
30
30
 
31
- define_method "#{processor_name}?" do
31
+ define_method :"#{processor_name}?" do
32
32
  processor == processor_name
33
33
  end
34
34
  end
@@ -44,7 +44,7 @@ module Pay
44
44
 
45
45
  # Helper methods for payment processors
46
46
  %w[braintree stripe paddle_billing paddle_classic fake_processor].each do |processor_name|
47
- define_method "#{processor_name}?" do
47
+ define_method :"#{processor_name}?" do
48
48
  customer.processor == processor_name
49
49
  end
50
50
 
@@ -265,7 +265,7 @@ module Pay
265
265
  end
266
266
 
267
267
  # Retrieve payment method details from transaction
268
- payment_method = transaction.send("#{attribute_name}_details")
268
+ payment_method = transaction.send(:"#{attribute_name}_details")
269
269
 
270
270
  {
271
271
  payment_method_type: :card,
@@ -59,6 +59,10 @@ module Pay
59
59
  attributes[:trial_ends_at] = Time.parse(object.next_billed_at)
60
60
  when "paused"
61
61
  attributes[:pause_starts_at] = Time.parse(object.paused_at)
62
+ when "active", "past_due"
63
+ attributes[:trial_ends_at] = nil
64
+ attributes[:pause_starts_at] = nil
65
+ attributes[:ends_at] = nil
62
66
  end
63
67
 
64
68
  case object.scheduled_change&.action
@@ -44,12 +44,15 @@ module Pay
44
44
  status: object.state || object.status
45
45
  }
46
46
 
47
- # If paused or delete while on trial, set ends_at to match
48
47
  case attributes[:status]
49
48
  when "trialing"
50
49
  attributes[:trial_ends_at] = Time.zone.parse(object.next_bill_date)
51
50
  attributes[:ends_at] = nil
51
+ when "active", "past_due"
52
+ attributes[:trial_ends_at] = nil
53
+ attributes[:ends_at] = nil
52
54
  when "paused", "deleted"
55
+ # If paused or delete while on trial, set ends_at to match
53
56
  attributes[:trial_ends_at] = nil
54
57
  attributes[:ends_at] = Time.zone.parse(object.next_bill_date)
55
58
  end
@@ -29,7 +29,7 @@ module Pay
29
29
  refunds = []
30
30
  object.refunds.auto_paging_each { |refund| refunds << refund }
31
31
 
32
- payment_method = object.payment_method_details.send(object.payment_method_details.type)
32
+ payment_method = object.payment_method_details.try(object.payment_method_details.type)
33
33
  attrs = {
34
34
  amount: object.amount,
35
35
  amount_captured: object.amount_captured,
@@ -60,7 +60,7 @@ module Pay
60
60
 
61
61
  # Extracts payment method details from a Stripe::PaymentMethod object
62
62
  def self.extract_attributes(payment_method)
63
- details = payment_method.send(payment_method.type)
63
+ details = payment_method.try(payment_method.type)
64
64
 
65
65
  {
66
66
  payment_method_type: payment_method.type,
@@ -342,13 +342,13 @@ module Pay
342
342
  # create_usage_record(quantity: 4, action: :increment)
343
343
  # create_usage_record(subscription_item_id: "si_1234", quantity: 100, action: :set)
344
344
  def create_usage_record(**options)
345
- subscription_item_id = options.fetch(:subscription_item_id, metered_subscription_item&.dig("id"))
345
+ subscription_item_id = options.delete(:subscription_item_id) || metered_subscription_item&.dig("id")
346
346
  ::Stripe::SubscriptionItem.create_usage_record(subscription_item_id, options, stripe_options)
347
347
  end
348
348
 
349
349
  # Returns usage record summaries for a subscription item
350
350
  def usage_record_summaries(**options)
351
- subscription_item_id = options.fetch(:subscription_item_id, metered_subscription_item&.dig("id"))
351
+ subscription_item_id = options.delete(:subscription_item_id) || metered_subscription_item&.dig("id")
352
352
  ::Stripe::SubscriptionItem.list_usage_record_summaries(subscription_item_id, options, stripe_options)
353
353
  end
354
354
 
data/lib/pay/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Pay
2
- VERSION = "7.1.0"
2
+ VERSION = "7.1.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pay
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.1.0
4
+ version: 7.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Charnes
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2023-12-06 00:00:00.000000000 Z
13
+ date: 2024-01-12 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -104,14 +104,6 @@ files:
104
104
  - lib/pay/fake_processor/merchant.rb
105
105
  - lib/pay/fake_processor/payment_method.rb
106
106
  - lib/pay/fake_processor/subscription.rb
107
- - lib/pay/lemon_squeezy.rb
108
- - lib/pay/lemon_squeezy/billable.rb
109
- - lib/pay/lemon_squeezy/charge.rb
110
- - lib/pay/lemon_squeezy/error.rb
111
- - lib/pay/lemon_squeezy/payment_method.rb
112
- - lib/pay/lemon_squeezy/subscription.rb
113
- - lib/pay/lemon_squeezy/webhooks/subscription.rb
114
- - lib/pay/lemon_squeezy/webhooks/transaction_completed.rb
115
107
  - lib/pay/nano_id.rb
116
108
  - lib/pay/paddle_billing.rb
117
109
  - lib/pay/paddle_billing/billable.rb
@@ -184,7 +176,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
176
  - !ruby/object:Gem::Version
185
177
  version: '0'
186
178
  requirements: []
187
- rubygems_version: 3.4.22
179
+ rubygems_version: 3.5.3
188
180
  signing_key:
189
181
  specification_version: 4
190
182
  summary: Payments engine for Ruby on Rails
@@ -1,90 +0,0 @@
1
- module Pay
2
- module PaddleBilling
3
- class Billable
4
- attr_reader :pay_customer
5
-
6
- delegate :processor_id,
7
- :processor_id?,
8
- :email,
9
- :customer_name,
10
- :card_token,
11
- to: :pay_customer
12
-
13
- def initialize(pay_customer)
14
- @pay_customer = pay_customer
15
- end
16
-
17
- def customer_attributes
18
- {email: email, name: customer_name}
19
- end
20
-
21
- # Retrieves a Paddle::Customer object
22
- #
23
- # Finds an existing Paddle::Customer if processor_id exists
24
- # Creates a new Paddle::Customer using `email` and `customer_name` if empty processor_id
25
- #
26
- # Returns a Paddle::Customer object
27
- def customer
28
- if processor_id?
29
- ::Paddle::Customer.retrieve(id: processor_id)
30
- else
31
- sc = ::Paddle::Customer.create(email: email, name: customer_name)
32
- pay_customer.update!(processor_id: sc.id)
33
- sc
34
- end
35
- rescue ::Paddle::Error => e
36
- raise Pay::PaddleBilling::Error, e
37
- end
38
-
39
- # Syncs name and email to Paddle::Customer
40
- # You can also pass in other attributes that will be merged into the default attributes
41
- def update_customer!(**attributes)
42
- customer unless processor_id?
43
- attrs = customer_attributes.merge(attributes)
44
- ::Paddle::Customer.update(id: processor_id, **attrs)
45
- end
46
-
47
- def charge(amount, options = {})
48
- return Pay::Error unless options
49
-
50
- items = options[:items]
51
- opts = options.except(:items).merge(customer_id: processor_id)
52
- transaction = ::Paddle::Transaction.create(items: items, **opts)
53
-
54
- attrs = {
55
- amount: transaction.details.totals.grand_total,
56
- created_at: transaction.created_at,
57
- currency: transaction.currency_code,
58
- metadata: transaction.details.line_items&.first&.id
59
- }
60
-
61
- charge = pay_customer.charges.find_or_initialize_by(processor_id: transaction.id)
62
- charge.update(attrs)
63
- charge
64
- rescue ::Paddle::Error => e
65
- raise Pay::PaddleBilling::Error, e
66
- end
67
-
68
- def subscribe(name: Pay.default_product_name, plan: Pay.default_plan_name, **options)
69
- # pass
70
- end
71
-
72
- # Paddle does not use payment method tokens. The method signature has it here
73
- # to have a uniform API with the other payment processors.
74
- def add_payment_method(token = nil, default: true)
75
- Pay::PaddleBilling::PaymentMethod.sync(pay_customer: pay_customer)
76
- end
77
-
78
- def trial_end_date(subscription)
79
- return unless subscription.state == "trialing"
80
- Time.zone.parse(subscription.next_payment[:date]).end_of_day
81
- end
82
-
83
- def processor_subscription(subscription_id, options = {})
84
- ::Paddle::Subscription.retrieve(id: subscription_id, **options)
85
- rescue ::Paddle::Error => e
86
- raise Pay::PaddleBilling::Error, e
87
- end
88
- end
89
- end
90
- end
@@ -1,68 +0,0 @@
1
- module Pay
2
- module PaddleBilling
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 self.sync(charge_id, object: nil, try: 0, retries: 1)
13
- # Skip loading the latest charge details from the API if we already have it
14
- object ||= ::Paddle::Transaction.retrieve(id: charge_id)
15
-
16
- # Ignore transactions that aren't completed
17
- return unless object.status == "completed"
18
-
19
- # Ignore charges without a Customer
20
- return if object.customer_id.blank?
21
-
22
- pay_customer = Pay::Customer.find_by(processor: :paddle_billing, processor_id: object.customer_id)
23
- return unless pay_customer
24
-
25
- # Ignore transactions that are payment method changes
26
- # But update the customer's payment method
27
- if object.origin == "subscription_payment_method_change"
28
- Pay::PaddleBilling::PaymentMethod.sync(pay_customer: pay_customer, attributes: object.payments.first)
29
- return
30
- end
31
-
32
- attrs = {
33
- amount: object.details.totals.grand_total,
34
- created_at: object.created_at,
35
- currency: object.currency_code,
36
- metadata: object.details.line_items&.first&.id,
37
- subscription: pay_customer.subscriptions.find_by(processor_id: object.subscription_id)
38
- }
39
-
40
- if object.payment
41
- case object.payment.method_details.type.downcase
42
- when "card"
43
- attrs[:payment_method_type] = "card"
44
- attrs[:brand] = details.card.type
45
- attrs[:exp_month] = details.card.expiry_month
46
- attrs[:exp_year] = details.card.expiry_year
47
- attrs[:last4] = details.card.last4
48
- when "paypal"
49
- attrs[:payment_method_type] = "paypal"
50
- end
51
-
52
- # Update customer's payment method
53
- Pay::PaddleBilling::PaymentMethod.sync(pay_customer: pay_customer, attributes: object.payments.first)
54
- end
55
-
56
- # Update or create the charge
57
- if (pay_charge = pay_customer.charges.find_by(processor_id: object.id))
58
- pay_charge.with_lock do
59
- pay_charge.update!(attrs)
60
- end
61
- pay_charge
62
- else
63
- pay_customer.charges.create!(attrs.merge(processor_id: object.id))
64
- end
65
- end
66
- end
67
- end
68
- 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,40 +0,0 @@
1
- module Pay
2
- module PaddleBilling
3
- class PaymentMethod
4
- attr_reader :pay_payment_method
5
-
6
- delegate :customer, :processor_id, to: :pay_payment_method
7
-
8
- def self.sync(pay_customer:, attributes:)
9
- details = attributes.method_details
10
- attrs = {
11
- type: details.type.downcase
12
- }
13
-
14
- case details.type.downcase
15
- when "card"
16
- attrs[:brand] = details.card.type
17
- attrs[:last4] = details.card.last4
18
- attrs[:exp_month] = details.card.expiry_month
19
- attrs[:exp_year] = details.card.expiry_year
20
- end
21
-
22
- payment_method = pay_customer.payment_methods.find_or_initialize_by(processor_id: attributes.stored_payment_method_id)
23
- payment_method.update!(attrs)
24
- payment_method
25
- end
26
-
27
- def initialize(pay_payment_method)
28
- @pay_payment_method = pay_payment_method
29
- end
30
-
31
- # Sets payment method as default
32
- def make_default!
33
- end
34
-
35
- # Remove payment method
36
- def detach
37
- end
38
- end
39
- end
40
- end
@@ -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 Subscription
5
- def call(event)
6
- Pay::PaddleBilling::Subscription.sync(event.id, object: event)
7
- end
8
- end
9
- end
10
- end
11
- 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,138 +0,0 @@
1
- module Pay
2
- module LemonSqueezy
3
- autoload :Billable, "pay/stripe/billable"
4
- autoload :Charge, "pay/stripe/charge"
5
- autoload :Error, "pay/stripe/error"
6
- autoload :Merchant, "pay/stripe/merchant"
7
- autoload :PaymentMethod, "pay/stripe/payment_method"
8
- autoload :Subscription, "pay/stripe/subscription"
9
-
10
- module Webhooks
11
- autoload :AccountUpdated, "pay/stripe/webhooks/account_updated"
12
- autoload :ChargeRefunded, "pay/stripe/webhooks/charge_refunded"
13
- autoload :ChargeSucceeded, "pay/stripe/webhooks/charge_succeeded"
14
- autoload :CheckoutSessionCompleted, "pay/stripe/webhooks/checkout_session_completed"
15
- autoload :CheckoutSessionAsyncPaymentSucceeded, "pay/stripe/webhooks/checkout_session_async_payment_succeeded"
16
- autoload :CustomerDeleted, "pay/stripe/webhooks/customer_deleted"
17
- autoload :CustomerUpdated, "pay/stripe/webhooks/customer_updated"
18
- autoload :PaymentActionRequired, "pay/stripe/webhooks/payment_action_required"
19
- autoload :PaymentFailed, "pay/stripe/webhooks/payment_failed"
20
- autoload :PaymentIntentSucceeded, "pay/stripe/webhooks/payment_intent_succeeded"
21
- autoload :PaymentMethodAttached, "pay/stripe/webhooks/payment_method_attached"
22
- autoload :PaymentMethodDetached, "pay/stripe/webhooks/payment_method_detached"
23
- autoload :PaymentMethodUpdated, "pay/stripe/webhooks/payment_method_updated"
24
- autoload :SubscriptionCreated, "pay/stripe/webhooks/subscription_created"
25
- autoload :SubscriptionDeleted, "pay/stripe/webhooks/subscription_deleted"
26
- autoload :SubscriptionRenewing, "pay/stripe/webhooks/subscription_renewing"
27
- autoload :SubscriptionUpdated, "pay/stripe/webhooks/subscription_updated"
28
- autoload :SubscriptionTrialWillEnd, "pay/stripe/webhooks/subscription_trial_will_end"
29
- end
30
-
31
- extend Env
32
-
33
- REQUIRED_VERSION = "~> 1"
34
-
35
- def self.enabled?
36
- return false unless Pay.enabled_processors.include?(:lemonsqueezy) && defined?(::Lemonzsqueezy)
37
-
38
- Pay::Engine.version_matches?(required: REQUIRED_VERSION, current: ::Lemonsqueezy::VERSION) || (raise "[Pay] lemonsqueezy gem must be version #{REQUIRED_VERSION}")
39
- end
40
-
41
- def self.setup
42
- ::Stripe.api_key = private_key
43
-
44
- # Used by Stripe to identify Pay for support
45
- ::Stripe.set_app_info("PayRails", partner_id: "pp_partner_IqhY0UExnJYLxg", version: Pay::VERSION, url: "https://github.com/pay-rails/pay")
46
-
47
- # Automatically retry requests that fail
48
- # This automatically includes idempotency keys in the request to guarantee that retires are safe
49
- # https://github.com/stripe/stripe-ruby#configuring-automatic-retries
50
- ::Stripe.max_network_retries = 2
51
- end
52
-
53
- def self.public_key
54
- find_value_by_name(:stripe, :public_key)
55
- end
56
-
57
- def self.private_key
58
- find_value_by_name(:stripe, :private_key)
59
- end
60
-
61
- def self.signing_secret
62
- find_value_by_name(:stripe, :signing_secret)
63
- end
64
-
65
- def self.configure_webhooks
66
- Pay::Webhooks.configure do |events|
67
- # Listen to the charge event to make sure we get non-subscription
68
- # purchases as well. Invoice is only for subscriptions and manual creation
69
- # so it does not include individual charges.
70
- events.subscribe "stripe.charge.succeeded", Pay::Stripe::Webhooks::ChargeSucceeded.new
71
- events.subscribe "stripe.charge.refunded", Pay::Stripe::Webhooks::ChargeRefunded.new
72
-
73
- events.subscribe "stripe.payment_intent.succeeded", Pay::Stripe::Webhooks::PaymentIntentSucceeded.new
74
-
75
- # Warn user of upcoming charges for their subscription. This is handy for
76
- # notifying annual users their subscription will renew shortly.
77
- # This probably should be ignored for monthly subscriptions.
78
- events.subscribe "stripe.invoice.upcoming", Pay::Stripe::Webhooks::SubscriptionRenewing.new
79
-
80
- # Payment action is required to process an invoice
81
- events.subscribe "stripe.invoice.payment_action_required", Pay::Stripe::Webhooks::PaymentActionRequired.new
82
-
83
- # If an invoice payment fails, we want to notify the user via email to update their payment details
84
- events.subscribe "stripe.invoice.payment_failed", Pay::Stripe::Webhooks::PaymentFailed.new
85
-
86
- # If a subscription is manually created on Stripe, we want to sync
87
- events.subscribe "stripe.customer.subscription.created", Pay::Stripe::Webhooks::SubscriptionCreated.new
88
-
89
- # If the plan, quantity, or trial ending date is updated on Stripe, we want to sync
90
- events.subscribe "stripe.customer.subscription.updated", Pay::Stripe::Webhooks::SubscriptionUpdated.new
91
-
92
- # When a customers subscription is canceled, we want to update our records
93
- events.subscribe "stripe.customer.subscription.deleted", Pay::Stripe::Webhooks::SubscriptionDeleted.new
94
-
95
- # When a customers subscription trial period is 3 days from ending or ended immediately this event is fired
96
- events.subscribe "stripe.customer.subscription.trial_will_end", Pay::Stripe::Webhooks::SubscriptionTrialWillEnd.new
97
-
98
- # Monitor changes for customer's default card changing and invoice credit updates
99
- events.subscribe "stripe.customer.updated", Pay::Stripe::Webhooks::CustomerUpdated.new
100
-
101
- # If a customer was deleted in Stripe, their subscriptions should be cancelled
102
- events.subscribe "stripe.customer.deleted", Pay::Stripe::Webhooks::CustomerDeleted.new
103
-
104
- # If a customer's payment source was deleted in Stripe, we should update as well
105
- events.subscribe "stripe.payment_method.attached", Pay::Stripe::Webhooks::PaymentMethodAttached.new
106
- events.subscribe "stripe.payment_method.updated", Pay::Stripe::Webhooks::PaymentMethodUpdated.new
107
- events.subscribe "stripe.payment_method.card_automatically_updated", Pay::Stripe::Webhooks::PaymentMethodUpdated.new
108
- events.subscribe "stripe.payment_method.detached", Pay::Stripe::Webhooks::PaymentMethodDetached.new
109
-
110
- # If an account is updated in stripe, we should update it as well
111
- events.subscribe "stripe.account.updated", Pay::Stripe::Webhooks::AccountUpdated.new
112
-
113
- # Handle subscriptions in Stripe Checkout Sessions
114
- events.subscribe "stripe.checkout.session.completed", Pay::Stripe::Webhooks::CheckoutSessionCompleted.new
115
- events.subscribe "stripe.checkout.session.async_payment_succeeded", Pay::Stripe::Webhooks::CheckoutSessionAsyncPaymentSucceeded.new
116
- end
117
- end
118
-
119
- def self.to_client_reference_id(record)
120
- raise ArgumentError, "#{record.class.name} does not include Pay. Allowed models: #{model_names.to_a.join(", ")}" unless model_names.include?(record.class.name)
121
- [record.class.name, record.id].join("_")
122
- end
123
-
124
- def self.find_by_client_reference_id(client_reference_id)
125
- # If there is a client reference ID, make sure we have a Pay::Customer record
126
- # client_reference_id should be in the format of "User/1"
127
- model_name, id = client_reference_id.split("_", 2)
128
-
129
- # Only allow model names that use Pay
130
- return unless model_names.include?(model_name)
131
-
132
- model_name.constantize.find(id)
133
- rescue ActiveRecord::RecordNotFound
134
- Rails.logger.error "[Pay] Unable to locate record with: #{client_reference_id}"
135
- nil
136
- end
137
- end
138
- end