pay 2.7.0 → 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.

Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +93 -57
  3. data/app/models/pay/application_record.rb +1 -0
  4. data/app/models/pay/charge.rb +1 -1
  5. data/app/models/pay/subscription.rb +1 -1
  6. data/db/migrate/20200603134434_add_data_to_pay_models.rb +2 -11
  7. data/db/migrate/20210309004259_add_data_to_pay_billable.rb +1 -10
  8. data/db/migrate/20210714175351_add_uniqueness_to_pay_models.rb +6 -0
  9. data/lib/generators/active_record/billable_generator.rb +44 -0
  10. data/lib/generators/active_record/merchant_generator.rb +44 -0
  11. data/lib/generators/active_record/templates/billable_migration.rb +17 -0
  12. data/lib/generators/active_record/templates/merchant_migration.rb +12 -0
  13. data/lib/generators/pay/{pay_generator.rb → billable_generator.rb} +2 -3
  14. data/lib/generators/pay/merchant_generator.rb +17 -0
  15. data/lib/generators/pay/orm_helpers.rb +10 -6
  16. data/lib/pay/adapter.rb +9 -0
  17. data/lib/pay/braintree/subscription.rb +2 -0
  18. data/lib/pay/env.rb +8 -0
  19. data/lib/pay/fake_processor/subscription.rb +2 -0
  20. data/lib/pay/paddle/subscription.rb +2 -0
  21. data/lib/pay/stripe/billable.rb +36 -44
  22. data/lib/pay/stripe/charge.rb +55 -2
  23. data/lib/pay/stripe/subscription.rb +62 -5
  24. data/lib/pay/stripe/webhooks/charge_refunded.rb +2 -7
  25. data/lib/pay/stripe/webhooks/charge_succeeded.rb +2 -8
  26. data/lib/pay/stripe/webhooks/checkout_session_async_payment_succeeded.rb +13 -0
  27. data/lib/pay/stripe/webhooks/checkout_session_completed.rb +13 -0
  28. data/lib/pay/stripe/webhooks/payment_intent_succeeded.rb +2 -8
  29. data/lib/pay/stripe/webhooks/payment_method_attached.rb +17 -0
  30. data/lib/pay/stripe/webhooks/payment_method_automatically_updated.rb +17 -0
  31. data/lib/pay/stripe/webhooks/payment_method_detached.rb +17 -0
  32. data/lib/pay/stripe/webhooks/subscription_created.rb +1 -36
  33. data/lib/pay/stripe/webhooks/subscription_deleted.rb +1 -9
  34. data/lib/pay/stripe/webhooks/subscription_renewing.rb +4 -6
  35. data/lib/pay/stripe/webhooks/subscription_updated.rb +1 -29
  36. data/lib/pay/stripe.rb +6 -0
  37. data/lib/pay/version.rb +1 -1
  38. metadata +14 -6
  39. data/app/models/pay.rb +0 -5
  40. data/lib/generators/active_record/pay_generator.rb +0 -58
  41. 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: d696d24ee2bb2b4827f6d6e31db738752ebb2eadca4ea0e79144518fc9375be9
4
- data.tar.gz: 8aad550b117bee7e28c9231832f4f344c37054db4f1a7d0176f034c780d0abed
3
+ metadata.gz: 2cb954b3125acb413cdebfcf57687b4ff9f33987c0500dd72f350c293f491322
4
+ data.tar.gz: b4f9b23d452a3ab76b21902ebcad03b2c927a7e7eb17f58c9ac06d3df22232a3
5
5
  SHA512:
6
- metadata.gz: 5dc610b8d7b67ed4073fea783b290d3cd6ada3f4df1ed7bac26a0c4770f4a5ab854bf492fe6541f14b069ae61b10369024689a9f832d625ba2201a14deb24fc1
7
- data.tar.gz: 3801e3d1da5a833869ed46d28e04d633df5e1b55e51900bcae1a8b437663b93ee1b5ab45698cb54e00a145fb1752cb4c195ec877070b367b79d8c3b03ce81e8d
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,61 +51,49 @@ And then execute:
51
51
  bundle
