pay 2.1.1 → 2.2.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 +41 -30
- data/Rakefile +6 -12
- data/app/controllers/pay/payments_controller.rb +1 -0
- data/app/mailers/pay/user_mailer.rb +2 -2
- data/app/views/pay/payments/show.html.erb +1 -1
- data/db/migrate/20170205020145_create_pay_subscriptions.rb +2 -1
- data/db/migrate/20170727235816_create_pay_charges.rb +1 -0
- data/lib/generators/active_record/pay_generator.rb +1 -1
- data/lib/generators/active_record/templates/migration.rb +1 -1
- data/lib/generators/pay/orm_helpers.rb +1 -2
- data/lib/pay.rb +8 -2
- data/lib/pay/billable.rb +2 -2
- data/lib/pay/braintree.rb +1 -1
- data/lib/pay/braintree/billable.rb +8 -0
- data/lib/pay/stripe.rb +1 -0
- data/lib/pay/stripe/billable.rb +8 -5
- data/lib/pay/stripe/subscription.rb +1 -1
- data/lib/pay/version.rb +1 -1
- metadata +6 -21
- data/db/migrate/20170503131610_add_fields_to_billable.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b0dc3430e6f89e4c1516a122bde97173ee5bdb1bfa835bb968b36083b633c4f
|
4
|
+
data.tar.gz: 0dbd1c62002fa67fbf9e78591f52199c9322e6d52868fb443e640f93dd2863d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d6e108e2377cfabdd8da381f225094d4f8f2e0fb25ca28dbadf0cfbfaad1bbafbbb1f4613c92ac0bd8dc0d87c4de14b21d32004ab31ab572588bef4926746f92
|
7
|
+
data.tar.gz: 68ebaeed4f068419a51860d853bd914ba6c5076e590bac85005feb431a404bb7ea8c3fbbe113876e0f6ec56ad539d43e698504b99aa5951bc76894d18961f8c6
|
data/README.md
CHANGED
@@ -2,17 +2,19 @@
|
|
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)
|
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
|
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)
|
11
|
+
- Stripe ([supports SCA](https://stripe.com/docs/strong-customer-authentication) using API version `2020-08-27`)
|
12
12
|
- Braintree
|
13
13
|
|
14
14
|
Want to add a new payment provider? Contributions are welcome and the instructions [are here](https://github.com/jasoncharnes/pay/wiki/New-Payment-Provider).
|
15
15
|
|
16
|
+
**Check the CHANGELOG for any required migrations or changes needed if you're upgrading from a previous version of Pay.**
|
17
|
+
|
16
18
|
## Tutorial
|
17
19
|
|
18
20
|
Want to see how Pay works? Check out our video getting started guide.
|
@@ -43,37 +45,21 @@ And then execute:
|
|
43
45
|
bundle
|
44
46
|
```
|
45
47
|
|
46
|
-
|
47
|
-
|
48
|
-
```bash
|
49
|
-
gem install pay
|
50
|
-
```
|
51
|
-
|
52
|
-
## Setup
|
53
|
-
|
54
|
-
### Migrations
|
55
|
-
|
56
|
-
This engine will create a subscription model and the neccessary migrations for the model you want to make "billable." The most common use case for the billable model is a User.
|
48
|
+
#### Migrations
|
57
49
|
|
58
50
|
To add the migrations to your application, run the following migration:
|
59
51
|
|
60
|
-
|
61
|
-
|
62
|
-
This will install three migrations:
|
52
|
+
`bin/rails pay:install:migrations`
|
63
53
|
|
64
|
-
|
65
|
-
- db/migrate/create_charges.pay.rb
|
66
|
-
- db/migrate/add_status_to_subscriptions.pay.rb
|
54
|
+
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.
|
67
55
|
|
68
|
-
|
69
|
-
`Billable` model. The `pay` generator will add fields to the model and
|
70
|
-
add the `Pay::Billable` module to it.
|
56
|
+
`bin/rails g pay User`
|
71
57
|
|
72
|
-
|
58
|
+
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.
|
73
59
|
|
74
|
-
|
60
|
+
Finally, run the migrations
|
75
61
|
|
76
|
-
|
62
|
+
`rake db:migrate`
|
77
63
|
|
78
64
|
#### Getting NoMethodError?
|
79
65
|
|
@@ -92,6 +78,8 @@ class User < ActiveRecord::Base
|
|
92
78
|
end
|
93
79
|
```
|
94
80
|
|
81
|
+
An `email` attribute or method on your `Billable` model is required.
|
82
|
+
|
95
83
|
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.
|
96
84
|
|
97
85
|
## Configuration
|
@@ -251,13 +239,20 @@ def subscribe(name: 'default', plan: 'default', **options)
|
|
251
239
|
end
|
252
240
|
```
|
253
241
|
|
242
|
+
For example, you can pass the `quantity` option to subscribe to a plan with for per-seat pricing.
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
|
246
|
+
user.subscribe(name: "default", plan: "default", quantity: 3)
|
247
|
+
```
|
248
|
+
|
254
249
|
##### Name
|
255
250
|
|
256
251
|
Name is an internally used name for the subscription.
|
257
252
|
|
258
253
|
##### Plan
|
259
254
|
|
260
|
-
Plan is the plan ID from the payment processor.
|
255
|
+
Plan is the plan ID or price ID from the payment processor. For example: `plan_xxxxx` or `price_xxxxx`
|
261
256
|
|
262
257
|
##### Options
|
263
258
|
|
@@ -511,6 +506,20 @@ You can also use the `STRIPE_PRIVATE_KEY` and `STRIPE_SIGNING_SECRET` environmen
|
|
511
506
|
|
512
507
|
**To see how to use Stripe Elements JS & Devise, [click here](https://github.com/jasoncharnes/pay/wiki/Using-Stripe-Elements-and-Devise).**
|
513
508
|
|
509
|
+
You need the following event types to trigger the webhook:
|
510
|
+
|
511
|
+
```
|
512
|
+
customer.subscription.updated
|
513
|
+
customer.subscription.deleted
|
514
|
+
customer.subscription.created
|
515
|
+
payment_method.updated
|
516
|
+
invoice.payment_action_required
|
517
|
+
customer.updated
|
518
|
+
customer.deleted
|
519
|
+
charge.succeeded
|
520
|
+
charge.refunded
|
521
|
+
```
|
522
|
+
|
514
523
|
##### Strong Customer Authentication (SCA)
|
515
524
|
|
516
525
|
Our Stripe integration **requires** the use of Payment Method objects to correctly support Strong Customer Authentication with Stripe. If you've previously been using card tokens, you'll need to upgrade your Javascript integration.
|
@@ -525,9 +534,7 @@ correctly for SCA payments.
|
|
525
534
|
stripe listen --forward-to localhost:3000/pay/webhooks/stripe
|
526
535
|
```
|
527
536
|
|
528
|
-
You should use `stripe.
|
529
|
-
|
530
|
-
The Javascript will now need to use createPaymentMethod instead of createToken. https://stripe.com/docs/js/payment_intents/create_payment_method
|
537
|
+
You should use `stripe.confirmCardSetup` on the client to collect card information anytime you want to save the card and charge them later (adding a card, then charging them on the next page for example). Use `stripe.confirmCardPayment` if you'd like to charge the customer immediately (think checking out of a shopping cart).
|
531
538
|
|
532
539
|
The Javascript also needs to have a PaymentIntent or SetupIntent created server-side and the ID passed into the Javascript to do this. That way it knows how to safely handle the card tokenization if it meets the SCA requirements.
|
533
540
|
|
@@ -545,6 +552,7 @@ If a user's email is updated and they have a `processor_id` set, Pay will enqueu
|
|
545
552
|
|
546
553
|
It's important you set a queue_adapter for this to happen. If you don't, the code will be executed immediately upon user update. [More information here](https://guides.rubyonrails.org/v4.2/active_job_basics.html#backends)
|
547
554
|
|
555
|
+
|
548
556
|
## Contributors
|
549
557
|
|
550
558
|
- [Jason Charnes](https://twitter.com/jmcharnes)
|
@@ -558,7 +566,10 @@ If you have an issue you'd like to submit, please do so using the issue tracker
|
|
558
566
|
|
559
567
|
If you'd like to open a PR please make sure the following things pass:
|
560
568
|
|
561
|
-
|
569
|
+
```ruby
|
570
|
+
bin/rails db:test:prepare
|
571
|
+
bin/rails test
|
572
|
+
```
|
562
573
|
|
563
574
|
## License
|
564
575
|
|
data/Rakefile
CHANGED
@@ -14,27 +14,21 @@ RDoc::Task.new(:rdoc) do |rdoc|
|
|
14
14
|
rdoc.rdoc_files.include("lib/**/*.rb")
|
15
15
|
end
|
16
16
|
|
17
|
-
APP_RAKEFILE = File.expand_path("
|
18
|
-
|
17
|
+
APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
|
19
18
|
load "rails/tasks/engine.rake"
|
19
|
+
|
20
20
|
load "rails/tasks/statistics.rake"
|
21
21
|
|
22
|
-
|
22
|
+
unless Rails.env.test?
|
23
|
+
require "bundler/gem_tasks"
|
24
|
+
end
|
25
|
+
|
23
26
|
require "rake/testtask"
|
24
27
|
|
25
28
|
Rake::TestTask.new(:test) do |t|
|
26
|
-
t.libs << "lib"
|
27
29
|
t.libs << "test"
|
28
30
|
t.pattern = "test/**/*_test.rb"
|
29
31
|
t.verbose = false
|
30
32
|
end
|
31
33
|
|
32
34
|
task default: :test
|
33
|
-
|
34
|
-
task :console do
|
35
|
-
require "irb"
|
36
|
-
require "irb/completion"
|
37
|
-
require "pay"
|
38
|
-
ARGV.clear
|
39
|
-
IRB.start
|
40
|
-
end
|
@@ -51,7 +51,7 @@
|
|
51
51
|
</div>
|
52
52
|
<% end %>
|
53
53
|
|
54
|
-
<%= link_to t("back"),
|
54
|
+
<%= link_to t("back"), @redirect_to, class: "inline-block w-full px-4 py-3 bg-gray-200 hover:bg-gray-300 text-center text-gray-700 rounded-lg" %>
|
55
55
|
</div>
|
56
56
|
|
57
57
|
<p class="text-center text-gray-500 text-sm">
|
@@ -1,7 +1,8 @@
|
|
1
1
|
class CreatePaySubscriptions < ActiveRecord::Migration[4.2]
|
2
2
|
def change
|
3
3
|
create_table :pay_subscriptions do |t|
|
4
|
-
|
4
|
+
# Some Billable objects use string as ID, add `type: :string` if needed
|
5
|
+
t.references :owner, polymorphic: true
|
5
6
|
t.string :name, null: false
|
6
7
|
t.string :processor, null: false
|
7
8
|
t.string :processor_id, null: false
|
@@ -1,6 +1,7 @@
|
|
1
1
|
class CreatePayCharges < ActiveRecord::Migration[4.2]
|
2
2
|
def change
|
3
3
|
create_table :pay_charges do |t|
|
4
|
+
# Some Billable objects use string as ID, add `type: :string` if needed
|
4
5
|
t.references :owner, polymorphic: true
|
5
6
|
t.string :processor, null: false
|
6
7
|
t.string :processor_id, null: false
|
@@ -26,7 +26,7 @@ module ActiveRecord
|
|
26
26
|
end
|
27
27
|
|
28
28
|
indent_depth = class_path.size - 1
|
29
|
-
content = content.split("\n").map { |line| " " * indent_depth + line }
|
29
|
+
content = content.split("\n").map { |line| " " * indent_depth + line }.join("\n") << "\n"
|
30
30
|
|
31
31
|
inject_into_class(model_path, class_path.last, content) if model_exists?
|
32
32
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
class
|
3
|
+
class AddPayBillableTo<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
|
4
4
|
def change
|
5
5
|
change_table :<%= table_name %> do |t|
|
6
6
|
<%= migration_data -%>
|
data/lib/pay.rb
CHANGED
@@ -105,11 +105,17 @@ module Pay
|
|
105
105
|
class BraintreeError < Error
|
106
106
|
attr_reader :result
|
107
107
|
|
108
|
-
def initialize(result)
|
108
|
+
def initialize(result = nil)
|
109
109
|
@result = result
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
113
|
+
class BraintreeAuthorizationError < BraintreeError
|
114
|
+
def message
|
115
|
+
"Either the data you submitted is malformed and does not match the API or the API key you used may not be authorized to perform this action."
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
113
119
|
class InvalidPaymentMethod < Error
|
114
120
|
attr_reader :payment
|
115
121
|
|
@@ -118,7 +124,7 @@ module Pay
|
|
118
124
|
end
|
119
125
|
|
120
126
|
def message
|
121
|
-
"This payment attempt failed
|
127
|
+
"This payment attempt failed because of an invalid payment method."
|
122
128
|
end
|
123
129
|
end
|
124
130
|
|
data/lib/pay/billable.rb
CHANGED
@@ -20,8 +20,8 @@ module Pay
|
|
20
20
|
include Pay::Stripe::Billable if defined? ::Stripe
|
21
21
|
include Pay::Braintree::Billable if defined? ::Braintree
|
22
22
|
|
23
|
-
has_many :charges, class_name: Pay.chargeable_class, foreign_key: :owner_id, inverse_of: :owner
|
24
|
-
has_many :subscriptions, class_name: Pay.subscription_class, foreign_key: :owner_id, inverse_of: :owner
|
23
|
+
has_many :charges, class_name: Pay.chargeable_class, foreign_key: :owner_id, inverse_of: :owner, as: :owner
|
24
|
+
has_many :subscriptions, class_name: Pay.subscription_class, foreign_key: :owner_id, inverse_of: :owner, as: :owner
|
25
25
|
|
26
26
|
attribute :plan, :string
|
27
27
|
attribute :quantity, :integer
|
data/lib/pay/braintree.rb
CHANGED
@@ -19,7 +19,7 @@ module Pay
|
|
19
19
|
|
20
20
|
Pay.charge_model.include Pay::Braintree::Charge
|
21
21
|
Pay.subscription_model.include Pay::Braintree::Subscription
|
22
|
-
Pay.billable_models.each { |model| model.include Pay::
|
22
|
+
Pay.billable_models.each { |model| model.include Pay::Braintree::Billable }
|
23
23
|
end
|
24
24
|
|
25
25
|
def public_key
|
@@ -24,6 +24,8 @@ module Pay
|
|
24
24
|
|
25
25
|
result.customer
|
26
26
|
end
|
27
|
+
rescue ::Braintree::AuthorizationError
|
28
|
+
raise BraintreeAuthorizationError
|
27
29
|
rescue ::Braintree::BraintreeError => e
|
28
30
|
raise BraintreeError, e.message
|
29
31
|
end
|
@@ -42,6 +44,8 @@ module Pay
|
|
42
44
|
raise BraintreeError.new(result), result.message unless result.success?
|
43
45
|
|
44
46
|
save_braintree_transaction(result.transaction)
|
47
|
+
rescue ::Braintree::AuthorizationError
|
48
|
+
raise BraintreeAuthorizationError
|
45
49
|
rescue ::Braintree::BraintreeError => e
|
46
50
|
raise BraintreeError, e.message
|
47
51
|
end
|
@@ -67,6 +71,8 @@ module Pay
|
|
67
71
|
raise BraintreeError.new(result), result.message unless result.success?
|
68
72
|
|
69
73
|
create_subscription(result.subscription, "braintree", name, plan, status: :active)
|
74
|
+
rescue ::Braintree::AuthorizationError
|
75
|
+
raise BraintreeAuthorizationError
|
70
76
|
rescue ::Braintree::BraintreeError => e
|
71
77
|
raise BraintreeError, e.message
|
72
78
|
end
|
@@ -88,6 +94,8 @@ module Pay
|
|
88
94
|
update_braintree_card_on_file result.payment_method
|
89
95
|
update_subscriptions_to_payment_method(result.payment_method.token)
|
90
96
|
true
|
97
|
+
rescue ::Braintree::AuthorizationError
|
98
|
+
raise BraintreeAuthorizationError
|
91
99
|
rescue ::Braintree::BraintreeError => e
|
92
100
|
raise BraintreeError, e.message
|
93
101
|
end
|
data/lib/pay/stripe.rb
CHANGED
data/lib/pay/stripe/billable.rb
CHANGED
@@ -48,17 +48,20 @@ module Pay
|
|
48
48
|
#
|
49
49
|
# Returns Pay::Subscription
|
50
50
|
def create_stripe_subscription(name, plan, options = {})
|
51
|
+
quantity = options.delete(:quantity) || 1
|
51
52
|
opts = {
|
52
53
|
expand: ["pending_setup_intent", "latest_invoice.payment_intent"],
|
53
|
-
items: [plan: plan],
|
54
|
+
items: [plan: plan, quantity: quantity],
|
54
55
|
off_session: true
|
55
56
|
}.merge(options)
|
56
57
|
|
57
58
|
# Inherit trial from plan unless trial override was specified
|
58
59
|
opts[:trial_from_plan] = true unless opts[:trial_period_days]
|
59
60
|
|
60
|
-
|
61
|
-
|
61
|
+
opts[:customer] = stripe_customer.id
|
62
|
+
|
63
|
+
stripe_sub = ::Stripe::Subscription.create(opts)
|
64
|
+
subscription = create_subscription(stripe_sub, "stripe", name, plan, status: stripe_sub.status, quantity: quantity)
|
62
65
|
|
63
66
|
# No trial, card requires SCA
|
64
67
|
if subscription.incomplete?
|
@@ -94,7 +97,7 @@ module Pay
|
|
94
97
|
def update_stripe_email!
|
95
98
|
customer = stripe_customer
|
96
99
|
customer.email = email
|
97
|
-
customer.
|
100
|
+
customer.name = customer_name
|
98
101
|
customer.save
|
99
102
|
end
|
100
103
|
|
@@ -134,7 +137,7 @@ module Pay
|
|
134
137
|
private
|
135
138
|
|
136
139
|
def create_stripe_customer
|
137
|
-
customer = ::Stripe::Customer.create(email: email,
|
140
|
+
customer = ::Stripe::Customer.create(email: email, name: customer_name)
|
138
141
|
update(processor: "stripe", processor_id: customer.id)
|
139
142
|
|
140
143
|
# Update the user's card on file if a token was passed in
|
@@ -37,7 +37,7 @@ module Pay
|
|
37
37
|
subscription = processor_subscription
|
38
38
|
subscription.cancel_at_period_end = false
|
39
39
|
subscription.plan = plan
|
40
|
-
subscription.
|
40
|
+
subscription.proration_behavior = (prorate ? "create_prorations" : "none")
|
41
41
|
subscription.trial_end = on_trial? ? trial_ends_at.to_i : "now"
|
42
42
|
subscription.quantity = quantity if quantity?
|
43
43
|
subscription.save
|
data/lib/pay/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pay
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Charnes
|
8
8
|
- Chris Oliver
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-
|
12
|
+
date: 2020-11-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -73,20 +73,6 @@ dependencies:
|
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '2.3'
|
76
|
-
- !ruby/object:Gem::Dependency
|
77
|
-
name: bundler
|
78
|
-
requirement: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
type: :development
|
84
|
-
prerelease: false
|
85
|
-
version_requirements: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
76
|
- !ruby/object:Gem::Dependency
|
91
77
|
name: byebug
|
92
78
|
requirement: !ruby/object:Gem::Requirement
|
@@ -233,7 +219,6 @@ files:
|
|
233
219
|
- config/locales/en.yml
|
234
220
|
- config/routes.rb
|
235
221
|
- db/migrate/20170205020145_create_pay_subscriptions.rb
|
236
|
-
- db/migrate/20170503131610_add_fields_to_billable.rb
|
237
222
|
- db/migrate/20170727235816_create_pay_charges.rb
|
238
223
|
- db/migrate/20190816015720_add_status_to_pay_subscriptions.rb
|
239
224
|
- lib/generators/active_record/pay_generator.rb
|
@@ -273,7 +258,7 @@ homepage: https://github.com/jasoncharnes/pay
|
|
273
258
|
licenses:
|
274
259
|
- MIT
|
275
260
|
metadata: {}
|
276
|
-
post_install_message:
|
261
|
+
post_install_message:
|
277
262
|
rdoc_options: []
|
278
263
|
require_paths:
|
279
264
|
- lib
|
@@ -288,8 +273,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
288
273
|
- !ruby/object:Gem::Version
|
289
274
|
version: '0'
|
290
275
|
requirements: []
|
291
|
-
rubygems_version: 3.
|
292
|
-
signing_key:
|
276
|
+
rubygems_version: 3.1.4
|
277
|
+
signing_key:
|
293
278
|
specification_version: 4
|
294
279
|
summary: A Ruby on Rails subscription engine.
|
295
280
|
test_files: []
|
@@ -1,16 +0,0 @@
|
|
1
|
-
class AddFieldsToBillable < ActiveRecord::Migration[4.2]
|
2
|
-
def change
|
3
|
-
unless ActiveRecord::Base.connection.table_exists?(Pay.billable_table)
|
4
|
-
create_table Pay.billable_table.to_sym
|
5
|
-
end
|
6
|
-
|
7
|
-
add_column Pay.billable_table, :processor, :string
|
8
|
-
add_column Pay.billable_table, :processor_id, :string
|
9
|
-
add_column Pay.billable_table, :trial_ends_at, :datetime
|
10
|
-
add_column Pay.billable_table, :card_type, :string
|
11
|
-
add_column Pay.billable_table, :card_last4, :string
|
12
|
-
add_column Pay.billable_table, :card_exp_month, :string
|
13
|
-
add_column Pay.billable_table, :card_exp_year, :string
|
14
|
-
add_column Pay.billable_table, :extra_billing_info, :text
|
15
|
-
end
|
16
|
-
end
|