stripe-ruby-mock 2.5.0 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/stripe_mock.rb +3 -0
  4. data/lib/stripe_mock/api/account_balance.rb +14 -0
  5. data/lib/stripe_mock/api/webhooks.rb +2 -0
  6. data/lib/stripe_mock/client.rb +4 -0
  7. data/lib/stripe_mock/data.rb +78 -3
  8. data/lib/stripe_mock/instance.rb +21 -4
  9. data/lib/stripe_mock/request_handlers/accounts.rb +18 -2
  10. data/lib/stripe_mock/request_handlers/balance.rb +17 -0
  11. data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +27 -6
  12. data/lib/stripe_mock/request_handlers/invoices.rb +20 -4
  13. data/lib/stripe_mock/request_handlers/payouts.rb +32 -0
  14. data/lib/stripe_mock/request_handlers/subscriptions.rb +65 -9
  15. data/lib/stripe_mock/request_handlers/tokens.rb +6 -0
  16. data/lib/stripe_mock/request_handlers/validators/param_validators.rb +7 -1
  17. data/lib/stripe_mock/server.rb +4 -0
  18. data/lib/stripe_mock/util.rb +8 -2
  19. data/lib/stripe_mock/version.rb +1 -1
  20. data/lib/stripe_mock/webhook_fixtures/account.updated.json +1 -1
  21. data/lib/stripe_mock/webhook_fixtures/charge.updated.json +58 -0
  22. data/lib/stripe_mock/webhook_fixtures/customer.subscription.created.json +40 -10
  23. data/lib/stripe_mock/webhook_fixtures/customer.subscription.deleted.json +39 -10
  24. data/lib/stripe_mock/webhook_fixtures/customer.subscription.trial_will_end.json +39 -10
  25. data/lib/stripe_mock/webhook_fixtures/customer.subscription.updated.json +39 -10
  26. data/lib/stripe_mock/webhook_fixtures/invoice.payment_succeeded.json +92 -85
  27. data/spec/shared_stripe_examples/account_examples.rb +8 -0
  28. data/spec/shared_stripe_examples/balance_examples.rb +11 -0
  29. data/spec/shared_stripe_examples/bank_examples.rb +27 -0
  30. data/spec/shared_stripe_examples/dispute_examples.rb +10 -0
  31. data/spec/shared_stripe_examples/invoice_examples.rb +68 -6
  32. data/spec/shared_stripe_examples/payout_examples.rb +68 -0
  33. data/spec/shared_stripe_examples/plan_examples.rb +7 -1
  34. data/spec/shared_stripe_examples/subscription_examples.rb +132 -2
  35. data/spec/shared_stripe_examples/webhook_event_examples.rb +69 -0
  36. data/spec/support/stripe_examples.rb +2 -0
  37. data/spec/util_spec.rb +35 -1
  38. metadata +10 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ce6d1ae38721fc9f43fa69e3d82217593b0789d9
4
- data.tar.gz: abbbfb0dd70438e23ac276215602a3d3a77705b1
3
+ metadata.gz: 27d9481d4fc8140fc2d42f733fc529fbb7a121cf
4
+ data.tar.gz: a8eeabea5e8b7d9181f597b9968e6e98b8fba4ed
5
5
  SHA512:
6
- metadata.gz: 49d92a3efee46c78cd157fd84de5e8eb456b6686b06c00a23262648395b0dd2cb647620304de703e52e5919102ce6c782a4947b50c39aef90428a02af9cfe9b0
7
- data.tar.gz: c87d09dd495bdca773e0ea39169f04900e7467f315f220ca556d907e9c0f294ddad399a73c2765e27e9ebe319b42f1b68b9ef825a02707c4877096777154a8c4
6
+ metadata.gz: b089c35e1b06284105b79baa151a5c61ebf54ec1e405406e3d0f827964c9e30f6e33b02a92dfc11ee83ec4a0e71a8a7fa35448c9a859476481bbbff2f60d15a1
7
+ data.tar.gz: e913cc264d89d765911c9de0066cc57a819f5235b3a2fb4d6266f7dd5561669e3ebe45e12faa5be8e12a74cc4a67ed51ca6adc2064bdcc02b1394dc5cf298899
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', '~> 2.5.0', :require => 'stripe_mock'
15
+ gem 'stripe-ruby-mock', '~> 2.5.1', :require => 'stripe_mock'
16
16
 
