pay 0.0.2 → 1.0.0.beta2
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 +5 -5
- data/MIT-LICENSE +1 -1
- data/README.md +256 -29
- data/Rakefile +1 -6
- data/app/controllers/pay/webhooks/braintree_controller.rb +56 -0
- data/app/jobs/pay/email_sync_job.rb +12 -0
- data/app/mailers/pay/user_mailer.rb +42 -0
- data/app/models/pay/charge.rb +31 -0
- data/app/models/pay/subscription.rb +77 -0
- data/app/views/pay/user_mailer/receipt.html.erb +20 -0
- data/app/views/pay/user_mailer/refund.html.erb +21 -0
- data/app/views/pay/user_mailer/subscription_renewing.html.erb +6 -0
- data/config/routes.rb +3 -1
- data/db/migrate/20170205020145_create_subscriptions.rb +1 -1
- data/db/migrate/20170503131610_add_fields_to_users.rb +3 -2
- data/db/migrate/20170727235816_create_charges.rb +17 -0
- data/lib/generators/pay/email_views_generator.rb +13 -0
- data/lib/pay.rb +65 -1
- data/lib/pay/billable.rb +54 -24
- data/lib/pay/billable/sync_email.rb +41 -0
- data/lib/pay/braintree.rb +16 -0
- data/lib/pay/braintree/api.rb +30 -0
- data/lib/pay/braintree/billable.rb +219 -0
- data/lib/pay/braintree/charge.rb +27 -0
- data/lib/pay/braintree/subscription.rb +173 -0
- data/lib/pay/engine.rb +14 -1
- data/lib/pay/receipts.rb +37 -0
- data/lib/pay/stripe.rb +17 -0
- data/lib/pay/stripe/api.rb +13 -0
- data/lib/pay/stripe/billable.rb +143 -0
- data/lib/pay/stripe/charge.rb +30 -0
- data/lib/pay/stripe/subscription.rb +48 -0
- data/lib/pay/stripe/webhooks.rb +39 -0
- data/lib/pay/stripe/webhooks/charge_refunded.rb +25 -0
- data/lib/pay/stripe/webhooks/charge_succeeded.rb +47 -0
- data/lib/pay/stripe/webhooks/customer_deleted.rb +31 -0
- data/lib/pay/stripe/webhooks/customer_updated.rb +19 -0
- data/lib/pay/stripe/webhooks/source_deleted.rb +19 -0
- data/lib/pay/stripe/webhooks/subscription_created.rb +46 -0
- data/lib/pay/stripe/webhooks/subscription_deleted.rb +21 -0
- data/lib/pay/stripe/webhooks/subscription_renewing.rb +25 -0
- data/lib/pay/stripe/webhooks/subscription_updated.rb +35 -0
- data/lib/pay/version.rb +1 -1
- metadata +124 -30
- data/app/models/subscription.rb +0 -59
- data/config/initializers/pay.rb +0 -3
- data/config/initializers/stripe.rb +0 -1
- data/db/development.sqlite3 +0 -0
- data/lib/pay/billable/braintree.rb +0 -57
- data/lib/pay/billable/stripe.rb +0 -47
- data/lib/tasks/pay_tasks.rake +0 -4
data/Rakefile
CHANGED
@@ -15,12 +15,11 @@ RDoc::Task.new(:rdoc) do |rdoc|
|
|
15
15
|
end
|
16
16
|
|
17
17
|
APP_RAKEFILE = File.expand_path('../test/dummy/Rakefile', __FILE__)
|
18
|
-
load 'rails/tasks/engine.rake'
|
19
18
|
|
19
|
+
load 'rails/tasks/engine.rake'
|
20
20
|
load 'rails/tasks/statistics.rake'
|
21
21
|
|
22
22
|
require 'bundler/gem_tasks'
|
23
|
-
|
24
23
|
require 'rake/testtask'
|
25
24
|
|
26
25
|
Rake::TestTask.new(:test) do |t|
|
@@ -39,7 +38,3 @@ task :console do
|
|
39
38
|
ARGV.clear
|
40
39
|
IRB.start
|
41
40
|
end
|
42
|
-
|
43
|
-
require 'rubocop/rake_task'
|
44
|
-
|
45
|
-
RuboCop::RakeTask.new
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Pay
|
2
|
+
module Webhooks
|
3
|
+
class BraintreeController < 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
|
+
case verified_event.kind
|
10
|
+
when "subscription_charged_successfully"
|
11
|
+
subscription_charged_successfully(verified_event)
|
12
|
+
when "subscription_canceled"
|
13
|
+
subscription_canceled(verified_event)
|
14
|
+
end
|
15
|
+
|
16
|
+
render json: {success: true}
|
17
|
+
rescue Braintree::InvalidSignature => e
|
18
|
+
head :ok
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def subscription_charged_successfully(event)
|
24
|
+
subscription = event.subscription
|
25
|
+
return if subscription.nil?
|
26
|
+
|
27
|
+
user = Pay.user_model.find_by(processor: :braintree, processor_id: subscription.id)
|
28
|
+
return unless user.present?
|
29
|
+
|
30
|
+
charge = user.save_braintree_transaction(subscription.transactions.first)
|
31
|
+
|
32
|
+
if Pay.send_emails
|
33
|
+
Pay::UserMailer.receipt(user, charge).deliver_later
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def subscription_canceled(event)
|
38
|
+
subscription = event.subscription
|
39
|
+
return if subscription.nil?
|
40
|
+
|
41
|
+
user = Pay.user_model.find_by(processor: :braintree, processor_id: subscription.id)
|
42
|
+
return unless user.present?
|
43
|
+
|
44
|
+
# User canceled or failed to make payments
|
45
|
+
user.update(braintree_subscription_id: nil)
|
46
|
+
end
|
47
|
+
|
48
|
+
def verified_webhook
|
49
|
+
@webhook_notification ||= Braintree::WebhookNotification.parse(
|
50
|
+
params[:bt_signature],
|
51
|
+
params[:bt_payload]
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Pay
|
2
|
+
class EmailSyncJob < ApplicationJob
|
3
|
+
queue_as :default
|
4
|
+
|
5
|
+
def perform(id)
|
6
|
+
billable = Pay.user_model.find(id)
|
7
|
+
billable.sync_email_with_processor
|
8
|
+
rescue ActiveRecord::RecordNotFound
|
9
|
+
Rails.logger.info "Couldn't find a #{Pay.billable_class} with ID = #{id}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Pay
|
2
|
+
class UserMailer < ApplicationMailer
|
3
|
+
def receipt(user, charge)
|
4
|
+
@user, @charge = user, charge
|
5
|
+
|
6
|
+
if charge.respond_to? :receipt
|
7
|
+
attachments[charge.filename] = charge.receipt
|
8
|
+
end
|
9
|
+
|
10
|
+
mail(
|
11
|
+
to: to(user),
|
12
|
+
subject: Pay.email_receipt_subject,
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def refund(user, charge)
|
17
|
+
@user, @charge = user, charge
|
18
|
+
|
19
|
+
mail(
|
20
|
+
to: to(user),
|
21
|
+
subject: Pay.email_refund_subject,
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def subscription_renewing(user, subscription)
|
26
|
+
mail(
|
27
|
+
to: to(user),
|
28
|
+
subject: Pay.email_renewing_subject,
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def to(user)
|
35
|
+
if user.respond_to?(:name)
|
36
|
+
"#{user.name} <#{user.email}>"
|
37
|
+
else
|
38
|
+
user.email
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Pay
|
2
|
+
class Charge < ApplicationRecord
|
3
|
+
self.table_name = Pay.chargeable_table
|
4
|
+
|
5
|
+
# Associations
|
6
|
+
belongs_to :owner, class_name: Pay.billable_class, foreign_key: :owner_id
|
7
|
+
|
8
|
+
# Scopes
|
9
|
+
scope :sorted, -> { order(created_at: :desc) }
|
10
|
+
default_scope -> { sorted }
|
11
|
+
|
12
|
+
# Validations
|
13
|
+
validates :amount, presence: true
|
14
|
+
validates :processor, presence: true
|
15
|
+
validates :processor_id, presence: true
|
16
|
+
validates :card_type, presence: true
|
17
|
+
|
18
|
+
def processor_charge
|
19
|
+
send("#{processor}_charge")
|
20
|
+
end
|
21
|
+
|
22
|
+
def refund!(refund_amount = nil)
|
23
|
+
refund_amount ||= amount
|
24
|
+
send("#{processor}_refund!", refund_amount)
|
25
|
+
end
|
26
|
+
|
27
|
+
def charged_to
|
28
|
+
"#{card_type} (**** **** **** #{card_last4})"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Pay
|
2
|
+
class Subscription < ApplicationRecord
|
3
|
+
self.table_name = Pay.subscription_table
|
4
|
+
|
5
|
+
# Associations
|
6
|
+
belongs_to :owner, class_name: Pay.billable_class, foreign_key: :owner_id
|
7
|
+
|
8
|
+
# Validations
|
9
|
+
validates :name, presence: true
|
10
|
+
validates :processor, presence: true
|
11
|
+
validates :processor_id, presence: true
|
12
|
+
validates :processor_plan, presence: true
|
13
|
+
validates :quantity, presence: true
|
14
|
+
|
15
|
+
# Scopes
|
16
|
+
scope :for_name, ->(name) { where(name: name) }
|
17
|
+
scope :on_trial, ->{ where.not(trial_ends_at: nil).where("? < trial_ends_at", Time.zone.now) }
|
18
|
+
scope :cancelled, ->{ where.not(ends_at: nil) }
|
19
|
+
scope :on_grace_period, ->{ cancelled.where("? < ends_at", Time.zone.now) }
|
20
|
+
scope :active, ->{ where(ends_at: nil).or(on_grace_period).or(on_trial) }
|
21
|
+
|
22
|
+
attribute :prorate, :boolean, default: true
|
23
|
+
|
24
|
+
def no_prorate
|
25
|
+
self.prorate = false
|
26
|
+
end
|
27
|
+
|
28
|
+
def skip_trial
|
29
|
+
self.trial_ends_at = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_trial?
|
33
|
+
trial_ends_at? && Time.zone.now < trial_ends_at
|
34
|
+
end
|
35
|
+
|
36
|
+
def cancelled?
|
37
|
+
ends_at?
|
38
|
+
end
|
39
|
+
|
40
|
+
def on_grace_period?
|
41
|
+
cancelled? && Time.zone.now < ends_at
|
42
|
+
end
|
43
|
+
|
44
|
+
def active?
|
45
|
+
ends_at.nil? || on_grace_period? || on_trial?
|
46
|
+
end
|
47
|
+
|
48
|
+
def cancel
|
49
|
+
send("#{processor}_cancel")
|
50
|
+
end
|
51
|
+
|
52
|
+
def cancel_now!
|
53
|
+
send("#{processor}_cancel_now!")
|
54
|
+
end
|
55
|
+
|
56
|
+
def resume
|
57
|
+
unless on_grace_period?
|
58
|
+
raise StandardError,
|
59
|
+
'You can only resume subscriptions within their grace period.'
|
60
|
+
end
|
61
|
+
|
62
|
+
send("#{processor}_resume")
|
63
|
+
|
64
|
+
update(ends_at: nil)
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
def swap(plan)
|
69
|
+
send("#{processor}_swap", plan)
|
70
|
+
update(processor_plan: plan, ends_at: nil)
|
71
|
+
end
|
72
|
+
|
73
|
+
def processor_subscription
|
74
|
+
owner.processor_subscription(processor_id)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
We received payment for your subscription. Thanks for your business!<br/>
|
2
|
+
<br/>
|
3
|
+
Questions? Please reply to this email.<br/>
|
4
|
+
<br/>
|
5
|
+
------------------------------------<br/>
|
6
|
+
RECEIPT - SUBSCRIPTION<br/>
|
7
|
+
<br/>
|
8
|
+
Amount: USD <%= ActionController::Base.helpers.number_to_currency(@charge.amount / 100.0) %><br/>
|
9
|
+
<br/>
|
10
|
+
Charged to: <%= @charge.charged_to %><br/>
|
11
|
+
Transaction ID: <%= @charge.id %><br/>
|
12
|
+
Date: <%= @charge.created_at %><br/>
|
13
|
+
<% if @charge.owner.extra_billing_info? %>
|
14
|
+
<%= @charge.owner.extra_billing_info %><br/>
|
15
|
+
<% end %>
|
16
|
+
<br/>
|
17
|
+
<br/>
|
18
|
+
<%= Pay.business_name %><br/>
|
19
|
+
<%= simple_format Pay.business_address %>
|
20
|
+
------------------------------------<br/>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
We have processed your refund.<br/>
|
2
|
+
Please allow up to 7 business days for your refund to appear in your account<br/>
|
3
|
+
<br/>
|
4
|
+
Questions? Please reply to this email.<br/>
|
5
|
+
<br/>
|
6
|
+
------------------------------------<br/>
|
7
|
+
RECEIPT - REFUND<br/>
|
8
|
+
<br/>
|
9
|
+
Amount: USD <%= ActionController::Base.helpers.number_to_currency(@charge.amount / 100.0) %><br/>
|
10
|
+
<br/>
|
11
|
+
Refunded to: <%= @charge.charged_to %><br/>
|
12
|
+
Transaction ID: <%= @charge.id %><br/>
|
13
|
+
Date: <%= @charge.created_at %><br/>
|
14
|
+
<% if @charge.owner.extra_billing_info? %>
|
15
|
+
<%= @charge.owner.extra_billing_info %><br/>
|
16
|
+
<% end %>
|
17
|
+
<br/>
|
18
|
+
<br/>
|
19
|
+
<%= Pay.business_name %><br/>
|
20
|
+
<%= simple_format Pay.business_address %>
|
21
|
+
------------------------------------<br/>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<h3>Your upcoming subscription renewal</h3>
|
2
|
+
<p>This is just a friendly reminder that your <%= Pay.business_name %> subscription will renew automatically on <%= @subscription %>.</p>
|
3
|
+
|
4
|
+
<p>You may manage your subscription via your account. If you have any questions, please hit reply and let us know.</p>
|
5
|
+
|
6
|
+
<p>- The <%= Pay.business_name %> Team</p>
|
data/config/routes.rb
CHANGED
@@ -6,10 +6,11 @@ class AddFieldsToUsers < ActiveRecord::Migration[4.2]
|
|
6
6
|
|
7
7
|
add_column Pay.billable_table, :processor, :string
|
8
8
|
add_column Pay.billable_table, :processor_id, :string
|
9
|
-
add_column Pay.billable_table, :
|
10
|
-
add_column Pay.billable_table, :
|
9
|
+
add_column Pay.billable_table, :trial_ends_at, :datetime
|
10
|
+
add_column Pay.billable_table, :card_type, :string
|
11
11
|
add_column Pay.billable_table, :card_last4, :string
|
12
12
|
add_column Pay.billable_table, :card_exp_month, :string
|
13
13
|
add_column Pay.billable_table, :card_exp_year, :string
|
14
|
+
add_column Pay.billable_table, :extra_billing_info, :text
|
14
15
|
end
|
15
16
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class CreateCharges < ActiveRecord::Migration[5.1]
|
2
|
+
def change
|
3
|
+
create_table :pay_charges do |t|
|
4
|
+
t.references :owner
|
5
|
+
t.string :processor, null: false
|
6
|
+
t.string :processor_id, null: false
|
7
|
+
t.integer :amount, null: false
|
8
|
+
t.integer :amount_refunded
|
9
|
+
t.string :card_type
|
10
|
+
t.string :card_last4
|
11
|
+
t.string :card_exp_month
|
12
|
+
t.string :card_exp_year
|
13
|
+
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Pay
|
4
|
+
module Generators
|
5
|
+
class EmailViewsGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path("../../../..", __FILE__)
|
7
|
+
|
8
|
+
def copy_views
|
9
|
+
directory 'app/views/pay/user_mailer', 'app/views/pay/user_mailer'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/pay.rb
CHANGED
@@ -1,15 +1,79 @@
|
|
1
|
-
require 'stripe'
|
2
1
|
require 'pay/engine'
|
3
2
|
require 'pay/billable'
|
3
|
+
require 'pay/receipts'
|
4
4
|
|
5
5
|
module Pay
|
6
6
|
# Define who owns the subscription
|
7
7
|
mattr_accessor :billable_class
|
8
8
|
mattr_accessor :billable_table
|
9
|
+
mattr_accessor :braintree_gateway
|
10
|
+
|
9
11
|
@@billable_class = 'User'
|
10
12
|
@@billable_table = @@billable_class.tableize
|
11
13
|
|
14
|
+
mattr_accessor :chargeable_class
|
15
|
+
mattr_accessor :chargeable_table
|
16
|
+
@@chargeable_class = 'Pay::Charge'
|
17
|
+
@@chargeable_table = 'pay_charges'
|
18
|
+
|
19
|
+
mattr_accessor :subscription_class
|
20
|
+
mattr_accessor :subscription_table
|
21
|
+
@@subscription_class = 'Pay::Subscription'
|
22
|
+
@@subscription_table = 'pay_subscriptions'
|
23
|
+
|
24
|
+
# Business details for receipts
|
25
|
+
mattr_accessor :application_name
|
26
|
+
mattr_accessor :business_address
|
27
|
+
mattr_accessor :business_name
|
28
|
+
mattr_accessor :support_email
|
29
|
+
|
30
|
+
# Email configuration
|
31
|
+
mattr_accessor :send_emails
|
32
|
+
@@send_emails = true
|
33
|
+
|
34
|
+
mattr_accessor :email_receipt_subject
|
35
|
+
@@email_receipt_subject = 'Payment receipt'
|
36
|
+
mattr_accessor :email_refund_subject
|
37
|
+
@@email_refund_subject = 'Payment refunded'
|
38
|
+
mattr_accessor :email_renewing_subject
|
39
|
+
@@email_renewing_subject = 'Your upcoming subscription renewal'
|
40
|
+
|
12
41
|
def self.setup
|
13
42
|
yield self
|
14
43
|
end
|
44
|
+
|
45
|
+
def self.user_model
|
46
|
+
if Rails.application.config.cache_classes
|
47
|
+
@@user_model ||= billable_class.constantize
|
48
|
+
else
|
49
|
+
billable_class.constantize
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.charge_model
|
54
|
+
if Rails.application.config.cache_classes
|
55
|
+
@@charge_model ||= chargeable_class.constantize
|
56
|
+
else
|
57
|
+
chargeable_class.constantize
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.subscription_model
|
62
|
+
if Rails.application.config.cache_classes
|
63
|
+
@@subscription_model ||= subscription_class.constantize
|
64
|
+
else
|
65
|
+
subscription_class.constantize
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.receipts_supported?
|
70
|
+
charge_model.respond_to?(:receipt) &&
|
71
|
+
application_name.present? &&
|
72
|
+
business_name &&
|
73
|
+
business_address &&
|
74
|
+
support_email
|
75
|
+
end
|
76
|
+
|
77
|
+
class Error < StandardError
|
78
|
+
end
|
15
79
|
end
|
data/lib/pay/billable.rb
CHANGED
@@ -1,58 +1,92 @@
|
|
1
|
-
require 'pay/billable/
|
2
|
-
require 'pay/billable/braintree'
|
1
|
+
require 'pay/billable/sync_email'
|
3
2
|
|
4
3
|
module Pay
|
5
4
|
module Billable
|
6
5
|
extend ActiveSupport::Concern
|
7
6
|
|
8
7
|
included do
|
9
|
-
include Pay::Billable::
|
10
|
-
include Pay::Billable::Braintree
|
8
|
+
include Pay::Billable::SyncEmail
|
11
9
|
|
12
|
-
has_many :
|
10
|
+
has_many :charges, class_name: Pay.chargeable_class, foreign_key: :owner_id, inverse_of: :owner
|
11
|
+
has_many :subscriptions, class_name: Pay.subscription_class, foreign_key: :owner_id, inverse_of: :owner
|
13
12
|
|
14
13
|
attribute :plan, :string
|
15
14
|
attribute :quantity, :integer
|
16
15
|
attribute :card_token, :string
|
17
16
|
end
|
18
17
|
|
19
|
-
def customer
|
18
|
+
def customer
|
20
19
|
check_for_processor
|
21
|
-
|
20
|
+
raise Pay::Error, "Email is required to create a customer" if email.nil?
|
21
|
+
|
22
|
+
customer = send("#{processor}_customer")
|
23
|
+
update_card(card_token) if card_token.present?
|
24
|
+
customer
|
22
25
|
end
|
23
26
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
+
def customer_name
|
28
|
+
[try(:first_name), try(:last_name)].compact.join(" ")
|
29
|
+
end
|
30
|
+
|
31
|
+
def charge(amount_in_cents, options = {})
|
32
|
+
check_for_processor
|
33
|
+
send("create_#{processor}_charge", amount_in_cents, options)
|
34
|
+
end
|
35
|
+
|
36
|
+
def subscribe(name: 'default', plan: 'default', **options)
|
37
|
+
check_for_processor
|
38
|
+
send("create_#{processor}_subscription", name, plan, options)
|
27
39
|
end
|
28
40
|
|
29
41
|
def update_card(token)
|
30
42
|
check_for_processor
|
43
|
+
customer if processor_id.nil?
|
31
44
|
send("update_#{processor}_card", token)
|
32
45
|
end
|
33
46
|
|
47
|
+
def on_trial?(name: 'default', plan: nil)
|
48
|
+
return true if default_generic_trial?(name, plan)
|
49
|
+
|
50
|
+
sub = subscription(name: name)
|
51
|
+
return sub && sub.on_trial? if plan.nil?
|
52
|
+
|
53
|
+
sub && sub.on_trial? && sub.processor_plan == plan
|
54
|
+
end
|
55
|
+
|
56
|
+
def on_generic_trial?
|
57
|
+
trial_ends_at? && trial_ends_at > Time.zone.now
|
58
|
+
end
|
59
|
+
|
34
60
|
def processor_subscription(subscription_id)
|
35
61
|
check_for_processor
|
36
62
|
send("#{processor}_subscription", subscription_id)
|
37
63
|
end
|
38
64
|
|
39
|
-
def subscribed?(name
|
40
|
-
subscription = subscription(name)
|
65
|
+
def subscribed?(name: 'default', processor_plan: nil)
|
66
|
+
subscription = subscription(name: name)
|
41
67
|
|
42
68
|
return false if subscription.nil?
|
43
|
-
return subscription.active? if
|
69
|
+
return subscription.active? if processor_plan.nil?
|
44
70
|
|
45
|
-
subscription.active? && subscription.
|
71
|
+
subscription.active? && subscription.processor_plan == processor_plan
|
46
72
|
end
|
47
73
|
|
48
|
-
def subscription(name
|
74
|
+
def subscription(name: 'default')
|
49
75
|
subscriptions.for_name(name).last
|
50
76
|
end
|
51
77
|
|
78
|
+
def invoice!
|
79
|
+
send("#{processor}_invoice!")
|
80
|
+
end
|
81
|
+
|
82
|
+
def upcoming_invoice
|
83
|
+
send("#{processor}_upcoming_invoice")
|
84
|
+
end
|
85
|
+
|
52
86
|
private
|
53
87
|
|
54
88
|
def check_for_processor
|
55
|
-
raise StandardError,
|
89
|
+
raise StandardError, "No payment processor selected. Make sure to set the #{Pay.billable_class}'s `processor` attribute to either 'stripe' or 'braintree'." unless processor
|
56
90
|
end
|
57
91
|
|
58
92
|
def create_subscription(subscription, processor, name, plan, qty = 1)
|
@@ -61,19 +95,15 @@ module Pay
|
|
61
95
|
processor: processor,
|
62
96
|
processor_id: subscription.id,
|
63
97
|
processor_plan: plan,
|
64
|
-
trial_ends_at:
|
98
|
+
trial_ends_at: send("#{processor}_trial_end_date", subscription),
|
65
99
|
quantity: qty,
|
66
100
|
ends_at: nil
|
67
101
|
)
|
68
102
|
end
|
69
103
|
|
70
|
-
def
|
71
|
-
|
72
|
-
|
73
|
-
card_last4: card.last4,
|
74
|
-
card_exp_month: card.exp_month,
|
75
|
-
card_exp_year: card.exp_year
|
76
|
-
)
|
104
|
+
def default_generic_trial?(name, plan)
|
105
|
+
# Generic trials don't have plans or custom names
|
106
|
+
plan.nil? && name == 'default' && on_generic_trial?
|
77
107
|
end
|
78
108
|
end
|
79
109
|
end
|