pay 6.2.3 → 6.3.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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 38b66c0598271a99f2293bf71a7c44e8877a98d45e06540597ae81c3de9e2d53
4
- data.tar.gz: c95b9e20ad640bc614fb293f708034e4ca4339868abf89def91eb245ce3c3f21
3
+ metadata.gz: aeee41b07bfa798c33c4d05b73c7035905f562d45cec48564d543e371ff53a7e
4
+ data.tar.gz: 7b7b1695db44d1f3e00637431f91be10e12c54541921f4b555d83253b981dc04
5
5
  SHA512:
6
- metadata.gz: 8b72f9b22b361d10f9693009f48395474f3b93b46e9031faaa3e109eeb16f2a3e2645cd54084d948f04a5d249cc07568b351ad40e25cb3a2b23c4a82a44c0a60
7
- data.tar.gz: 0a2135703836be6edfcd5994035d8c7b57d866365b381b66646b03347134b3a87b8506aa19981966124611aaf2cf2b6889c9f3fad415a7344737a28097dcc77c
6
+ metadata.gz: ee0f52b211a5894d00d7226d486ccdbce5ca8f18a66a1fa1fcd7c37344bd842f0672cf4c4070d7ee12684b8c64801fcd8c8674fa22d17f7204e95609f3b5cfa0
7
+ data.tar.gz: 4dcf8f4142c67ae179749e955baff64b454c2fc2eba3664727fd41572d22b0e6c1913cac9d5bc2c063e4c484ade0663b401b6d44d283a203c65145f678d28e77
@@ -28,6 +28,10 @@ module Pay
28
28
  mail mail_arguments
29
29
  end
30
30
 
31
+ def payment_failed
32
+ mail mail_arguments
33
+ end
34
+
31
35
  private
32
36
 
33
37
  def mail_arguments
@@ -50,7 +50,7 @@ module Pay
50
50
  customer.processor == processor_name
51
51
  end
52
52
 
53
- scope processor_name, -> { where(processor: processor_name) }
53
+ scope processor_name, -> { joins(:customer).where(pay_customers: {processor: processor_name}) }
54
54
  end
55
55
 
56
56
  delegate :capture, :credit_note!, :credit_notes, to: :payment_processor
@@ -46,7 +46,7 @@ module Pay
46
46
  end
47
47
 
48
48
  def subscription(name: Pay.default_product_name)
49
- subscriptions.order(id: :desc).for_name(name).first
49
+ subscriptions.order(created_at: :desc).for_name(name).first
50
50
  end
51
51
 
52
52
  def subscribed?(name: Pay.default_product_name, processor_plan: nil)
@@ -93,9 +93,10 @@ module Pay
93
93
  subscription.trial_ends_at == subscription.ends_at
94
94
  end
95
95
 
96
- # Attempts to pay all past_due subscriptions
97
- def retry_past_due_subscriptions!
98
- subscriptions.past_due.each(&:retry_failed_payment)
96
+ # Attempts to pay all past_due subscription invoices to bring them back to active state
97
+ # Pass in `statuses: []` if you would like to only include specific subscription statuses
98
+ def retry_past_due_subscriptions!(status: [:past_due])
99
+ subscriptions.where(status: Array.wrap(status)).each(&:retry_failed_payments)
99
100
  end
100
101
  end
101
102
  end
@@ -17,6 +17,7 @@ module Pay
17
17
  scope :active_or_paused, -> { active.or(paused) }
18
18
  scope :incomplete, -> { where(status: :incomplete) }
19
19
  scope :past_due, -> { where(status: :past_due) }
20
+ scope :unpaid, -> { where(status: :unpaid) }
20
21
  scope :metered, -> { where(metered: true) }
21
22
  scope :with_active_customer, -> { joins(:customer).merge(Customer.active) }
22
23
  scope :with_deleted_customer, -> { joins(:customer).merge(Customer.deleted) }
@@ -131,6 +132,10 @@ module Pay
131
132
  status == "past_due"
132
133
  end
133
134
 
135
+ def unpaid?
136
+ status == "unpaid"
137
+ end
138
+
134
139
  def incomplete?
135
140
  status == "incomplete"
136
141
  end
@@ -1,6 +1,5 @@
1
1
  <h3>Extra confirmation is needed to process your payment</h3>