17
17
  ## Features
18
18
 
@@ -26,6 +26,7 @@ require 'stripe_mock/api/client'
26
26
  require 'stripe_mock/api/server'
27
27
 
28
28
  require 'stripe_mock/api/bank_tokens'
29
+ require 'stripe_mock/api/account_balance'
29
30
  require 'stripe_mock/api/conversion_rate'
30
31
  require 'stripe_mock/api/card_tokens'
31
32
  require 'stripe_mock/api/debug'
@@ -45,6 +46,7 @@ require 'stripe_mock/request_handlers/helpers/token_helpers.rb'
45
46
  require 'stripe_mock/request_handlers/validators/param_validators.rb'
46
47
 
47
48
  require 'stripe_mock/request_handlers/accounts.rb'
49
+ require 'stripe_mock/request_handlers/balance.rb'
48
50
  require 'stripe_mock/request_handlers/balance_transactions.rb'
49
51
  require 'stripe_mock/request_handlers/charges.rb'
50
52
  require 'stripe_mock/request_handlers/cards.rb'
@@ -60,6 +62,7 @@ require 'stripe_mock/request_handlers/plans.rb'
60
62
  require 'stripe_mock/request_handlers/recipients.rb'
61
63
  require 'stripe_mock/request_handlers/refunds.rb'
62
64
  require 'stripe_mock/request_handlers/transfers.rb'
65
+ require 'stripe_mock/request_handlers/payouts.rb'
63
66
  require 'stripe_mock/request_handlers/subscriptions.rb'
64
67
  require 'stripe_mock/request_handlers/tokens.rb'
65
68
  require 'stripe_mock/request_handlers/country_spec.rb'
@@ -0,0 +1,14 @@
1
+ module StripeMock
2
+
3
+ def self.set_account_balance(value)
4
+ case @state
5
+ when 'local'
6
+ instance.account_balance = value
7
+ when 'remote'
8
+ client.set_account_balance(value)
9
+ else
10
+ raise UnstartedStateError
11
+ end
12
+ end
13
+
14
+ end
@@ -18,6 +18,7 @@ module StripeMock
18
18
  json[:account] = params.delete(:account) if params.key?(:account)
19
19
  json[:data][:object] = Util.rmerge(json[:data][:object], params)
20
20
  json.delete(:id)
21
+ json[:created] = params[:created] || Time.now.to_i
21
22
 
22
23
  if @state == 'local'
23
24
  event_data = instance.generate_webhook_event(json)
@@ -43,6 +44,7 @@ module StripeMock
43
44
  'account.external_account.deleted',
44
45
  'balance.available',
45
46
  'charge.succeeded',
47
+ 'charge.updated',
46
48
  'charge.failed',
47
49
  'charge.refunded',
48
50
  'charge.dispute.created',
@@ -73,6 +73,10 @@ module StripeMock
73
73
  timeout_wrap { @pipe.set_conversion_rate(value) }
74
74
  end
75
75
 
76
+ def set_account_balance(value)
77
+ timeout_wrap { @pipe.set_account_balance(value) }
78
+ end
79
+
76
80
  def destroy_resource(type, id)
77
81
  timeout_wrap { @pipe.destroy_resource(type, id) }
78
82
  end
@@ -12,7 +12,7 @@ module StripeMock
12
12
  timezone: "US/Pacific",
13
13
  details_submitted: false,
14
14
  charges_enabled: false,
15
- transfers_enabled: false,
15
+ payouts_enabled: false,
16
16
  currencies_supported: [
17
17
  "usd"
18
18
  ],
@@ -103,7 +103,7 @@ module StripeMock
103
103
 
