stripe-ruby-mock 3.1.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/rspec_tests.yml +7 -10
- data/CHANGELOG.md +24 -0
- data/Gemfile +0 -5
- data/README.md +3 -3
- data/bin/stripe-mock-server +1 -0
- data/lib/stripe_mock/api/client.rb +1 -1
- data/lib/stripe_mock/data.rb +53 -9
- data/lib/stripe_mock/instance.rb +4 -2
- data/lib/stripe_mock/request_handlers/charges.rb +20 -1
- data/lib/stripe_mock/request_handlers/checkout_session.rb +12 -11
- data/lib/stripe_mock/request_handlers/customers.rb +12 -1
- data/lib/stripe_mock/request_handlers/helpers/search_helpers.rb +67 -0
- data/lib/stripe_mock/request_handlers/invoices.rb +18 -3
- data/lib/stripe_mock/request_handlers/payment_intents.rb +11 -2
- data/lib/stripe_mock/request_handlers/payment_methods.rb +5 -1
- data/lib/stripe_mock/request_handlers/payouts.rb +10 -3
- data/lib/stripe_mock/request_handlers/prices.rb +13 -4
- data/lib/stripe_mock/request_handlers/products.rb +14 -5
- data/lib/stripe_mock/request_handlers/subscriptions.rb +11 -2
- data/lib/stripe_mock/request_handlers/tax_ids.rb +66 -0
- data/lib/stripe_mock/server.rb +9 -4
- data/lib/stripe_mock/test_strategies/base.rb +0 -1
- data/lib/stripe_mock/version.rb +1 -1
- data/lib/stripe_mock.rb +2 -0
- data/spec/shared_stripe_examples/bank_token_examples.rb +5 -7
- data/spec/shared_stripe_examples/charge_examples.rb +97 -0
- data/spec/shared_stripe_examples/checkout_session_examples.rb +0 -5
- data/spec/shared_stripe_examples/customer_examples.rb +56 -0
- data/spec/shared_stripe_examples/invoice_examples.rb +86 -1
- data/spec/shared_stripe_examples/payment_intent_examples.rb +75 -13
- data/spec/shared_stripe_examples/payment_method_examples.rb +10 -0
- data/spec/shared_stripe_examples/payout_examples.rb +26 -6
- data/spec/shared_stripe_examples/price_examples.rb +70 -1
- data/spec/shared_stripe_examples/product_examples.rb +71 -0
- data/spec/shared_stripe_examples/subscription_examples.rb +65 -6
- data/spec/spec_helper.rb +1 -1
- data/stripe-ruby-mock.gemspec +3 -3
- metadata +22 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 148628f00d214cfaa405f65529b1b8155da9475063166370b0b287084afcd0d4
|
4
|
+
data.tar.gz: ac5f7249f7a83d1fe2ac9f7a1eb4ff007465b404289f1f8bd60d277fe110d4d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8627e73ab695f6a0403d8438abb979a3b4b241d1b04419a2e82844225426dbd19a02eef3ac95a719f644ece575090e46f68b504ab83d5a865e46d1e14f353099
|
7
|
+
data.tar.gz: 9ea4b6e5b061a0d8342f4459fd558df25df4888bf713142e21263e73029411e6f226baa86eb6341de726891cb4245a34ef0c0d744e21b378d6afe0dcae64eda8
|
@@ -18,21 +18,18 @@ permissions:
|
|
18
18
|
|
19
19
|
jobs:
|
20
20
|
test:
|
21
|
-
|
22
21
|
runs-on: ubuntu-latest
|
23
22
|
strategy:
|
24
23
|
matrix:
|
25
|
-
ruby
|
26
|
-
|
24
|
+
ruby: ['3.1', '3.2', '3.3']
|
27
25
|
steps:
|
28
|
-
- uses: actions/checkout@
|
29
|
-
- name:
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
|
26
|
+
- uses: actions/checkout@v4
|
27
|
+
- name: Install Ruby and gems
|
28
|
+
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
29
|
+
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
30
|
+
uses: ruby/setup-ruby@v1
|
34
31
|
with:
|
35
|
-
ruby-version: ${{ matrix.ruby
|
32
|
+
ruby-version: ${{ matrix.ruby }}
|
36
33
|
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
37
34
|
- name: Run tests
|
38
35
|
run: bundle exec rspec
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,29 @@
|
|
1
1
|
### Unreleased
|
2
2
|
|
3
|
+
### 4.1.0 (2025-04-24)
|
4
|
+
- [#920](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/920) Adds DRB as a dependency in preparation to Ruby 3.4.0 [@lucascppessoa](https://github.com/lucascppessoa)
|
5
|
+
- [#927](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/927) Allow :cancel_url nil in create Checkout Session [@shu-illy](https://github.com/shu-illy)
|
6
|
+
- [#929](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/929) Actions uses only supported ruby versions [@alexmamonchik](https://github.com/alexmamonchik)
|
7
|
+
- [#925](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/925) Fix github actions and add missing product attributes [@bettysteger](https://github.com/bettysteger)
|
8
|
+
- [#928](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/928) Add tax ID endpoints and data [@lfittl](https://github.com/lfittl)
|
9
|
+
- [#835](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/835) Account: replace deprecated verification hash by requirements [@fabianoarruda](https://github.com/fabianoarruda)
|
10
|
+
- [#903](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/903) Add require option to require additional file [@stevenharman](https://github.com/stevenharman)
|
11
|
+
- [#904](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/904) Add has_more to Subscription.items data [@stevenharman](https://github.com/stevenharman)
|
12
|
+
- [#843](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/843) Some updates around subscriptions [@donnguyen](https://github.com/donnguyen)
|
13
|
+
- [#917](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/917) Removed charges on PI and added latest_charge [@espen](https://github.com/espen)
|
14
|
+
- [#916](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/916) Better tests for payout [@espen](https://github.com/espen)
|
15
|
+
- [#862](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/862) Add simple support for us bank accounts [@smtlaissezfaire](https://github.com/smtlaissezfaire)
|
16
|
+
- [#907](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/907) Fix calls to use raise instead of throw [@smtlaissezfaire](https://github.com/smtlaissezfaire)
|
17
|
+
- [#908](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/908) Add update_payout [@espen](https://github.com/espen)
|
18
|
+
|
19
|
+
### 4.0.0 (2024-08-07)
|
20
|
+
- [#905](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/905) Allow Stripe SDK v11 by [@stevenharman ](https://github.com/stevenharman)
|
21
|
+
- [#830](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/830) Implement search API by [@adamstegman](https://github.com/adamstegman)
|
22
|
+
- [#848](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/848) Extending runtime dependency on Stripe gem from version 5 through 11 by [@smakani](https://github.com/smakani)
|
23
|
+
- [#893](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/893) Adds support for stripe-ruby v10 by [@fabianoarruda](https://github.com/fabianoarruda)
|
24
|
+
|
25
|
+
|
26
|
+
### 3.1.0 (2024-01-03)
|
3
27
|
- [#693](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/693) gemspec: add change,issue,source_code URL by [@mtmail](https://github.com/mtmail)
|
4
28
|
- [#700](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/700) update the balance API to respond with instant_available by [@iamnader](https://github.com/iamnader)
|
5
29
|
- [#687](https://github.com/stripe-ruby-mock/stripe-ruby-mock/pull/687) Add PaymentIntent Webhooks by [@klaustopher](https://github.com/klaustopher)
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -12,7 +12,7 @@ This gem has unexpectedly grown in popularity and I've gotten pretty busy, so I'
|
|
12
12
|
|
13
13
|
In your gemfile:
|
14
14
|
|
15
|
-
gem 'stripe-ruby-mock',
|
15
|
+
gem 'stripe-ruby-mock', :require => 'stripe_mock'
|
16
16
|
|
17
17
|
## !!! Important
|
18
18
|
|
@@ -29,8 +29,8 @@ version `3.0.0` has [breaking changes](https://github.com/stripe-ruby-mock/strip
|
|
29
29
|
|
30
30
|
### Requirements
|
31
31
|
|
32
|
-
* ruby >= 2.
|
33
|
-
* stripe
|
32
|
+
* ruby >= 2.7.0
|
33
|
+
* stripe > 5 & < 11
|
34
34
|
|
35
35
|
### Specifications
|
36
36
|
|
data/bin/stripe-mock-server
CHANGED
@@ -11,6 +11,7 @@ opts = Trollop::options do
|
|
11
11
|
opt :server, "Server to use", :type => :string, :default => 'thin'
|
12
12
|
opt :debug, "Request and response output", :default => true
|
13
13
|
opt :pid_path, "Location to put server pid file", :type => :string, :default => './stripe-mock-server.pid'
|
14
|
+
opt :require, "Extra path to require when loading the server; can be specified multiple times", :type => :string, :multi => true
|
14
15
|
end
|
15
16
|
|
16
17
|
require 'stripe_mock'
|
@@ -27,7 +27,7 @@ module StripeMock
|
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
-
def self.redirect_to_mock_server(method, url, api_key: nil, api_base: nil, params: {}, headers: {})
|
30
|
+
def self.redirect_to_mock_server(method, url, api_key: nil, api_base: nil, usage: [], params: {}, headers: {})
|
31
31
|
handler = Instance.handler_for_method_url("#{method} #{url}")
|
32
32
|
|
33
33
|
if mock_error = client.error_queue.error_for_handler_name(handler[:name])
|
data/lib/stripe_mock/data.rb
CHANGED
@@ -34,10 +34,15 @@ module StripeMock
|
|
34
34
|
|
35
35
|
]
|
36
36
|
},
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
requirements: {
|
38
|
+
alternatives: [],
|
39
|
+
current_deadline: nil,
|
40
|
+
currently_due: [],
|
41
|
+
disabled_reason: nil,
|
42
|
+
errors: [],
|
43
|
+
eventually_due: [],
|
44
|
+
past_due: [],
|
45
|
+
pending_verification: []
|
41
46
|
},
|
42
47
|
transfer_schedule: {
|
43
48
|
delay_days: 7,
|
@@ -122,6 +127,25 @@ module StripeMock
|
|
122
127
|
}.merge(params)
|
123
128
|
end
|
124
129
|
|
130
|
+
def self.mock_tax_id(params)
|
131
|
+
{
|
132
|
+
id: 'test_cus_default',
|
133
|
+
object: 'tax_id',
|
134
|
+
country: 'DE',
|
135
|
+
created: 1559079603,
|
136
|
+
customer: nil,
|
137
|
+
livemode: false,
|
138
|
+
type: 'eu_vat',
|
139
|
+
value: 'DE123456789',
|
140
|
+
verification: nil,
|
141
|
+
owner: {
|
142
|
+
type: 'self',
|
143
|
+
customer: nil
|
144
|
+
},
|
145
|
+
metadata: {}
|
146
|
+
}.merge(params)
|
147
|
+
end
|
148
|
+
|
125
149
|
def self.mock_tax_rate(params)
|
126
150
|
{
|
127
151
|
id: 'test_cus_default',
|
@@ -382,7 +406,8 @@ module StripeMock
|
|
382
406
|
currency: StripeMock.default_currency
|
383
407
|
},
|
384
408
|
quantity: 1
|
385
|
-
}]
|
409
|
+
}],
|
410
|
+
has_more: false
|
386
411
|
},
|
387
412
|
cancel_at_period_end: false,
|
388
413
|
canceled_at: nil,
|
@@ -401,7 +426,12 @@ module StripeMock
|
|
401
426
|
default_payment_method: nil,
|
402
427
|
pending_invoice_item_interval: nil,
|
403
428
|
next_pending_invoice_item_invoice: nil,
|
404
|
-
|
429
|
+
pending_setup_intent: nil,
|
430
|
+
latest_invoice: nil,
|
431
|
+
application_fee_percent: nil,
|
432
|
+
cancel_at: nil,
|
433
|
+
end_at: nil,
|
434
|
+
pause_collection: nil
|
405
435
|
}, params)
|
406
436
|
end
|
407
437
|
|
@@ -642,15 +672,18 @@ module StripeMock
|
|
642
672
|
attributes:[],
|
643
673
|
caption: nil,
|
644
674
|
created: 1466698000,
|
675
|
+
default_price: nil,
|
645
676
|
deactivate_on: [],
|
646
677
|
description: nil,
|
647
678
|
images: [],
|
679
|
+
marketing_features: [],
|
648
680
|
livemode: false,
|
649
681
|
metadata: {},
|
650
682
|
name: "The Mock Product",
|
651
683
|
package_dimensions: nil,
|
652
684
|
shippable: nil,
|
653
685
|
statement_descriptor: nil,
|
686
|
+
tax_code: nil,
|
654
687
|
type: "service",
|
655
688
|
unit_label: "my_unit",
|
656
689
|
updated: 1537939442,
|
@@ -1221,7 +1254,8 @@ module StripeMock
|
|
1221
1254
|
statement_descriptor: nil,
|
1222
1255
|
trial_period_days: nil
|
1223
1256
|
},
|
1224
|
-
quantity: 2
|
1257
|
+
quantity: 2,
|
1258
|
+
price: mock_price
|
1225
1259
|
}.merge(params)
|
1226
1260
|
end
|
1227
1261
|
|
@@ -1336,7 +1370,17 @@ module StripeMock
|
|
1336
1370
|
country: 'DE',
|
1337
1371
|
fingerprint: 'FD81kbVPe7M05BMj',
|
1338
1372
|
last4: params.dig(:sepa_debit, :iban)&.[](-4..) || '3000'
|
1339
|
-
}
|
1373
|
+
},
|
1374
|
+
us_bank_account: {
|
1375
|
+
account_holder_type: "individual",
|
1376
|
+
account_type: "checking",
|
1377
|
+
bank_name: "STRIPE TEST BANK",
|
1378
|
+
financial_connections_account: "fca_0614042384b19afec4474940",
|
1379
|
+
fingerprint: "7bc48d016359a45a",
|
1380
|
+
last4: "6789",
|
1381
|
+
networks: {"preferred"=>"ach", "supported"=>["ach"]},
|
1382
|
+
routing_number: "110000000"
|
1383
|
+
},
|
1340
1384
|
}
|
1341
1385
|
|
1342
1386
|
{
|
@@ -1396,7 +1440,7 @@ module StripeMock
|
|
1396
1440
|
id: cs_id,
|
1397
1441
|
object: 'checkout.session',
|
1398
1442
|
billing_address_collection: nil,
|
1399
|
-
cancel_url:
|
1443
|
+
cancel_url: nil,
|
1400
1444
|
client_reference_id: nil,
|
1401
1445
|
customer: nil,
|
1402
1446
|
customer_email: nil,
|
data/lib/stripe_mock/instance.rb
CHANGED
@@ -52,6 +52,7 @@ module StripeMock
|
|
52
52
|
include StripeMock::RequestHandlers::CountrySpec
|
53
53
|
include StripeMock::RequestHandlers::Payouts
|
54
54
|
include StripeMock::RequestHandlers::EphemeralKey
|
55
|
+
include StripeMock::RequestHandlers::TaxIds
|
55
56
|
include StripeMock::RequestHandlers::TaxRates
|
56
57
|
include StripeMock::RequestHandlers::Checkout
|
57
58
|
include StripeMock::RequestHandlers::Checkout::Session
|
@@ -59,7 +60,7 @@ module StripeMock
|
|
59
60
|
attr_reader :accounts, :balance, :balance_transactions, :bank_tokens, :charges, :coupons, :customers,
|
60
61
|
:disputes, :events, :invoices, :invoice_items, :orders, :payment_intents, :payment_methods,
|
61
62
|
:setup_intents, :plans, :prices, :promotion_codes, :recipients, :refunds, :transfers, :payouts,
|
62
|
-
:subscriptions, :country_spec, :subscriptions_items, :products, :tax_rates, :checkout_sessions,
|
63
|
+
:subscriptions, :country_spec, :subscriptions_items, :products, :tax_ids, :tax_rates, :checkout_sessions,
|
63
64
|
:checkout_session_line_items
|
64
65
|
|
65
66
|
attr_accessor :error_queue, :debug, :conversion_rate, :account_balance
|
@@ -93,6 +94,7 @@ module StripeMock
|
|
93
94
|
@subscriptions = {}
|
94
95
|
@subscriptions_items = {}
|
95
96
|
@country_spec = {}
|
97
|
+
@tax_ids = {}
|
96
98
|
@tax_rates = {}
|
97
99
|
@checkout_sessions = {}
|
98
100
|
@checkout_session_line_items = {}
|
@@ -109,7 +111,7 @@ module StripeMock
|
|
109
111
|
@base_strategy = TestStrategies::Base.new
|
110
112
|
end
|
111
113
|
|
112
|
-
def mock_request(method, url, api_key: nil, api_base: nil, params: {}, headers: {})
|
114
|
+
def mock_request(method, url, api_key: nil, api_base: nil, usage: [], params: {}, headers: {})
|
113
115
|
return {} if method == :xtest
|
114
116
|
|
115
117
|
api_key ||= (Stripe.api_key || DUMMY_API_KEY)
|
@@ -5,7 +5,8 @@ module StripeMock
|
|
5
5
|
def Charges.included(klass)
|
6
6
|
klass.add_handler 'post /v1/charges', :new_charge
|
7
7
|
klass.add_handler 'get /v1/charges', :get_charges
|
8
|
-
klass.add_handler 'get /v1/charges/
|
8
|
+
klass.add_handler 'get /v1/charges/search', :search_charges
|
9
|
+
klass.add_handler 'get /v1/charges/((?!search).*)', :get_charge
|
9
10
|
klass.add_handler 'post /v1/charges/(.*)/capture', :capture_charge
|
10
11
|
klass.add_handler 'post /v1/charges/(.*)/refund', :refund_charge
|
11
12
|
klass.add_handler 'post /v1/charges/(.*)/refunds', :refund_charge
|
@@ -90,6 +91,24 @@ module StripeMock
|
|
90
91
|
Data.mock_list_object(clone.values, params)
|
91
92
|
end
|
92
93
|
|
94
|
+
SEARCH_FIELDS = [
|
95
|
+
"amount",
|
96
|
+
"currency",
|
97
|
+
"customer",
|
98
|
+
"payment_method_details.card.brand",
|
99
|
+
"payment_method_details.card.exp_month",
|
100
|
+
"payment_method_details.card.exp_year",
|
101
|
+
"payment_method_details.card.fingerprint",
|
102
|
+
"payment_method_details.card.last4",
|
103
|
+
"status",
|
104
|
+
].freeze
|
105
|
+
def search_charges(route, method_url, params, headers)
|
106
|
+
require_param(:query) unless params[:query]
|
107
|
+
|
108
|
+
results = search_results(charges.values, params[:query], fields: SEARCH_FIELDS, resource_name: "charges")
|
109
|
+
Data.mock_list_object(results, params)
|
110
|
+
end
|
111
|
+
|
93
112
|
def get_charge(route, method_url, params, headers)
|
94
113
|
route =~ method_url
|
95
114
|
charge_id = $1 || params[:charge]
|
@@ -12,16 +12,17 @@ module StripeMock
|
|
12
12
|
def new_session(route, method_url, params, headers)
|
13
13
|
id = params[:id] || new_id('cs')
|
14
14
|
|
15
|
-
|
16
|
-
require_param(p) if params[p].nil? || params[p].empty?
|
17
|
-
end
|
15
|
+
require_param(:success_url) if params[:success_url].nil? || params[:success_url].empty?
|
18
16
|
|
19
17
|
line_items = nil
|
20
18
|
if params[:line_items]
|
21
19
|
line_items = params[:line_items].each_with_index.map do |line_item, i|
|
22
|
-
|
20
|
+
unless line_item[:quantity]
|
21
|
+
raise Stripe::InvalidRequestError.new("Quantity is required. Add `quantity` to `line_items[#{i}]`", :line_items)
|
22
|
+
end
|
23
|
+
|
23
24
|
unless line_item[:price] || line_item[:price_data] || (line_item[:amount] && line_item[:currency] && line_item[:name])
|
24
|
-
|
25
|
+
raise Stripe::InvalidRequestError.new("Price or amount and currency is required. Add `price`, `price_data`, or `amount`, `currency` and `name` to `line_items[#{i}]`", :line_items)
|
25
26
|
end
|
26
27
|
{
|
27
28
|
id: new_id("li"),
|
@@ -48,11 +49,11 @@ module StripeMock
|
|
48
49
|
if line_items
|
49
50
|
amount = 0
|
50
51
|
|
51
|
-
line_items.each do |line_item|
|
52
|
+
line_items.each do |line_item|
|
52
53
|
price = prices[line_item[:price]]
|
53
54
|
|
54
55
|
if price.nil?
|
55
|
-
raise StripeMock::StripeMockError.new("Price not found for ID: #{line_item[:price]}")
|
56
|
+
raise StripeMock::StripeMockError.new("Price not found for ID: #{line_item[:price]}", :line_items)
|
56
57
|
end
|
57
58
|
|
58
59
|
amount += (price[:unit_amount] * line_item[:quantity])
|
@@ -78,7 +79,7 @@ module StripeMock
|
|
78
79
|
checkout_session_line_items[id] = line_items
|
79
80
|
when "setup"
|
80
81
|
if !params[:line_items].nil? && !params[:line_items].empty?
|
81
|
-
|
82
|
+
raise Stripe::InvalidRequestError.new("You cannot pass `line_items` in `setup` mode", :line_items, http_status: 400)
|
82
83
|
end
|
83
84
|
setup_intent = new_setup_intent(nil, nil, {
|
84
85
|
customer: params[:customer],
|
@@ -91,7 +92,7 @@ module StripeMock
|
|
91
92
|
require_param(:line_items) if params[:line_items].nil? || params[:line_items].empty?
|
92
93
|
checkout_session_line_items[id] = line_items
|
93
94
|
else
|
94
|
-
|
95
|
+
raise Stripe::InvalidRequestError.new("Invalid mode: must be one of payment, setup, or subscription", :mode, http_status: 400)
|
95
96
|
end
|
96
97
|
|
97
98
|
checkout_sessions[id] = {
|
@@ -156,7 +157,7 @@ module StripeMock
|
|
156
157
|
price = prices[line_item[:price]].clone
|
157
158
|
|
158
159
|
if price.nil?
|
159
|
-
raise StripeMock::StripeMockError.new("Price not found for ID: #{line_item[:price]}")
|
160
|
+
raise StripeMock::StripeMockError.new("Price not found for ID: #{line_item[:price]}", :line_items)
|
160
161
|
end
|
161
162
|
|
162
163
|
{
|
@@ -170,7 +171,7 @@ module StripeMock
|
|
170
171
|
}
|
171
172
|
end
|
172
173
|
else
|
173
|
-
|
174
|
+
raise Stripe::InvalidRequestError.new("Only payment and subscription sessions have line items", :line_items)
|
174
175
|
end
|
175
176
|
end
|
176
177
|
end
|
@@ -5,9 +5,10 @@ module StripeMock
|
|
5
5
|
def Customers.included(klass)
|
6
6
|
klass.add_handler 'post /v1/customers', :new_customer
|
7
7
|
klass.add_handler 'post /v1/customers/([^/]*)', :update_customer
|
8
|
-
klass.add_handler 'get /v1/customers/([^/]*)',
|
8
|
+
klass.add_handler 'get /v1/customers/((?!search)[^/]*)', :get_customer
|
9
9
|
klass.add_handler 'delete /v1/customers/([^/]*)', :delete_customer
|
10
10
|
klass.add_handler 'get /v1/customers', :list_customers
|
11
|
+
klass.add_handler 'get /v1/customers/search', :search_customers
|
11
12
|
klass.add_handler 'delete /v1/customers/([^/]*)/discount', :delete_customer_discount
|
12
13
|
end
|
13
14
|
|
@@ -140,6 +141,16 @@ module StripeMock
|
|
140
141
|
Data.mock_list_object(customers[stripe_account]&.values, params)
|
141
142
|
end
|
142
143
|
|
144
|
+
SEARCH_FIELDS = ["email", "name", "phone"].freeze
|
145
|
+
def search_customers(route, method_url, params, headers)
|
146
|
+
require_param(:query) unless params[:query]
|
147
|
+
|
148
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
149
|
+
all_customers = customers[stripe_account]&.values
|
150
|
+
results = search_results(all_customers, params[:query], fields: SEARCH_FIELDS, resource_name: "customers")
|
151
|
+
Data.mock_list_object(results, params)
|
152
|
+
end
|
153
|
+
|
143
154
|
def delete_customer_discount(route, method_url, params, headers)
|
144
155
|
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
145
156
|
route =~ method_url
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module Helpers
|
4
|
+
# Only supports exact matches on a single field, e.g.
|
5
|
+
# - 'amount:100'
|
6
|
+
# - 'email:"name@domain.com"'
|
7
|
+
# - 'name:"Foo Bar"'
|
8
|
+
# - 'metadata["foo"]:"bar"'
|
9
|
+
QUERYSTRING_PATTERN = /\A(?<field>[\w\.]+)(\[['"](?<metadata_key>[^'"]*)['"]\])?:['"]?(?<value>[^'"]*)['"]?\z/
|
10
|
+
def search_results(all_values, querystring, fields: [], resource_name:)
|
11
|
+
values = all_values.dup
|
12
|
+
query_match = QUERYSTRING_PATTERN.match(querystring)
|
13
|
+
raise Stripe::InvalidRequestError.new(
|
14
|
+
'We were unable to parse your search query.' \
|
15
|
+
' Try using the format `metadata["key"]:"value"` to query for metadata or key:"value" to query for other fields.',
|
16
|
+
nil,
|
17
|
+
http_status: 400,
|
18
|
+
) unless query_match
|
19
|
+
|
20
|
+
case query_match[:field]
|
21
|
+
when *fields
|
22
|
+
values = values.select { |resource|
|
23
|
+
exact_match?(actual: field_value(resource, field: query_match[:field]), expected: query_match[:value])
|
24
|
+
}
|
25
|
+
when "metadata"
|
26
|
+
values = values.select { |resource|
|
27
|
+
resource[:metadata] &&
|
28
|
+
exact_match?(actual: resource[:metadata][query_match[:metadata_key].to_sym], expected: query_match[:value])
|
29
|
+
}
|
30
|
+
else
|
31
|
+
raise Stripe::InvalidRequestError.new(
|
32
|
+
"Field `#{query_match[:field]}` is an unsupported search field for resource `#{resource_name}`." \
|
33
|
+
" See http://stripe.com/docs/search#query-fields-for-#{resource_name.gsub('_', '-')} for a list of supported fields.",
|
34
|
+
nil,
|
35
|
+
http_status: 400,
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
values
|
40
|
+
end
|
41
|
+
|
42
|
+
def exact_match?(actual:, expected:)
|
43
|
+
# allow comparisons of integers
|
44
|
+
if actual.respond_to?(:to_i) && actual.to_i == actual
|
45
|
+
expected = expected.to_i
|
46
|
+
end
|
47
|
+
# allow comparisons of boolean
|
48
|
+
case expected
|
49
|
+
when "true"
|
50
|
+
expected = true
|
51
|
+
when "false"
|
52
|
+
expected = false
|
53
|
+
end
|
54
|
+
|
55
|
+
actual == expected
|
56
|
+
end
|
57
|
+
|
58
|
+
def field_value(resource, field:)
|
59
|
+
value = resource
|
60
|
+
field.split('.').each do |segment|
|
61
|
+
value = value[segment.to_sym]
|
62
|
+
end
|
63
|
+
value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -6,7 +6,8 @@ module StripeMock
|
|
6
6
|
klass.add_handler 'post /v1/invoices', :new_invoice
|
7
7
|
klass.add_handler 'get /v1/invoices/upcoming', :upcoming_invoice
|
8
8
|
klass.add_handler 'get /v1/invoices/(.*)/lines', :get_invoice_line_items
|
9
|
-
klass.add_handler 'get /v1/invoices/(.*)',
|
9
|
+
klass.add_handler 'get /v1/invoices/((?!search).*)', :get_invoice
|
10
|
+
klass.add_handler 'get /v1/invoices/search', :search_invoices
|
10
11
|
klass.add_handler 'get /v1/invoices', :list_invoices
|
11
12
|
klass.add_handler 'post /v1/invoices/(.*)/pay', :pay_invoice
|
12
13
|
klass.add_handler 'post /v1/invoices/(.*)', :update_invoice
|
@@ -25,6 +26,14 @@ module StripeMock
|
|
25
26
|
invoices[$1].merge!(params)
|
26
27
|
end
|
27
28
|
|
29
|
+
SEARCH_FIELDS = ["currency", "customer", "number", "receipt_number", "subscription", "total"].freeze
|
30
|
+
def search_invoices(route, method_url, params, headers)
|
31
|
+
require_param(:query) unless params[:query]
|
32
|
+
|
33
|
+
results = search_results(invoices.values, params[:query], fields: SEARCH_FIELDS, resource_name: "invoices")
|
34
|
+
Data.mock_list_object(results, params)
|
35
|
+
end
|
36
|
+
|
28
37
|
def list_invoices(route, method_url, params, headers)
|
29
38
|
params[:offset] ||= 0
|
30
39
|
params[:limit] ||= 10
|
@@ -68,6 +77,9 @@ module StripeMock
|
|
68
77
|
raise Stripe::InvalidRequestError.new('When previewing changes to a subscription, you must specify either `subscription` or `subscription_items`', nil, http_status: 400) if !params[:subscription_proration_date].nil? && params[:subscription].nil? && params[:subscription_plan].nil?
|
69
78
|
raise Stripe::InvalidRequestError.new('Cannot specify proration date without specifying a subscription', nil, http_status: 400) if !params[:subscription_proration_date].nil? && params[:subscription].nil?
|
70
79
|
|
80
|
+
if params[:subscription] && params[:customer].nil?
|
81
|
+
params[:customer] = subscriptions[params[:subscription]][:customer]
|
82
|
+
end
|
71
83
|
customer = customers[stripe_account][params[:customer]]
|
72
84
|
assert_existence :customer, params[:customer], customer
|
73
85
|
|
@@ -105,8 +117,9 @@ module StripeMock
|
|
105
117
|
invoice_lines = []
|
106
118
|
|
107
119
|
if prorating
|
120
|
+
plan_amount = subscription[:plan][:amount] || subscription[:plan][:unit_amount]
|
108
121
|
unused_amount = (
|
109
|
-
|
122
|
+
plan_amount.to_f *
|
110
123
|
subscription[:quantity] *
|
111
124
|
(subscription[:current_period_end] - subscription_proration_date.to_i) / (subscription[:current_period_end] - subscription[:current_period_start])
|
112
125
|
).ceil
|
@@ -160,11 +173,13 @@ module StripeMock
|
|
160
173
|
private
|
161
174
|
|
162
175
|
def get_mock_subscription_line_item(subscription)
|
176
|
+
plan_amount = subscription[:plan][:amount] || subscription[:plan][:unit_amount]
|
177
|
+
|
163
178
|
Data.mock_line_item(
|
164
179
|
id: subscription[:id],
|
165
180
|
type: "subscription",
|
166
181
|
plan: subscription[:plan],
|
167
|
-
amount: subscription[:status] == 'trialing' ? 0 :
|
182
|
+
amount: subscription[:status] == 'trialing' ? 0 : plan_amount * subscription[:quantity],
|
168
183
|
discountable: true,
|
169
184
|
quantity: subscription[:quantity],
|
170
185
|
period: {
|
@@ -6,7 +6,8 @@ module StripeMock
|
|
6
6
|
def PaymentIntents.included(klass)
|
7
7
|
klass.add_handler 'post /v1/payment_intents', :new_payment_intent
|
8
8
|
klass.add_handler 'get /v1/payment_intents', :get_payment_intents
|
9
|
-
klass.add_handler 'get /v1/payment_intents/(.*)',
|
9
|
+
klass.add_handler 'get /v1/payment_intents/((?!search).*)', :get_payment_intent
|
10
|
+
klass.add_handler 'get /v1/payment_intents/search', :search_payment_intents
|
10
11
|
klass.add_handler 'post /v1/payment_intents/(.*)/confirm', :confirm_payment_intent
|
11
12
|
klass.add_handler 'post /v1/payment_intents/(.*)/capture', :capture_payment_intent
|
12
13
|
klass.add_handler 'post /v1/payment_intents/(.*)/cancel', :cancel_payment_intent
|
@@ -70,6 +71,14 @@ module StripeMock
|
|
70
71
|
payment_intent
|
71
72
|
end
|
72
73
|
|
74
|
+
SEARCH_FIELDS = ["amount", "currency", "customer", "status"].freeze
|
75
|
+
def search_payment_intents(route, method_url, params, headers)
|
76
|
+
require_param(:query) unless params[:query]
|
77
|
+
|
78
|
+
results = search_results(payment_intents.values, params[:query], fields: SEARCH_FIELDS, resource_name: "payment_intents")
|
79
|
+
Data.mock_list_object(results, params)
|
80
|
+
end
|
81
|
+
|
73
82
|
def capture_payment_intent(route, method_url, params, headers)
|
74
83
|
route =~ method_url
|
75
84
|
payment_intent = assert_existence :payment_intent, $1, payment_intents[$1]
|
@@ -184,7 +193,7 @@ module StripeMock
|
|
184
193
|
payment_method: payment_intent[:payment_method]
|
185
194
|
)
|
186
195
|
|
187
|
-
payment_intent[:
|
196
|
+
payment_intent[:latest_charge] = charge_id
|
188
197
|
|
189
198
|
payment_intent
|
190
199
|
end
|
@@ -116,8 +116,12 @@ module StripeMock
|
|
116
116
|
end
|
117
117
|
end
|
118
118
|
|
119
|
+
def valid_types
|
120
|
+
%w(card ideal sepa_debit us_bank_account)
|
121
|
+
end
|
122
|
+
|
119
123
|
def invalid_type?(type)
|
120
|
-
|
124
|
+
!valid_types.include?(type)
|
121
125
|
end
|
122
126
|
end
|
123
127
|
end
|
@@ -4,18 +4,25 @@ module StripeMock
|
|
4
4
|
|
5
5
|
def Payouts.included(klass)
|
6
6
|
klass.add_handler 'post /v1/payouts', :new_payout
|
7
|
+
klass.add_handler 'post /v1/payouts/(.*)', :update_payout
|
7
8
|
klass.add_handler 'get /v1/payouts', :list_payouts
|
8
9
|
klass.add_handler 'get /v1/payouts/(.*)', :get_payout
|
9
10
|
end
|
10
11
|
|
11
12
|
def new_payout(route, method_url, params, headers)
|
12
|
-
id
|
13
|
+
params[:id] ||= new_id("po")
|
13
14
|
|
14
|
-
unless params[:amount].is_a?(Integer) || (params[:amount].is_a?(String) && /^\d+$/.match(params[:amount]))
|
15
|
+
unless (params[:amount].is_a?(Integer) && params[:amount].positive?) || (params[:amount].is_a?(String) && /^\d+$/.match(params[:amount]))
|
15
16
|
raise Stripe::InvalidRequestError.new("Invalid integer: #{params[:amount]}", 'amount', http_status: 400)
|
16
17
|
end
|
17
18
|
|
18
|
-
payouts[id] = Data.mock_payout(params.merge :id => id)
|
19
|
+
payouts[params[:id]] = Data.mock_payout(params.merge :id => params[:id])
|
20
|
+
end
|
21
|
+
|
22
|
+
def update_payout(route, method_url, params, headers)
|
23
|
+
route =~ method_url
|
24
|
+
assert_existence :payout, $1, payouts[$1]
|
25
|
+
payouts[$1].merge!(params)
|
19
26
|
end
|
20
27
|
|
21
28
|
def list_payouts(route, method_url, params, headers)
|