pay 2.6.10 → 2.7.2
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 +93 -54
- data/app/models/pay/application_record.rb +1 -0
- data/app/models/pay/charge.rb +3 -1
- data/app/models/pay/subscription.rb +5 -3
- data/db/migrate/20200603134434_add_data_to_pay_models.rb +2 -18
- data/db/migrate/20210309004259_add_data_to_pay_billable.rb +10 -0
- data/db/migrate/20210406215234_add_currency_to_pay_charges.rb +5 -0
- data/db/migrate/20210406215506_add_application_fee_to_pay_models.rb +7 -0
- data/db/migrate/20210714175351_add_uniqueness_to_pay_models.rb +6 -0
- data/lib/generators/active_record/billable_generator.rb +44 -0
- data/lib/generators/active_record/merchant_generator.rb +44 -0
- data/lib/generators/active_record/templates/billable_migration.rb +17 -0
- data/lib/generators/active_record/templates/merchant_migration.rb +12 -0
- data/lib/generators/pay/{pay_generator.rb → billable_generator.rb} +2 -3
- data/lib/generators/pay/merchant_generator.rb +17 -0
- data/lib/generators/pay/orm_helpers.rb +10 -6
- data/lib/pay.rb +22 -0
- data/lib/pay/adapter.rb +22 -0
- data/lib/pay/billable.rb +4 -0
- data/lib/pay/braintree/billable.rb +8 -1
- data/lib/pay/braintree/subscription.rb +6 -0
- data/lib/pay/env.rb +8 -0
- data/lib/pay/fake_processor/subscription.rb +6 -0
- data/lib/pay/merchant.rb +37 -0
- data/lib/pay/paddle/subscription.rb +9 -0
- data/lib/pay/paddle/webhooks/subscription_payment_succeeded.rb +3 -1
- data/lib/pay/stripe.rb +11 -0
- data/lib/pay/stripe/billable.rb +39 -36
- data/lib/pay/stripe/charge.rb +62 -4
- data/lib/pay/stripe/merchant.rb +66 -0
- data/lib/pay/stripe/subscription.rb +87 -21
- data/lib/pay/stripe/webhooks/account_updated.rb +17 -0
- data/lib/pay/stripe/webhooks/charge_refunded.rb +2 -7
- data/lib/pay/stripe/webhooks/charge_succeeded.rb +2 -8
- data/lib/pay/stripe/webhooks/checkout_session_async_payment_succeeded.rb +13 -0
- data/lib/pay/stripe/webhooks/checkout_session_completed.rb +13 -0
- data/lib/pay/stripe/webhooks/payment_intent_succeeded.rb +2 -8
- data/lib/pay/stripe/webhooks/payment_method_attached.rb +17 -0
- data/lib/pay/stripe/webhooks/payment_method_automatically_updated.rb +17 -0
- data/lib/pay/stripe/webhooks/payment_method_detached.rb +17 -0
- data/lib/pay/stripe/webhooks/subscription_created.rb +1 -35
- data/lib/pay/stripe/webhooks/subscription_deleted.rb +1 -9
- data/lib/pay/stripe/webhooks/subscription_renewing.rb +4 -6
- data/lib/pay/stripe/webhooks/subscription_updated.rb +1 -28
- data/lib/pay/version.rb +1 -1
- metadata +22 -6
- data/lib/generators/active_record/pay_generator.rb +0 -58
- data/lib/generators/active_record/templates/migration.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2cb954b3125acb413cdebfcf57687b4ff9f33987c0500dd72f350c293f491322
|
4
|
+
data.tar.gz: b4f9b23d452a3ab76b21902ebcad03b2c927a7e7eb17f58c9ac06d3df22232a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60d31163be2531db82eb4eb1cd6218f83e3b88d4a2a18821f4f88f19465f9e6bf2c7215f4a3ac00348582f98b3122f3820a54bdb6d19e338d6d37e68b14e0803
|
7
|
+
data.tar.gz: 6cc782accfeea3325fb93c6c15d3044efb08de166a07c90f868fc202cbc99d6fd9eda5d07db8cb97f14edff4c1d257be6261d408deafc8d967e399b6107e1cf5
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
## Pay - Payments engine for Ruby on Rails
|
4
4
|
|
5
|
-
[![Build Status](https://github.com/pay-rails/pay/workflows/Tests/badge.svg)](https://github.com/pay-rails/pay/actions) [![Gem Version](https://badge.fury.io/rb/pay.svg)](https://badge.fury.io/rb/pay)
|
5
|
+
[![Build Status](https://github.com/pay-rails/pay/workflows/Tests/badge.svg)](https://github.com/pay-rails/pay/actions) [![Gem Version](https://badge.fury.io/rb/pay.svg)](https://badge.fury.io/rb/pay)
|
6
6
|
|
7
7
|
<img src="docs/images/stripe_partner_badge.svg" height="26px">
|
8
8
|
|
@@ -51,58 +51,49 @@ And then execute:
|
|
51
51
|
bundle
|
52
52
|
```
|
53
53
|
|
54
|
-
|
54
|
+
Next, we need to add migrations to your application, run the following migration:
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
```
|
56
|
+
````bash
|
57
|
+
bin/rails pay:install:migrations
|
58
|
+
````
|
60
59
|
|
61
|
-
|
62
|
-
|
63
|
-
To add the migrations to your application, run the following migration:
|
64
|
-
|
65
|
-
`bin/rails pay:install:migrations`
|
60
|
+
>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.
|
66
61
|
|
67
62
|
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
63
|
|
69
|
-
|
64
|
+
```bash
|
65
|
+
bin/rails g pay:billable User
|
66
|
+
```
|
70
67
|
|
71
68
|
This will generate a migration to add Pay fields to our User model and automatically includes the `Pay::Billable` module in our `User` model. Repeat this for all the models you want to make payments in your app.
|
72
69
|
|
73
|
-
|
74
|
-
|
75
|
-
`rake db:migrate`
|
70
|
+
**Note:** An `email` attribute or method on your `Billable` model is required.
|
76
71
|
|
77
|
-
|
72
|
+
To sync customer names, your `Billable` model should respond to the `first_name` and `last_name` methods. Pay will sync these over to your Customer objects in Stripe and Braintree.
|
78
73
|
|
79
|
-
|
74
|
+
Finally, run the migrations
|
80
75
|
|
81
|
-
|
76
|
+
```bash
|
77
|
+
bin/rails db:migrate
|
78
|
+
```
|
82
79
|
|
83
|
-
|
80
|
+
> If you run into `NoMethodError (undefined method 'stripe_customer' for #<User:0x00007fbc34b9bf20>)`, fully restart your Rails application `bin/spring stop && rails s`
|
84
81
|
|
85
|
-
|
82
|
+
Lastly, make sure you've configured your ActionMailer default_url_options so Pay can generate links to for features like Stripe Checkout.
|
86
83
|
|
87
84
|
```ruby
|
88
|
-
#
|
89
|
-
|
90
|
-
include Pay::Billable
|
91
|
-
end
|
85
|
+
# config/application.rb
|
86
|
+
config.action_mailer.default_url_options = { host: "example.com" }
|
92
87
|
```
|
93
88
|
|
94
|
-
An `email` attribute or method on your `Billable` model is required.
|
95
|
-
|
96
|
-
To sync over customer names, your `Billable` model should respond to the `first_name` and `last_name` methods. Pay will sync these over to your Customer objects in Stripe and Braintree.
|
97
|
-
|
98
89
|
## Configuration
|
99
90
|
|
100
91
|
Need to make some changes to how Pay is used? You can create an initializer `config/initializers/pay.rb`
|
101
92
|
|
102
93
|
```ruby
|
103
94
|
Pay.setup do |config|
|
104
|
-
config.chargeable_class = 'Pay::Charge'
|
105
|
-
config.chargeable_table = 'pay_charges'
|
95
|
+
# config.chargeable_class = 'Pay::Charge'
|
96
|
+
# config.chargeable_table = 'pay_charges'
|
106
97
|
|
107
98
|
# For use in the receipt/refund/renewal mailers
|
108
99
|
config.business_name = "Business Name"
|
@@ -136,29 +127,63 @@ end
|
|
136
127
|
|
137
128
|
### Credentials
|
138
129
|
|
139
|
-
|
130
|
+
Pay automatically looks up credentials for each payment provider. We recommend storing them in the Rails credentials.
|
131
|
+
|
132
|
+
##### Rails Credentials & Secrets
|
133
|
+
|
134
|
+
You'll need to add your API keys to your Rails credentials. You can do this by running:
|
135
|
+
|
136
|
+
```bash
|
137
|
+
bin/rails credentials:edit --environment=development
|
138
|
+
```
|
139
|
+
|
140
|
+
They should be formatted like the following:
|
141
|
+
|
142
|
+
```yaml
|
143
|
+
stripe:
|
144
|
+
private_key: sk_test_xxxx
|
145
|
+
public_key: pk_test_yyyy
|
146
|
+
signing_secret: whsec_zzzz
|
147
|
+
|
148
|
+
braintree:
|
149
|
+
private_key: xxxx
|
150
|
+
public_key: yyyy
|
151
|
+
merchant_id: aaaa
|
152
|
+
environment: sandbox
|
153
|
+
|
154
|
+
paddle:
|
155
|
+
vendor_id: xxxx
|
156
|
+
vendor_auth_code: yyyy
|
157
|
+
public_key_base64: MII...==
|
158
|
+
environment: sandbox
|
159
|
+
```
|
160
|
+
|
161
|
+
You can also nest these credentials under the Rails environment if using a shared credentials file or secrets.
|
140
162
|
|
141
163
|
```yaml
|
142
164
|
development:
|
143
165
|
stripe:
|
144
|
-
private_key:
|
145
|
-
public_key:
|
146
|
-
signing_secret:
|
147
|
-
|
148
|
-
private_key: xxxx
|
149
|
-
public_key: yyyy
|
150
|
-
merchant_id: aaaa
|
151
|
-
environment: sandbox
|
152
|
-
paddle:
|
153
|
-
vendor_id: xxxx
|
154
|
-
vendor_auth_code: yyyy
|
155
|
-
public_key_base64: MII...==
|
156
|
-
environment: sandbox
|
166
|
+
private_key: sk_test_xxxx
|
167
|
+
public_key: pk_test_yyyy
|
168
|
+
signing_secret: whsec_zzzz
|
169
|
+
# ...
|
157
170
|
```
|
158
171
|
|
159
|
-
|
160
|
-
|
161
|
-
|
172
|
+
##### Environment Variables
|
173
|
+
|
174
|
+
Pay will also check environment variables for API keys:
|
175
|
+
|
176
|
+
* `STRIPE_PUBLIC_KEY`
|
177
|
+
* `STRIPE_PRIVATE_KEY`
|
178
|
+
* `STRIPE_SIGNING_SECRET`
|
179
|
+
* `BRAINTREE_MERCHANT_ID`
|
180
|
+
* `BRAINTREE_PUBLIC_KEY`
|
181
|
+
* `BRAINTREE_PRIVATE_KEY`
|
182
|
+
* `BRAINTREE_ENVIRONMENT`
|
183
|
+
* `PADDLE_VENDOR_ID`
|
184
|
+
* `PADDLE_VENDOR_AUTH_CODE`
|
185
|
+
* `PADDLE_PUBLIC_KEY_BASE64`
|
186
|
+
* `PADDLE_ENVIRONMENT`
|
162
187
|
|
163
188
|
### Generators
|
164
189
|
|
@@ -176,11 +201,13 @@ bin/rails generate pay:email_views
|
|
176
201
|
|
177
202
|
### Emails
|
178
203
|
|
179
|
-
Emails can be enabled/disabled using the `send_emails` configuration option (enabled
|
204
|
+
Emails can be enabled/disabled using the `send_emails` configuration option (enabled by default).
|
180
205
|
|
181
|
-
|
182
|
-
|
183
|
-
-
|
206
|
+
When enabled, the following emails will be sent when:
|
207
|
+
|
208
|
+
- A charge succeeded
|
209
|
+
- A charge was refunded
|
210
|
+
- A subscription is about to renew
|
184
211
|
|
185
212
|
|
186
213
|
## Billable API
|
@@ -585,10 +612,18 @@ If you have a catch all route (for 404s etc) and need to control where/when the
|
|
585
612
|
|
586
613
|
```ruby
|
587
614
|
# config/initializers/pay.rb
|
588
|
-
|
615
|
+
Pay.setup do |config|
|
616
|
+
# ...
|
617
|
+
|
618
|
+
config.automount_routes = false
|
619
|
+
end
|
589
620
|
|
590
621
|
# config/routes.rb
|
591
|
-
|
622
|
+
Rails.application.routes.draw do
|
623
|
+
mount Pay::Engine, at: '/pay' # You can change the `at` path to feed your needs.
|
624
|
+
|
625
|
+
# Other routes here
|
626
|
+
end
|
592
627
|
```
|
593
628
|
|
594
629
|
If you just want to modify where the engine mounts it's routes then you can change the path.
|
@@ -596,7 +631,11 @@ If you just want to modify where the engine mounts it's routes then you can chan
|
|
596
631
|
```ruby
|
597
632
|
# config/initializers/pay.rb
|
598
633
|
|
599
|
-
|
634
|
+
Pay.setup do |config|
|
635
|
+
# ...
|
636
|
+
|
637
|
+
config.routes_path = '/pay'
|
638
|
+
end
|
600
639
|
```
|
601
640
|
|
602
641
|
## Payment Providers
|
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) }
|
@@ -15,10 +16,11 @@ module Pay
|
|
15
16
|
# Validations
|
16
17
|
validates :amount, presence: true
|
17
18
|
validates :processor, presence: true
|
18
|
-
validates :processor_id, presence: true
|
19
|
+
validates :processor_id, presence: true, uniqueness: {scope: :processor, case_sensitive: false}
|
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,11 +9,12 @@ 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
|
15
16
|
validates :processor, presence: true
|
16
|
-
validates :processor_id, presence: true
|
17
|
+
validates :processor_id, presence: true, uniqueness: {scope: :processor, case_sensitive: false}
|
17
18
|
validates :processor_plan, presence: true
|
18
19
|
validates :quantity, presence: true
|
19
20
|
validates :status, 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
|
|
@@ -115,8 +117,8 @@ module Pay
|
|
115
117
|
owner.invoice!(subscription_id: processor_id)
|
116
118
|
end
|
117
119
|
|
118
|
-
def processor_subscription(options
|
119
|
-
|
120
|
+
def processor_subscription(**options)
|
121
|
+
payment_processor.subscription(**options)
|
120
122
|
end
|
121
123
|
|
122
124
|
def latest_payment
|
@@ -1,22 +1,6 @@
|
|
1
1
|
class AddDataToPayModels < ActiveRecord::Migration[4.2]
|
2
2
|
def change
|
3
|
-
add_column :pay_subscriptions, :data,
|
4
|
-
add_column :pay_charges, :data,
|
5
|
-
end
|
6
|
-
|
7
|
-
def data_column_type
|
8
|
-
default_hash = ActiveRecord::Base.configurations.default_hash
|
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
|
16
|
-
when "postgresql"
|
17
|
-
:jsonb
|
18
|
-
else
|
19
|
-
:text
|
20
|
-
end
|
3
|
+
add_column :pay_subscriptions, :data, Pay::Adapter.json_column_type
|
4
|
+
add_column :pay_charges, :data, Pay::Adapter.json_column_type
|
21
5
|
end
|
22
6
|
end
|
@@ -0,0 +1,10 @@
|
|
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, Pay::Adapter.json_column_type
|
8
|
+
end
|
9
|
+
end
|
10
|
+
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
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/active_record"
|
4
|
+
require "generators/pay/orm_helpers"
|
5
|
+
|
6
|
+
module ActiveRecord
|
7
|
+
module Generators
|
8
|
+
class BillableGenerator < ActiveRecord::Generators::Base
|
9
|
+
include Pay::Generators::OrmHelpers
|
10
|
+
source_root File.expand_path("../templates", __FILE__)
|
11
|
+
|
12
|
+
def copy_pay_billable_migration
|
13
|
+
if (behavior == :invoke && model_exists?) || (behavior == :revoke && migration_exists?(table_name))
|
14
|
+
migration_template "billable_migration.rb", "#{migration_path}/add_pay_billable_to_#{table_name}.rb", migration_version: migration_version
|
15
|
+
else
|
16
|
+
say "#{model_path} does not exist.", :red
|
17
|
+
say "⚠️ Make sure the #{name} model exists before running this generator."
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# If the file already contains the contents, the user will receive this warning:
|
22
|
+
#
|
23
|
+
# File unchanged! The supplied flag value not found!
|
24
|
+
#
|
25
|
+
# This can be ignored as it just means the contents already exist and the file is unchanged.
|
26
|
+
# Thor will be updated to improve this message: https://github.com/rails/thor/issues/706
|
27
|
+
def inject_pay_billable_content
|
28
|
+
return unless model_exists?
|
29
|
+
|
30
|
+
content = model_contents
|
31
|
+
class_path = (namespaced? ? class_name.to_s.split("::") : [class_name])
|
32
|
+
indent_depth = class_path.size - 1
|
33
|
+
content = content.split("\n").map { |line| " " * indent_depth + line }.join("\n") << "\n"
|
34
|
+
inject_into_class(model_path, class_path.last, content)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def model_contents
|
40
|
+
" include Pay::Billable"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/active_record"
|
4
|
+
require "generators/pay/orm_helpers"
|
5
|
+
|
6
|
+
module ActiveRecord
|
7
|
+
module Generators
|
8
|
+
class MerchantGenerator < ActiveRecord::Generators::Base
|
9
|
+
include Pay::Generators::OrmHelpers
|
10
|
+
source_root File.expand_path("../templates", __FILE__)
|
11
|
+
|
12
|
+
def copy_pay_merchant_migration
|
13
|
+
if (behavior == :invoke && model_exists?) || (behavior == :revoke && migration_exists?(table_name))
|
14
|
+
migration_template "merchant_migration.rb", "#{migration_path}/add_pay_merchant_to_#{table_name}.rb", migration_version: migration_version
|
15
|
+
else
|
16
|
+
say "#{model_path} does not exist.", :red
|
17
|
+
say "⚠️ Make sure the #{name} model exists before running this generator."
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# If the file already contains the contents, the user will receive this warning:
|
22
|
+
#
|
23
|
+
# File unchanged! The supplied flag value not found!
|
24
|
+
#
|
25
|
+
# This can be ignored as it just means the contents already exist and the file is unchanged.
|
26
|
+
# Thor will be updated to improve this message: https://github.com/rails/thor/issues/706
|
27
|
+
def inject_pay_merchant_content
|
28
|
+
return unless model_exists?
|
29
|
+
|
30
|
+
content = model_contents
|
31
|
+
class_path = (namespaced? ? class_name.to_s.split("::") : [class_name])
|
32
|
+
indent_depth = class_path.size - 1
|
33
|
+
content = content.split("\n").map { |line| " " * indent_depth + line }.join("\n") << "\n"
|
34
|
+
inject_into_class(model_path, class_path.last, content)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def model_contents
|
40
|
+
" include Pay::Merchant"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|