104
104
  def self.mock_customer(sources, params)
105
105
  cus_id = params[:id] || "test_cus_default"
106
- currency = params[:currency] || nil
106
+ currency = params[:currency] || 'usd'
107
107
  sources.each {|source| source[:customer] = cus_id}
108
108
  {
109
109
  email: 'stripe_mock@example.com',
@@ -207,7 +207,8 @@ module StripeMock
207
207
  metadata: {},
208
208
  charge: "ch_4fWhYjzQ23UFWT",
209
209
  receipt_number: nil,
210
- status: "succeeded"
210
+ status: "succeeded",
211
+ reason: "requested_by_customer"
211
212
  }.merge(params)
212
213
  end
213
214
 
@@ -284,6 +285,7 @@ module StripeMock
284
285
  def self.mock_subscription(params={})
285
286
  StripeMock::Util.rmerge({
286
287
  created: 1478204116,
288
+ billing: 'charge_automatically',
287
289
  current_period_start: 1308595038,
288
290
  current_period_end: 1308681468,
289
291
  status: 'trialing',
@@ -620,6 +622,21 @@ module StripeMock
620
622
  }.merge(params)
621
623
  end
622
624
 
625
+ def self.mock_payout(params={})
626
+ currency = params[:currency] || 'usd'
627
+ id = params[:id] || 'po_test_payout'
628
+ {
629
+ :amount => 100,
630
+ :id => id,
631
+ :livemode => false,
632
+ :metadata => {},
633
+ :currency => currency,
634
+ :object => "payout",
635
+ :date => 1304114826,
636
+ :description => "Payout description",
637
+ }.merge(params)
638
+ end
639
+
623
640
  def self.mock_disputes(ids=[])
624
641
  disputes = {}
625
642
  ids.each do |id|
@@ -909,6 +926,38 @@ module StripeMock
909
926
  }
910
927
  end
911
928
 
929
+ def self.mock_balance(usd_balance = 10000)
930
+ {
931
+ object: "balance",
932
+ available: [
933
+ {
934
+ currency: "usd",
935
+ amount: usd_balance,
936
+ source_types: {
937
+ card: 25907032203,
938
+ bank_account: 108476658,
939
+ bitcoin_receiver: 1545182
940
+ }
941
+ }],
942
+ connect_reserved: [
943
+ {
944
+ currency: "usd",
945
+ amount: 4700
946
+ }],
947
+ livemode: false,
948
+ pending: [
949
+ {
950
+ currency: "usd",
951
+ amount: 22738833554,
952
+ source_types: {
953
+ card: 22738826610,
954
+ bank_account: 0,
955
+ bitcoin_receiver: 6944
956
+ }
957
+ }]
958
+ }
959
+ end
960
+
912
961
  def self.mock_balance_transactions(ids=[])
913
962
  bts = {}
914
963
  ids.each do |id|
@@ -952,5 +1001,31 @@ module StripeMock
952
1001
  type: "charge"
953
1002
  }.merge(params)
954
1003
  end
1004
+
1005
+ def self.mock_subscription_item(params = {})
1006
+ iid = params[:id] || 'test_txn_default'
1007
+ {
1008
+ id: iid,
1009
+ object: 'subscription_item',
1010
+ created: 1504716183,
1011
+ metadata: {
1012
+ },
1013
+ plan: {
1014
+ id: 'PER_USER_PLAN1',
1015
+ object: 'plan',
1016
+ amount: 1337,
1017
+ created: 1504716177,
1018
+ currency: 'usd',
1019
+ interval: 'month',
1020
+ interval_count: 1,
1021
+ livemode: false,
1022
+ metadata: {},
1023
+ name: 'StripeMock Default Plan ID',
1024
+ statement_descriptor: nil,
1025
+ trial_period_days: nil
1026
+ },
1027
+ quantity: 2
1028
+ }.merge(params)
1029
+ end
955
1030
  end
956
1031
  end
@@ -21,6 +21,7 @@ module StripeMock
21
21
  end
