pay 2.4.2 → 2.6.1

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.

Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -4
  3. data/app/controllers/pay/webhooks/braintree_controller.rb +7 -53
  4. data/app/controllers/pay/webhooks/paddle_controller.rb +19 -18
  5. data/app/controllers/pay/webhooks/stripe_controller.rb +47 -0
  6. data/app/models/pay/charge.rb +22 -3
  7. data/app/models/pay/subscription.rb +23 -24
  8. data/app/views/pay/stripe/_checkout_button.html.erb +21 -0
  9. data/config/routes.rb +1 -1
  10. data/lib/pay.rb +13 -12
  11. data/lib/pay/billable.rb +33 -33
  12. data/lib/pay/billable/sync_email.rb +1 -1
  13. data/lib/pay/braintree.rb +34 -15
  14. data/lib/pay/braintree/authorization_error.rb +9 -0
  15. data/lib/pay/braintree/billable.rb +33 -30
  16. data/lib/pay/braintree/charge.rb +8 -10
  17. data/lib/pay/braintree/error.rb +9 -0
  18. data/lib/pay/braintree/subscription.rb +34 -15
  19. data/lib/pay/braintree/webhooks/subscription_canceled.rb +19 -0
  20. data/lib/pay/braintree/webhooks/subscription_charged_successfully.rb +24 -0
  21. data/lib/pay/braintree/webhooks/subscription_charged_unsuccessfully.rb +24 -0
  22. data/lib/pay/braintree/webhooks/subscription_expired.rb +19 -0
  23. data/lib/pay/braintree/webhooks/subscription_trial_ended.rb +19 -0
  24. data/lib/pay/braintree/webhooks/subscription_went_active.rb +19 -0
  25. data/lib/pay/braintree/webhooks/subscription_went_past_due.rb +19 -0
  26. data/lib/pay/engine.rb +0 -23
  27. data/lib/pay/errors.rb +0 -44
  28. data/lib/pay/paddle.rb +30 -16
  29. data/lib/pay/paddle/billable.rb +26 -22
  30. data/lib/pay/paddle/charge.rb +8 -12
  31. data/lib/pay/paddle/error.rb +9 -0
  32. data/lib/pay/paddle/subscription.rb +29 -18
  33. data/lib/pay/paddle/webhooks/subscription_cancelled.rb +3 -3
  34. data/lib/pay/paddle/webhooks/subscription_created.rb +15 -15
  35. data/lib/pay/paddle/webhooks/subscription_payment_refunded.rb +3 -3
  36. data/lib/pay/paddle/webhooks/subscription_payment_succeeded.rb +11 -11
  37. data/lib/pay/paddle/webhooks/subscription_updated.rb +11 -11
  38. data/lib/pay/stripe.rb +65 -15
  39. data/lib/pay/stripe/billable.rb +136 -69
  40. data/lib/pay/stripe/charge.rb +9 -15
  41. data/lib/pay/stripe/error.rb +9 -0
  42. data/lib/pay/stripe/subscription.rb +27 -11
  43. data/lib/pay/stripe/webhooks/charge_succeeded.rb +1 -20
  44. data/lib/pay/stripe/webhooks/subscription_created.rb +1 -0
  45. data/lib/pay/version.rb +1 -1
  46. data/lib/pay/webhooks.rb +13 -0
  47. data/lib/pay/webhooks/delegator.rb +61 -0
  48. metadata +20 -69
  49. data/lib/pay/paddle/webhooks.rb +0 -1
  50. data/lib/pay/stripe/webhooks.rb +0 -39
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4832547f758ca266af9bdb4e727dfec425fb7ace4cf6d3372f47dd0f73057ad4
4
- data.tar.gz: 854f6d697267fe7e3c45799f036241266067140892d32470ee6be9d24f860e50
3
+ metadata.gz: ef6938df82189d79a9388ed5b4d5575087fa899078fad1bcd61f54b4b8d62d0d
4
+ data.tar.gz: '06933776eac195dea9025b28600813f92c97bc77d5e25eb978ea29ed5bf02674'
5
5
  SHA512:
6
- metadata.gz: 7ca4679542933ddac4d75c5091dcc8653ffbe0f839d396aeec0d2aa0714117bb1a72e2b03d11f62e0d2508f1b7be71affd4f5703ec5c1da48462f35a7b194bf6
7
- data.tar.gz: 62e21bae437f10db633efe35d993382a76c9b42e8cad661bed57f4a6cdc348889d7baae2b9c80d2f1219b050cc12d0c7e40c11dce4e87c613d077ed1005c7706
6
+ metadata.gz: e1f3b44d448aecba61a78eb6708dc1a1d4e47b8d80be5aef3801275624ce0b55cc1b17151d695fa23adbb8e0a13699bd67a29b9ab12a49e61d3881ff36a0f2f0
7
+ data.tar.gz: 1bfcef1dcf8451e62ccdfd6516b1dd69fc289b6644994016d2548ac67cd87c822112544d5e6a7f9424a05b42c4b0be8afb1e284482d081bf621a7896aec5e09d
data/README.md CHANGED
@@ -8,9 +8,9 @@ Pay is a payments engine for Ruby on Rails 4.2 and higher.
8
8
 
9
9
  **Current Payment Providers**
10
10
 
11
- - Stripe ([supports SCA](https://stripe.com/docs/strong-customer-authentication) using API version `2020-08-27`)
12
- - Braintree
13
- - Paddle
11
+ - Stripe ([SCA Compatible](https://stripe.com/docs/strong-customer-authentication) using API version `2020-08-27`)
12
+ - Paddle (SCA Compatible & supports PayPal)
13
+ - Braintree (supports PayPal)
14
14
 
15
15
  Want to add a new payment provider? Contributions are welcome and the instructions [are here](https://github.com/jasoncharnes/pay/wiki/New-Payment-Provider).
16
16
 
@@ -31,7 +31,6 @@ gem 'pay', '~> 2.0'
31
31
 
32
32
  # To use Stripe, also include:
33
33
  gem 'stripe', '< 6.0', '>= 2.8'
34
- gem 'stripe_event', '~> 2.3'
35
34
 
36
35
  # To use Braintree + PayPal, also include:
37
36
  gem 'braintree', '< 3.0', '>= 2.92.0'
@@ -6,66 +6,20 @@ module Pay
6
6
  end
7
7
 
8
8
  def create
9
- case webhook_notification.kind
10
- when "subscription_charged_successfully"
11
- subscription_charged_successfully(webhook_notification)
12
- when "subscription_canceled"
13
- subscription_canceled(webhook_notification)
14
- when "subscription_trial_ended"
15
- subscription_trial_ended(webhook_notification)
16
- end
17
-
18
- render json: {success: true}, status: :ok
19
- rescue ::Braintree::InvalidSignature
9
+ delegate_event(verified_event)
20
10
  head :ok
11
+ rescue ::Braintree::InvalidSignature
12
+ head :bad_request
21
13
  end
22
14
 
23
15
  private
24
16
 
25
- def subscription_charged_successfully(event)
26
- subscription = event.subscription
27
- return if subscription.nil?
28
-
29
- pay_subscription = Pay.subscription_model.find_by(processor: :braintree, processor_id: subscription.id)
30
- return unless pay_subscription.present?
31
-
32
- billable = pay_subscription.owner
33
- charge = billable.save_braintree_transaction(subscription.transactions.first)
34
-
35
- if Pay.send_emails
36
- Pay::UserMailer.with(billable: billable, charge: charge).receipt.deliver_later
37
- end
38
- end
39
-
40
- def subscription_canceled(event)
41
- subscription = event.subscription
42
- return if subscription.nil?
43
-
44
- pay_subscription = Pay.subscription_model.find_by(processor: :braintree, processor_id: subscription.id)
45
- return unless pay_subscription.present?
46
-
47
- billable = pay_subscription.owner
48
- return if billable.nil?
49
-
50
- # User canceled or failed to make payments
51
- billable.update(braintree_subscription_id: nil)
52
- end
53
-
54
- def subscription_trial_ended(event)
55
- subscription = event.subscription
56
- return if subscription.nil?
57
-
58
- pay_subscription = Pay.subscription_model.find_by(processor: :braintree, processor_id: subscription.id)
59
- return unless pay_subscription.present?
60
-
61
- pay_subscription.update(trial_ends_at: Time.zone.now)
17
+ def delegate_event(event)
18
+ Pay::Webhooks.instrument type: "braintree.#{event.kind}", event: event
62
19
  end
63
20
 
64
- def webhook_notification
65
- @webhook_notification ||= Pay.braintree_gateway.webhook_notification.parse(
66
- params[:bt_signature],
67
- params[:bt_payload]
68
- )
21
+ def verified_event
22
+ Pay.braintree_gateway.webhook_notification.parse(params[:bt_signature], params[:bt_payload])
69
23
  end
70
24
  end
71
25
  end
@@ -6,28 +6,29 @@ module Pay
6
6
  end
7
7
 
8
8
  def create
9
- verifier = Pay::Paddle::Webhooks::SignatureVerifier.new(check_params.as_json)
10
- if verifier.verify
11
- case params["alert_name"]
12
- when "subscription_created"
13
- Pay::Paddle::Webhooks::SubscriptionCreated.new(check_params.as_json)
14
- when "subscription_updated"
15
- Pay::Paddle::Webhooks::SubscriptionUpdated.new(check_params.as_json)
16
- when "subscription_cancelled"
17
- Pay::Paddle::Webhooks::SubscriptionCancelled.new(check_params.as_json)
18
- when "subscription_payment_succeeded"
19
- Pay::Paddle::Webhooks::SubscriptionPaymentSucceeded.new(check_params.as_json)
20
- when "subscription_payment_refunded"
21
- Pay::Paddle::Webhooks::SubscriptionPaymentRefunded.new(check_params.as_json)
22
- end
23
- render json: {success: true}, status: :ok
24
- else
25
- head :ok
26
- end
9
+ delegate_event(verified_event)
10
+ head :ok
11
+ rescue Pay::Paddle::Error
12
+ head :bad_request
27
13
  end
28
14
 
29
15
  private
30
16
 
17
+ def delegate_event(event)
18
+ Pay::Webhooks.instrument type: "paddle.#{type}", event: event
19
+ end
20
+
21
+ def type
22
+ params[:alert_name]
23
+ end
24
+
25
+ def verified_event
26
+ event = check_params.as_json
27
+ verifier = Pay::Paddle::Webhooks::SignatureVerifier.new(event)
28
+ return event if verifier.verify
29
+ raise Pay::Paddle::Error, "Unable to verify Paddle webhook event"
30
+ end
31
+
31
32
  def check_params
32
33
  params.except(:action, :controller).permit!
33
34
  end
@@ -0,0 +1,47 @@
1
+ module Pay
2
+ module Webhooks
3
+ class StripeController < Pay::ApplicationController
4
+ if Rails.application.config.action_controller.default_protect_from_forgery
5
+ skip_before_action :verify_authenticity_token
6
+ end
7
+
8
+ def create
9
+ delegate_event(verified_event)
10
+ head :ok
11
+ rescue ::Stripe::SignatureVerificationError => e
12
+ log_error(e)
13
+ head :bad_request
14
+ end
15
+
16
+ private
17
+
18
+ def delegate_event(event)
19
+ Pay::Webhooks.instrument type: "stripe.#{event.type}", event: event
20
+ end
21
+
22
+ def verified_event
23
+ payload = request.body.read
24
+ signature = request.headers["Stripe-Signature"]
25
+ possible_secrets = secrets(payload, signature)
26
+
27
+ possible_secrets.each_with_index do |secret, i|
28
+ return ::Stripe::Webhook.construct_event(payload, signature, secret.to_s)
29
+ rescue ::Stripe::SignatureVerificationError
30
+ raise if i == possible_secrets.length - 1
31
+ next
32
+ end
33
+ end
34
+
35
+ def secrets(payload, signature)
36
+ secret = Pay::Stripe.signing_secret
37
+ return Array.wrap(secret) if secret
38
+ raise ::Stripe::SignatureVerificationError.new("Cannot verify signature without a Stripe signing secret", signature, http_body: payload)
39
+ end
40
+
41
+ def log_error(e)
42
+ logger.error e.message
43
+ e.backtrace.each { |line| logger.error " #{line}" }
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,5 +1,5 @@
1
1
  module Pay
2
- class Charge < ApplicationRecord
2
+ class Charge < Pay::ApplicationRecord
3
3
  self.table_name = Pay.chargeable_table
4
4
 
5
5
  # Only serialize for non-json columns
@@ -18,13 +18,32 @@ module Pay
18
18
  validates :processor_id, presence: true
19
19
  validates :card_type, presence: true
20
20
 
21
+ store_accessor :data, :paddle_receipt_url
22
+
23
+ # Helpers for payment processors
24
+ %w[braintree stripe paddle].each do |processor_name|
25
+ define_method "#{processor_name}?" do
26
+ processor == processor_name
27
+ end
28
+
29
+ scope processor_name, -> { where(processor: processor_name) }
30
+ end
31
+
32
+ def payment_processor
33
+ @payment_processor ||= payment_processor_for(processor).new(self)
34
+ end
35
+
36
+ def payment_processor_for(name)
37
+ "Pay::#{name.to_s.classify}::Charge".constantize
38
+ end
39
+
21
40
  def processor_charge
22
- send("#{processor}_charge")
41
+ payment_processor.charge
23
42
  end
24
43
 
25
44
  def refund!(refund_amount = nil)
26
45
  refund_amount ||= amount
27
- send("#{processor}_refund!", refund_amount)
46
+ payment_processor.refund!(refund_amount)
28
47
  end
29
48
 
30
49
  def charged_to
@@ -1,5 +1,5 @@
1
1
  module Pay
2
- class Subscription < ApplicationRecord
2
+ class Subscription < Pay::ApplicationRecord
3
3
  self.table_name = Pay.subscription_table
4
4
 
5
5
  STATUSES = %w[incomplete incomplete_expired trialing active past_due canceled unpaid paused]
@@ -27,6 +27,11 @@ module Pay
27
27
  scope :incomplete, -> { where(status: :incomplete) }
28
28
  scope :past_due, -> { where(status: :past_due) }
29
29
 
30
+ # TODO: Include these with a module
31
+ store_accessor :data, :paddle_update_url
32
+ store_accessor :data, :paddle_cancel_url
33
+ store_accessor :data, :paddle_paused_from
34
+
30
35
  attribute :prorate, :boolean, default: true
31
36
 
32
37
  # Helpers for payment processors
@@ -38,6 +43,21 @@ module Pay
38
43
  scope processor_name, -> { where(processor: processor_name) }
39
44
  end
40
45
 
46
+ def payment_processor
47
+ @payment_processor ||= payment_processor_for(processor).new(self)
48
+ end
49
+
50
+ def payment_processor_for(name)
51
+ "Pay::#{name.to_s.classify}::Subscription".constantize
52
+ end
53
+
54
+ delegate :on_grace_period?,
55
+ :paused?,
56
+ :pause,
57
+ :cancel,
58
+ :cancel_now!,
59
+ to: :payment_processor
60
+
41
61
  def no_prorate
42
62
  self.prorate = false
43
63
  end
@@ -58,11 +78,6 @@ module Pay
58
78
  canceled?
59
79
  end
60
80
 
61
- def on_grace_period?
62
- return unless processor?
63
- send("#{processor}_on_grace_period?")
64
- end
65
-
66
81
  def active?
67
82
  ["trialing", "active"].include?(status) && (ends_at.nil? || on_grace_period? || on_trial?)
68
83
  end
@@ -79,30 +94,14 @@ module Pay
79
94
  past_due? || incomplete?
80
95
  end
81
96
 
82
- def paused?
83
- send("#{processor}_paused?")
84
- end
85
-
86
- def pause
87
- send("#{processor}_pause")
88
- end
89
-
90
- def cancel
91
- send("#{processor}_cancel")
92
- end
93
-
94
- def cancel_now!
95
- send("#{processor}_cancel_now!")
96
- end
97
-
98
97
  def resume
99
- send("#{processor}_resume")
98
+ payment_processor.resume
100
99
  update(ends_at: nil, status: "active")
101
100
  self
102
101
  end
103
102
 
104
103
  def swap(plan)
105
- send("#{processor}_swap", plan)
104
+ payment_processor.swap(plan)
106
105
  update(processor_plan: plan, ends_at: nil)
107
106
  end
108
107
 
@@ -0,0 +1,21 @@
1
+ <%= button_tag title,
2
+ id: "checkout-#{session.id}",
3
+ class: local_assigns[:class],
4
+ style: (local_assigns[:class] || local_assigns[:style]) ? local_assigns[:style] : 'background-color:#6772E5;color:#FFF;padding:8px 12px;border:0;border-radius:4px;font-size:1em'
5
+ %>
6
+ <%= tag.div id: "error-for-#{session.id}" %>
7
+
8
+ <script>
9
+ (() => {
10
+ const checkoutButton = document.getElementById("checkout-<%= session.id %>");
11
+ checkoutButton.addEventListener('click', function () {
12
+ Stripe("<%= Pay::Stripe.public_key %>").redirectToCheckout({
13
+ sessionId: '<%= session.id %>'
14
+ }).then(function (result) {
15
+ if (result.error) {
16
+ document.getElementById('error-message').innerText = result.error.message;
17
+ }
18
+ });
19
+ });
20
+ })()
21
+ </script>
data/config/routes.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Pay::Engine.routes.draw do
4
4
  resources :payments, only: [:show], module: :pay
5
- post "webhooks/stripe", to: "stripe_event/webhook#event"
5
+ post "webhooks/stripe", to: "pay/webhooks/stripe#create"
6
6
  post "webhooks/braintree", to: "pay/webhooks/braintree#create"
7
7
  post "webhooks/paddle", to: "pay/webhooks/paddle#create"
8
8
  end
data/lib/pay.rb CHANGED
@@ -1,10 +1,20 @@
1
+ require "pay/version"
1
2
  require "pay/engine"
2
- require "pay/billable"
3
- require "pay/receipts"
4
- require "pay/payment"
5
3
  require "pay/errors"
6
4
 
7
5
  module Pay
6
+ autoload :Billable, "pay/billable"
7
+ autoload :Env, "pay/env"
8
+ autoload :Payment, "pay/payment"
9
+ autoload :Receipts, "pay/receipts"
10
+
11
+ # Payment processors
12
+ autoload :Braintree, "pay/braintree"
13
+ autoload :Paddle, "pay/paddle"
14
+ autoload :Stripe, "pay/stripe"
15
+
16
+ autoload :Webhooks, "pay/webhooks"
17
+
8
18
  # Define who owns the subscription
9
19
  mattr_accessor :billable_class
10
20
  mattr_accessor :billable_table
@@ -36,15 +46,6 @@ module Pay
36
46
  mattr_accessor :send_emails
37
47
  @@send_emails = true
38
48
 
39
- mattr_accessor :email_receipt_subject
40
- @@email_receipt_subject = "Payment receipt"
41
- mattr_accessor :email_refund_subject
42
- @@email_refund_subject = "Payment refunded"
43
- mattr_accessor :email_renewing_subject
44
- @@email_renewing_subject = "Your upcoming subscription renewal"
45
- mattr_accessor :email_action_required_subject
46
- @@email_action_required_subject = "Confirm your payment"
47
-
48
49
  mattr_accessor :automount_routes
49
50
  @@automount_routes = true
50
51
 
data/lib/pay/billable.rb CHANGED
@@ -17,9 +17,6 @@ module Pay
17
17
 
18
18
  included do |base|
19
19
  include Pay::Billable::SyncEmail
20
- include Pay::Stripe::Billable if defined? ::Stripe
21
- include Pay::Braintree::Billable if defined? ::Braintree
22
- include Pay::Paddle::Billable if defined? ::PaddlePay
23
20
 
24
21
  has_many :charges, class_name: Pay.chargeable_class, foreign_key: :owner_id, inverse_of: :owner, as: :owner
25
22
  has_many :subscriptions, class_name: Pay.subscription_class, foreign_key: :owner_id, inverse_of: :owner, as: :owner
@@ -29,17 +26,34 @@ module Pay
29
26
  attribute :card_token, :string
30
27
  end
31
28
 
29
+ def payment_processor
30
+ @payment_processor ||= payment_processor_for(processor).new(self)
31
+ end
32
+
33
+ def payment_processor_for(name)
34
+ "Pay::#{name.to_s.classify}::Billable".constantize
35
+ end
36
+
37
+ # Reset the payment processor when it changes
32
38
  def processor=(value)
33
39
  super(value)
34
40
  self.processor_id = nil if processor_changed?
41
+ @payment_processor = nil
35
42
  end
36
43
 
44
+ def processor
45
+ super.inquiry
46
+ end
47
+
48
+ delegate :charge, to: :payment_processor
49
+ delegate :subscribe, to: :payment_processor
50
+ delegate :update_card, to: :payment_processor
51
+
37
52
  def customer
38
- check_for_processor
39
53
  raise Pay::Error, I18n.t("errors.email_required") if email.nil?
40
54
 
41
- customer = send("#{processor}_customer")
42
- update_card(card_token) if card_token.present?
55
+ customer = payment_processor.customer
56
+ payment_processor.update_card(card_token) if card_token.present?
43
57
  customer
44
58
  end
45
59
 
@@ -47,20 +61,9 @@ module Pay
47
61
  [try(:first_name), try(:last_name)].compact.join(" ")
48
62
  end
49
63
 
50
- def charge(amount_in_cents, options = {})
51
- check_for_processor
52
- send("create_#{processor}_charge", amount_in_cents, options)
53
- end
54
-
55
- def subscribe(name: Pay.default_product_name, plan: Pay.default_plan_name, **options)
56
- check_for_processor
57
- send("create_#{processor}_subscription", name, plan, options)
58
- end
59
-
60
- def update_card(token)
61
- check_for_processor
62
- customer if processor_id.nil?
63
- send("update_#{processor}_card", token)
64
+ def create_setup_intent
65
+ ActiveSupport::Deprecation.warn("This method will be removed in the next release. Use `@billable.payment_processor.create_setup_intent` instead.")
66
+ payment_processor.create_setup_intent
64
67
  end
65
68
 
66
69
  def on_trial?(name: Pay.default_product_name, plan: nil)
@@ -77,8 +80,7 @@ module Pay
77
80
  end
78
81
 
79
82
  def processor_subscription(subscription_id, options = {})
80
- check_for_processor
81
- send("#{processor}_subscription", subscription_id, options)
83
+ payment_processor.processor_subscription(subscription_id, options)
82
84
  end
83
85
 
84
86
  def subscribed?(name: Pay.default_product_name, processor_plan: nil)
@@ -100,11 +102,13 @@ module Pay
100
102
  end
101
103
 
102
104
  def invoice!(options = {})
103
- send("#{processor}_invoice!", options)
105
+ ActiveSupport::Deprecation.warn("This will be removed in the next release. Use `@billable.payment_processor.invoice!` instead.")
106
+ payment_processor.invoice!(options)
104
107
  end
105
108
 
106
109
  def upcoming_invoice
107
- send("#{processor}_upcoming_invoice")
110
+ ActiveSupport::Deprecation.warn("This will be removed in the next release. Use `@billable.payment_processor.upcoming_invoice` instead.")
111
+ payment_processor.upcoming_invoice
108
112
  end
109
113
 
110
114
  def stripe?
@@ -116,7 +120,7 @@ module Pay
116
120
  end
117
121
 
118
122
  def paypal?
119
- braintree? && card_type == "PayPal"
123
+ card_type == "PayPal"
120
124
  end
121
125
 
122
126
  def paddle?
@@ -127,14 +131,8 @@ module Pay
127
131
  subscription(name: name)&.has_incomplete_payment?
128
132
  end
129
133
 
130
- private
131
-
132
- def check_for_processor
133
- raise StandardError, I18n.t("errors.no_processor", class_name: self.class.name) unless processor
134
- end
135
-
136
134
  # Used for creating a Pay::Subscription in the database
137
- def create_subscription(subscription, processor, name, plan, options = {})
135
+ def create_pay_subscription(subscription, processor, name, plan, options = {})
138
136
  options[:quantity] ||= 1
139
137
 
140
138
  options.merge!(
@@ -142,12 +140,14 @@ module Pay
142
140
  processor: processor,
143
141
  processor_id: subscription.id,
144
142
  processor_plan: plan,
145
- trial_ends_at: send("#{processor}_trial_end_date", subscription),
143
+ trial_ends_at: payment_processor.trial_end_date(subscription),
146
144
  ends_at: nil
147
145
  )
148
146
  subscriptions.create!(options)
149
147
  end
150
148
 
149
+ private
150
+
151
151
  def default_generic_trial?(name, plan)
152
152
  # Generic trials don't have plans or custom names
153
153
  plan.nil? && name == "default" && on_generic_trial?