2
2
  <p>Your <%= Pay.application_name %> subscription requires confirmation to process your payment to continue access.</p>
3
-
4
- <p><%= link_to "Click here to confirm your payment", pay.payment_url(params[:payment_intent_id]) %>. If you have any questions, please hit reply and let us know.</p>
5
-
3
+ <p><%= link_to "Confirm your payment", pay.payment_url(params[:payment_intent_id]) %></p>
4
+ <p>If you have any questions, please hit reply and let us know.</p>
6
5
  <p>— The <%= Pay.application_name %> Team</p>
@@ -0,0 +1,5 @@
1
+ <h3>Your payment was declined</h3>
2
+ <p>We were unable to charge your payment method for your <%= Pay.application_name %> subscription. Please update your billing information.</p>
3
+ <p><%= link_to "Update billing information", root_url %></p>
4
+ <p>Let us know if you have any questions.</p>
5
+ <p>— The <%= Pay.application_name %> Team</p>
@@ -1,6 +1,4 @@
1
1
  <h3>Your upcoming <%= Pay.application_name %> subscription renewal</h3>
2
- <p>This is just a friendly reminder that your <%= link_to Pay.application_name, root_url %> subscription will renew automatically on <%= l params[:date].to_date, format: :long %>.</p>
3
-
2
+ <p>This is a friendly reminder that your <%= link_to Pay.application_name, root_url %> subscription will renew automatically on <%= l params[:date].to_date, format: :long %>.</p>
4
3
  <p>You may <%= link_to "manage your subscription", root_url %> via your account. If you have any questions, please hit reply and let us know.</p>
5
-
6
4
  <p>— The <%= Pay.application_name %> Team</p>
@@ -1,6 +1,4 @@
1
1
  <h3>Your <%= Pay.application_name %> trial has ended</h3>
2
2
  <p>This is just a friendly reminder that your <%= link_to Pay.application_name, root_url %> trial has ended.</p>
3
-
4
3
  <p>You may <%= link_to "manage your subscription", root_url %> via your account. If you have any questions, please hit reply and let us know.</p>
5
-
6
4
  <p>— The <%= Pay.application_name %> Team</p>
@@ -1,6 +1,4 @@
1
1
  <h3>Your <%= Pay.application_name %> trial is ending soon</h3>
2
2
  <p>This is just a friendly reminder that your <%= link_to Pay.application_name, root_url %> trial will be ending soon.</p>
3
-
4
3
  <p>You may <%= link_to "manage your subscription", root_url %> via your account. If you have any questions, please hit reply and let us know.</p>
5
-
6
4
  <p>— The <%= Pay.application_name %> Team</p>
@@ -56,6 +56,8 @@ en:
56
56
  subject: "[%{application}] Your upcoming subscription renewal"
57
57
  payment_action_required:
58
58
  subject: "[%{application}] Confirm your payment"
59
+ payment_failed:
60
+ subject: "[%{application}] Action Required – Your payment failed"
59
61
  subscription_trial_will_end:
60
62
  subject: "[%{application}] Your trial is ending soon"
61
63
  subscription_trial_ended:
@@ -174,12 +174,17 @@ module Pay
174
174
  attrs[:metadata] = transaction.custom_fields
175
175
  attrs[:currency] = transaction.currency_iso_code
176
176
  attrs[:application_fee_amount] = transaction.service_fee_amount
177
+ attrs[:created_at] = transaction.created_at
177
178
 
178
179
  # Associate charge with subscription if we can
179
180
  if transaction.subscription_id
180
181
  pay_subscription = pay_customer.subscriptions.find_by(processor_id: transaction.subscription_id)
181
- attrs[:subscription] = pay_subscription
182
- attrs[:metadata] = pay_subscription.metadata
182
+ pay_subscription ||= Pay::Braintree::Subscription.sync(transaction.subscription_id)
183
+
184
+ if pay_subscription
185
+ attrs[:subscription] = pay_subscription
186
+ attrs[:metadata] = pay_subscription.metadata
187
+ end
183
188
  end
184
189
 
185
190
  charge = pay_customer.charges.find_or_initialize_by(processor_id: transaction.id)
@@ -28,6 +28,9 @@ module Pay
28
28
  pay_customer = Pay::Customer.find_by(processor: :braintree, processor_id: payment_method.customer_id)