22
22
 
23
23
  include StripeMock::RequestHandlers::Accounts
24
+ include StripeMock::RequestHandlers::Balance
24
25
  include StripeMock::RequestHandlers::BalanceTransactions
25
26
  include StripeMock::RequestHandlers::Charges
26
27
  include StripeMock::RequestHandlers::Cards
@@ -39,16 +40,17 @@ module StripeMock
39
40
  include StripeMock::RequestHandlers::Transfers
40
41
  include StripeMock::RequestHandlers::Tokens
41
42
  include StripeMock::RequestHandlers::CountrySpec
43
+ include StripeMock::RequestHandlers::Payouts
42
44
 
43
-
44
- attr_reader :accounts, :balance_transactions, :bank_tokens, :charges, :coupons, :customers,
45
+ attr_reader :accounts, :balance, :balance_transactions, :bank_tokens, :charges, :coupons, :customers,
45
46
  :disputes, :events, :invoices, :invoice_items, :orders, :plans, :recipients,
46
- :refunds, :transfers, :subscriptions, :country_spec
47
+ :refunds, :transfers, :payouts, :subscriptions, :country_spec, :subscriptions_items
47
48
 
48
- attr_accessor :error_queue, :debug, :conversion_rate
49
+ attr_accessor :error_queue, :debug, :conversion_rate, :account_balance
49
50
 
50
51
  def initialize
51
52
  @accounts = {}
53
+ @balance = Data.mock_balance
52
54
  @balance_transactions = Data.mock_balance_transactions(['txn_05RsQX2eZvKYlo2C0FRTGSSA','txn_15RsQX2eZvKYlo2C0ERTYUIA', 'txn_25RsQX2eZvKYlo2C0ZXCVBNM', 'txn_35RsQX2eZvKYlo2C0QAZXSWE', 'txn_45RsQX2eZvKYlo2C0EDCVFRT', 'txn_55RsQX2eZvKYlo2C0OIKLJUY', 'txn_65RsQX2eZvKYlo2C0ASDFGHJ', 'txn_75RsQX2eZvKYlo2C0EDCXSWQ', 'txn_85RsQX2eZvKYlo2C0UJMCDET', 'txn_95RsQX2eZvKYlo2C0EDFRYUI'])
53
55
  @bank_tokens = {}
54
56
  @card_tokens = {}
@@ -64,14 +66,18 @@ module StripeMock
64
66
  @recipients = {}
65
67
  @refunds = {}
66
68
  @transfers = {}
69
+ @payouts = {}
67
70
  @subscriptions = {}
71
+ @subscriptions_items = []
68
72
  @country_spec = {}
69
73
 
70
74
  @debug = false
71
75
  @error_queue = ErrorQueue.new
72
76
  @id_counter = 0
73
77
  @balance_transaction_counter = 0
78
+ @dispute_counter = 0
74
79
  @conversion_rate = 1.0
80
+ @account_balance = 10000
75
81
 
76
82
  # This is basically a cache for ParamValidators
77
83
  @base_strategy = TestStrategies::Base.new
@@ -125,6 +131,8 @@ module StripeMock
125
131
  case object
126
132
  when :balance_transaction
127
133
  id = new_balance_transaction('txn', attributes)
134
+ when :dispute
135
+ id = new_dispute('dp', attributes)
128
136
  else
129
137
  raise UnsupportedRequestError.new "Unsupported stripe object `#{object}`"
130
138
  end
@@ -134,6 +142,9 @@ module StripeMock
134
142
  when :balance_transaction
135
143
  btxn = assert_existence :balance_transaction, id, @balance_transactions[id]
136
144
  btxn.merge!(attributes)
145
+ when :dispute
146
+ dispute = assert_existence :dispute, id, @disputes[id]
147
+ dispute.merge!(attributes)
137
148
  else
138
149
  raise UnsupportedRequestError.new "Unsupported stripe object `#{object}`"
139
150
  end
@@ -169,6 +180,12 @@ module StripeMock
169
180
  id
