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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 026eec665e0972815526e10a0f8082c9dc7de99c8df6dfe890aa34630f902828
4
- data.tar.gz: 44a6a608fcc55f9d235191716b78a55b1d3f595e8e9233f630ecdd1b3ca0d3e8
3
+ metadata.gz: 6b0dc3430e6f89e4c1516a122bde97173ee5bdb1bfa835bb968b36083b633c4f
4
+ data.tar.gz: 0dbd1c62002fa67fbf9e78591f52199c9322e6d52868fb443e640f93dd2863d0
5
5
  SHA512:
6
- metadata.gz: cb4cf20991b9ff113c6cad8d86df842bae567c4dc24d0a0c8b862ef8430380d36adfda3dfaaceaa0f28e2b84904cd35ee832981ec3a71c822e0f00ac008a17ad
7
- data.tar.gz: 507a29aa827680ffb1dc36cf66142ad94d96f8aa25ead267dfb96fbbda9e431687eae4d410bd6bf7f3ecf8bc07a4d8ca4bf05441795f657a10ba713470b3c1e8
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), API version [2019-03-14](https://stripe.com/docs/upgrades#2019-03-14) or higher required)
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
- Or install it yourself as:
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
- `$ bin/rails pay:install:migrations`
61
-
62
- This will install three migrations:
52
+ `bin/rails pay:install:migrations`
63
53
 
64
- - db/migrate/create_subscriptions.pay.rb
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
- You'll also need a model that can make payments. This is called a
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
- `$ bin/rails g pay User`
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
- #### Run the Migrations
60
+ Finally, run the migrations
75
61
 
76
- Finally, run the migrations with `$ rake db:migrate`
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.handleCardSetup` 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.handleCardPayment` if you'd like to charge the customer immediately (think checking out of a shopping cart).
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
- - `rake test`
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("../test/dummy/Rakefile", __FILE__)
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
- require "bundler/gem_tasks"
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
@@ -1,6 +1,7 @@
1
1
  module Pay
2
2
  class PaymentsController < ApplicationController
3
3
  def show
4
+ @redirect_to = params[:back].presence || root_path
4
5
  @payment = Payment.from_id(params[:id])
5
6
  end
6
7
  end
@@ -44,8 +44,8 @@ module Pay
44
44
  private
45
45
 
46
46
  def to(user)
47
- if user.respond_to?(:name)
48
- "#{user.name} <#{user.email}>"
47
+ if user.respond_to?(:customer_name)
48
+ "#{user.customer_name} <#{user.email}>"
49
49
  else
50
50
  user.email
51
51
  end
@@ -51,7 +51,7 @@
51
51
  </div>
52
52
  <% end %>
53
53
 
54
- <%= link_to t("back"), root_path, class: "inline-block w-full px-4 py-3 bg-gray-200 hover:bg-gray-300 text-center text-gray-700 rounded-lg" %>
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
- t.references :owner
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 } .join("\n") << "\n"
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 AddPayTo<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
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 -%>
@@ -4,10 +4,9 @@ module Pay
4
4
  module Generators
5
5
  module OrmHelpers
6
6
  def model_contents
7
- buffer = <<-CONTENT
7
+ <<-CONTENT
8
8
  include Pay::Billable
9
9
  CONTENT
10
- buffer
11
10
  end
12
11
 
13
12
  private
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 beacuse of an invalid payment method."
127
+ "This payment attempt failed because of an invalid payment method."
122
128
  end
123
129
  end
124
130
 
@@ -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
@@ -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::Stripe::Billable }
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
@@ -12,6 +12,7 @@ module Pay
12
12
 
13
13
  def setup
14
14
  ::Stripe.api_key = private_key
15
+ ::Stripe.api_version = "2020-08-27"
15
16
  ::StripeEvent.signing_secret = signing_secret
16
17
 
17
18
  Pay.charge_model.include Pay::Stripe::Charge
@@ -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
- stripe_sub = customer.subscriptions.create(opts)
61
- subscription = create_subscription(stripe_sub, "stripe", name, plan, status: stripe_sub.status)
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.description = customer_name
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, description: customer_name)
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.prorate = prorate
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
@@ -1,3 +1,3 @@
1
1
  module Pay
2
- VERSION = "2.1.1"
2
+ VERSION = "2.2.2"
3
3
  end
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.1.1
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-03-28 00:00:00.000000000 Z
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.0.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