29
29
  return unless pay_customer
30
30
 
31
+ # Sync the PaymentMethod since we've got it
32
+ pay_customer.save_payment_method(payment_method, default: payment_method.default?)
33
+
31
34
  attributes = {
32
35
  created_at: object.created_at,
33
36
  current_period_end: object.billing_period_end_date,
@@ -301,13 +301,26 @@ module Pay
301
301
  end
302
302
 
303
303
  # Retries the latest invoice for a Past Due subscription and attempts to pay it
304
- def retry_failed_payment
305
- payment_intent = ::Stripe::PaymentIntent.confirm(subscription.latest_invoice.payment_intent.id)
304
+ def retry_failed_payment(payment_intent_id: nil)
305
+ payment_intent_id ||= subscription.latest_invoice.payment_intent.id
306
+ payment_intent = ::Stripe::PaymentIntent.retrieve({id: payment_intent_id}, stripe_options)
307
+
308
+ payment_intent = if payment_intent.status == "requires_payment_method"
309
+ ::Stripe::PaymentIntent.confirm(payment_intent_id, {payment_method: pay_subscription.customer.default_payment_method.processor_id}, stripe_options)
310
+ else
311
+ ::Stripe::PaymentIntent.confirm(payment_intent_id, stripe_options)
312
+ end
306
313
  Pay::Payment.new(payment_intent).validate
307
314
  rescue ::Stripe::StripeError => e
308
315
  raise Pay::Stripe::Error, e
309
316
  end
310
317
 
318
+ def pay_open_invoices
319
+ ::Stripe::Invoice.list({subscription: processor_id, status: :open}, stripe_options).auto_paging_each do |invoice|
320
+ retry_failed_payment(payment_intent_id: invoice.payment_intent)
321
+ end
322
+ end
323
+
311
324
  private
312
325
 
313
326
  # Options for Stripe requests
@@ -0,0 +1,24 @@
1
+ module Pay
2
+ module Stripe
3
+ module Webhooks
4
+ class PaymentFailed
5
+ def call(event)
6
+ # Event is of type "invoice" see:
7
+ # https://stripe.com/docs/api/invoices/object
8
+
9
+ object = event.data.object
10
+
11
+ pay_subscription = Pay::Subscription.find_by_processor_and_id(:stripe, object.subscription)
12
+ return if pay_subscription.nil?
13
+
14
+ if Pay.send_email?(:payment_failed, pay_subscription)
15
+ Pay.mailer.with(
16
+ pay_customer: pay_subscription.customer,
17
+ stripe_invoice: object
18
+ ).payment_failed.deliver_now
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
data/lib/pay/stripe.rb CHANGED
@@ -16,6 +16,7 @@ module Pay
16
16
  autoload :CustomerDeleted, "pay/stripe/webhooks/customer_deleted"
17
17
  autoload :CustomerUpdated, "pay/stripe/webhooks/customer_updated"
18
18
  autoload :PaymentActionRequired, "pay/stripe/webhooks/payment_action_required"
19
+ autoload :PaymentFailed, "pay/stripe/webhooks/payment_failed"
19
20
  autoload :PaymentIntentSucceeded, "pay/stripe/webhooks/payment_intent_succeeded"
20
21
  autoload :PaymentMethodAttached, "pay/stripe/webhooks/payment_method_attached"
21
22
  autoload :PaymentMethodDetached, "pay/stripe/webhooks/payment_method_detached"
@@ -78,6 +79,9 @@ module Pay
78
79
  # Payment action is required to process an invoice
79
80
  events.subscribe "stripe.invoice.payment_action_required", Pay::Stripe::Webhooks::PaymentActionRequired.new
80
81
 
82
+ # If an invoice payment fails, we want to notify the user via email to update their payment details
83
+ events.subscribe "stripe.invoice.payment_failed", Pay::Stripe::Webhooks::PaymentFailed.new
84
+
81
85
  # If a subscription is manually created on Stripe, we want to sync
82
86
  events.subscribe "stripe.customer.subscription.created", Pay::Stripe::Webhooks::SubscriptionCreated.new
83
87
 
data/lib/pay/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Pay
2
- VERSION = "6.2.3"
2
+ VERSION = "6.3.0"
3
3
  end
data/lib/pay.rb CHANGED
@@ -59,6 +59,7 @@ module Pay
59
59
  mattr_accessor :emails
60
60
  @@emails = ActiveSupport::OrderedOptions.new
61
61
  @@emails.payment_action_required = true
62
+ @@emails.payment_failed = true
62
63
  @@emails.receipt = true
63
64
  @@emails.refund = true
64
65
  # This only applies to Stripe, therefor we supply the second argument of price
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pay
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.2.3
4
+ version: 6.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Charnes
8
8
  - Chris Oliver
9
+ - Collin Jilbert
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2023-01-05 00:00:00.000000000 Z
13
+ date: 2023-01-13 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: rails
@@ -25,66 +26,11 @@ dependencies:
25
26
  - - ">="
26
27
  - !ruby/object:Gem::Version
27
28
  version: 6.0.0
28
- - !ruby/object:Gem::Dependency
29
- name: mocha
30
- requirement: !ruby/object:Gem::Requirement
31
- requirements:
32
- - - ">="
33
- - !ruby/object:Gem::Version
34
- version: '0'
35
- type: :development
36
- prerelease: false
37
- version_requirements: !ruby/object:Gem::Requirement
38
- requirements:
39
- - - ">="
40
- - !ruby/object:Gem::Version
41
- version: '0'
42
- - !ruby/object:Gem::Dependency
43
- name: standardrb
44
- requirement: !ruby/object:Gem::Requirement
45
- requirements:
46
- - - ">="
47
- - !ruby/object:Gem::Version
48
- version: '0'
49
- type: :development
50
- prerelease: false
51
- version_requirements: !ruby/object:Gem::Requirement
52
- requirements:
53
- - - ">="
54
- - !ruby/object:Gem::Version
55
- version: '0'
56
- - !ruby/object:Gem::Dependency
57
- name: vcr
58
- requirement: !ruby/object:Gem::Requirement
59
- requirements:
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- version: '0'
63
- type: :development
64
- prerelease: false
65
- version_requirements: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- version: '0'
70
- - !ruby/object:Gem::Dependency
71
- name: webmock
72
- requirement: !ruby/object:Gem::Requirement
73
- requirements:
74
- - - ">="
75
- - !ruby/object:Gem::Version
76
- version: '0'
77
- type: :development
78
- prerelease: false
79
- version_requirements: !ruby/object:Gem::Requirement
80
- requirements:
81
- - - ">="
82
- - !ruby/object:Gem::Version
83
- version: '0'
84
29
  description: Stripe, Paddle, and Braintree payments for Ruby on Rails apps
85
30
  email:
86
31
  - jason@thecharnes.com
87
32
  - excid3@gmail.com
33
+ - cjilbert504@gmail.com
88
34
  executables: []
89
35
  extensions: []
90
36
  extra_rdoc_files: []
@@ -116,6 +62,7 @@ files:
116
62
  - app/views/pay/payments/show.html.erb
117
63
  - app/views/pay/stripe/_checkout_button.html.erb
118
64
  - app/views/pay/user_mailer/payment_action_required.html.erb
65
+ - app/views/pay/user_mailer/payment_failed.html.erb
119
66
  - app/views/pay/user_mailer/receipt.html.erb
120
67
  - app/views/pay/user_mailer/refund.html.erb
121
68
  - app/views/pay/user_mailer/subscription_renewing.html.erb
@@ -187,6 +134,7 @@ files:
187
134
  - lib/pay/stripe/webhooks/customer_deleted.rb
188
135
  - lib/pay/stripe/webhooks/customer_updated.rb
189
136
  - lib/pay/stripe/webhooks/payment_action_required.rb
137
+ - lib/pay/stripe/webhooks/payment_failed.rb
190
138
  - lib/pay/stripe/webhooks/payment_intent_succeeded.rb
191
139
  - lib/pay/stripe/webhooks/payment_method_attached.rb
192
140
  - lib/pay/stripe/webhooks/payment_method_detached.rb
@@ -220,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
220
168
  - !ruby/object:Gem::Version
221
169
  version: '0'
222
170
  requirements: []
223
- rubygems_version: 3.3.26
171
+ rubygems_version: 3.4.1
224
172
  signing_key:
225
173
  specification_version: 4
226
174
  summary: Payments engine for Ruby on Rails