170
181
  end
171
182
 
183
+ def new_dispute(prefix, params = {})
184
+ id = "#{StripeMock.global_id_prefix}#{prefix}_#{@dispute_counter += 1}"
185
+ @disputes[id] = Data.mock_dispute(params.merge(id: id))
186
+ id
187
+ end
188
+
172
189
  def symbolize_names(hash)
173
190
  Stripe::Util.symbolize_names(hash)
174
191
  end
@@ -26,8 +26,12 @@ module StripeMock
26
26
 
27
27
  def update_account(route, method_url, params, headers)
28
28
  route =~ method_url
29
- assert_existence :account, $1, accounts[$1]
30
- accounts[$1].merge!(params)
29
+ account = assert_existence :account, $1, accounts[$1]
30
+ account.merge!(params)
31
+ if blank_value?(params[:tos_acceptance], :date)
32
+ raise Stripe::InvalidRequestError.new("Invalid integer: ", "tos_acceptance[date]", http_status: 400)
33
+ end
34
+ account
31
35
  end
32
36
 
33
37
  def list_accounts(route, method_url, params, headers)
@@ -49,6 +53,18 @@ module StripeMock
49
53
  accounts[acc[:id]] = acc
50
54
  end
51
55
  end
56
+
57
+ # Checks if setting a blank value
58
+ #
59
+ # returns true if the key is included in the hash
60
+ # and its value is empty or nil
61
+ def blank_value?(hash, key)
62
+ if hash.key?(key)
63
+ value = hash[key]
64
+ return true if value.nil? || "" == value
65
+ end
66
+ false
67
+ end
52
68
  end
53
69
  end
54
70
  end
@@ -0,0 +1,17 @@
1
+ module StripeMock
2
+ module RequestHandlers
3
+ module Balance
4
+
5
+ def Balance.included(klass)
6
+ klass.add_handler 'get /v1/balance', :get_balance
7
+ end
8
+
9
+ def get_balance(route, method_url, params, headers)
10
+ route =~ method_url
11
+
12
+ return_balance = Data.mock_balance(account_balance)
13
+ return_balance
14
+ end
15
+ end
16
+ end
17
+ end
@@ -9,12 +9,14 @@ module StripeMock
9
9
  def custom_subscription_params(plan, cus, options = {})
10
10
  verify_trial_end(options[:trial_end]) if options[:trial_end]
11
11
 
12
- start_time = options[:current_period_start] || Time.now.utc.to_i
13
- params = { plan: plan, customer: cus[:id], current_period_start: start_time }
12
+ now = Time.now.utc.to_i
13
+ created_time = options[:created] || now
14
+ start_time = options[:current_period_start] || now
15
+ params = { plan: plan, customer: cus[:id], current_period_start: start_time, created: created_time }
14
16
  params.merge! options.select {|k,v| k =~ /application_fee_percent|quantity|metadata|tax_percent/}
15
17
  # TODO: Implement coupon logic
16
18
 
17
- if ((plan[:trial_period_days]||0) == 0 && options[:trial_end].nil?) || options[:trial_end] == "now"
19
+ if (((plan && plan[:trial_period_days]) || 0) == 0 && options[:trial_end].nil?) || options[:trial_end] == "now"
18
20
  end_time = get_ending_time(start_time, plan)
19
21
  params.merge!({status: 'active', current_period_end: end_time, trial_start: nil, trial_end: nil})
20
22
  else
@@ -28,12 +30,16 @@ module StripeMock
28
30
  def add_subscription_to_customer(cus, sub)
29
31
  if sub[:trial_end].nil? || sub[:trial_end] == "now"
30
32
  id = new_id('ch')
31
- charges[id] = Data.mock_charge(:id => id, :customer => cus[:id], :amount => sub[:plan][:amount])
33
+ charges[id] = Data.mock_charge(
34
+ :id => id,
35
+ :customer => cus[:id],
36
+ :amount => (sub[:plan] ? sub[:plan][:amount] : total_items_amount(sub[:items][:data]))
37
+ )
32
38
  end