52
52
  ```
53
53
 
54
- Make sure you've configured your ActionMailer default_url_options so Pay can generate links to for features like Stripe Checkout.
54
+ Next, we need to add migrations to your application, run the following migration:
55
55
 
56
- ```ruby
57
- # config/application.rb
58
- config.action_mailer.default_url_options = { host: "example.com" }
59
- ```
60
-
61
- #### Migrations
62
-
63
- To add the migrations to your application, run the following migration:
64
-
65
- `bin/rails pay:install:migrations`
56
+ ````bash
57
+ bin/rails pay:install:migrations
58
+ ````
66
59
 
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.
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.
69
61
 
70
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.
71
63
 
72
- `bin/rails g pay User`
64
+ ```bash
65
+ bin/rails g pay:billable User
66
+ ```
73
67
 
74
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.
75
69
 
76
- Finally, run the migrations
77
-
78
- `rake db:migrate`
70
+ **Note:** An `email` attribute or method on your `Billable` model is required.
79
71
 
80
- #### Getting NoMethodError?
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.
81
73
 
82
- `NoMethodError (undefined method 'stripe_customer' for #<User:0x00007fbc34b9bf20>)`
74
+ Finally, run the migrations
83
75
 
84
- Fully restart your Rails application `bin/spring stop && rails s`
76
+ ```bash
77
+ bin/rails db:migrate
78
+ ```
85
79
 
86
- ## Usage
80
+ > If you run into `NoMethodError (undefined method 'stripe_customer' for #<User:0x00007fbc34b9bf20>)`, fully restart your Rails application `bin/spring stop && rails s`
87
81
 
88
- The `Pay::Billable` module should be included in the models you want to make payments and subscriptions.
82
+ Lastly, make sure you've configured your ActionMailer default_url_options so Pay can generate links to for features like Stripe Checkout.
89
83
 
90
84
  ```ruby
91
- # app/models/user.rb
92
- class User < ActiveRecord::Base
93
- include Pay::Billable
94
- end
85
+ # config/application.rb
86
+ config.action_mailer.default_url_options = { host: "example.com" }
95
87
  ```
96
88
 
97
- An `email` attribute or method on your `Billable` model is required.
98
-
99
- 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.
100
-
101
89
  ## Configuration
102
90
 
103
91
  Need to make some changes to how Pay is used? You can create an initializer `config/initializers/pay.rb`
104
92
 
105
93
  ```ruby
106
94
  Pay.setup do |config|
107
- config.chargeable_class = 'Pay::Charge'
108
- config.chargeable_table = 'pay_charges'
95
+ # config.chargeable_class = 'Pay::Charge'
96
+ # config.chargeable_table = 'pay_charges'
109
97
 
110
98
  # For use in the receipt/refund/renewal mailers
111
99
  config.business_name = "Business Name"
@@ -139,29 +127,63 @@ end
139
127
 
140
128
  ### Credentials
141
129
 
142
- You'll need to add your private Stripe API key to your Rails secrets `config/secrets.yml`, credentials `rails credentials:edit`
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.
143
162
 
144
163
  ```yaml
145
164
  development:
146
165
  stripe:
147
- private_key: xxxx
148
- public_key: yyyy
149
- signing_secret: zzzz
150
- braintree:
151
- private_key: xxxx
152
- public_key: yyyy
153
- merchant_id: aaaa
154
- environment: sandbox
155
- paddle:
156
- vendor_id: xxxx
157
- vendor_auth_code: yyyy
158
- public_key_base64: MII...==
159
- environment: sandbox
166
+ private_key: sk_test_xxxx
167
+ public_key: pk_test_yyyy
168
+ signing_secret: whsec_zzzz
169
+ # ...
160
170
  ```
161
171
 
162
- For Stripe, you can also use the `STRIPE_PUBLIC_KEY`, `STRIPE_PRIVATE_KEY` and `STRIPE_SIGNING_SECRET` environment variables.
163
- For Braintree, you can also use `BRAINTREE_MERCHANT_ID`, `BRAINTREE_PUBLIC_KEY`, `BRAINTREE_PRIVATE_KEY`, and `BRAINTREE_ENVIRONMENT` environment variables.
164
- For Paddle, you can also use `PADDLE_VENDOR_ID`, `PADDLE_VENDOR_AUTH_CODE`, `PADDLE_PUBLIC_KEY_BASE64` and `PADDLE_ENVIRONMENT` environment variables.
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`
165
187
 
166
188
  ### Generators
167
189
 
@@ -179,11 +201,13 @@ bin/rails generate pay:email_views
179
201
 
180
202
  ### Emails
181
203
 
182
- Emails can be enabled/disabled using the `send_emails` configuration option (enabled per default). When enabled, the following emails will be sent:
204
+ Emails can be enabled/disabled using the `send_emails` configuration option (enabled by default).
183
205
 
184
- - When a charge succeeded
185
- - When a charge was refunded
186
- - When a subscription is about to renew
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
187
211
 
188
212
 
189
213
  ## Billable API
@@ -588,10 +612,18 @@ If you have a catch all route (for 404s etc) and need to control where/when the
588
612
 
589
613
  ```ruby
590
614
  # config/initializers/pay.rb
591
- config.automount_routes = false
615
+ Pay.setup do |config|
616
+ # ...
617
+
618
+ config.automount_routes = false
619
+ end
592
620
 
593
621
  # config/routes.rb
594
- mount Pay::Engine, at: '/secret-webhook-path'
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
595
627
  ```
596
628
 
597
629
  If you just want to modify where the engine mounts it's routes then you can change the path.
@@ -599,7 +631,11 @@ If you just want to modify where the engine mounts it's routes then you can chan
599
631
  ```ruby
600
632
  # config/initializers/pay.rb
601
633
 
602
- config.routes_path = '/secret-webhook-path'
634
+ Pay.setup do |config|
635
+ # ...
636
+
637
+ config.routes_path = '/pay'
638
+ end
603
639
  ```
604
640
 
605
641
  ## Payment Providers
@@ -1,6 +1,7 @@
1
1
  module Pay
2
2
  class ApplicationRecord < Pay.model_parent_class.constantize
3
3
  self.abstract_class = true
4
+ self.table_name_prefix = "pay_"
4
5
 
5
6
  def self.json_column?(name)
6
7
  return unless connected? && table_exists?
@@ -16,7 +16,7 @@ module Pay
16
16
  # Validations
17
17
  validates :amount, presence: true
18
18
  validates :processor, presence: true
19
- validates :processor_id, presence: true
19
+ validates :processor_id, presence: true, uniqueness: {scope: :processor, case_sensitive: false}
20
20
  validates :card_type, presence: true
21
21
 
22
22
  store_accessor :data, :paddle_receipt_url
@@ -14,7 +14,7 @@ module Pay
14
14
  # Validations
15
15
  validates :name, presence: true
16
16
  validates :processor, presence: true
17
- validates :processor_id, presence: true
17
+ validates :processor_id, presence: true, uniqueness: {scope: :processor, case_sensitive: false}
18
18
  validates :processor_plan, presence: true
19
19
  validates :quantity, presence: true
20
20
  validates :status, presence: true
@@ -1,15 +1,6 @@
1
1
  class AddDataToPayModels < ActiveRecord::Migration[4.2]
2
2
  def change
3
- add_column :pay_subscriptions, :data, data_column_type
4
- add_column :pay_charges, :data, data_column_type
5
- end
6
-
7
- def data_column_type
8
- case Pay::Adapter.current_adapter
9
- when "postgresql"
10
- :jsonb
11
- else
12
- :json
13
- end
3
+ add_column :pay_subscriptions, :data, Pay::Adapter.json_column_type
4
+ add_column :pay_charges, :data, Pay::Adapter.json_column_type
14
5
  end
15
6
  end
@@ -4,16 +4,7 @@ class AddDataToPayBillable < ActiveRecord::Migration[4.2]
4
4
  Rails.application.eager_load!
5
5
 
6
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
7
+ add_column model.table_name, :pay_data, Pay::Adapter.json_column_type
17
8
  end
18
9
  end
19
10
  end
@@ -0,0 +1,6 @@
1
+ class AddUniquenessToPayModels < ActiveRecord::Migration[6.1]
2
+ def change
3
+ add_index :pay_charges, [:processor, :processor_id], unique: true
4
+ add_index :pay_subscriptions, [:processor, :processor_id], unique: true
5
+ end
6
+ 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
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddPayBillableTo<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
4
+ def change
5
+ change_table :<%= table_name %>, bulk: true do |t|
6
+ t.string :processor
7
+ t.string :processor_id
8
+ t.public_send(Pay::Adapter.json_column_type, :pay_data)
9
+ t.datetime :trial_ends_at
10
+ t.string :card_type
11
+ t.string :card_last4
12
+ t.string :card_exp_month
13
+ t.string :card_exp_year
14
+ t.text :extra_billing_info
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddPayMerchantTo<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
4
+ def change
5
+ add_column table_name, :merchant_processor, :string
6
+
7
+ # We may already have the pay_data column if a Pay::Billable object is also a Pay::Merchant
8
+ unless ActiveRecord::Base.connection.column_exists?(table_name, :pay_data)
9
+ add_column :<%= table_name %>, :pay_data, Pay::Adapter.json_column_type
10
+ end
11
+ end
12
+ end
@@ -4,13 +4,12 @@ require "rails/generators/named_base"
4
4
 
5
5
  module Pay
6
6
  module Generators
7
- class PayGenerator < Rails::Generators::NamedBase
7
+ class BillableGenerator < Rails::Generators::NamedBase
8
8
  include Rails::Generators::ResourceHelpers
9
9
 
10
- namespace "pay"
11
10
  source_root File.expand_path("../templates", __FILE__)
12
11
 
13
- desc "Generates a migration to add Billable fields to a model."
12
+ desc "Generates a migration to add Pay::Billable fields to a model."
14
13
 
15
14
  hook_for :orm
16
15
  end