pay 2.6.11 → 2.7.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 +4 -4
- data/README.md +3 -0
- data/app/models/pay.rb +5 -0
- data/app/models/pay/charge.rb +2 -0
- data/app/models/pay/subscription.rb +2 -0
- data/db/migrate/20200603134434_add_data_to_pay_models.rb +2 -9
- data/db/migrate/20210309004259_add_data_to_pay_billable.rb +19 -0
- data/db/migrate/{20210423235138_add_currency_to_pay_charges.rb → 20210406215234_add_currency_to_pay_charges.rb} +1 -1
- data/db/migrate/20210406215506_add_application_fee_to_pay_models.rb +7 -0
- data/lib/pay.rb +22 -0
- data/lib/pay/adapter.rb +13 -0
- data/lib/pay/billable.rb +4 -0
- data/lib/pay/braintree/billable.rb +8 -1
- data/lib/pay/merchant.rb +37 -0
- data/lib/pay/paddle/webhooks/subscription_payment_succeeded.rb +3 -1
- data/lib/pay/stripe.rb +5 -0
- data/lib/pay/stripe/billable.rb +32 -21
- data/lib/pay/stripe/charge.rb +9 -4
- data/lib/pay/stripe/merchant.rb +66 -0
- data/lib/pay/stripe/subscription.rb +25 -20
- data/lib/pay/stripe/webhooks/account_updated.rb +17 -0
- data/lib/pay/stripe/webhooks/subscription_created.rb +2 -1
- data/lib/pay/stripe/webhooks/subscription_updated.rb +3 -2
- data/lib/pay/version.rb +1 -1
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d696d24ee2bb2b4827f6d6e31db738752ebb2eadca4ea0e79144518fc9375be9
|
4
|
+
data.tar.gz: 8aad550b117bee7e28c9231832f4f344c37054db4f1a7d0176f034c780d0abed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5dc610b8d7b67ed4073fea783b290d3cd6ada3f4df1ed7bac26a0c4770f4a5ab854bf492fe6541f14b069ae61b10369024689a9f832d625ba2201a14deb24fc1
|
7
|
+
data.tar.gz: 3801e3d1da5a833869ed46d28e04d633df5e1b55e51900bcae1a8b437663b93ee1b5ab45698cb54e00a145fb1752cb4c195ec877070b367b79d8c3b03ce81e8d
|
data/README.md
CHANGED
@@ -64,6 +64,9 @@ To add the migrations to your application, run the following migration:
|
|
64
64
|
|
65
65
|
`bin/rails pay:install:migrations`
|
66
66
|
|
67
|
+
>If your models rely on non integer ids (uuids for example) you will need to alter the `create_pay_subscriptions` and `create_pay_charges` migrations to ensure the `owner_id` column's type matches the model's id's format.
|
68
|
+
> As commented in the migrations adding a type parameter to the `t.references :owner` line will ensure the `owner_id` column is of the correct type.
|
69
|
+
|
67
70
|
We also need to run migrations to add Pay to the User, Account, Team, etc models that we want to make payments in our app.
|
68
71
|
|
69
72
|
`bin/rails g pay User`
|
data/app/models/pay.rb
ADDED
data/app/models/pay/charge.rb
CHANGED
@@ -7,6 +7,7 @@ module Pay
|
|
7
7
|
|
8
8
|
# Associations
|
9
9
|
belongs_to :owner, polymorphic: true
|
10
|
+
belongs_to :subscription, optional: true, class_name: "Pay::Subscription", foreign_key: :pay_subscription_id
|
10
11
|
|
11
12
|
# Scopes
|
12
13
|
scope :sorted, -> { order(created_at: :desc) }
|
@@ -19,6 +20,7 @@ module Pay
|
|
19
20
|
validates :card_type, presence: true
|
20
21
|
|
21
22
|
store_accessor :data, :paddle_receipt_url
|
23
|
+
store_accessor :data, :stripe_account
|
22
24
|
|
23
25
|
# Helpers for payment processors
|
24
26
|
%w[braintree stripe paddle fake_processor].each do |processor_name|
|
@@ -9,6 +9,7 @@ module Pay
|
|
9
9
|
|
10
10
|
# Associations
|
11
11
|
belongs_to :owner, polymorphic: true
|
12
|
+
has_many :charges, class_name: "Pay::Charge", foreign_key: :pay_subscription_id
|
12
13
|
|
13
14
|
# Validations
|
14
15
|
validates :name, presence: true
|
@@ -31,6 +32,7 @@ module Pay
|
|
31
32
|
store_accessor :data, :paddle_update_url
|
32
33
|
store_accessor :data, :paddle_cancel_url
|
33
34
|
store_accessor :data, :paddle_paused_from
|
35
|
+
store_accessor :data, :stripe_account
|
34
36
|
|
35
37
|
attribute :prorate, :boolean, default: true
|
36
38
|
|
@@ -5,18 +5,11 @@ class AddDataToPayModels < ActiveRecord::Migration[4.2]
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def data_column_type
|
8
|
-
|
9
|
-
|
10
|
-
# Rails 6.1 uses a symbol key instead of a string
|
11
|
-
adapter = default_hash.dig(:adapter) || default_hash.dig("adapter")
|
12
|
-
|
13
|
-
case adapter
|
14
|
-
when "mysql2"
|
15
|
-
:json
|
8
|
+
case Pay::Adapter.current_adapter
|
16
9
|
when "postgresql"
|
17
10
|
:jsonb
|
18
11
|
else
|
19
|
-
:
|
12
|
+
:json
|
20
13
|
end
|
21
14
|
end
|
22
15
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class AddDataToPayBillable < ActiveRecord::Migration[4.2]
|
2
|
+
def change
|
3
|
+
# Load all the billable models
|
4
|
+
Rails.application.eager_load!
|
5
|
+
|
6
|
+
Pay.billable_models.each do |model|
|
7
|
+
add_column model.table_name, :pay_data, data_column_type
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def data_column_type
|
12
|
+
case Pay::Adapter.current_adapter
|
13
|
+
when "postgresql"
|
14
|
+
:jsonb
|
15
|
+
else
|
16
|
+
:json
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
class AddApplicationFeeToPayModels < ActiveRecord::Migration[4.2]
|
2
|
+
def change
|
3
|
+
add_column :pay_charges, :application_fee_amount, :integer
|
4
|
+
add_column :pay_subscriptions, :application_fee_percent, :decimal, precision: 8, scale: 2
|
5
|
+
add_column :pay_charges, :pay_subscription_id, :integer
|
6
|
+
end
|
7
|
+
end
|
data/lib/pay.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
require "pay/version"
|
2
2
|
require "pay/engine"
|
3
3
|
require "pay/errors"
|
4
|
+
require "pay/adapter"
|
4
5
|
|
5
6
|
module Pay
|
6
7
|
autoload :Billable, "pay/billable"
|
7
8
|
autoload :Env, "pay/env"
|
9
|
+
autoload :Merchant, "pay/merchant"
|
8
10
|
autoload :Payment, "pay/payment"
|
9
11
|
autoload :Receipts, "pay/receipts"
|
10
12
|
|
@@ -66,6 +68,26 @@ module Pay
|
|
66
68
|
Pay::Billable.includers
|
67
69
|
end
|
68
70
|
|
71
|
+
def self.merchant_models
|
72
|
+
Pay::Merchant.includers
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.find_merchant(account_key, account_value)
|
76
|
+
merchant_models.each do |model|
|
77
|
+
case Pay::Adapter.current_adapter
|
78
|
+
when "postgresql"
|
79
|
+
return model.find_by("pay_data @> ?", {account_key.to_sym => account_value}.to_json)
|
80
|
+
when "mysql2"
|
81
|
+
return model.find_by("JSON_CONTAINS(pay_data, ?)", {account_key.to_sym => account_value}.to_json)
|
82
|
+
when "sqlite3"
|
83
|
+
return model.find_by("json_extract(pay_data, ?) =?", "$.#{account_key}", account_value)
|
84
|
+
else
|
85
|
+
model.find_by(pay_data: {account_key.to_sym => account_value})
|
86
|
+
end
|
87
|
+
end
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
69
91
|
def self.find_billable(processor:, processor_id:)
|
70
92
|
billable_models.each do |model|
|
71
93
|
if (record = model.find_by(processor: processor, processor_id: processor_id))
|
data/lib/pay/adapter.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Pay
|
2
|
+
module Adapter
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def self.current_adapter
|
6
|
+
if ActiveRecord::Base.respond_to?(:connection_db_config)
|
7
|
+
ActiveRecord::Base.connection_db_config.adapter
|
8
|
+
else
|
9
|
+
ActiveRecord::Base.connection_config[:adapter]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/pay/billable.rb
CHANGED
@@ -26,6 +26,10 @@ module Pay
|
|
26
26
|
attribute :card_token, :string
|
27
27
|
attribute :pay_fake_processor_allowed, :boolean, default: false
|
28
28
|
|
29
|
+
# Account(s) for marketplace payments
|
30
|
+
store_accessor :pay_data, :stripe_account
|
31
|
+
store_accessor :pay_data, :braintree_account
|
32
|
+
|
29
33
|
validate :pay_fake_processor_is_allowed, if: :processor_changed?
|
30
34
|
end
|
31
35
|
|
@@ -151,9 +151,16 @@ module Pay
|
|
151
151
|
attrs = card_details_for_braintree_transaction(transaction)
|
152
152
|
attrs[:amount] = transaction.amount.to_f * 100
|
153
153
|
|
154
|
+
# Associate charge with subscription if we can
|
155
|
+
if transaction.subscription_id
|
156
|
+
attrs[:subscription] = Pay::Subscription.find_by(processor: :braintree, processor_id: transaction.subscription_id)
|
157
|
+
end
|
158
|
+
|
154
159
|
charge = billable.charges.find_or_initialize_by(
|
155
160
|
processor: :braintree,
|
156
|
-
processor_id: transaction.id
|
161
|
+
processor_id: transaction.id,
|
162
|
+
currency: transaction.currency_iso_code,
|
163
|
+
application_fee_amount: transaction.service_fee_amount
|
157
164
|
)
|
158
165
|
charge.update(attrs)
|
159
166
|
charge
|
data/lib/pay/merchant.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Pay
|
2
|
+
module Merchant
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
# Keep track of which Merchant models we have
|
6
|
+
class << self
|
7
|
+
attr_reader :includers
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.included(base = nil, &block)
|
11
|
+
@includers ||= []
|
12
|
+
@includers << base if base
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
included do
|
17
|
+
store_accessor :pay_data, :stripe_connect_account_id
|
18
|
+
store_accessor :pay_data, :onboarding_complete
|
19
|
+
end
|
20
|
+
|
21
|
+
def merchant
|
22
|
+
@merchant ||= merchant_processor_for(merchant_processor).new(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def merchant_processor_for(name)
|
26
|
+
"Pay::#{name.to_s.classify}::Merchant".constantize
|
27
|
+
end
|
28
|
+
|
29
|
+
def stripe_connect_account_id?
|
30
|
+
!!stripe_connect_account_id
|
31
|
+
end
|
32
|
+
|
33
|
+
def onboarding_complete?
|
34
|
+
!!onboarding_complete
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -30,8 +30,10 @@ module Pay
|
|
30
30
|
params = {
|
31
31
|
amount: Integer(event["sale_gross"].to_f * 100),
|
32
32
|
card_type: event["payment_method"],
|
33
|
+
created_at: Time.zone.parse(event["event_time"]),
|
34
|
+
currency: event["currency"],
|
33
35
|
paddle_receipt_url: event["receipt_url"],
|
34
|
-
|
36
|
+
subscription: Pay::Subscription.find_by(processor: :paddle, processor_id: event["subscription_id"])
|
35
37
|
}
|
36
38
|
|
37
39
|
payment_information = Pay::Paddle::Billable.new(user).payment_information(event["subscription_id"])
|
data/lib/pay/stripe.rb
CHANGED
@@ -4,8 +4,10 @@ module Pay
|
|
4
4
|
autoload :Charge, "pay/stripe/charge"
|
5
5
|
autoload :Subscription, "pay/stripe/subscription"
|
6
6
|
autoload :Error, "pay/stripe/error"
|
7
|
+
autoload :Merchant, "pay/stripe/merchant"
|
7
8
|
|
8
9
|
module Webhooks
|
10
|
+
autoload :AccountUpdated, "pay/stripe/webhooks/account_updated"
|
9
11
|
autoload :ChargeRefunded, "pay/stripe/webhooks/charge_refunded"
|
10
12
|
autoload :ChargeSucceeded, "pay/stripe/webhooks/charge_succeeded"
|
11
13
|
autoload :CustomerDeleted, "pay/stripe/webhooks/customer_deleted"
|
@@ -81,6 +83,9 @@ module Pay
|
|
81
83
|
events.subscribe "stripe.payment_method.updated", Pay::Stripe::Webhooks::PaymentMethodUpdated.new
|
82
84
|
events.subscribe "stripe.payment_method.card_automatically_updated", Pay::Stripe::Webhooks::PaymentMethodUpdated.new
|
83
85
|
events.subscribe "stripe.payment_method.detached", Pay::Stripe::Webhooks::PaymentMethodUpdated.new
|
86
|
+
|
87
|
+
# If an account is updated in stripe, we should update it as well
|
88
|
+
events.subscribe "stripe.account.updated", Pay::Stripe::Webhooks::AccountUpdated.new
|
84
89
|
end
|
85
90
|
end
|
86
91
|
end
|
data/lib/pay/stripe/billable.rb
CHANGED
@@ -10,6 +10,7 @@ module Pay
|
|
10
10
|
:email,
|
11
11
|
:customer_name,
|
12
12
|
:card_token,
|
13
|
+
:stripe_account,
|
13
14
|
to: :billable
|
14
15
|
|
15
16
|
class << self
|
@@ -27,17 +28,17 @@ module Pay
|
|
27
28
|
# Returns Stripe::Customer
|
28
29
|
def customer
|
29
30
|
stripe_customer = if processor_id?
|
30
|
-
::Stripe::Customer.retrieve(processor_id)
|
31
|
+
::Stripe::Customer.retrieve(processor_id, {stripe_account: stripe_account})
|
31
32
|
else
|
32
|
-
sc = ::Stripe::Customer.create(email: email, name: customer_name)
|
33
|
-
billable.update(processor: :stripe, processor_id: sc.id)
|
33
|
+
sc = ::Stripe::Customer.create({email: email, name: customer_name}, {stripe_account: stripe_account})
|
34
|
+
billable.update(processor: :stripe, processor_id: sc.id, stripe_account: stripe_account)
|
34
35
|
sc
|
35
36
|
end
|
36
37
|
|
37
38
|
# Update the user's card on file if a token was passed in
|
38
39
|
if card_token.present?
|
39
|
-
payment_method = ::Stripe::PaymentMethod.attach(card_token, customer: stripe_customer.id)
|
40
|
-
stripe_customer = ::Stripe::Customer.update(stripe_customer.id, invoice_settings: {default_payment_method: payment_method.id})
|
40
|
+
payment_method = ::Stripe::PaymentMethod.attach(card_token, {customer: stripe_customer.id}, {stripe_account: stripe_account})
|
41
|
+
stripe_customer = ::Stripe::Customer.update(stripe_customer.id, {invoice_settings: {default_payment_method: payment_method.id}}, {stripe_account: stripe_account})
|
41
42
|
update_card_on_file(payment_method.card)
|
42
43
|
end
|
43
44
|
|
@@ -60,7 +61,7 @@ module Pay
|
|
60
61
|
payment_method: stripe_customer.invoice_settings.default_payment_method
|
61
62
|
}.merge(options)
|
62
63
|
|
63
|
-
payment_intent = ::Stripe::PaymentIntent.create(args)
|
64
|
+
payment_intent = ::Stripe::PaymentIntent.create(args, {stripe_account: stripe_account})
|
64
65
|
Pay::Payment.new(payment_intent).validate
|
65
66
|
|
66
67
|
# Create a new charge object
|
@@ -86,8 +87,8 @@ module Pay
|
|
86
87
|
# Load the Stripe customer to verify it exists and update card if needed
|
87
88
|
opts[:customer] = customer.id
|
88
89
|
|
89
|
-
stripe_sub = ::Stripe::Subscription.create(opts)
|
90
|
-
subscription = billable.create_pay_subscription(stripe_sub, "stripe", name, plan, status: stripe_sub.status, quantity: quantity)
|
90
|
+
stripe_sub = ::Stripe::Subscription.create(opts, {stripe_account: stripe_account})
|
91
|
+
subscription = billable.create_pay_subscription(stripe_sub, "stripe", name, plan, status: stripe_sub.status, quantity: quantity, stripe_account: stripe_account, application_fee_percent: stripe_sub.application_fee_percent)
|
91
92
|
|
92
93
|
# No trial, card requires SCA
|
93
94
|
if subscription.incomplete?
|
@@ -111,8 +112,8 @@ module Pay
|
|
111
112
|
|
112
113
|
return true if payment_method_id == stripe_customer.invoice_settings.default_payment_method
|
113
114
|
|
114
|
-
payment_method = ::Stripe::PaymentMethod.attach(payment_method_id, customer: stripe_customer.id)
|
115
|
-
::Stripe::Customer.update(stripe_customer.id, invoice_settings: {default_payment_method: payment_method.id})
|
115
|
+
payment_method = ::Stripe::PaymentMethod.attach(payment_method_id, {customer: stripe_customer.id}, {stripe_account: stripe_account})
|
116
|
+
::Stripe::Customer.update(stripe_customer.id, {invoice_settings: {default_payment_method: payment_method.id}}, {stripe_account: stripe_account})
|
116
117
|
|
117
118
|
update_card_on_file(payment_method.card)
|
118
119
|
true
|
@@ -121,33 +122,33 @@ module Pay
|
|
121
122
|
end
|
122
123
|
|
123
124
|
def update_email!
|
124
|
-
::Stripe::Customer.update(processor_id, {email: email, name: customer_name})
|
125
|
+
::Stripe::Customer.update(processor_id, {email: email, name: customer_name}, {stripe_account: stripe_account})
|
125
126
|
end
|
126
127
|
|
127
128
|
def processor_subscription(subscription_id, options = {})
|
128
|
-
::Stripe::Subscription.retrieve(options.merge(id: subscription_id))
|
129
|
+
::Stripe::Subscription.retrieve(options.merge(id: subscription_id), {stripe_account: stripe_account})
|
129
130
|
end
|
130
131
|
|
131
132
|
def invoice!(options = {})
|
132
133
|
return unless processor_id?
|
133
|
-
::Stripe::Invoice.create(options.merge(customer: processor_id)).pay
|
134
|
+
::Stripe::Invoice.create(options.merge(customer: processor_id), {stripe_account: stripe_account}).pay
|
134
135
|
end
|
135
136
|
|
136
137
|
def upcoming_invoice
|
137
|
-
::Stripe::Invoice.upcoming(customer: processor_id)
|
138
|
+
::Stripe::Invoice.upcoming({customer: processor_id}, {stripe_account: stripe_account})
|
138
139
|
end
|
139
140
|
|
140
141
|
# Used by webhooks when the customer or source changes
|
141
142
|
def sync_card_from_stripe
|
142
143
|
if (payment_method_id = customer.invoice_settings.default_payment_method)
|
143
|
-
update_card_on_file ::Stripe::PaymentMethod.retrieve(payment_method_id).card
|
144
|
+
update_card_on_file ::Stripe::PaymentMethod.retrieve(payment_method_id, {stripe_account: stripe_account}).card
|
144
145
|
else
|
145
146
|
billable.update(card_type: nil, card_last4: nil)
|
146
147
|
end
|
147
148
|
end
|
148
149
|
|
149
150
|
def create_setup_intent
|
150
|
-
::Stripe::SetupIntent.create(customer: processor_id, usage: :off_session)
|
151
|
+
::Stripe::SetupIntent.create({customer: processor_id, usage: :off_session}, {stripe_account: stripe_account})
|
151
152
|
end
|
152
153
|
|
153
154
|
def trial_end_date(stripe_sub)
|
@@ -170,15 +171,25 @@ module Pay
|
|
170
171
|
def save_pay_charge(object)
|
171
172
|
charge = billable.charges.find_or_initialize_by(processor: :stripe, processor_id: object.id)
|
172
173
|
|
173
|
-
|
174
|
+
attrs = {
|
174
175
|
amount: object.amount,
|
175
176
|
card_last4: object.payment_method_details.card.last4,
|
176
177
|
card_type: object.payment_method_details.card.brand,
|
177
178
|
card_exp_month: object.payment_method_details.card.exp_month,
|
178
179
|
card_exp_year: object.payment_method_details.card.exp_year,
|
179
|
-
created_at: Time.zone.at(object.created)
|
180
|
-
|
180
|
+
created_at: Time.zone.at(object.created),
|
181
|
+
currency: object.currency,
|
182
|
+
stripe_account: stripe_account,
|
183
|
+
application_fee_amount: object.application_fee_amount
|
184
|
+
}
|
185
|
+
|
186
|
+
# Associate charge with subscription if we can
|
187
|
+
if object.invoice
|
188
|
+
invoice = (object.invoice.is_a?(::Stripe::Invoice) ? object.invoice : ::Stripe::Invoice.retrieve(object.invoice))
|
189
|
+
attrs[:subscription] = Pay::Subscription.find_by(processor: :stripe, processor_id: invoice.subscription)
|
190
|
+
end
|
181
191
|
|
192
|
+
charge.update(attrs)
|
182
193
|
charge
|
183
194
|
end
|
184
195
|
|
@@ -213,7 +224,7 @@ module Pay
|
|
213
224
|
}
|
214
225
|
end
|
215
226
|
|
216
|
-
::Stripe::Checkout::Session.create(args.merge(options))
|
227
|
+
::Stripe::Checkout::Session.create(args.merge(options), {stripe_account: stripe_account})
|
217
228
|
end
|
218
229
|
|
219
230
|
# https://stripe.com/docs/api/checkout/sessions/create
|
@@ -240,7 +251,7 @@ module Pay
|
|
240
251
|
customer: processor_id,
|
241
252
|
return_url: options.delete(:return_url) || root_url
|
242
253
|
}
|
243
|
-
::Stripe::BillingPortal::Session.create(args.merge(options))
|
254
|
+
::Stripe::BillingPortal::Session.create(args.merge(options), {stripe_account: stripe_account})
|
244
255
|
end
|
245
256
|
end
|
246
257
|
end
|
data/lib/pay/stripe/charge.rb
CHANGED
@@ -3,20 +3,25 @@ module Pay
|
|
3
3
|
class Charge
|
4
4
|
attr_reader :pay_charge
|
5
5
|
|
6
|
-
delegate :processor_id, :owner, to: :pay_charge
|
6
|
+
delegate :processor_id, :owner, :stripe_account, to: :pay_charge
|
7
7
|
|
8
8
|
def initialize(pay_charge)
|
9
9
|
@pay_charge = pay_charge
|
10
10
|
end
|
11
11
|
|
12
12
|
def charge
|
13
|
-
::Stripe::Charge.retrieve(id: processor_id, expand: ["customer", "invoice.subscription"])
|
13
|
+
::Stripe::Charge.retrieve({id: processor_id, expand: ["customer", "invoice.subscription"]}, {stripe_account: stripe_account})
|
14
14
|
rescue ::Stripe::StripeError => e
|
15
15
|
raise Pay::Stripe::Error, e
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
# https://stripe.com/docs/api/refunds/create
|
19
|
+
#
|
20
|
+
# refund!
|
21
|
+
# refund!(5_00)
|
22
|
+
# refund!(5_00, refund_application_fee: true)
|
23
|
+
def refund!(amount_to_refund, **options)
|
24
|
+
::Stripe::Refund.create(options.merge(charge: processor_id, amount: amount_to_refund), {stripe_account: stripe_account})
|
20
25
|
pay_charge.update(amount_refunded: amount_to_refund)
|
21
26
|
rescue ::Stripe::StripeError => e
|
22
27
|
raise Pay::Stripe::Error, e
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Pay
|
2
|
+
module Stripe
|
3
|
+
class Merchant
|
4
|
+
attr_reader :merchant
|
5
|
+
|
6
|
+
delegate :stripe_connect_account_id,
|
7
|
+
to: :merchant
|
8
|
+
|
9
|
+
def initialize(merchant)
|
10
|
+
@merchant = merchant
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_account(**options)
|
14
|
+
defaults = {
|
15
|
+
type: "express",
|
16
|
+
capabilities: {
|
17
|
+
card_payments: {requested: true},
|
18
|
+
transfers: {requested: true}
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
stripe_account = ::Stripe::Account.create(defaults.merge(options))
|
23
|
+
merchant.update(stripe_connect_account_id: stripe_account.id)
|
24
|
+
stripe_account
|
25
|
+
rescue ::Stripe::StripeError => e
|
26
|
+
raise Pay::Stripe::Error, e
|
27
|
+
end
|
28
|
+
|
29
|
+
def account
|
30
|
+
::Stripe::Account.retrieve(stripe_connect_account_id)
|
31
|
+
rescue ::Stripe::StripeError => e
|
32
|
+
raise Pay::Stripe::Error, e
|
33
|
+
end
|
34
|
+
|
35
|
+
def account_link(refresh_url:, return_url:, type: "account_onboarding", **options)
|
36
|
+
::Stripe::AccountLink.create({
|
37
|
+
account: stripe_connect_account_id,
|
38
|
+
refresh_url: refresh_url,
|
39
|
+
return_url: return_url,
|
40
|
+
type: type
|
41
|
+
})
|
42
|
+
rescue ::Stripe::StripeError => e
|
43
|
+
raise Pay::Stripe::Error, e
|
44
|
+
end
|
45
|
+
|
46
|
+
# A single-use login link for Express accounts to access their Stripe dashboard
|
47
|
+
def login_link(**options)
|
48
|
+
::Stripe::Account.create_login_link(stripe_connect_account_id)
|
49
|
+
rescue ::Stripe::StripeError => e
|
50
|
+
raise Pay::Stripe::Error, e
|
51
|
+
end
|
52
|
+
|
53
|
+
# Transfer money from the platform to this connected account
|
54
|
+
# https://stripe.com/docs/connect/charges-transfers#transfer-availability
|
55
|
+
def transfer(amount:, currency: "usd", **options)
|
56
|
+
::Stripe::Transfer.create({
|
57
|
+
amount: amount,
|
58
|
+
currency: currency,
|
59
|
+
destination: stripe_connect_account_id
|
60
|
+
}.merge(options))
|
61
|
+
rescue ::Stripe::StripeError => e
|
62
|
+
raise Pay::Stripe::Error, e
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -16,6 +16,7 @@ module Pay
|
|
16
16
|
:prorate?,
|
17
17
|
:quantity,
|
18
18
|
:quantity?,
|
19
|
+
:stripe_account,
|
19
20
|
:trial_ends_at,
|
20
21
|
to: :pay_subscription
|
21
22
|
|
@@ -28,19 +29,15 @@ module Pay
|
|
28
29
|
end
|
29
30
|
|
30
31
|
def cancel
|
31
|
-
|
32
|
-
|
33
|
-
subscription.save
|
34
|
-
|
35
|
-
new_ends_at = on_trial? ? trial_ends_at : Time.at(subscription.current_period_end)
|
36
|
-
pay_subscription.update(ends_at: new_ends_at)
|
32
|
+
stripe_sub = ::Stripe::Subscription.update(processor_id, {cancel_at_period_end: true}, {stripe_account: stripe_account})
|
33
|
+
pay_subscription.update(ends_at: (on_trial? ? trial_ends_at : Time.at(stripe_sub.current_period_end)))
|
37
34
|
rescue ::Stripe::StripeError => e
|
38
35
|
raise Pay::Stripe::Error, e
|
39
36
|
end
|
40
37
|
|
41
38
|
def cancel_now!
|
42
|
-
|
43
|
-
pay_subscription.update(ends_at: Time.
|
39
|
+
::Stripe::Subscription.delete(processor_id, {stripe_account: stripe_account})
|
40
|
+
pay_subscription.update(ends_at: Time.current, status: :canceled)
|
44
41
|
rescue ::Stripe::StripeError => e
|
45
42
|
raise Pay::Stripe::Error, e
|
46
43
|
end
|
@@ -68,23 +65,31 @@ module Pay
|
|
68
65
|
raise StandardError, "You can only resume subscriptions within their grace period."
|
69
66
|
end
|
70
67
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
68
|
+
::Stripe::Subscription.update(
|
69
|
+
processor_id,
|
70
|
+
{
|
71
|
+
plan: processor_plan,
|
72
|
+
trial_end: (on_trial? ? trial_ends_at.to_i : "now"),
|
73
|
+
cancel_at_period_end: false
|
74
|
+
},
|
75
|
+
{stripe_account: stripe_account}
|
76
|
+
)
|
76
77
|
rescue ::Stripe::StripeError => e
|
77
78
|
raise Pay::Stripe::Error, e
|
78
79
|
end
|
79
80
|
|
80
81
|
def swap(plan)
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
82
|
+
::Stripe::Subscription.update(
|
83
|
+
processor_id,
|
84
|
+
{
|
85
|
+
cancel_at_period_end: false,
|
86
|
+
plan: plan,
|
87
|
+
proration_behavior: (prorate ? "create_prorations" : "none"),
|
88
|
+
trial_end: (on_trial? ? trial_ends_at.to_i : "now"),
|
89
|
+
quantity: quantity
|
90
|
+
},
|
91
|
+
{stripe_account: stripe_account}
|
92
|
+
)
|
88
93
|
rescue ::Stripe::StripeError => e
|
89
94
|
raise Pay::Stripe::Error, e
|
90
95
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Pay
|
2
|
+
module Stripe
|
3
|
+
module Webhooks
|
4
|
+
class AccountUpdated
|
5
|
+
def call(event)
|
6
|
+
object = event.data.object
|
7
|
+
|
8
|
+
merchant = Pay.find_merchant("stripe_connect_account_id", object.id)
|
9
|
+
|
10
|
+
return unless merchant.present?
|
11
|
+
|
12
|
+
merchant.update(onboarding_complete: object.charges_enabled)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -21,9 +21,10 @@ module Pay
|
|
21
21
|
subscription = Pay.subscription_model.new(name: Pay.default_product_name, owner: owner, processor: :stripe, processor_id: object.id)
|
22
22
|
end
|
23
23
|
|
24
|
+
subscription.application_fee_percent = object.application_fee_percent
|
25
|
+
subscription.processor_plan = object.plan.id
|
24
26
|
subscription.quantity = object.quantity
|
25
27
|
subscription.status = object.status
|
26
|
-
subscription.processor_plan = object.plan.id
|
27
28
|
subscription.trial_ends_at = Time.at(object.trial_end) if object.trial_end.present?
|
28
29
|
|
29
30
|
# If user was on trial, their subscription ends at the end of the trial
|
@@ -14,9 +14,10 @@ module Pay
|
|
14
14
|
return
|
15
15
|
end
|
16
16
|
|
17
|
-
subscription.
|
18
|
-
subscription.quantity = object.quantity
|
17
|
+
subscription.application_fee_percent = object.application_fee_percent
|
19
18
|
subscription.processor_plan = object.plan.id
|
19
|
+
subscription.quantity = object.quantity
|
20
|
+
subscription.status = object.status
|
20
21
|
subscription.trial_ends_at = Time.at(object.trial_end) if object.trial_end.present?
|
21
22
|
|
22
23
|
# If user was on trial, their subscription ends at the end of the trial
|
data/lib/pay/version.rb
CHANGED
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: 2.
|
4
|
+
version: 2.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Charnes
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2021-05-
|
12
|
+
date: 2021-05-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -125,6 +125,7 @@ files:
|
|
125
125
|
- app/jobs/pay/email_sync_job.rb
|
126
126
|
- app/mailers/pay/application_mailer.rb
|
127
127
|
- app/mailers/pay/user_mailer.rb
|
128
|
+
- app/models/pay.rb
|
128
129
|
- app/models/pay/application_record.rb
|
129
130
|
- app/models/pay/charge.rb
|
130
131
|
- app/models/pay/subscription.rb
|
@@ -141,7 +142,9 @@ files:
|
|
141
142
|
- db/migrate/20170727235816_create_pay_charges.rb
|
142
143
|
- db/migrate/20190816015720_add_status_to_pay_subscriptions.rb
|
143
144
|
- db/migrate/20200603134434_add_data_to_pay_models.rb
|
144
|
-
- db/migrate/
|
145
|
+
- db/migrate/20210309004259_add_data_to_pay_billable.rb
|
146
|
+
- db/migrate/20210406215234_add_currency_to_pay_charges.rb
|
147
|
+
- db/migrate/20210406215506_add_application_fee_to_pay_models.rb
|
145
148
|
- lib/generators/active_record/pay_generator.rb
|
146
149
|
- lib/generators/active_record/templates/migration.rb
|
147
150
|
- lib/generators/pay/email_views_generator.rb
|
@@ -149,6 +152,7 @@ files:
|
|
149
152
|
- lib/generators/pay/pay_generator.rb
|
150
153
|
- lib/generators/pay/views_generator.rb
|
151
154
|
- lib/pay.rb
|
155
|
+
- lib/pay/adapter.rb
|
152
156
|
- lib/pay/billable.rb
|
153
157
|
- lib/pay/billable/sync_email.rb
|
154
158
|
- lib/pay/braintree.rb
|
@@ -172,6 +176,7 @@ files:
|
|
172
176
|
- lib/pay/fake_processor/charge.rb
|
173
177
|
- lib/pay/fake_processor/error.rb
|
174
178
|
- lib/pay/fake_processor/subscription.rb
|
179
|
+
- lib/pay/merchant.rb
|
175
180
|
- lib/pay/paddle.rb
|
176
181
|
- lib/pay/paddle/billable.rb
|
177
182
|
- lib/pay/paddle/charge.rb
|
@@ -189,7 +194,9 @@ files:
|
|
189
194
|
- lib/pay/stripe/billable.rb
|
190
195
|
- lib/pay/stripe/charge.rb
|
191
196
|
- lib/pay/stripe/error.rb
|
197
|
+
- lib/pay/stripe/merchant.rb
|
192
198
|
- lib/pay/stripe/subscription.rb
|
199
|
+
- lib/pay/stripe/webhooks/account_updated.rb
|
193
200
|
- lib/pay/stripe/webhooks/charge_refunded.rb
|
194
201
|
- lib/pay/stripe/webhooks/charge_succeeded.rb
|
195
202
|
- lib/pay/stripe/webhooks/customer_deleted.rb
|
@@ -223,7 +230,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
223
230
|
- !ruby/object:Gem::Version
|
224
231
|
version: '0'
|
225
232
|
requirements: []
|
226
|
-
rubygems_version: 3.2.
|
233
|
+
rubygems_version: 3.2.15
|
227
234
|
signing_key:
|
228
235
|
specification_version: 4
|
229
236
|
summary: Payments engine for Ruby on Rails
|