stripe-rails 1.8.2 → 1.10.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c3458e73514e9d287513ab9ff1192ccc37f7eed53681d407027f8a828c4e629
4
- data.tar.gz: 3cf53318d3cc31fac81c7d4ea4e5d981138eb1a0266dcc4a261fd8a49ddb014b
3
+ metadata.gz: 73acf591d97fe139b79c035da2794c439658693ad685e109e538c9e43d06fb8d
4
+ data.tar.gz: 18ffadcb37501896be79ee56f57c48a8a3213b9330bca42d5edc17de92f5a3ba
5
5
  SHA512:
6
- metadata.gz: c4283ef2ffddcddda494634e58cdda112f26dc82fc14428eaa8130e4d94b138862cdf6b8aa04886ad3291dd67788d75780420f4e00847845a59a1016d4ac7c4f
7
- data.tar.gz: 2ea2f1dc27ab45a92e4ba49b67430bb1b0b51a3379e192740ec4bc9eb7bb068004c9b9d213937727cc95718328e4c9786611969d515e5e9db5b3fa306c2698ed
6
+ metadata.gz: 29d167609bc9a3dd383acce2f4aaf1a833fe17158d12dfc08e87d164cd58e1da2a141009b6de127e04f8a03186e44f88f1bfffc019a93bfb45ff47545a57f77c
7
+ data.tar.gz: 72c31c0977018cdd1fe81134aef5e888c2820ae7264d1c263f90a6521dd904ea7cfe9a3c1d8e4fa0982059365ff0c311649aec807534a607d018b2d0fe74e202
@@ -0,0 +1,45 @@
1
+ name: Ruby
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ pull_request:
8
+ branches:
9
+ - master
10
+
11
+ jobs:
12
+ build:
13
+ runs-on: ubuntu-latest
14
+
15
+ strategy:
16
+ matrix:
17
+ ruby: [2.4.x, 2.5.x, 2.6.x, 2.7.x]
18
+ gemfile: [Gemfile, gemfiles/rails51.gemfile, gemfiles/rails52.gemfile, gemfiles/rails4.gemfile]
19
+ exclude:
20
+ - ruby: 2.7.x
21
+ gemfile: gemfiles/rails4.gemfile
22
+ steps:
23
+ - uses: actions/checkout@v1
24
+ - name: Set up Ruby
25
+ uses: actions/setup-ruby@v1
26
+ with:
27
+ ruby-version: ${{ matrix.ruby }}
28
+ - name: Set up Code Climate
29
+ run: |
30
+ curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
31
+ chmod +x ./cc-test-reporter
32
+ ./cc-test-reporter before-build
33
+ - name: Build and Test
34
+ env:
35
+ BUNDLE_GEMFILE: ${{ matrix.gemfile }}
36
+ CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
37
+ RUBY_VERSION: ${{ matrix.ruby }}
38
+ run: |
39
+ gem uninstall bundler
40
+ gem install bundler -v 1.17.3
41
+ bundle install --jobs 4 --retry 3
42
+ bundle exec rake
43
+ if [ `basename $BUNDLE_GEMFILE` == "Gemfile" ] && [ $RUBY_VERSION == "2.7.x" ] && [ ! -z ${CC_TEST_REPORTER_ID} ] ;
44
+ then ./cc-test-reporter after-build --exit-code $? ;
45
+ fi
@@ -1,3 +1,25 @@
1
+ ## Unreleased
2
+
3
+ ## 1.10.2 (2020-09-18)
4
+
5
+ - adds missing callback `invoice.paid`. Thanks @SyborgStudios.
6
+
7
+ ## 1.10.1 (2020-05-29)
8
+
9
+ - adds missing callbacks for `payment_intent`. Thanks @klapperkopp .
10
+
11
+ ## 1.10.0 (2020-03-31)
12
+
13
+ - Adds support for using multiple tiers in a plan, thanks @cpsoinos
14
+
15
+ ## 1.9.1 (2019-10-28)
16
+
17
+ - Fixes issue with `rake stripe:verify` thanks @Millariel !
18
+
19
+ ## 1.9.0 (2019-09-01)
20
+
21
+ - Adds support for multiple signing secrets. Thanks again @jacobcsmith !
22
+
1
23
  ## 1.8.2 (2019-08-31)