33
39
 
34
40
  if cus[:currency].nil?
35
- cus[:currency] = sub[:plan][:currency]
36
- elsif cus[:currency] != sub[:plan][:currency]
41
+ cus[:currency] = sub[:items][:data][0][:plan][:currency]
42
+ elsif cus[:currency] != sub[:items][:data][0][:plan][:currency]
37
43
  raise Stripe::InvalidRequestError.new( "Can't combine currencies on a single customer. This customer has had a subscription, coupon, or invoice item with currency #{cus[:currency]}", 'currency', http_status: 400)
38
44
  end
39
45
  cus[:subscriptions][:total_count] = (cus[:subscriptions][:total_count] || 0) + 1
@@ -50,6 +56,8 @@ module StripeMock
50
56
  # `intervals` is set to 1 when calculating current_period_end from current_period_start & plan
51
57
  # `intervals` is set to 2 when calculating Stripe::Invoice.upcoming end from current_period_start & plan
52
58
  def get_ending_time(start_time, plan, intervals = 1)
59
+ return start_time unless plan
60
+
53
61
  case plan[:interval]
54
62
  when "week"
55
63
  start_time + (604800 * (plan[:interval_count] || 1) * intervals)
@@ -74,6 +82,19 @@ module StripeMock
74
82
  end
75
83
  end
76
84
 
85
+ def total_items_amount(items)
86
+ total = 0
87
+ items.each { |i| total += (i[:quantity] || 1) * i[:plan][:amount] }
88
+ total
89
+ end
90
+
91
+ def mock_subscription_items(items = [])
92
+ data = []
93
+ items.each do |i|
94
+ data << Data.mock_subscription_item(i.merge(plan: plans[i[:plan].to_s]))
95
+ end
96
+ data
97
+ end
77
98
  end
78
99
  end
79
100
  end
@@ -73,7 +73,7 @@ module StripeMock
73
73
  else
74
74
  customer[:subscriptions][:data].min_by { |sub| sub[:current_period_end] }
75
75
  end
76
-
76
+
77
77
  if params[:subscription_proration_date] && !((subscription[:current_period_start]..subscription[:current_period_end]) === params[:subscription_proration_date])
78
78
  raise Stripe::InvalidRequestError.new('Cannot specify proration date outside of current subscription period', nil, http_status: 400)
79
79
  end
@@ -112,14 +112,30 @@ module StripeMock
112
112
  quantity: subscription[:quantity],
113
113
  proration: true
114
114
  )
115
+
116
+ preview_plan = assert_existence :plan, params[:subscription_plan], plans[params[:subscription_plan]]
117
+ if preview_plan[:interval] == subscription[:plan][:interval] && preview_plan[:interval_count] == subscription[:plan][:interval_count] && params[:subscription_trial_end].nil?
118
+ remaining_amount = preview_plan[:amount] * subscription_quantity * (subscription[:current_period_end] - subscription_proration_date.to_i) / (subscription[:current_period_end] - subscription[:current_period_start])
119
+ invoice_lines << Data.mock_line_item(
120
+ id: new_id('ii'),
121
+ amount: remaining_amount,
122
+ description: 'Remaining time',
123
+ plan: preview_plan,
124
+ period: {
125
+ start: subscription_proration_date.to_i,
126
+ end: subscription[:current_period_end]
127
+ },
128
+ quantity: subscription_quantity,
129
+ proration: true
130
+ )
131
+ end
115
132
  end
116
133
 
117
134
  subscription_line = get_mock_subscription_line_item(preview_subscription)
118
135
  invoice_lines << subscription_line
119
136
 
120
- id = new_id('in')
121
- invoices[id] = Data.mock_invoice(invoice_lines,
122
- id: id,
137
+ Data.mock_invoice(invoice_lines,
138
+ id: new_id('in'),
123
139
  customer: customer[:id],
124
140
  discount: customer[:discount],
125
141
  date: invoice_date,