2
24
 
3
25
  - adds missing callbacks for `payment_intent`, `payment_method` and `setup_intent`. Thanks @jacobcsmith !
data/Gemfile CHANGED
@@ -11,12 +11,12 @@ end
11
11
 
12
12
  group :test do
13
13
  gem 'mocha'
14
- gem 'simplecov', require: false
14
+ gem 'simplecov', '< 0.18', require: false
15
15
  gem 'stripe-ruby-mock'
16
16
  gem 'webmock'
17
17
  # Required for system tests
18
18
  gem 'capybara'
19
- gem 'chromedriver-helper'
19
+ gem 'webdrivers'
20
20
  gem 'puma'
21
21
  gem 'selenium-webdriver'
22
22
  end
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Stripe::Rails: A Rails Engine for use with [stripe.com](https://stripe.com)
2
- [![Gem Version](https://badge.fury.io/rb/stripe-rails.png)](http://badge.fury.io/rb/stripe-rails)
3
- [![Build Status](https://travis-ci.org/tansengming/stripe-rails.png?branch=master)](https://travis-ci.org/tansengming/stripe-rails)
2
+ [![Gem Version](https://badge.fury.io/rb/stripe-rails.svg)](https://badge.fury.io/rb/stripe-rails)
3
+ [![Build Status](https://travis-ci.org/tansengming/stripe-rails.svg?branch=master)](https://travis-ci.org/tansengming/stripe-rails)
4
4
  [![Code Climate](https://codeclimate.com/github/tansengming/stripe-rails/badges/gpa.svg)](https://codeclimate.com/github/tansengming/stripe-rails)
5
5
  [![Test Coverage](https://codeclimate.com/github/tansengming/stripe-rails/badges/coverage.svg)](https://codeclimate.com/github/tansengming/stripe-rails/coverage)
6
6
  [![Tidelift](https://tidelift.com/badges/github/tansengming/stripe-rails)](#)
@@ -188,6 +188,23 @@ Stripe.plan :bronze do |plan|
188
188
  plan.product_id = 'prod_XXXXXXXXXXXXXX'
189
189
  plan.amount = 999 # $9.99
190
190
  plan.interval = 'month'
191
+
192
+ # Use graduated pricing tiers
193
+ # ref: https://stripe.com/docs/api/plans/object#plan_object-tiers
194
+ plan.tiers = [
195
+ {
196
+ unit_amount: 1500,
197
+ up_to: 10
198
+ },
199
+ {
200
+ unit_amount: 1000,
201
+ up_to: 'inf'
202
+ }
203
+ ]
204
+ plan.tiers_mode = 'graduated'
205
+
206
+ # set the usage type to 'metered'
207
+ plan.usage_type = 'metered'
191
208
  end
192
209
  ```
193
210
 
@@ -310,29 +327,32 @@ Your new webhook URL would then be `http://myproductionapp/payment/stripe-integr
310
327
  ### Signed Webhooks
311
328
 
312
329
  Validation of your webhook's signature uses your webhook endpoint signing secret.
313
- Before you can verify signatures, you need to retrieve your endpoint’s secret your
330
+ Before you can verify signatures, you need to retrieve your endpoint’s secret from your
314
331
  Stripe Dashboard. Select an endpoint for which you want to obtain
315
332
  the secret, then select the Click to reveal button.
316
333
 
317
334
  ```ruby
318
335
  # config/application.rb
319
336
  # ...
320
- config.stripe.signing_secret = 'whsec_XXXYYYZZZ'
337
+ config.stripe.signing_secrets = ['whsec_XXXYYYZZZ']
321
338
  ```
322
339
 
323
- Each secret is unique to the endpoint to which it corresponds. If you use multiple endpoints,
340
+ Each secret is unique to the endpoint to which it corresponds. If you use multiple endpoint,
324
341
  you must obtain a secret for each one. After this setup, Stripe starts to sign each webhook
325
- it sends to the endpoint. Because of this, we recommend setting this variable with an environment
326
- variable:
342
+ it sends to the endpoint. Because of this, we recommend setting this variable with environment
343
+ variables:
327
344
 
328
345
  ```sh
329
346
  export STRIPE_SIGNING_SECRET=whsec_XXXYYYZZZ
347
+ export STRIPE_CONNECT_SIGNING_SECRET=whsec_AAABBBCCC
330
348
  ```
331
349
 
332
350
  ```ruby
333
- config.stripe.signing_secret = ENV.fetch('STRIPE_SIGNING_SECRET')
351
+ config.stripe.signing_secrets = [ENV.fetch('STRIPE_SIGNING_SECRET'), ENV.fetch('STRIPE_CONNECT_SIGNING_SECRET')]
334
352
  ```
335
353
 
354
+ The first secret that successfully matches for each incoming webhook will be used to verify the incoming events.
355
+
336
356
  #### Testing Signed Webhooks Locally
337
357
 
338
358
  In order to test signed webhooks, you'll need to trigger test webhooks from your Stripe dashboard,
@@ -351,7 +371,7 @@ as documented above:
351
371
  ```ruby
352
372
  # config/application.rb
353
373
  # ...
354
- config.stripe.signing_secret = 'whsec_XXXYYYZZZ'
374
+ config.stripe.signing_secrets = ['whsec_XXXYYYZZZ']
355
375
  ```
356
376
 
357
377
  And you'll need to restart your rails server with:
@@ -11,15 +11,27 @@ module Stripe
11
11
  id = request['id']
12
12
  body = request.body.read
13
13
  sig_header = request.headers['HTTP_STRIPE_SIGNATURE']
14
- endpoint_secret = ::Rails.application.config.stripe.signing_secret
14
+ endpoint_secrets = ::Rails.application.config.stripe.signing_secrets
15
15
 
16
- if Object.const_defined?('Stripe::Webhook') && sig_header && endpoint_secret
17
- event = ::Stripe::Webhook.construct_event(body, sig_header, endpoint_secret)
16
+ if Object.const_defined?('Stripe::Webhook') && sig_header && endpoint_secrets
17
+ event = webhook_event(body, sig_header, endpoint_secrets)
18
18
  else
19
19
  event = Stripe::Event.retrieve(id)
20
20
  end
21
21
 
22
22
  yield event
23
23
  end
24
+
25
+ private
26
+
27
+ def webhook_event(body, sig_header, endpoint_secrets)
28
+ endpoint_secrets.each_with_index do |secret, i|
29
+ begin
30
+ return ::Stripe::Webhook.construct_event(body, sig_header, secret.to_s)
31
+ rescue ::Stripe::SignatureVerificationError
32
+ raise if i == endpoint_secrets.length - 1
33
+ end
34
+ end
35
+ end
24
36
  end
25
37
  end
@@ -1,6 +1,7 @@
1
1
  source :rubygems
2
2
 
3
3
  gem 'rails', '~> 4.2'
4
+ gem 'sprockets', '< 4'
4
5
 
5
6
  gem 'rake'
6
7
  gem 'responders', '~> 2.0' # to support Rails 4.2
@@ -13,7 +14,7 @@ group :test do
13
14
  gem 'webmock'
14
15
  # Required for system tests
15
16
  gem 'capybara'
16
- gem 'chromedriver-helper'
17
+ gem 'webdrivers'
17
18
  gem 'puma'
18
19
  gem 'selenium-webdriver'
19
20
  end
@@ -0,0 +1,20 @@
1
+ source :rubygems
2
+
3
+ gem 'rails', '~> 5.1.0'
4
+
5
+ gem 'rake'
6
+ gem 'responders'
7
+ gem 'sprockets', '< 4'
8
+ gem 'stripe'
9
+
10
+ group :test do
11
+ gem 'mocha'
12
+ gem 'simplecov', require: false
13
+ gem 'stripe-ruby-mock'
14
+ gem 'webmock'
15
+ # Required for system tests
16
+ gem 'capybara'
17
+ gem 'puma'
18
+ gem 'selenium-webdriver'
19
+ gem 'webdrivers'
20
+ end
@@ -0,0 +1,20 @@
1
+ source :rubygems
2
+
3
+ gem 'rails', '~> 5.2.0'
4
+
5
+ gem 'rake'
6
+ gem 'responders'
7
+ gem 'sprockets', '< 4'
8
+ gem 'stripe'
9
+
10
+ group :test do
11
+ gem 'mocha'
12
+ gem 'simplecov', require: false
13
+ gem 'stripe-ruby-mock'
14
+ gem 'webmock'
15
+ # Required for system tests
16
+ gem 'capybara'
17
+ gem 'puma'
18
+ gem 'selenium-webdriver'
19
+ gem 'webdrivers'
20
+ end
@@ -11,9 +11,9 @@
11
11
  # product.type = 'service'
12
12
  # end
13
13
 
14
- # Once you have your productss defined, you can run
14
+ # Once you have your products defined, you can run
15
15
  #
16
16
  # rake stripe:prepare
17
17
  #
18
- # This will export any new plans to stripe.com so that you can
18
+ # This will export any new products to stripe.com so that you can
19
19
  # begin using them in your API calls.
@@ -0,0 +1,34 @@
1
+ module Stripe
2
+ module Plans
3
+ class BillingTier
4
+ include ActiveModel::Validations
5
+
6
+ validates_presence_of :up_to
7
+ validates_presence_of :flat_amount, if: ->(tier) { tier.unit_amount.nil? },
8
+ message: 'one of `flat_amount` or `unit_amount` must be specified!'
9
+ validates_presence_of :unit_amount, if: ->(tier) { tier.flat_amount.nil? },
10
+ message: 'one of `flat_amount` or `unit_amount` must be specified!'
11
+ validates_absence_of :flat_amount, if: ->(tier) { tier.unit_amount.present? },
12
+ message: 'only one of `flat_amount` or `unit_amount` should be specified!'
13
+ validates_absence_of :unit_amount, if: ->(tier) { tier.flat_amount.present? },
14
+ message: 'only one of `flat_amount` or `unit_amount` should be specified!'
15
+
16
+ attr_accessor :up_to, :flat_amount, :unit_amount
17
+
18
+ def initialize(attrs)
19
+ @up_to = attrs[:up_to]
20
+ @flat_amount = attrs[:flat_amount]
21
+ @unit_amount = attrs[:unit_amount]
22
+ end
23
+
24
+ def to_h
25
+ {
26
+ up_to: up_to,
27
+ flat_amount: flat_amount,
28
+ unit_amount: unit_amount
29
+ }.compact
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -47,6 +47,7 @@ module Stripe
47
47
  callback 'invoice.created'
48
48
  callback 'invoice.finalized'
49
49
  callback 'invoice.marked_uncollectible'
50
+ callback 'invoice.paid'
50
51
  callback 'invoice.payment_action_required'
51
52
  callback 'invoice.payment_failed'
52
53
  callback 'invoice.payment_succeeded'
@@ -63,8 +64,10 @@ module Stripe
63
64
  callback 'order.updated'
64
65
  callback 'order_return.created'
65
66
  callback 'payment_intent.amount_capturable_updated'
67
+ callback 'payment_intent.canceled'
66
68
  callback 'payment_intent.created'
67
69
  callback 'payment_intent.payment_failed'
70
+ callback 'payment_intent.processing'
68
71
  callback 'payment_intent.succeeded'
69
72
  callback 'payment_method.attached'
70
73
  callback 'payment_method.card_automatically_updated'
@@ -8,7 +8,16 @@ module Stripe
8
8
  attr_accessor :testing
9
9
  end
10
10
 
11
- stripe_config = config.stripe = Struct.new(:api_base, :api_version, :secret_key, :verify_ssl_certs, :signing_secret, :publishable_key, :endpoint, :debug_js, :auto_mount, :eager_load, :open_timeout, :read_timeout).new
11
+ stripe_config = config.stripe = Struct.new(:api_base, :api_version, :secret_key, :verify_ssl_certs, :signing_secret, :signing_secrets, :publishable_key, :endpoint, :debug_js, :auto_mount, :eager_load, :open_timeout, :read_timeout) do
12
+ # for backwards compatibility treat signing_secret as an alias for signing_secrets
13
+ def signing_secret=(value)
14
+ self.signing_secrets = Array(value)
15
+ end
16
+
17
+ def signing_secret
18
+ self.signing_secrets && self.signing_secrets.first
19
+ end
20
+ end.new
12
21
 
13
22
  def stripe_config.api_key=(key)
14
23
  warn "[DEPRECATION] to align with stripe nomenclature, stripe.api_key has been renamed to config.stripe.secret_key"
@@ -12,16 +12,20 @@ module Stripe
12
12
  :interval,
13
13
  :interval_count,
14
14
  :metadata,
15
- :name,
15
+ :name,
16
16
  :nickname,
17
17
  :product_id,
18
18
  :statement_descriptor,
19
+ :tiers,
19
20
  :tiers_mode,
21
+ :transform_usage,
20
22
  :trial_period_days,
21
23
  :usage_type
22
24
 
23
- validates_presence_of :id, :amount, :currency
24
-
25
+ validates_presence_of :id, :currency
26
+ validates_presence_of :amount, unless: ->(p) { p.billing_scheme == 'tiered' }
27
+ validates_absence_of :transform_usage, if: ->(p) { p.billing_scheme == 'tiered' }
28
+ validates_presence_of :tiers_mode, if: ->(p) { p.billing_scheme == 'tiered' }
25
29
  validates_inclusion_of :interval,
26
30
  in: %w(day week month year),
27
31
  message: "'%{value}' is not one of 'day', 'week', 'month' or 'year'"
@@ -38,6 +42,11 @@ module Stripe
38
42
  validate :aggregate_usage_must_be_metered, if: ->(p) { p.aggregate_usage.present? }
39
43
  validate :valid_constant_name, unless: ->(p) { p.constant_name.nil? }
40
44
 
45
+ # validations for when using tiered billing
46
+ validate :tiers_must_be_array, if: ->(p) { p.tiers.present? }
47
+ validate :billing_scheme_must_be_tiered, if: ->(p) { p.tiers.present? }
48
+ validate :validate_tiers, if: ->(p) { p.billing_scheme == 'tiered' }
49
+
41
50
  def initialize(*args)
42
51
  super(*args)
43
52
  @currency = 'usd'
@@ -54,6 +63,22 @@ module Stripe
54
63
  errors.add(:base, 'must have a product_id or a name') unless (@product_id.present? ^ @name.present?)
55
64
  end
56
65
 
66
+ def billing_scheme_must_be_tiered
67
+ errors.add(:billing_scheme, 'must be set to `tiered` when specifying `tiers`') unless billing_scheme == 'tiered'
68
+ end
69
+
70
+ def tiers_must_be_array
71
+ errors.add(:tiers, 'must be an Array') unless tiers.is_a?(Array)
72
+ end
73
+
74
+ def billing_tiers
75
+ @billing_tiers = tiers.map { |t| Stripe::Plans::BillingTier.new(t) } if tiers
76
+ end
77
+
78
+ def validate_tiers
79
+ billing_tiers.all?(&:valid?)
80
+ end
81
+
57
82
  module ConstTester; end
58
83
  def valid_constant_name
59
84
  ConstTester.const_set(constant_name.to_s.upcase, constant_name)
@@ -82,8 +107,11 @@ module Stripe
82
107
  usage_type: usage_type,
83
108
  aggregate_usage: aggregate_usage,
84
109
  billing_scheme: billing_scheme,
85
- nickname: nickname
86
- }
110
+ nickname: nickname,
111
+ tiers: tiers ? tiers.map(&:to_h) : nil,
112
+ tiers_mode: tiers_mode,
113
+ transform_usage: transform_usage
114
+ }.compact
87
115
  end
88
116
 
89
117
  def product_options
@@ -11,6 +11,7 @@ module Stripe
11
11
  :caption,
12
12
  :metadata,
13
13
  :shippable,
14
+ :unit_label,
14
15
  :url,
15
16
  :statement_descriptor
16
17
 
@@ -42,6 +43,7 @@ module Stripe
42
43
  caption: caption,
43
44
  metadata: metadata,
44
45
  shippable: shippable,
46
+ unit_label: unit_label,
45
47
  url: url,
46
48
  statement_descriptor: statement_descriptor
47
49
  }